From 976459d3e8a8b889cebc2cf281e38b0fbc19c9b9 Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Tue, 17 Dec 2019 23:15:02 +0100 Subject: Rewrite WebSocket handling code --- MediaBrowser.Controller/IServerApplicationHost.cs | 2 - .../Net/BasePeriodicWebSocketListener.cs | 1 - MediaBrowser.Controller/Net/IHttpServer.cs | 22 +----- .../Net/IWebSocketConnection.cs | 28 ++------ .../Session/ISessionController.cs | 3 +- MediaBrowser.Controller/Session/SessionInfo.cs | 80 +++++++--------------- 6 files changed, 32 insertions(+), 104 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/IServerApplicationHost.cs b/MediaBrowser.Controller/IServerApplicationHost.cs index 25f0905eb..0790b6cd6 100644 --- a/MediaBrowser.Controller/IServerApplicationHost.cs +++ b/MediaBrowser.Controller/IServerApplicationHost.cs @@ -92,7 +92,5 @@ namespace MediaBrowser.Controller string ReverseVirtualPath(string path); Task ExecuteHttpHandlerAsync(HttpContext context, Func next); - - Task ExecuteWebsocketHandlerAsync(HttpContext context, Func next); } } diff --git a/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs b/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs index ee5c1a165..9d71426d8 100644 --- a/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs +++ b/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs @@ -154,7 +154,6 @@ namespace MediaBrowser.Controller.Net { MessageType = Name, Data = data - }, cancellationToken).ConfigureAwait(false); state.DateLastSendUtc = DateTime.UtcNow; diff --git a/MediaBrowser.Controller/Net/IHttpServer.cs b/MediaBrowser.Controller/Net/IHttpServer.cs index 46933c046..694e3954e 100644 --- a/MediaBrowser.Controller/Net/IHttpServer.cs +++ b/MediaBrowser.Controller/Net/IHttpServer.cs @@ -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; @@ -19,11 +18,6 @@ namespace MediaBrowser.Controller.Net /// The URL prefix. string[] UrlPrefixes { get; } - /// - /// Stops this instance. - /// - void Stop(); - /// /// Occurs when [web socket connected]. /// @@ -39,23 +33,11 @@ namespace MediaBrowser.Controller.Net /// string GlobalResponse { get; set; } - /// - /// Sends the http context to the socket listener - /// - /// - /// - Task ProcessWebSocketRequest(HttpContext ctx); - /// /// The HTTP request handler /// - /// - /// - /// - /// - /// + /// /// - Task RequestHandler(IHttpRequest httpReq, string urlString, string host, string localPath, - CancellationToken cancellationToken); + Task RequestHandler(HttpContext context); } } diff --git a/MediaBrowser.Controller/Net/IWebSocketConnection.cs b/MediaBrowser.Controller/Net/IWebSocketConnection.cs index 566897b31..e2a714d5b 100644 --- a/MediaBrowser.Controller/Net/IWebSocketConnection.cs +++ b/MediaBrowser.Controller/Net/IWebSocketConnection.cs @@ -1,9 +1,9 @@ using System; +using System.Net; using System.Net.WebSockets; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Model.Net; -using MediaBrowser.Model.Services; using Microsoft.AspNetCore.Http; namespace MediaBrowser.Controller.Net @@ -15,12 +15,6 @@ namespace MediaBrowser.Controller.Net /// event EventHandler Closed; - /// - /// Gets the id. - /// - /// The id. - Guid Id { get; } - /// /// Gets the last activity date. /// @@ -32,6 +26,7 @@ namespace MediaBrowser.Controller.Net /// /// The URL. string Url { get; set; } + /// /// Gets or sets the query string. /// @@ -54,7 +49,7 @@ namespace MediaBrowser.Controller.Net /// Gets the remote end point. /// /// The remote end point. - string RemoteEndPoint { get; } + IPAddress RemoteEndPoint { get; } /// /// Sends a message asynchronously. @@ -66,21 +61,6 @@ namespace MediaBrowser.Controller.Net /// message Task SendAsync(WebSocketMessage message, CancellationToken cancellationToken); - /// - /// Sends a message asynchronously. - /// - /// The buffer. - /// The cancellation token. - /// Task. - Task SendAsync(byte[] buffer, CancellationToken cancellationToken); - - /// - /// Sends a message asynchronously. - /// - /// The text. - /// The cancellation token. - /// Task. - /// buffer - Task SendAsync(string text, CancellationToken cancellationToken); + Task ProcessAsync(CancellationToken cancellationToken = default); } } diff --git a/MediaBrowser.Controller/Session/ISessionController.cs b/MediaBrowser.Controller/Session/ISessionController.cs index a59c96ac7..04450085b 100644 --- a/MediaBrowser.Controller/Session/ISessionController.cs +++ b/MediaBrowser.Controller/Session/ISessionController.cs @@ -1,3 +1,4 @@ +using System; using System.Threading; using System.Threading.Tasks; @@ -20,6 +21,6 @@ namespace MediaBrowser.Controller.Session /// /// Sends the message. /// - Task SendMessage(string name, string messageId, T data, ISessionController[] allControllers, CancellationToken cancellationToken); + Task SendMessage(string name, Guid messageId, T data, CancellationToken cancellationToken); } } diff --git a/MediaBrowser.Controller/Session/SessionInfo.cs b/MediaBrowser.Controller/Session/SessionInfo.cs index acda6a416..63ed43a83 100644 --- a/MediaBrowser.Controller/Session/SessionInfo.cs +++ b/MediaBrowser.Controller/Session/SessionInfo.cs @@ -10,13 +10,23 @@ using Microsoft.Extensions.Logging; namespace MediaBrowser.Controller.Session { /// - /// Class SessionInfo + /// Class SessionInfo. /// - 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 /// The name of the device. public string DeviceName { get; set; } - public string DeviceType { get; set; } - /// /// Gets or sets the now playing item. /// @@ -126,28 +134,6 @@ namespace MediaBrowser.Controller.Session [JsonIgnore] public ISessionController[] SessionControllers { get; set; } - /// - /// Gets or sets the application icon URL. - /// - /// The application icon URL. - public string AppIconUrl { get; set; } - - /// - /// Gets or sets the supported commands. - /// - /// The supported commands. - public string[] SupportedCommands - { - get - { - if (Capabilities == null) - { - return new string[] { }; - } - return Capabilities.SupportedCommands; - } - } - public TranscodingInfo TranscodingInfo { get; set; } /// @@ -219,6 +205,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 EnsureController(Func factory) { var controllers = SessionControllers.ToList(); @@ -267,10 +261,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) @@ -293,9 +283,6 @@ namespace MediaBrowser.Controller.Session } } - // 1 second - private const long ProgressIncrement = 10000000; - private async void OnProgressTimerCallback(object state) { if (_disposed) @@ -354,8 +341,7 @@ namespace MediaBrowser.Controller.Session } } - private bool _disposed = false; - + /// public void Dispose() { _disposed = true; @@ -367,30 +353,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; } } } -- cgit v1.2.3 From 5ca68f9623e414b85ddbda1f97895f1b90bd05e0 Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Thu, 26 Dec 2019 20:57:46 +0100 Subject: Fix nullref exception and added logging --- .../HttpServer/HttpListenerHost.cs | 17 +++--- .../HttpServer/WebSocketConnection.cs | 63 ++++++++-------------- .../Session/SessionManager.cs | 3 +- .../Session/SessionWebSocketListener.cs | 2 +- .../Session/WebSocketController.cs | 5 +- .../Net/IWebSocketConnection.cs | 16 +++--- 6 files changed, 41 insertions(+), 65 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs index 4baf96ab5..ebae4d0b1 100644 --- a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs +++ b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs @@ -518,30 +518,29 @@ namespace Emby.Server.Implementations.HttpServer return; } - var url = context.Request.GetDisplayUrl(); - _logger.LogInformation("WS {Url}. UserAgent: {UserAgent}", url, context.Request.Headers[HeaderNames.UserAgent].ToString()); - try { - var webSocket = await context.WebSockets.AcceptWebSocketAsync(null).ConfigureAwait(false); + _logger.LogInformation("WS Request from {IP}", context.Connection.RemoteIpAddress); + + WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync().ConfigureAwait(false); var connection = new WebSocketConnection( _loggerFactory.CreateLogger(), webSocket, - context.Connection.RemoteIpAddress) + context.Connection.RemoteIpAddress, + context.Request.Query) { - Url = url, - QueryString = context.Request.Query, OnReceive = ProcessWebSocketMessageReceived }; WebSocketConnected?.Invoke(this, new GenericEventArgs(connection)); await connection.ProcessAsync().ConfigureAwait(false); + _logger.LogInformation("WS closed from {IP}", context.Connection.RemoteIpAddress); } - catch (WebSocketException ex) + catch (Exception ex) // Otherwise ASP.Net will ignore the exception { - _logger.LogError(ex, "ProcessWebSocketRequest error"); + _logger.LogError(ex, "WebSocketRequestHandler error"); if (!context.Response.HasStarted) { context.Response.StatusCode = 500; diff --git a/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs b/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs index b4f420e5d..88974f9ab 100644 --- a/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs +++ b/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs @@ -1,4 +1,6 @@ -using System; +#nullable enable + +using System; using System.Buffers; using System.IO.Pipelines; using System.Net; @@ -39,47 +41,38 @@ namespace Emby.Server.Implementations.HttpServer /// /// Initializes a new instance of the class. /// + /// The logger. /// The socket. /// The remote end point. - /// The logger. - /// socket - public WebSocketConnection(ILogger logger, WebSocket socket, IPAddress remoteEndPoint) + /// The query. + public WebSocketConnection( + ILogger logger, + WebSocket socket, + IPAddress? remoteEndPoint, + IQueryCollection query) { - if (socket == null) - { - throw new ArgumentNullException(nameof(socket)); - } - - if (remoteEndPoint != null) - { - throw new ArgumentNullException(nameof(remoteEndPoint)); - } - - if (logger == null) - { - throw new ArgumentNullException(nameof(logger)); - } - + _logger = logger; _socket = socket; RemoteEndPoint = remoteEndPoint; - _logger = logger; + QueryString = query; _jsonOptions = JsonDefaults.GetOptions(); + LastActivityDate = DateTime.Now; } /// - public event EventHandler Closed; + public event EventHandler? Closed; /// /// Gets or sets the remote end point. /// - public IPAddress RemoteEndPoint { get; private set; } + public IPAddress? RemoteEndPoint { get; } /// /// Gets or sets the receive action. /// /// The receive action. - public Func OnReceive { get; set; } + public Func? OnReceive { get; set; } /// /// Gets the last activity date. @@ -87,17 +80,11 @@ namespace Emby.Server.Implementations.HttpServer /// The last activity date. public DateTime LastActivityDate { get; private set; } - /// - /// Gets or sets the URL. - /// - /// The URL. - public string Url { get; set; } - /// /// Gets or sets the query string. /// /// The query string. - public IQueryCollection QueryString { get; set; } + public IQueryCollection QueryString { get; } /// /// Gets the state. @@ -115,11 +102,6 @@ namespace Emby.Server.Implementations.HttpServer /// message public Task SendAsync(WebSocketMessage message, CancellationToken cancellationToken) { - if (message == null) - { - throw new ArgumentNullException(nameof(message)); - } - var json = JsonSerializer.SerializeToUtf8Bytes(message, _jsonOptions); return _socket.SendAsync(json, WebSocketMessageType.Text, true, cancellationToken); } @@ -140,7 +122,7 @@ namespace Emby.Server.Implementations.HttpServer int bytesRead = receiveresult.Count; if (bytesRead == 0) { - continue; + break; } // Tell the PipeWriter how much was read from the Socket @@ -154,6 +136,8 @@ namespace Emby.Server.Implementations.HttpServer break; } + LastActivityDate = DateTime.UtcNow; + if (receiveresult.EndOfMessage) { await ProcessInternal(pipe.Reader).ConfigureAwait(false); @@ -162,10 +146,7 @@ namespace Emby.Server.Implementations.HttpServer if (_socket.State == WebSocketState.Open) { - await _socket.CloseAsync( - WebSocketCloseStatus.NormalClosure, - string.Empty, // REVIEW: human readable explanation as to why the connection is closed. - cancellationToken).ConfigureAwait(false); + _logger.LogWarning("Stopped reading from websocket before it was closed"); } Closed?.Invoke(this, EventArgs.Empty); @@ -175,8 +156,6 @@ namespace Emby.Server.Implementations.HttpServer private async Task ProcessInternal(PipeReader reader) { - LastActivityDate = DateTime.UtcNow; - if (OnReceive == null) { return; diff --git a/Emby.Server.Implementations/Session/SessionManager.cs b/Emby.Server.Implementations/Session/SessionManager.cs index db00ceeb7..0d5df1dad 100644 --- a/Emby.Server.Implementations/Session/SessionManager.cs +++ b/Emby.Server.Implementations/Session/SessionManager.cs @@ -1726,6 +1726,7 @@ namespace Emby.Server.Implementations.Session string.Equals(i.Client, client)); } + /// public SessionInfo GetSessionByAuthenticationToken(AuthenticationInfo info, string deviceId, string remoteEndpoint, string appVersion) { if (info == null) @@ -1733,7 +1734,7 @@ namespace Emby.Server.Implementations.Session throw new ArgumentNullException(nameof(info)); } - var user = info.UserId.Equals(Guid.Empty) + var user = info.UserId == Guid.Empty ? null : _userManager.GetUserById(info.UserId); diff --git a/Emby.Server.Implementations/Session/SessionWebSocketListener.cs b/Emby.Server.Implementations/Session/SessionWebSocketListener.cs index 13b42698d..d4e4ba1f2 100644 --- a/Emby.Server.Implementations/Session/SessionWebSocketListener.cs +++ b/Emby.Server.Implementations/Session/SessionWebSocketListener.cs @@ -56,7 +56,7 @@ namespace Emby.Server.Implementations.Session } else { - _logger.LogWarning("Unable to determine session based on url: {0}", e.Argument.Url); + _logger.LogWarning("Unable to determine session based on query string: {0}", e.Argument.QueryString); } } diff --git a/Emby.Server.Implementations/Session/WebSocketController.cs b/Emby.Server.Implementations/Session/WebSocketController.cs index c17e67da9..536013c7a 100644 --- a/Emby.Server.Implementations/Session/WebSocketController.cs +++ b/Emby.Server.Implementations/Session/WebSocketController.cs @@ -53,11 +53,12 @@ namespace Emby.Server.Implementations.Session private void OnConnectionClosed(object sender, EventArgs e) { - _logger.LogDebug("Removing websocket from session {Session}", _session.Id); var connection = (IWebSocketConnection)sender; + _logger.LogDebug("Removing websocket from session {Session}", _session.Id); _sockets.Remove(connection); - _sessionManager.CloseIfNeeded(_session); + connection.Closed -= OnConnectionClosed; connection.Dispose(); + _sessionManager.CloseIfNeeded(_session); } /// diff --git a/MediaBrowser.Controller/Net/IWebSocketConnection.cs b/MediaBrowser.Controller/Net/IWebSocketConnection.cs index e2a714d5b..d5555884d 100644 --- a/MediaBrowser.Controller/Net/IWebSocketConnection.cs +++ b/MediaBrowser.Controller/Net/IWebSocketConnection.cs @@ -1,3 +1,5 @@ +#nullable enable + using System; using System.Net; using System.Net.WebSockets; @@ -13,7 +15,7 @@ namespace MediaBrowser.Controller.Net /// /// Occurs when [closed]. /// - event EventHandler Closed; + event EventHandler? Closed; /// /// Gets the last activity date. @@ -21,23 +23,17 @@ namespace MediaBrowser.Controller.Net /// The last activity date. DateTime LastActivityDate { get; } - /// - /// Gets or sets the URL. - /// - /// The URL. - string Url { get; set; } - /// /// Gets or sets the query string. /// /// The query string. - IQueryCollection QueryString { get; set; } + IQueryCollection QueryString { get; } /// /// Gets or sets the receive action. /// /// The receive action. - Func OnReceive { get; set; } + Func? OnReceive { get; set; } /// /// Gets the state. @@ -49,7 +45,7 @@ namespace MediaBrowser.Controller.Net /// Gets the remote end point. /// /// The remote end point. - IPAddress RemoteEndPoint { get; } + IPAddress? RemoteEndPoint { get; } /// /// Sends a message asynchronously. -- cgit v1.2.3 From 4d311870d2f40f67da6df5641b53df637fdee88d Mon Sep 17 00:00:00 2001 From: Bond-009 Date: Fri, 27 Dec 2019 14:42:53 +0100 Subject: Fix websocket handling --- .../HttpServer/WebSocketConnection.cs | 73 +++++++++------------- .../Session/WebSocketController.cs | 2 - .../Net/IWebSocketConnection.cs | 2 +- 3 files changed, 30 insertions(+), 47 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs b/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs index 88974f9ab..913a51217 100644 --- a/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs +++ b/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs @@ -99,7 +99,6 @@ namespace Emby.Server.Implementations.HttpServer /// The message. /// The cancellation token. /// Task. - /// message public Task SendAsync(WebSocketMessage message, CancellationToken cancellationToken) { var json = JsonSerializer.SerializeToUtf8Bytes(message, _jsonOptions); @@ -117,7 +116,6 @@ namespace Emby.Server.Implementations.HttpServer { // Allocate at least 512 bytes from the PipeWriter Memory memory = writer.GetMemory(512); - receiveresult = await _socket.ReceiveAsync(memory, cancellationToken); int bytesRead = receiveresult.Count; if (bytesRead == 0) @@ -144,33 +142,30 @@ namespace Emby.Server.Implementations.HttpServer } } while (_socket.State == WebSocketState.Open && receiveresult.MessageType != WebSocketMessageType.Close); - if (_socket.State == WebSocketState.Open) - { - _logger.LogWarning("Stopped reading from websocket before it was closed"); - } - Closed?.Invoke(this, EventArgs.Empty); - _socket.Dispose(); + await _socket.CloseAsync( + WebSocketCloseStatus.NormalClosure, + string.Empty, + cancellationToken).ConfigureAwait(false); } private async Task ProcessInternal(PipeReader reader) { + ReadResult result = await reader.ReadAsync().ConfigureAwait(false); + ReadOnlySequence buffer = result.Buffer; + if (OnReceive == null) { + // Tell the PipeReader how much of the buffer we have consumed + reader.AdvanceTo(buffer.End); return; } + WebSocketMessage stub; try { - var result = await reader.ReadAsync().ConfigureAwait(false); - if (!result.IsCompleted) - { - return; - } - WebSocketMessage stub; - var buffer = result.Buffer; if (buffer.IsSingleSegment) { stub = JsonSerializer.Deserialize>(buffer.FirstSpan, _jsonOptions); @@ -188,46 +183,36 @@ namespace Emby.Server.Implementations.HttpServer ArrayPool.Shared.Return(buf); } } - - var info = new WebSocketMessageInfo - { - MessageType = stub.MessageType, - Data = stub.Data.ToString(), - Connection = this - }; - - await OnReceive(info).ConfigureAwait(false); } catch (JsonException ex) { + // Tell the PipeReader how much of the buffer we have consumed + reader.AdvanceTo(buffer.End); _logger.LogError(ex, "Error processing web socket message"); + return; } - } - /// - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } + // Tell the PipeReader how much of the buffer we have consumed + reader.AdvanceTo(buffer.End); - /// - /// Releases unmanaged and - optionally - managed resources. - /// - /// true to release both managed and unmanaged resources; false to release only unmanaged resources. - protected virtual void Dispose(bool dispose) - { - if (_disposed) + _logger.LogDebug("WS received message: {@Message}", stub); + + var info = new WebSocketMessageInfo { - return; - } + MessageType = stub.MessageType, + Data = stub.Data?.ToString(), // Data can be null + Connection = this + }; + + _logger.LogDebug("WS message info: {@MessageInfo}", info); - if (dispose) + await OnReceive(info).ConfigureAwait(false); + + // Stop reading if there's no more data coming + if (result.IsCompleted) { - _socket.Dispose(); + return; } - - _disposed = true; } } } diff --git a/Emby.Server.Implementations/Session/WebSocketController.cs b/Emby.Server.Implementations/Session/WebSocketController.cs index 536013c7a..c3c4b716f 100644 --- a/Emby.Server.Implementations/Session/WebSocketController.cs +++ b/Emby.Server.Implementations/Session/WebSocketController.cs @@ -57,7 +57,6 @@ namespace Emby.Server.Implementations.Session _logger.LogDebug("Removing websocket from session {Session}", _session.Id); _sockets.Remove(connection); connection.Closed -= OnConnectionClosed; - connection.Dispose(); _sessionManager.CloseIfNeeded(_session); } @@ -96,7 +95,6 @@ namespace Emby.Server.Implementations.Session foreach (var socket in _sockets) { socket.Closed -= OnConnectionClosed; - socket.Dispose(); } _disposed = true; diff --git a/MediaBrowser.Controller/Net/IWebSocketConnection.cs b/MediaBrowser.Controller/Net/IWebSocketConnection.cs index d5555884d..09e43c683 100644 --- a/MediaBrowser.Controller/Net/IWebSocketConnection.cs +++ b/MediaBrowser.Controller/Net/IWebSocketConnection.cs @@ -10,7 +10,7 @@ using Microsoft.AspNetCore.Http; namespace MediaBrowser.Controller.Net { - public interface IWebSocketConnection : IDisposable + public interface IWebSocketConnection { /// /// Occurs when [closed]. -- cgit v1.2.3 From 8865b3ea3d0af201c37aa129016b843f0b9fe686 Mon Sep 17 00:00:00 2001 From: Bond-009 Date: Fri, 27 Dec 2019 15:20:27 +0100 Subject: Remove dead code and improve logging --- .../HttpServer/HttpListenerHost.cs | 8 +- .../HttpServer/WebSocketConnection.cs | 4 +- .../Middleware/WebSocketMiddleware.cs | 39 -------- .../WebSockets/WebSocketHandler.cs | 10 -- .../WebSockets/WebSocketManager.cs | 104 --------------------- .../System/ActivityLogWebSocketListener.cs | 17 ++-- .../Net/BasePeriodicWebSocketListener.cs | 11 +-- 7 files changed, 18 insertions(+), 175 deletions(-) delete mode 100644 Emby.Server.Implementations/Middleware/WebSocketMiddleware.cs delete mode 100644 Emby.Server.Implementations/WebSockets/WebSocketHandler.cs delete mode 100644 Emby.Server.Implementations/WebSockets/WebSocketManager.cs (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs index ebae4d0b1..3cdb0ecae 100644 --- a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs +++ b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs @@ -520,7 +520,7 @@ namespace Emby.Server.Implementations.HttpServer try { - _logger.LogInformation("WS Request from {IP}", context.Connection.RemoteIpAddress); + _logger.LogInformation("WS {IP} request", context.Connection.RemoteIpAddress); WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync().ConfigureAwait(false); @@ -536,11 +536,11 @@ namespace Emby.Server.Implementations.HttpServer WebSocketConnected?.Invoke(this, new GenericEventArgs(connection)); await connection.ProcessAsync().ConfigureAwait(false); - _logger.LogInformation("WS closed from {IP}", context.Connection.RemoteIpAddress); + _logger.LogInformation("WS {IP} closed", context.Connection.RemoteIpAddress); } catch (Exception ex) // Otherwise ASP.Net will ignore the exception { - _logger.LogError(ex, "WebSocketRequestHandler error"); + _logger.LogError(ex, "WS {IP} WebSocketRequestHandler error"); if (!context.Response.HasStarted) { context.Response.StatusCode = 500; @@ -705,8 +705,6 @@ namespace Emby.Server.Implementations.HttpServer return Task.CompletedTask; } - _logger.LogDebug("Websocket message received: {0}", result.MessageType); - IEnumerable GetTasks() { foreach (var x in _webSocketListeners) diff --git a/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs b/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs index 913a51217..0afd0ecce 100644 --- a/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs +++ b/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs @@ -195,7 +195,7 @@ namespace Emby.Server.Implementations.HttpServer // Tell the PipeReader how much of the buffer we have consumed reader.AdvanceTo(buffer.End); - _logger.LogDebug("WS received message: {@Message}", stub); + _logger.LogDebug("WS {IP} received message: {@Message}", RemoteEndPoint, stub); var info = new WebSocketMessageInfo { @@ -204,7 +204,7 @@ namespace Emby.Server.Implementations.HttpServer Connection = this }; - _logger.LogDebug("WS message info: {@MessageInfo}", info); + _logger.LogDebug("WS {IP} message info: {@MessageInfo}", RemoteEndPoint, info); await OnReceive(info).ConfigureAwait(false); diff --git a/Emby.Server.Implementations/Middleware/WebSocketMiddleware.cs b/Emby.Server.Implementations/Middleware/WebSocketMiddleware.cs deleted file mode 100644 index fda32da5e..000000000 --- a/Emby.Server.Implementations/Middleware/WebSocketMiddleware.cs +++ /dev/null @@ -1,39 +0,0 @@ -using System.Threading.Tasks; -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Logging; -using WebSocketManager = Emby.Server.Implementations.WebSockets.WebSocketManager; - -namespace Emby.Server.Implementations.Middleware -{ - public class WebSocketMiddleware - { - private readonly RequestDelegate _next; - private readonly ILogger _logger; - private readonly WebSocketManager _webSocketManager; - - public WebSocketMiddleware(RequestDelegate next, ILogger logger, WebSocketManager webSocketManager) - { - _next = next; - _logger = logger; - _webSocketManager = webSocketManager; - } - - public async Task Invoke(HttpContext httpContext) - { - _logger.LogInformation("Handling request: " + httpContext.Request.Path); - - if (httpContext.WebSockets.IsWebSocketRequest) - { - var webSocketContext = await httpContext.WebSockets.AcceptWebSocketAsync(null).ConfigureAwait(false); - if (webSocketContext != null) - { - await _webSocketManager.OnWebSocketConnected(webSocketContext).ConfigureAwait(false); - } - } - else - { - await _next.Invoke(httpContext).ConfigureAwait(false); - } - } - } -} diff --git a/Emby.Server.Implementations/WebSockets/WebSocketHandler.cs b/Emby.Server.Implementations/WebSockets/WebSocketHandler.cs deleted file mode 100644 index eb1877440..000000000 --- a/Emby.Server.Implementations/WebSockets/WebSocketHandler.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System.Threading.Tasks; -using MediaBrowser.Model.Net; - -namespace Emby.Server.Implementations.WebSockets -{ - public interface IWebSocketHandler - { - Task ProcessMessage(WebSocketMessage message, TaskCompletionSource taskCompletionSource); - } -} diff --git a/Emby.Server.Implementations/WebSockets/WebSocketManager.cs b/Emby.Server.Implementations/WebSockets/WebSocketManager.cs deleted file mode 100644 index efd97e4ff..000000000 --- a/Emby.Server.Implementations/WebSockets/WebSocketManager.cs +++ /dev/null @@ -1,104 +0,0 @@ -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Linq; -using System.Net.WebSockets; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using MediaBrowser.Controller.Net; -using MediaBrowser.Model.Net; -using MediaBrowser.Model.Serialization; -using Microsoft.Extensions.Logging; -using UtfUnknown; - -namespace Emby.Server.Implementations.WebSockets -{ - public class WebSocketManager - { - private readonly IWebSocketHandler[] _webSocketHandlers; - private readonly IJsonSerializer _jsonSerializer; - private readonly ILogger _logger; - private const int BufferSize = 4096; - - public WebSocketManager(IWebSocketHandler[] webSocketHandlers, IJsonSerializer jsonSerializer, ILogger logger) - { - _webSocketHandlers = webSocketHandlers; - _jsonSerializer = jsonSerializer; - _logger = logger; - } - - public async Task OnWebSocketConnected(WebSocket webSocket) - { - var taskCompletionSource = new TaskCompletionSource(); - var cancellationToken = new CancellationTokenSource().Token; - WebSocketReceiveResult result; - var message = new List(); - - // Keep listening for incoming messages, otherwise the socket closes automatically - do - { - var buffer = WebSocket.CreateServerBuffer(BufferSize); - result = await webSocket.ReceiveAsync(buffer, cancellationToken).ConfigureAwait(false); - message.AddRange(buffer.Array.Take(result.Count)); - - if (result.EndOfMessage) - { - await ProcessMessage(message.ToArray(), taskCompletionSource).ConfigureAwait(false); - message.Clear(); - } - } while (!taskCompletionSource.Task.IsCompleted && - webSocket.State == WebSocketState.Open && - result.MessageType != WebSocketMessageType.Close); - - if (webSocket.State == WebSocketState.Open) - { - await webSocket.CloseAsync( - result.CloseStatus ?? WebSocketCloseStatus.NormalClosure, - result.CloseStatusDescription, - cancellationToken).ConfigureAwait(false); - } - } - - private async Task ProcessMessage(byte[] messageBytes, TaskCompletionSource taskCompletionSource) - { - var charset = CharsetDetector.DetectFromBytes(messageBytes).Detected?.EncodingName; - var message = string.Equals(charset, "utf-8", StringComparison.OrdinalIgnoreCase) - ? Encoding.UTF8.GetString(messageBytes, 0, messageBytes.Length) - : Encoding.ASCII.GetString(messageBytes, 0, messageBytes.Length); - - // All messages are expected to be valid JSON objects - if (!message.StartsWith("{", StringComparison.OrdinalIgnoreCase)) - { - _logger.LogDebug("Received web socket message that is not a json structure: {Message}", message); - return; - } - - try - { - var info = _jsonSerializer.DeserializeFromString>(message); - - _logger.LogDebug("Websocket message received: {0}", info.MessageType); - - var tasks = _webSocketHandlers.Select(handler => Task.Run(() => - { - try - { - handler.ProcessMessage(info, taskCompletionSource).ConfigureAwait(false); - } - catch (Exception ex) - { - _logger.LogError(ex, "{HandlerType} failed processing WebSocket message {MessageType}", - handler.GetType().Name, info.MessageType ?? string.Empty); - } - })); - - await Task.WhenAll(tasks); - } - catch (Exception ex) - { - _logger.LogError(ex, "Error processing web socket message"); - } - } - } -} diff --git a/MediaBrowser.Api/System/ActivityLogWebSocketListener.cs b/MediaBrowser.Api/System/ActivityLogWebSocketListener.cs index a036619b8..60b190a0e 100644 --- a/MediaBrowser.Api/System/ActivityLogWebSocketListener.cs +++ b/MediaBrowser.Api/System/ActivityLogWebSocketListener.cs @@ -1,5 +1,4 @@ -using System.Collections.Generic; -using System.Threading; +using System; using System.Threading.Tasks; using MediaBrowser.Controller.Net; using MediaBrowser.Model.Activity; @@ -11,7 +10,7 @@ namespace MediaBrowser.Api.System /// /// Class SessionInfoWebSocketListener /// - public class ActivityLogWebSocketListener : BasePeriodicWebSocketListener, WebSocketListenerState> + public class ActivityLogWebSocketListener : BasePeriodicWebSocketListener { /// /// Gets the name. @@ -27,10 +26,10 @@ namespace MediaBrowser.Api.System public ActivityLogWebSocketListener(ILogger logger, IActivityManager activityManager) : base(logger) { _activityManager = activityManager; - _activityManager.EntryCreated += _activityManager_EntryCreated; + _activityManager.EntryCreated += OnEntryCreated; } - void _activityManager_EntryCreated(object sender, GenericEventArgs e) + private void OnEntryCreated(object sender, GenericEventArgs e) { SendData(true); } @@ -39,15 +38,15 @@ namespace MediaBrowser.Api.System /// Gets the data to send. /// /// Task{SystemInfo}. - protected override Task> GetDataToSend() + protected override Task GetDataToSend() { - return Task.FromResult(new List()); + return Task.FromResult(Array.Empty()); } - + /// protected override void Dispose(bool dispose) { - _activityManager.EntryCreated -= _activityManager_EntryCreated; + _activityManager.EntryCreated -= OnEntryCreated; base.Dispose(dispose); } diff --git a/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs b/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs index 9d71426d8..b193cbb55 100644 --- a/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs +++ b/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs @@ -77,8 +77,6 @@ namespace MediaBrowser.Controller.Net return Task.CompletedTask; } - protected readonly CultureInfo UsCulture = new CultureInfo("en-US"); - /// /// Starts sending messages over a web socket /// @@ -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 { @@ -196,7 +194,7 @@ namespace MediaBrowser.Controller.Net /// The connection. private void DisposeConnection(Tuple 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(); @@ -241,6 +239,7 @@ namespace MediaBrowser.Controller.Net public void Dispose() { Dispose(true); + GC.SuppressFinalize(this); } } -- cgit v1.2.3 From 9bdb99fe92edaf06679ef855eae9f8bb69b970df Mon Sep 17 00:00:00 2001 From: Luke Foust Date: Sun, 22 Mar 2020 12:58:53 -0700 Subject: Add type to externalids to distinguish them in the UI --- MediaBrowser.Controller/Providers/IExternalId.cs | 19 +++++++++++++++ MediaBrowser.Model/Providers/ExternalIdInfo.cs | 6 +++++ MediaBrowser.Providers/Manager/ProviderManager.cs | 1 + MediaBrowser.Providers/Movies/MovieExternalIds.cs | 6 +++++ MediaBrowser.Providers/Music/MusicExternalIds.cs | 3 +++ .../Plugins/AudioDb/ExternalIds.cs | 16 +++++++++++-- .../Plugins/MusicBrainz/ExternalIds.cs | 28 ++++++++++++++++++---- MediaBrowser.Providers/TV/TvExternalIds.cs | 12 ++++++++++ .../Tmdb/BoxSets/TmdbBoxSetExternalId.cs | 3 +++ .../Tmdb/Movies/TmdbMovieExternalId.cs | 3 +++ .../Tmdb/People/TmdbPersonExternalId.cs | 3 +++ .../Tmdb/TV/TmdbSeriesExternalId.cs | 3 +++ 12 files changed, 96 insertions(+), 7 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/Providers/IExternalId.cs b/MediaBrowser.Controller/Providers/IExternalId.cs index d7e337bda..157a2076e 100644 --- a/MediaBrowser.Controller/Providers/IExternalId.cs +++ b/MediaBrowser.Controller/Providers/IExternalId.cs @@ -8,8 +8,27 @@ namespace MediaBrowser.Controller.Providers string Key { get; } + ExternalIdType Type { get; } + string UrlFormatString { get; } bool Supports(IHasProviderIds item); } + + public enum ExternalIdType + { + None, + Album, + AlbumArtist, + Artist, + BoxSet, + Episode, + Movie, + OtherArtist, + Person, + ReleaseGroup, + Season, + Series, + Track + } } diff --git a/MediaBrowser.Model/Providers/ExternalIdInfo.cs b/MediaBrowser.Model/Providers/ExternalIdInfo.cs index 2b481ad7e..8d6d91143 100644 --- a/MediaBrowser.Model/Providers/ExternalIdInfo.cs +++ b/MediaBrowser.Model/Providers/ExternalIdInfo.cs @@ -16,6 +16,12 @@ namespace MediaBrowser.Model.Providers /// The key. public string Key { get; set; } + /// + /// Gets or sets the type. + /// + /// The type. + public string Type { get; set; } + /// /// Gets or sets the URL format string. /// diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs index e7b349f67..608a0cd19 100644 --- a/MediaBrowser.Providers/Manager/ProviderManager.cs +++ b/MediaBrowser.Providers/Manager/ProviderManager.cs @@ -910,6 +910,7 @@ namespace MediaBrowser.Providers.Manager { Name = i.Name, Key = i.Key, + Type = i.Type == ExternalIdType.None ? null : i.Type.ToString(), UrlFormatString = i.UrlFormatString }); diff --git a/MediaBrowser.Providers/Movies/MovieExternalIds.cs b/MediaBrowser.Providers/Movies/MovieExternalIds.cs index 55810b1ed..1ede0e7a5 100644 --- a/MediaBrowser.Providers/Movies/MovieExternalIds.cs +++ b/MediaBrowser.Providers/Movies/MovieExternalIds.cs @@ -15,6 +15,9 @@ namespace MediaBrowser.Providers.Movies /// public string Key => MetadataProviders.Imdb.ToString(); + /// + public ExternalIdType Type => ExternalIdType.None; + /// public string UrlFormatString => "https://www.imdb.com/title/{0}"; @@ -39,6 +42,9 @@ namespace MediaBrowser.Providers.Movies /// public string Key => MetadataProviders.Imdb.ToString(); + /// + public ExternalIdType Type => ExternalIdType.Person; + /// public string UrlFormatString => "https://www.imdb.com/name/{0}"; diff --git a/MediaBrowser.Providers/Music/MusicExternalIds.cs b/MediaBrowser.Providers/Music/MusicExternalIds.cs index 628b9a9a1..54e034713 100644 --- a/MediaBrowser.Providers/Music/MusicExternalIds.cs +++ b/MediaBrowser.Providers/Music/MusicExternalIds.cs @@ -12,6 +12,9 @@ namespace MediaBrowser.Providers.Music /// public string Key => "IMVDb"; + /// + public ExternalIdType Type => ExternalIdType.None; + /// public string UrlFormatString => null; diff --git a/MediaBrowser.Providers/Plugins/AudioDb/ExternalIds.cs b/MediaBrowser.Providers/Plugins/AudioDb/ExternalIds.cs index 2d8cb431c..785185d61 100644 --- a/MediaBrowser.Providers/Plugins/AudioDb/ExternalIds.cs +++ b/MediaBrowser.Providers/Plugins/AudioDb/ExternalIds.cs @@ -12,6 +12,9 @@ namespace MediaBrowser.Providers.Plugins.AudioDb /// public string Key => MetadataProviders.AudioDbAlbum.ToString(); + /// + public ExternalIdType Type => ExternalIdType.None; + /// public string UrlFormatString => "https://www.theaudiodb.com/album/{0}"; @@ -22,11 +25,14 @@ namespace MediaBrowser.Providers.Plugins.AudioDb public class AudioDbOtherAlbumExternalId : IExternalId { /// - public string Name => "TheAudioDb Album"; + public string Name => "TheAudioDb"; /// public string Key => MetadataProviders.AudioDbAlbum.ToString(); + /// + public ExternalIdType Type => ExternalIdType.Album; + /// public string UrlFormatString => "https://www.theaudiodb.com/album/{0}"; @@ -42,6 +48,9 @@ namespace MediaBrowser.Providers.Plugins.AudioDb /// public string Key => MetadataProviders.AudioDbArtist.ToString(); + /// + public ExternalIdType Type => ExternalIdType.Artist; + /// public string UrlFormatString => "https://www.theaudiodb.com/artist/{0}"; @@ -52,11 +61,14 @@ namespace MediaBrowser.Providers.Plugins.AudioDb public class AudioDbOtherArtistExternalId : IExternalId { /// - public string Name => "TheAudioDb Artist"; + public string Name => "TheAudioDb"; /// public string Key => MetadataProviders.AudioDbArtist.ToString(); + /// + public ExternalIdType Type => ExternalIdType.OtherArtist; + /// public string UrlFormatString => "https://www.theaudiodb.com/artist/{0}"; diff --git a/MediaBrowser.Providers/Plugins/MusicBrainz/ExternalIds.cs b/MediaBrowser.Providers/Plugins/MusicBrainz/ExternalIds.cs index 03565a34c..ed9fa6307 100644 --- a/MediaBrowser.Providers/Plugins/MusicBrainz/ExternalIds.cs +++ b/MediaBrowser.Providers/Plugins/MusicBrainz/ExternalIds.cs @@ -8,11 +8,14 @@ namespace MediaBrowser.Providers.Music public class MusicBrainzReleaseGroupExternalId : IExternalId { /// - public string Name => "MusicBrainz Release Group"; + public string Name => "MusicBrainz"; /// public string Key => MetadataProviders.MusicBrainzReleaseGroup.ToString(); + /// + public ExternalIdType Type => ExternalIdType.ReleaseGroup; + /// public string UrlFormatString => Plugin.Instance.Configuration.Server + "/release-group/{0}"; @@ -23,11 +26,14 @@ namespace MediaBrowser.Providers.Music public class MusicBrainzAlbumArtistExternalId : IExternalId { /// - public string Name => "MusicBrainz Album Artist"; + public string Name => "MusicBrainz"; /// public string Key => MetadataProviders.MusicBrainzAlbumArtist.ToString(); + /// + public ExternalIdType Type => ExternalIdType.AlbumArtist; + /// public string UrlFormatString => Plugin.Instance.Configuration.Server + "/artist/{0}"; @@ -38,11 +44,14 @@ namespace MediaBrowser.Providers.Music public class MusicBrainzAlbumExternalId : IExternalId { /// - public string Name => "MusicBrainz Album"; + public string Name => "MusicBrainz"; /// public string Key => MetadataProviders.MusicBrainzAlbum.ToString(); + /// + public ExternalIdType Type => ExternalIdType.Album; + /// public string UrlFormatString => Plugin.Instance.Configuration.Server + "/release/{0}"; @@ -58,6 +67,9 @@ namespace MediaBrowser.Providers.Music /// public string Key => MetadataProviders.MusicBrainzArtist.ToString(); + /// + public ExternalIdType Type => ExternalIdType.Artist; + /// public string UrlFormatString => Plugin.Instance.Configuration.Server + "/artist/{0}"; @@ -68,12 +80,15 @@ namespace MediaBrowser.Providers.Music public class MusicBrainzOtherArtistExternalId : IExternalId { /// - public string Name => "MusicBrainz Artist"; + public string Name => "MusicBrainz"; /// public string Key => MetadataProviders.MusicBrainzArtist.ToString(); + /// + public ExternalIdType Type => ExternalIdType.OtherArtist; + /// public string UrlFormatString => Plugin.Instance.Configuration.Server + "/artist/{0}"; @@ -84,11 +99,14 @@ namespace MediaBrowser.Providers.Music public class MusicBrainzTrackId : IExternalId { /// - public string Name => "MusicBrainz Track"; + public string Name => "MusicBrainz"; /// public string Key => MetadataProviders.MusicBrainzTrack.ToString(); + /// + public ExternalIdType Type => ExternalIdType.Track; + /// public string UrlFormatString => Plugin.Instance.Configuration.Server + "/track/{0}"; diff --git a/MediaBrowser.Providers/TV/TvExternalIds.cs b/MediaBrowser.Providers/TV/TvExternalIds.cs index baf854285..a3c24f7dd 100644 --- a/MediaBrowser.Providers/TV/TvExternalIds.cs +++ b/MediaBrowser.Providers/TV/TvExternalIds.cs @@ -13,6 +13,9 @@ namespace MediaBrowser.Providers.TV /// public string Key => MetadataProviders.Zap2It.ToString(); + /// + public ExternalIdType Type => ExternalIdType.None; + /// public string UrlFormatString => "http://tvlistings.zap2it.com/overview.html?programSeriesId={0}"; @@ -28,6 +31,9 @@ namespace MediaBrowser.Providers.TV /// public string Key => MetadataProviders.Tvdb.ToString(); + /// + public ExternalIdType Type => ExternalIdType.None; + /// public string UrlFormatString => TvdbUtils.TvdbBaseUrl + "?tab=series&id={0}"; @@ -44,6 +50,9 @@ namespace MediaBrowser.Providers.TV /// public string Key => MetadataProviders.Tvdb.ToString(); + /// + public ExternalIdType Type => ExternalIdType.Season; + /// public string UrlFormatString => null; @@ -59,6 +68,9 @@ namespace MediaBrowser.Providers.TV /// public string Key => MetadataProviders.Tvdb.ToString(); + /// + public ExternalIdType Type => ExternalIdType.Episode; + /// public string UrlFormatString => TvdbUtils.TvdbBaseUrl + "?tab=episode&id={0}"; diff --git a/MediaBrowser.Providers/Tmdb/BoxSets/TmdbBoxSetExternalId.cs b/MediaBrowser.Providers/Tmdb/BoxSets/TmdbBoxSetExternalId.cs index 187295e1e..a51355254 100644 --- a/MediaBrowser.Providers/Tmdb/BoxSets/TmdbBoxSetExternalId.cs +++ b/MediaBrowser.Providers/Tmdb/BoxSets/TmdbBoxSetExternalId.cs @@ -13,6 +13,9 @@ namespace MediaBrowser.Providers.Tmdb.BoxSets /// public string Key => MetadataProviders.TmdbCollection.ToString(); + /// + public ExternalIdType Type => ExternalIdType.BoxSet; + /// public string UrlFormatString => TmdbUtils.BaseTmdbUrl + "collection/{0}"; diff --git a/MediaBrowser.Providers/Tmdb/Movies/TmdbMovieExternalId.cs b/MediaBrowser.Providers/Tmdb/Movies/TmdbMovieExternalId.cs index fc7a4583f..af565b079 100644 --- a/MediaBrowser.Providers/Tmdb/Movies/TmdbMovieExternalId.cs +++ b/MediaBrowser.Providers/Tmdb/Movies/TmdbMovieExternalId.cs @@ -14,6 +14,9 @@ namespace MediaBrowser.Providers.Tmdb.Movies /// public string Key => MetadataProviders.Tmdb.ToString(); + /// + public ExternalIdType Type => ExternalIdType.Movie; + /// public string UrlFormatString => TmdbUtils.BaseTmdbUrl + "movie/{0}"; diff --git a/MediaBrowser.Providers/Tmdb/People/TmdbPersonExternalId.cs b/MediaBrowser.Providers/Tmdb/People/TmdbPersonExternalId.cs index 2c61bc70a..1ec43c269 100644 --- a/MediaBrowser.Providers/Tmdb/People/TmdbPersonExternalId.cs +++ b/MediaBrowser.Providers/Tmdb/People/TmdbPersonExternalId.cs @@ -12,6 +12,9 @@ namespace MediaBrowser.Providers.Tmdb.People /// public string Key => MetadataProviders.Tmdb.ToString(); + /// + public ExternalIdType Type => ExternalIdType.Person; + /// public string UrlFormatString => TmdbUtils.BaseTmdbUrl + "person/{0}"; diff --git a/MediaBrowser.Providers/Tmdb/TV/TmdbSeriesExternalId.cs b/MediaBrowser.Providers/Tmdb/TV/TmdbSeriesExternalId.cs index 524a3b05e..43ef06bf7 100644 --- a/MediaBrowser.Providers/Tmdb/TV/TmdbSeriesExternalId.cs +++ b/MediaBrowser.Providers/Tmdb/TV/TmdbSeriesExternalId.cs @@ -12,6 +12,9 @@ namespace MediaBrowser.Providers.Tmdb.TV /// public string Key => MetadataProviders.Tmdb.ToString(); + /// + public ExternalIdType Type => ExternalIdType.Series; + /// public string UrlFormatString => TmdbUtils.BaseTmdbUrl + "tv/{0}"; -- cgit v1.2.3 From 0fb78cf54b51843c54e7ff59d191c490a5b196cd Mon Sep 17 00:00:00 2001 From: Luke Foust Date: Thu, 26 Mar 2020 14:26:12 -0700 Subject: Add documentation around Name, Id, and Type. Changed ExternalIdType to ExternalIdMediaType --- .../Providers/ExternalIdMediaType.cs | 45 ++++++++++++++++++++++ MediaBrowser.Controller/Providers/IExternalId.cs | 27 +++++-------- MediaBrowser.Model/Providers/ExternalIdInfo.cs | 17 ++++---- MediaBrowser.Providers/Manager/ProviderManager.cs | 2 +- MediaBrowser.Providers/Movies/MovieExternalIds.cs | 4 +- MediaBrowser.Providers/Music/MusicExternalIds.cs | 2 +- .../Plugins/AudioDb/ExternalIds.cs | 8 ++-- .../Plugins/MusicBrainz/ExternalIds.cs | 12 +++--- MediaBrowser.Providers/TV/TvExternalIds.cs | 8 ++-- .../Tmdb/BoxSets/TmdbBoxSetExternalId.cs | 2 +- .../Tmdb/Movies/TmdbMovieExternalId.cs | 2 +- .../Tmdb/People/TmdbPersonExternalId.cs | 2 +- .../Tmdb/TV/TmdbSeriesExternalId.cs | 2 +- 13 files changed, 84 insertions(+), 49 deletions(-) create mode 100644 MediaBrowser.Controller/Providers/ExternalIdMediaType.cs (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/Providers/ExternalIdMediaType.cs b/MediaBrowser.Controller/Providers/ExternalIdMediaType.cs new file mode 100644 index 000000000..470f1e24c --- /dev/null +++ b/MediaBrowser.Controller/Providers/ExternalIdMediaType.cs @@ -0,0 +1,45 @@ +namespace MediaBrowser.Controller.Providers +{ + /// The specific media type of an . + public enum ExternalIdMediaType + { + /// There is no specific media type + None, + + /// A music album + Album, + + /// The artist of a music album + AlbumArtist, + + /// The artist of a media item + Artist, + + /// A boxed set of media + BoxSet, + + /// A series episode + Episode, + + /// A movie + Movie, + + /// An alternative artist apart from the main artist + OtherArtist, + + /// A person + Person, + + /// A release group + ReleaseGroup, + + /// A single season of a series + Season, + + /// A series + Series, + + /// A music track + Track + } +} diff --git a/MediaBrowser.Controller/Providers/IExternalId.cs b/MediaBrowser.Controller/Providers/IExternalId.cs index 157a2076e..c877ffe1f 100644 --- a/MediaBrowser.Controller/Providers/IExternalId.cs +++ b/MediaBrowser.Controller/Providers/IExternalId.cs @@ -2,33 +2,24 @@ using MediaBrowser.Model.Entities; namespace MediaBrowser.Controller.Providers { + /// Represents and identifier for an external provider. public interface IExternalId { + /// Gets the name used to identify this provider string Name { get; } + /// Gets the unique key to distinguish this provider/type pair. This should be unique across providers. string Key { get; } - ExternalIdType Type { get; } + /// Gets the specific media type for this id. + ExternalIdMediaType Type { get; } + /// Gets the url format string for this id. string UrlFormatString { get; } + /// Determines whether this id supports a given item type. + /// The item. + /// True if this item is supported, otherwise false. bool Supports(IHasProviderIds item); } - - public enum ExternalIdType - { - None, - Album, - AlbumArtist, - Artist, - BoxSet, - Episode, - Movie, - OtherArtist, - Person, - ReleaseGroup, - Season, - Series, - Track - } } diff --git a/MediaBrowser.Model/Providers/ExternalIdInfo.cs b/MediaBrowser.Model/Providers/ExternalIdInfo.cs index 8d6d91143..befcc309b 100644 --- a/MediaBrowser.Model/Providers/ExternalIdInfo.cs +++ b/MediaBrowser.Model/Providers/ExternalIdInfo.cs @@ -1,31 +1,30 @@ -#pragma warning disable CS1591 - namespace MediaBrowser.Model.Providers { + /// + /// Represents the external id information for serialization to the client. + /// public class ExternalIdInfo { /// - /// Gets or sets the name. + /// Gets or sets the name of the external id provider (IE: IMDB, MusicBrainz, etc). /// - /// The name. public string Name { get; set; } /// - /// Gets or sets the key. + /// Gets or sets the unique key for this id. This key should be unique across all providers. /// - /// The key. public string Key { get; set; } /// - /// Gets or sets the type. + /// Gets or sets the media type (Album, Artist, etc). + /// This can be null if there is no specific type. + /// This string is also used to localize the media type on the client. /// - /// The type. public string Type { get; set; } /// /// Gets or sets the URL format string. /// - /// The URL format string. public string UrlFormatString { get; set; } } } diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs index 608a0cd19..fee988d50 100644 --- a/MediaBrowser.Providers/Manager/ProviderManager.cs +++ b/MediaBrowser.Providers/Manager/ProviderManager.cs @@ -910,7 +910,7 @@ namespace MediaBrowser.Providers.Manager { Name = i.Name, Key = i.Key, - Type = i.Type == ExternalIdType.None ? null : i.Type.ToString(), + Type = i.Type == ExternalIdMediaType.None ? null : i.Type.ToString(), UrlFormatString = i.UrlFormatString }); diff --git a/MediaBrowser.Providers/Movies/MovieExternalIds.cs b/MediaBrowser.Providers/Movies/MovieExternalIds.cs index 1ede0e7a5..a7b359a2d 100644 --- a/MediaBrowser.Providers/Movies/MovieExternalIds.cs +++ b/MediaBrowser.Providers/Movies/MovieExternalIds.cs @@ -16,7 +16,7 @@ namespace MediaBrowser.Providers.Movies public string Key => MetadataProviders.Imdb.ToString(); /// - public ExternalIdType Type => ExternalIdType.None; + public ExternalIdMediaType Type => ExternalIdMediaType.None; /// public string UrlFormatString => "https://www.imdb.com/title/{0}"; @@ -43,7 +43,7 @@ namespace MediaBrowser.Providers.Movies public string Key => MetadataProviders.Imdb.ToString(); /// - public ExternalIdType Type => ExternalIdType.Person; + public ExternalIdMediaType Type => ExternalIdMediaType.Person; /// public string UrlFormatString => "https://www.imdb.com/name/{0}"; diff --git a/MediaBrowser.Providers/Music/MusicExternalIds.cs b/MediaBrowser.Providers/Music/MusicExternalIds.cs index 54e034713..19879411e 100644 --- a/MediaBrowser.Providers/Music/MusicExternalIds.cs +++ b/MediaBrowser.Providers/Music/MusicExternalIds.cs @@ -13,7 +13,7 @@ namespace MediaBrowser.Providers.Music public string Key => "IMVDb"; /// - public ExternalIdType Type => ExternalIdType.None; + public ExternalIdMediaType Type => ExternalIdMediaType.None; /// public string UrlFormatString => null; diff --git a/MediaBrowser.Providers/Plugins/AudioDb/ExternalIds.cs b/MediaBrowser.Providers/Plugins/AudioDb/ExternalIds.cs index 785185d61..cd65acb76 100644 --- a/MediaBrowser.Providers/Plugins/AudioDb/ExternalIds.cs +++ b/MediaBrowser.Providers/Plugins/AudioDb/ExternalIds.cs @@ -13,7 +13,7 @@ namespace MediaBrowser.Providers.Plugins.AudioDb public string Key => MetadataProviders.AudioDbAlbum.ToString(); /// - public ExternalIdType Type => ExternalIdType.None; + public ExternalIdMediaType Type => ExternalIdMediaType.None; /// public string UrlFormatString => "https://www.theaudiodb.com/album/{0}"; @@ -31,7 +31,7 @@ namespace MediaBrowser.Providers.Plugins.AudioDb public string Key => MetadataProviders.AudioDbAlbum.ToString(); /// - public ExternalIdType Type => ExternalIdType.Album; + public ExternalIdMediaType Type => ExternalIdMediaType.Album; /// public string UrlFormatString => "https://www.theaudiodb.com/album/{0}"; @@ -49,7 +49,7 @@ namespace MediaBrowser.Providers.Plugins.AudioDb public string Key => MetadataProviders.AudioDbArtist.ToString(); /// - public ExternalIdType Type => ExternalIdType.Artist; + public ExternalIdMediaType Type => ExternalIdMediaType.Artist; /// public string UrlFormatString => "https://www.theaudiodb.com/artist/{0}"; @@ -67,7 +67,7 @@ namespace MediaBrowser.Providers.Plugins.AudioDb public string Key => MetadataProviders.AudioDbArtist.ToString(); /// - public ExternalIdType Type => ExternalIdType.OtherArtist; + public ExternalIdMediaType Type => ExternalIdMediaType.OtherArtist; /// public string UrlFormatString => "https://www.theaudiodb.com/artist/{0}"; diff --git a/MediaBrowser.Providers/Plugins/MusicBrainz/ExternalIds.cs b/MediaBrowser.Providers/Plugins/MusicBrainz/ExternalIds.cs index ed9fa6307..7d74a8d35 100644 --- a/MediaBrowser.Providers/Plugins/MusicBrainz/ExternalIds.cs +++ b/MediaBrowser.Providers/Plugins/MusicBrainz/ExternalIds.cs @@ -14,7 +14,7 @@ namespace MediaBrowser.Providers.Music public string Key => MetadataProviders.MusicBrainzReleaseGroup.ToString(); /// - public ExternalIdType Type => ExternalIdType.ReleaseGroup; + public ExternalIdMediaType Type => ExternalIdMediaType.ReleaseGroup; /// public string UrlFormatString => Plugin.Instance.Configuration.Server + "/release-group/{0}"; @@ -32,7 +32,7 @@ namespace MediaBrowser.Providers.Music public string Key => MetadataProviders.MusicBrainzAlbumArtist.ToString(); /// - public ExternalIdType Type => ExternalIdType.AlbumArtist; + public ExternalIdMediaType Type => ExternalIdMediaType.AlbumArtist; /// public string UrlFormatString => Plugin.Instance.Configuration.Server + "/artist/{0}"; @@ -50,7 +50,7 @@ namespace MediaBrowser.Providers.Music public string Key => MetadataProviders.MusicBrainzAlbum.ToString(); /// - public ExternalIdType Type => ExternalIdType.Album; + public ExternalIdMediaType Type => ExternalIdMediaType.Album; /// public string UrlFormatString => Plugin.Instance.Configuration.Server + "/release/{0}"; @@ -68,7 +68,7 @@ namespace MediaBrowser.Providers.Music public string Key => MetadataProviders.MusicBrainzArtist.ToString(); /// - public ExternalIdType Type => ExternalIdType.Artist; + public ExternalIdMediaType Type => ExternalIdMediaType.Artist; /// public string UrlFormatString => Plugin.Instance.Configuration.Server + "/artist/{0}"; @@ -87,7 +87,7 @@ namespace MediaBrowser.Providers.Music public string Key => MetadataProviders.MusicBrainzArtist.ToString(); /// - public ExternalIdType Type => ExternalIdType.OtherArtist; + public ExternalIdMediaType Type => ExternalIdMediaType.OtherArtist; /// public string UrlFormatString => Plugin.Instance.Configuration.Server + "/artist/{0}"; @@ -105,7 +105,7 @@ namespace MediaBrowser.Providers.Music public string Key => MetadataProviders.MusicBrainzTrack.ToString(); /// - public ExternalIdType Type => ExternalIdType.Track; + public ExternalIdMediaType Type => ExternalIdMediaType.Track; /// public string UrlFormatString => Plugin.Instance.Configuration.Server + "/track/{0}"; diff --git a/MediaBrowser.Providers/TV/TvExternalIds.cs b/MediaBrowser.Providers/TV/TvExternalIds.cs index a3c24f7dd..75d8b6bf5 100644 --- a/MediaBrowser.Providers/TV/TvExternalIds.cs +++ b/MediaBrowser.Providers/TV/TvExternalIds.cs @@ -14,7 +14,7 @@ namespace MediaBrowser.Providers.TV public string Key => MetadataProviders.Zap2It.ToString(); /// - public ExternalIdType Type => ExternalIdType.None; + public ExternalIdMediaType Type => ExternalIdMediaType.None; /// public string UrlFormatString => "http://tvlistings.zap2it.com/overview.html?programSeriesId={0}"; @@ -32,7 +32,7 @@ namespace MediaBrowser.Providers.TV public string Key => MetadataProviders.Tvdb.ToString(); /// - public ExternalIdType Type => ExternalIdType.None; + public ExternalIdMediaType Type => ExternalIdMediaType.None; /// public string UrlFormatString => TvdbUtils.TvdbBaseUrl + "?tab=series&id={0}"; @@ -51,7 +51,7 @@ namespace MediaBrowser.Providers.TV public string Key => MetadataProviders.Tvdb.ToString(); /// - public ExternalIdType Type => ExternalIdType.Season; + public ExternalIdMediaType Type => ExternalIdMediaType.Season; /// public string UrlFormatString => null; @@ -69,7 +69,7 @@ namespace MediaBrowser.Providers.TV public string Key => MetadataProviders.Tvdb.ToString(); /// - public ExternalIdType Type => ExternalIdType.Episode; + public ExternalIdMediaType Type => ExternalIdMediaType.Episode; /// public string UrlFormatString => TvdbUtils.TvdbBaseUrl + "?tab=episode&id={0}"; diff --git a/MediaBrowser.Providers/Tmdb/BoxSets/TmdbBoxSetExternalId.cs b/MediaBrowser.Providers/Tmdb/BoxSets/TmdbBoxSetExternalId.cs index a51355254..a83cde93c 100644 --- a/MediaBrowser.Providers/Tmdb/BoxSets/TmdbBoxSetExternalId.cs +++ b/MediaBrowser.Providers/Tmdb/BoxSets/TmdbBoxSetExternalId.cs @@ -14,7 +14,7 @@ namespace MediaBrowser.Providers.Tmdb.BoxSets public string Key => MetadataProviders.TmdbCollection.ToString(); /// - public ExternalIdType Type => ExternalIdType.BoxSet; + public ExternalIdMediaType Type => ExternalIdMediaType.BoxSet; /// public string UrlFormatString => TmdbUtils.BaseTmdbUrl + "collection/{0}"; diff --git a/MediaBrowser.Providers/Tmdb/Movies/TmdbMovieExternalId.cs b/MediaBrowser.Providers/Tmdb/Movies/TmdbMovieExternalId.cs index af565b079..f9ea00067 100644 --- a/MediaBrowser.Providers/Tmdb/Movies/TmdbMovieExternalId.cs +++ b/MediaBrowser.Providers/Tmdb/Movies/TmdbMovieExternalId.cs @@ -15,7 +15,7 @@ namespace MediaBrowser.Providers.Tmdb.Movies public string Key => MetadataProviders.Tmdb.ToString(); /// - public ExternalIdType Type => ExternalIdType.Movie; + public ExternalIdMediaType Type => ExternalIdMediaType.Movie; /// public string UrlFormatString => TmdbUtils.BaseTmdbUrl + "movie/{0}"; diff --git a/MediaBrowser.Providers/Tmdb/People/TmdbPersonExternalId.cs b/MediaBrowser.Providers/Tmdb/People/TmdbPersonExternalId.cs index 1ec43c269..854fd4156 100644 --- a/MediaBrowser.Providers/Tmdb/People/TmdbPersonExternalId.cs +++ b/MediaBrowser.Providers/Tmdb/People/TmdbPersonExternalId.cs @@ -13,7 +13,7 @@ namespace MediaBrowser.Providers.Tmdb.People public string Key => MetadataProviders.Tmdb.ToString(); /// - public ExternalIdType Type => ExternalIdType.Person; + public ExternalIdMediaType Type => ExternalIdMediaType.Person; /// public string UrlFormatString => TmdbUtils.BaseTmdbUrl + "person/{0}"; diff --git a/MediaBrowser.Providers/Tmdb/TV/TmdbSeriesExternalId.cs b/MediaBrowser.Providers/Tmdb/TV/TmdbSeriesExternalId.cs index 43ef06bf7..770448c7f 100644 --- a/MediaBrowser.Providers/Tmdb/TV/TmdbSeriesExternalId.cs +++ b/MediaBrowser.Providers/Tmdb/TV/TmdbSeriesExternalId.cs @@ -13,7 +13,7 @@ namespace MediaBrowser.Providers.Tmdb.TV public string Key => MetadataProviders.Tmdb.ToString(); /// - public ExternalIdType Type => ExternalIdType.Series; + public ExternalIdMediaType Type => ExternalIdMediaType.Series; /// public string UrlFormatString => TmdbUtils.BaseTmdbUrl + "tv/{0}"; -- cgit v1.2.3 From ca71ac72abf5d5ff31d50553283a43de298e0c73 Mon Sep 17 00:00:00 2001 From: Mark Monteiro Date: Thu, 2 Apr 2020 17:45:04 -0400 Subject: Replace EnableHttps and SupportsHttps with ListenWithHttps and CanConnectWithHttps --- Emby.Server.Implementations/ApplicationHost.cs | 15 ++++++++++----- .../EntryPoints/ExternalPortForwarding.cs | 2 +- .../HttpServer/HttpListenerHost.cs | 2 +- Jellyfin.Server/Program.cs | 4 ++-- MediaBrowser.Controller/IServerApplicationHost.cs | 5 ++--- MediaBrowser.Model/System/SystemInfo.cs | 4 ++-- 6 files changed, 18 insertions(+), 14 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index c959cc974..8158b4559 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -1408,7 +1408,7 @@ namespace Emby.Server.Implementations InternalMetadataPath = ApplicationPaths.InternalMetadataPath, CachePath = ApplicationPaths.CachePath, HttpServerPortNumber = HttpPort, - SupportsHttps = SupportsHttps, + SupportsHttps = CanConnectWithHttps, HttpsPortNumber = HttpsPort, OperatingSystem = OperatingSystem.Id.ToString(), OperatingSystemDisplayName = OperatingSystem.Name, @@ -1446,9 +1446,14 @@ namespace Emby.Server.Implementations }; } - public bool EnableHttps => SupportsHttps && ServerConfigurationManager.Configuration.EnableHttps; + /// + public bool ListenWithHttps => Certificate != null && ServerConfigurationManager.Configuration.EnableHttps; - public bool SupportsHttps => Certificate != null || ServerConfigurationManager.Configuration.IsBehindProxy; + /// + /// Gets a value indicating whether a client can connect to the server over HTTPS, either directly or via a + /// reverse proxy. + /// + public bool CanConnectWithHttps => ListenWithHttps || ServerConfigurationManager.Configuration.IsBehindProxy; public async Task GetLocalApiUrl(CancellationToken cancellationToken) { @@ -1509,10 +1514,10 @@ namespace Emby.Server.Implementations public string GetLocalApiUrl(ReadOnlySpan host) { var url = new StringBuilder(64); - url.Append(EnableHttps ? "https://" : "http://") + url.Append(ListenWithHttps ? "https://" : "http://") .Append(host) .Append(':') - .Append(EnableHttps ? HttpsPort : HttpPort); + .Append(ListenWithHttps ? HttpsPort : HttpPort); string baseUrl = ServerConfigurationManager.Configuration.BaseUrl; if (baseUrl.Length != 0) diff --git a/Emby.Server.Implementations/EntryPoints/ExternalPortForwarding.cs b/Emby.Server.Implementations/EntryPoints/ExternalPortForwarding.cs index e290c62e1..2023c470a 100644 --- a/Emby.Server.Implementations/EntryPoints/ExternalPortForwarding.cs +++ b/Emby.Server.Implementations/EntryPoints/ExternalPortForwarding.cs @@ -62,7 +62,7 @@ namespace Emby.Server.Implementations.EntryPoints .Append(config.PublicPort).Append(Separator) .Append(_appHost.HttpPort).Append(Separator) .Append(_appHost.HttpsPort).Append(Separator) - .Append(_appHost.EnableHttps).Append(Separator) + .Append(_appHost.ListenWithHttps).Append(Separator) .Append(config.EnableRemoteAccess).Append(Separator) .ToString(); } diff --git a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs index 7a812f320..e3f8ec014 100644 --- a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs +++ b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs @@ -422,7 +422,7 @@ namespace Emby.Server.Implementations.HttpServer private bool ValidateSsl(string remoteIp, string urlString) { - if (_config.Configuration.RequireHttps && _appHost.EnableHttps && !_config.Configuration.IsBehindProxy) + if (_config.Configuration.RequireHttps && _appHost.ListenWithHttps) { if (urlString.IndexOf("https://", StringComparison.OrdinalIgnoreCase) == -1) { diff --git a/Jellyfin.Server/Program.cs b/Jellyfin.Server/Program.cs index 4abdd59aa..ddd1054ad 100644 --- a/Jellyfin.Server/Program.cs +++ b/Jellyfin.Server/Program.cs @@ -274,7 +274,7 @@ namespace Jellyfin.Server _logger.LogInformation("Kestrel listening on {IpAddress}", address); options.Listen(address, appHost.HttpPort); - if (appHost.EnableHttps && appHost.Certificate != null) + if (appHost.ListenWithHttps) { options.Listen(address, appHost.HttpsPort, listenOptions => { @@ -289,7 +289,7 @@ namespace Jellyfin.Server _logger.LogInformation("Kestrel listening on all interfaces"); options.ListenAnyIP(appHost.HttpPort); - if (appHost.EnableHttps && appHost.Certificate != null) + if (appHost.ListenWithHttps) { options.ListenAnyIP(appHost.HttpsPort, listenOptions => { diff --git a/MediaBrowser.Controller/IServerApplicationHost.cs b/MediaBrowser.Controller/IServerApplicationHost.cs index 608ffc61c..d999f76db 100644 --- a/MediaBrowser.Controller/IServerApplicationHost.cs +++ b/MediaBrowser.Controller/IServerApplicationHost.cs @@ -39,10 +39,9 @@ namespace MediaBrowser.Controller int HttpsPort { get; } /// - /// Gets a value indicating whether [supports HTTPS]. + /// Gets a value indicating whether the server should listen on an HTTPS port. /// - /// true if [supports HTTPS]; otherwise, false. - bool EnableHttps { get; } + bool ListenWithHttps { get; } /// /// Gets a value indicating whether this instance has update available. diff --git a/MediaBrowser.Model/System/SystemInfo.cs b/MediaBrowser.Model/System/SystemInfo.cs index cfa7684c9..83c60563e 100644 --- a/MediaBrowser.Model/System/SystemInfo.cs +++ b/MediaBrowser.Model/System/SystemInfo.cs @@ -124,9 +124,9 @@ namespace MediaBrowser.Model.System public int HttpServerPortNumber { get; set; } /// - /// Gets or sets a value indicating whether [enable HTTPS]. + /// Gets or sets a value indicating whether a client can connect to the server over HTTPS, either directly or + /// via a reverse proxy. /// - /// true if [enable HTTPS]; otherwise, false. public bool SupportsHttps { get; set; } /// -- cgit v1.2.3 From 30ce346f343ca61f921ec7d6faf2f06311c04e71 Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Sun, 5 Apr 2020 18:10:56 +0200 Subject: Enable nullabe reference types for MediaBrowser.Model --- Emby.Dlna/Ssdp/DeviceDiscovery.cs | 16 +++--- .../Configuration/ServerConfigurationManager.cs | 2 +- .../Cryptography/CryptographyProvider.cs | 4 +- .../Devices/DeviceManager.cs | 16 ++---- .../EntryPoints/UdpServerEntryPoint.cs | 3 +- .../Library/MediaSourceManager.cs | 6 +-- Emby.Server.Implementations/Library/UserManager.cs | 10 ++-- .../LiveTv/EmbyTV/TimerManager.cs | 4 +- .../LiveTv/LiveTvManager.cs | 57 ++++++---------------- .../Playlists/PlaylistManager.cs | 5 +- .../ScheduledTasks/ScheduledTaskWorker.cs | 11 ++--- .../ScheduledTasks/TaskManager.cs | 11 +---- .../Updates/InstallationManager.cs | 2 +- MediaBrowser.Api/EnvironmentService.cs | 15 +----- MediaBrowser.Api/Images/RemoteImageService.cs | 3 +- MediaBrowser.Controller/LiveTv/TimerEventInfo.cs | 13 ++++- MediaBrowser.Model/Activity/ActivityLogEntry.cs | 1 + .../ApiClient/ServerDiscoveryInfo.cs | 1 + MediaBrowser.Model/Branding/BrandingOptions.cs | 1 + MediaBrowser.Model/Channels/ChannelFeatures.cs | 1 + MediaBrowser.Model/Channels/ChannelInfo.cs | 1 + MediaBrowser.Model/Channels/ChannelQuery.cs | 6 +++ .../Configuration/BaseApplicationConfiguration.cs | 1 + .../Configuration/EncodingOptions.cs | 13 +++++ MediaBrowser.Model/Configuration/LibraryOptions.cs | 1 + .../Configuration/MetadataOptions.cs | 4 ++ MediaBrowser.Model/Configuration/MetadataPlugin.cs | 1 + .../Configuration/MetadataPluginSummary.cs | 1 + .../Configuration/ServerConfiguration.cs | 1 + .../Configuration/UserConfiguration.cs | 1 + .../Configuration/XbmcMetadataOptions.cs | 1 + MediaBrowser.Model/Cryptography/ICryptoProvider.cs | 2 +- MediaBrowser.Model/Devices/ContentUploadHistory.cs | 6 ++- MediaBrowser.Model/Devices/DeviceInfo.cs | 1 + MediaBrowser.Model/Devices/DevicesOptions.cs | 3 ++ MediaBrowser.Model/Devices/LocalFileInfo.cs | 4 ++ MediaBrowser.Model/Diagnostics/IProcess.cs | 8 +++ MediaBrowser.Model/Diagnostics/IProcessFactory.cs | 11 +++++ MediaBrowser.Model/Dlna/AudioOptions.cs | 6 +++ MediaBrowser.Model/Dlna/CodecProfile.cs | 1 + MediaBrowser.Model/Dlna/ConditionProcessor.cs | 36 ++------------ MediaBrowser.Model/Dlna/ContainerProfile.cs | 4 +- MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs | 6 ++- MediaBrowser.Model/Dlna/DeviceIdentification.cs | 1 + MediaBrowser.Model/Dlna/DeviceProfile.cs | 1 + MediaBrowser.Model/Dlna/DeviceProfileInfo.cs | 1 + MediaBrowser.Model/Dlna/DirectPlayProfile.cs | 1 + MediaBrowser.Model/Dlna/HttpHeaderInfo.cs | 1 + MediaBrowser.Model/Dlna/ITranscoderSupport.cs | 5 ++ .../Dlna/MediaFormatProfileResolver.cs | 24 +++++---- MediaBrowser.Model/Dlna/ProfileCondition.cs | 25 +++++----- MediaBrowser.Model/Dlna/ResolutionConfiguration.cs | 1 + MediaBrowser.Model/Dlna/ResolutionNormalizer.cs | 5 +- MediaBrowser.Model/Dlna/ResolutionOptions.cs | 1 + MediaBrowser.Model/Dlna/ResponseProfile.cs | 4 +- MediaBrowser.Model/Dlna/SearchCriteria.cs | 9 ++-- MediaBrowser.Model/Dlna/StreamBuilder.cs | 2 + MediaBrowser.Model/Dlna/StreamInfo.cs | 1 + MediaBrowser.Model/Dlna/SubtitleProfile.cs | 1 + MediaBrowser.Model/Dlna/SubtitleStreamInfo.cs | 9 ++++ MediaBrowser.Model/Dlna/TranscodingProfile.cs | 1 + MediaBrowser.Model/Dlna/UpnpDeviceInfo.cs | 4 ++ MediaBrowser.Model/Dlna/VideoOptions.cs | 1 + MediaBrowser.Model/Dlna/XmlAttribute.cs | 1 + MediaBrowser.Model/Drawing/DrawingUtils.cs | 5 +- MediaBrowser.Model/Dto/BaseItemDto.cs | 1 + MediaBrowser.Model/Dto/BaseItemPerson.cs | 1 + MediaBrowser.Model/Dto/IHasServerId.cs | 1 + MediaBrowser.Model/Dto/ImageByNameInfo.cs | 1 + MediaBrowser.Model/Dto/ImageInfo.cs | 5 +- MediaBrowser.Model/Dto/ImageOptions.cs | 17 ++++--- MediaBrowser.Model/Dto/ItemIndex.cs | 20 -------- MediaBrowser.Model/Dto/MediaSourceInfo.cs | 1 + MediaBrowser.Model/Dto/MetadataEditorInfo.cs | 1 + MediaBrowser.Model/Dto/NameIdPair.cs | 1 + MediaBrowser.Model/Dto/NameValuePair.cs | 2 +- MediaBrowser.Model/Dto/RecommendationDto.cs | 1 + MediaBrowser.Model/Dto/UserDto.cs | 1 + MediaBrowser.Model/Dto/UserItemDataDto.cs | 1 + MediaBrowser.Model/Entities/ChapterInfo.cs | 1 + MediaBrowser.Model/Entities/DisplayPreferences.cs | 1 + MediaBrowser.Model/Entities/IHasProviderIds.cs | 2 +- MediaBrowser.Model/Entities/LibraryUpdateInfo.cs | 29 +++++------ MediaBrowser.Model/Entities/MediaAttachment.cs | 1 + MediaBrowser.Model/Entities/MediaStream.cs | 1 + MediaBrowser.Model/Entities/MediaUrl.cs | 1 + MediaBrowser.Model/Entities/PackageReviewInfo.cs | 13 ++--- MediaBrowser.Model/Entities/ParentalRating.cs | 24 ++++----- .../Entities/ProviderIdsExtensions.cs | 12 ++--- MediaBrowser.Model/Entities/VirtualFolderInfo.cs | 1 + MediaBrowser.Model/Events/GenericEventArgs.cs | 7 --- MediaBrowser.Model/Extensions/ListHelper.cs | 2 + MediaBrowser.Model/Extensions/StringHelper.cs | 4 +- MediaBrowser.Model/Globalization/CountryInfo.cs | 1 + MediaBrowser.Model/Globalization/CultureDto.cs | 1 + .../Globalization/ILocalizationManager.cs | 1 + .../Globalization/LocalizationOption.cs | 2 + MediaBrowser.Model/IO/FileSystemEntryInfo.cs | 27 +++++++--- MediaBrowser.Model/IO/FileSystemMetadata.cs | 1 + MediaBrowser.Model/IO/IFileSystem.cs | 1 + MediaBrowser.Model/IO/IIsoManager.cs | 1 - MediaBrowser.Model/IO/IIsoMount.cs | 2 +- MediaBrowser.Model/IO/IIsoMounter.cs | 12 ++--- MediaBrowser.Model/IO/IStreamHelper.cs | 1 + MediaBrowser.Model/Library/UserViewQuery.cs | 12 ++--- MediaBrowser.Model/LiveTv/BaseTimerInfoDto.cs | 1 + MediaBrowser.Model/LiveTv/GuideInfo.cs | 1 + MediaBrowser.Model/LiveTv/LiveTvChannelQuery.cs | 1 + MediaBrowser.Model/LiveTv/LiveTvInfo.cs | 12 ++--- MediaBrowser.Model/LiveTv/LiveTvOptions.cs | 1 + MediaBrowser.Model/LiveTv/LiveTvServiceInfo.cs | 1 + MediaBrowser.Model/LiveTv/RecordingQuery.cs | 1 + MediaBrowser.Model/LiveTv/SeriesTimerInfoDto.cs | 3 +- MediaBrowser.Model/LiveTv/SeriesTimerQuery.cs | 2 +- MediaBrowser.Model/LiveTv/TimerInfoDto.cs | 1 + MediaBrowser.Model/LiveTv/TimerQuery.cs | 1 + MediaBrowser.Model/MediaBrowser.Model.csproj | 2 + MediaBrowser.Model/MediaInfo/AudioCodec.cs | 4 +- MediaBrowser.Model/MediaInfo/BlurayDiscInfo.cs | 1 + MediaBrowser.Model/MediaInfo/LiveStreamRequest.cs | 18 ++++--- MediaBrowser.Model/MediaInfo/LiveStreamResponse.cs | 7 ++- MediaBrowser.Model/MediaInfo/MediaInfo.cs | 1 + .../MediaInfo/PlaybackInfoRequest.cs | 1 + .../MediaInfo/PlaybackInfoResponse.cs | 2 +- MediaBrowser.Model/MediaInfo/SubtitleTrackEvent.cs | 4 ++ MediaBrowser.Model/Net/EndPointInfo.cs | 1 + MediaBrowser.Model/Net/ISocket.cs | 1 + MediaBrowser.Model/Net/MimeTypes.cs | 18 +++---- MediaBrowser.Model/Net/NetworkShare.cs | 1 + MediaBrowser.Model/Net/SocketReceiveResult.cs | 10 ++-- MediaBrowser.Model/Net/WebSocketMessage.cs | 1 + .../Notifications/NotificationOption.cs | 16 +++--- .../Notifications/NotificationOptions.cs | 37 ++++++-------- .../Notifications/NotificationRequest.cs | 1 + .../Notifications/NotificationTypeInfo.cs | 1 + .../Playlists/PlaylistCreationRequest.cs | 1 + .../Playlists/PlaylistCreationResult.cs | 7 ++- MediaBrowser.Model/Playlists/PlaylistItemQuery.cs | 39 --------------- MediaBrowser.Model/Plugins/PluginInfo.cs | 1 + MediaBrowser.Model/Plugins/PluginPageInfo.cs | 1 + MediaBrowser.Model/Providers/ExternalIdInfo.cs | 1 + MediaBrowser.Model/Providers/ExternalUrl.cs | 1 + MediaBrowser.Model/Providers/ImageProviderInfo.cs | 11 +++-- MediaBrowser.Model/Providers/RemoteImageInfo.cs | 1 + MediaBrowser.Model/Providers/RemoteImageQuery.cs | 7 ++- MediaBrowser.Model/Providers/RemoteImageResult.cs | 1 + MediaBrowser.Model/Providers/RemoteSearchResult.cs | 20 ++++++-- MediaBrowser.Model/Providers/RemoteSubtitleInfo.cs | 1 + MediaBrowser.Model/Providers/SubtitleOptions.cs | 1 + .../Providers/SubtitleProviderInfo.cs | 1 + MediaBrowser.Model/Querying/AllThemeMediaResult.cs | 13 ++--- MediaBrowser.Model/Querying/EpisodeQuery.cs | 1 + MediaBrowser.Model/Querying/ItemCountsQuery.cs | 20 -------- MediaBrowser.Model/Querying/ItemSortBy.cs | 54 ++++++++++++++------ MediaBrowser.Model/Querying/LatestItemsQuery.cs | 20 +++++--- .../Querying/MovieRecommendationQuery.cs | 1 + MediaBrowser.Model/Querying/NextUpQuery.cs | 1 + MediaBrowser.Model/Querying/QueryFilters.cs | 1 + MediaBrowser.Model/Querying/QueryResult.cs | 1 + MediaBrowser.Model/Querying/ThemeMediaResult.cs | 2 +- .../Querying/UpcomingEpisodesQuery.cs | 1 + MediaBrowser.Model/Search/SearchHint.cs | 1 + MediaBrowser.Model/Search/SearchHintResult.cs | 1 + MediaBrowser.Model/Search/SearchQuery.cs | 1 + .../Serialization/IJsonSerializer.cs | 1 + MediaBrowser.Model/Serialization/IXmlSerializer.cs | 1 + MediaBrowser.Model/Services/ApiMemberAttribute.cs | 1 + MediaBrowser.Model/Services/IHasRequestFilter.cs | 10 ++-- MediaBrowser.Model/Services/IHttpRequest.cs | 4 +- MediaBrowser.Model/Services/IHttpResult.cs | 11 +++-- MediaBrowser.Model/Services/IRequest.cs | 1 + .../Services/QueryParamCollection.cs | 6 +-- MediaBrowser.Model/Services/RouteAttribute.cs | 1 + MediaBrowser.Model/Session/BrowseRequest.cs | 1 + MediaBrowser.Model/Session/ClientCapabilities.cs | 1 + MediaBrowser.Model/Session/GeneralCommand.cs | 1 + MediaBrowser.Model/Session/MessageCommand.cs | 1 + MediaBrowser.Model/Session/PlayRequest.cs | 1 + MediaBrowser.Model/Session/PlaybackProgressInfo.cs | 1 + MediaBrowser.Model/Session/PlaybackStopInfo.cs | 1 + MediaBrowser.Model/Session/PlayerStateInfo.cs | 1 + MediaBrowser.Model/Session/PlaystateRequest.cs | 2 +- MediaBrowser.Model/Session/SessionUserInfo.cs | 2 + MediaBrowser.Model/Session/TranscodingInfo.cs | 5 +- MediaBrowser.Model/Session/UserDataChangeInfo.cs | 1 + MediaBrowser.Model/Sync/SyncJob.cs | 1 + MediaBrowser.Model/Sync/SyncTarget.cs | 1 + MediaBrowser.Model/System/LogFile.cs | 1 + MediaBrowser.Model/System/PublicSystemInfo.cs | 1 + MediaBrowser.Model/System/SystemInfo.cs | 2 +- MediaBrowser.Model/System/WakeOnLanInfo.cs | 31 ++++++------ MediaBrowser.Model/Tasks/IScheduledTask.cs | 11 +++-- MediaBrowser.Model/Tasks/IScheduledTaskWorker.cs | 1 + MediaBrowser.Model/Tasks/ScheduledTaskHelpers.cs | 4 +- .../Tasks/TaskCompletionEventArgs.cs | 10 +++- MediaBrowser.Model/Tasks/TaskInfo.cs | 1 + MediaBrowser.Model/Tasks/TaskResult.cs | 1 + MediaBrowser.Model/Tasks/TaskTriggerInfo.cs | 1 + MediaBrowser.Model/Updates/CheckForUpdateResult.cs | 1 + MediaBrowser.Model/Updates/InstallationInfo.cs | 1 + MediaBrowser.Model/Updates/PackageInfo.cs | 1 + MediaBrowser.Model/Updates/PackageVersionInfo.cs | 1 + MediaBrowser.Model/Users/ForgotPasswordResult.cs | 1 + MediaBrowser.Model/Users/PinRedeemResult.cs | 1 + MediaBrowser.Model/Users/UserAction.cs | 1 + MediaBrowser.Model/Users/UserPolicy.cs | 1 + .../Manager/ItemImageProvider.cs | 24 +++++---- MediaBrowser.Providers/Manager/ProviderManager.cs | 6 +-- 208 files changed, 636 insertions(+), 506 deletions(-) delete mode 100644 MediaBrowser.Model/Dto/ItemIndex.cs delete mode 100644 MediaBrowser.Model/Playlists/PlaylistItemQuery.cs delete mode 100644 MediaBrowser.Model/Querying/ItemCountsQuery.cs (limited to 'MediaBrowser.Controller') diff --git a/Emby.Dlna/Ssdp/DeviceDiscovery.cs b/Emby.Dlna/Ssdp/DeviceDiscovery.cs index f95b8ce7d..ab5e56ab0 100644 --- a/Emby.Dlna/Ssdp/DeviceDiscovery.cs +++ b/Emby.Dlna/Ssdp/DeviceDiscovery.cs @@ -100,15 +100,13 @@ namespace Emby.Dlna.Ssdp var headers = headerDict.ToDictionary(i => i.Key, i => i.Value.Value.FirstOrDefault(), StringComparer.OrdinalIgnoreCase); - var args = new GenericEventArgs - { - Argument = new UpnpDeviceInfo + var args = new GenericEventArgs( + new UpnpDeviceInfo { Location = e.DiscoveredDevice.DescriptionLocation, Headers = headers, LocalIpAddress = e.LocalIpAddress - } - }; + }); DeviceDiscoveredInternal?.Invoke(this, args); } @@ -121,14 +119,12 @@ namespace Emby.Dlna.Ssdp var headers = headerDict.ToDictionary(i => i.Key, i => i.Value.Value.FirstOrDefault(), StringComparer.OrdinalIgnoreCase); - var args = new GenericEventArgs - { - Argument = new UpnpDeviceInfo + var args = new GenericEventArgs( + new UpnpDeviceInfo { Location = e.DiscoveredDevice.DescriptionLocation, Headers = headers - } - }; + }); DeviceLeft?.Invoke(this, args); } diff --git a/Emby.Server.Implementations/Configuration/ServerConfigurationManager.cs b/Emby.Server.Implementations/Configuration/ServerConfigurationManager.cs index f407317ec..5062683a1 100644 --- a/Emby.Server.Implementations/Configuration/ServerConfigurationManager.cs +++ b/Emby.Server.Implementations/Configuration/ServerConfigurationManager.cs @@ -91,7 +91,7 @@ namespace Emby.Server.Implementations.Configuration ValidateMetadataPath(newConfig); ValidateSslCertificate(newConfig); - ConfigurationUpdating?.Invoke(this, new GenericEventArgs { Argument = newConfig }); + ConfigurationUpdating?.Invoke(this, new GenericEventArgs(newConfig)); base.ReplaceConfiguration(newConfiguration); } diff --git a/Emby.Server.Implementations/Cryptography/CryptographyProvider.cs b/Emby.Server.Implementations/Cryptography/CryptographyProvider.cs index de83b023d..1e42dbf67 100644 --- a/Emby.Server.Implementations/Cryptography/CryptographyProvider.cs +++ b/Emby.Server.Implementations/Cryptography/CryptographyProvider.cs @@ -1,3 +1,5 @@ +#nullable enable + using System; using System.Collections.Generic; using System.Security.Cryptography; @@ -134,8 +136,6 @@ namespace Emby.Server.Implementations.Cryptography _randomNumberGenerator.Dispose(); } - _randomNumberGenerator = null; - _disposed = true; } } diff --git a/Emby.Server.Implementations/Devices/DeviceManager.cs b/Emby.Server.Implementations/Devices/DeviceManager.cs index adb8e793d..e8837892c 100644 --- a/Emby.Server.Implementations/Devices/DeviceManager.cs +++ b/Emby.Server.Implementations/Devices/DeviceManager.cs @@ -86,13 +86,7 @@ namespace Emby.Server.Implementations.Devices { _authRepo.UpdateDeviceOptions(deviceId, options); - if (DeviceOptionsUpdated != null) - { - DeviceOptionsUpdated(this, new GenericEventArgs>() - { - Argument = new Tuple(deviceId, options) - }); - } + DeviceOptionsUpdated?.Invoke(this, new GenericEventArgs>(new Tuple(deviceId, options))); } public DeviceOptions GetDeviceOptions(string deviceId) @@ -251,14 +245,12 @@ namespace Emby.Server.Implementations.Devices if (CameraImageUploaded != null) { - CameraImageUploaded?.Invoke(this, new GenericEventArgs - { - Argument = new CameraImageUploadInfo + CameraImageUploaded?.Invoke(this, new GenericEventArgs( + new CameraImageUploadInfo { Device = device, FileInfo = file - } - }); + })); } } diff --git a/Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs b/Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs index 50ba0f8fa..fa566d24b 100644 --- a/Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs +++ b/Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs @@ -44,10 +44,11 @@ namespace Emby.Server.Implementations.EntryPoints } /// - public async Task RunAsync() + public Task RunAsync() { _udpServer = new UdpServer(_logger, _appHost); _udpServer.Start(PortNumber, _cancellationTokenSource.Token); + return Task.CompletedTask; } /// diff --git a/Emby.Server.Implementations/Library/MediaSourceManager.cs b/Emby.Server.Implementations/Library/MediaSourceManager.cs index 70d5bd9f4..4f12ad046 100644 --- a/Emby.Server.Implementations/Library/MediaSourceManager.cs +++ b/Emby.Server.Implementations/Library/MediaSourceManager.cs @@ -521,11 +521,7 @@ namespace Emby.Server.Implementations.Library SetDefaultAudioAndSubtitleStreamIndexes(item, clone, user); } - return new Tuple(new LiveStreamResponse - { - MediaSource = clone - - }, liveStream as IDirectStreamProvider); + return new Tuple(new LiveStreamResponse(clone), liveStream as IDirectStreamProvider); } private static void AddMediaInfo(MediaSourceInfo mediaSource, bool isAudio) diff --git a/Emby.Server.Implementations/Library/UserManager.cs b/Emby.Server.Implementations/Library/UserManager.cs index 7b17cc913..614ab5669 100644 --- a/Emby.Server.Implementations/Library/UserManager.cs +++ b/Emby.Server.Implementations/Library/UserManager.cs @@ -131,7 +131,7 @@ namespace Emby.Server.Implementations.Library /// The user. private void OnUserUpdated(User user) { - UserUpdated?.Invoke(this, new GenericEventArgs { Argument = user }); + UserUpdated?.Invoke(this, new GenericEventArgs(user)); } /// @@ -140,7 +140,7 @@ namespace Emby.Server.Implementations.Library /// The user. private void OnUserDeleted(User user) { - UserDeleted?.Invoke(this, new GenericEventArgs { Argument = user }); + UserDeleted?.Invoke(this, new GenericEventArgs(user)); } public NameIdPair[] GetAuthenticationProviders() @@ -755,7 +755,7 @@ namespace Emby.Server.Implementations.Library _userRepository.CreateUser(user); - EventHelper.QueueEventIfNotNull(UserCreated, this, new GenericEventArgs { Argument = user }, _logger); + EventHelper.QueueEventIfNotNull(UserCreated, this, new GenericEventArgs(user), _logger); return user; } @@ -980,7 +980,7 @@ namespace Emby.Server.Implementations.Library if (fireEvent) { - UserPolicyUpdated?.Invoke(this, new GenericEventArgs { Argument = user }); + UserPolicyUpdated?.Invoke(this, new GenericEventArgs(user)); } } @@ -1050,7 +1050,7 @@ namespace Emby.Server.Implementations.Library if (fireEvent) { - UserConfigurationUpdated?.Invoke(this, new GenericEventArgs { Argument = user }); + UserConfigurationUpdated?.Invoke(this, new GenericEventArgs(user)); } } } diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs index 7ebb043d8..285a59a24 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs @@ -109,7 +109,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV if (startDate < now) { - TimerFired?.Invoke(this, new GenericEventArgs { Argument = item }); + TimerFired?.Invoke(this, new GenericEventArgs(item)); return; } @@ -151,7 +151,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV var timer = GetAll().FirstOrDefault(i => string.Equals(i.Id, timerId, StringComparison.OrdinalIgnoreCase)); if (timer != null) { - TimerFired?.Invoke(this, new GenericEventArgs { Argument = timer }); + TimerFired?.Invoke(this, new GenericEventArgs(timer)); } } diff --git a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs index b64fe8634..16c659532 100644 --- a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs @@ -149,27 +149,18 @@ namespace Emby.Server.Implementations.LiveTv { var timerId = e.Argument; - TimerCancelled?.Invoke(this, new GenericEventArgs - { - Argument = new TimerEventInfo - { - Id = timerId - } - }); + TimerCancelled?.Invoke(this, new GenericEventArgs(new TimerEventInfo(timerId))); } private void OnEmbyTvTimerCreated(object sender, GenericEventArgs e) { var timer = e.Argument; - TimerCreated?.Invoke(this, new GenericEventArgs - { - Argument = new TimerEventInfo + TimerCreated?.Invoke(this, new GenericEventArgs( + new TimerEventInfo(timer.Id) { - ProgramId = _tvDtoService.GetInternalProgramId(timer.ProgramId), - Id = timer.Id - } - }); + ProgramId = _tvDtoService.GetInternalProgramId(timer.ProgramId) + })); } public List GetTunerHostTypes() @@ -1725,13 +1716,7 @@ namespace Emby.Server.Implementations.LiveTv if (!(service is EmbyTV.EmbyTV)) { - TimerCancelled?.Invoke(this, new GenericEventArgs - { - Argument = new TimerEventInfo - { - Id = id - } - }); + TimerCancelled?.Invoke(this, new GenericEventArgs(new TimerEventInfo(id))); } } @@ -1748,13 +1733,7 @@ namespace Emby.Server.Implementations.LiveTv await service.CancelSeriesTimerAsync(timer.ExternalId, CancellationToken.None).ConfigureAwait(false); - SeriesTimerCancelled?.Invoke(this, new GenericEventArgs - { - Argument = new TimerEventInfo - { - Id = id - } - }); + SeriesTimerCancelled?.Invoke(this, new GenericEventArgs(new TimerEventInfo(id))); } public async Task GetTimer(string id, CancellationToken cancellationToken) @@ -2073,14 +2052,11 @@ namespace Emby.Server.Implementations.LiveTv if (!(service is EmbyTV.EmbyTV)) { - TimerCreated?.Invoke(this, new GenericEventArgs - { - Argument = new TimerEventInfo + TimerCreated?.Invoke(this, new GenericEventArgs( + new TimerEventInfo(newTimerId) { - ProgramId = _tvDtoService.GetInternalProgramId(info.ProgramId), - Id = newTimerId - } - }); + ProgramId = _tvDtoService.GetInternalProgramId(info.ProgramId) + })); } } @@ -2105,14 +2081,11 @@ namespace Emby.Server.Implementations.LiveTv await service.CreateSeriesTimerAsync(info, cancellationToken).ConfigureAwait(false); } - SeriesTimerCreated?.Invoke(this, new GenericEventArgs - { - Argument = new TimerEventInfo + SeriesTimerCreated?.Invoke(this, new GenericEventArgs( + new TimerEventInfo(newTimerId) { - ProgramId = _tvDtoService.GetInternalProgramId(info.ProgramId), - Id = newTimerId - } - }); + ProgramId = _tvDtoService.GetInternalProgramId(info.ProgramId) + })); } public async Task UpdateTimer(TimerInfoDto timer, CancellationToken cancellationToken) diff --git a/Emby.Server.Implementations/Playlists/PlaylistManager.cs b/Emby.Server.Implementations/Playlists/PlaylistManager.cs index 9b1510ac9..021bc47cd 100644 --- a/Emby.Server.Implementations/Playlists/PlaylistManager.cs +++ b/Emby.Server.Implementations/Playlists/PlaylistManager.cs @@ -153,10 +153,7 @@ namespace Emby.Server.Implementations.Playlists }); } - return new PlaylistCreationResult - { - Id = playlist.Id.ToString("N", CultureInfo.InvariantCulture) - }; + return new PlaylistCreationResult(playlist.Id.ToString("N", CultureInfo.InvariantCulture)); } finally { diff --git a/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs b/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs index 5b188d962..ca983764b 100644 --- a/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs +++ b/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs @@ -392,7 +392,7 @@ namespace Emby.Server.Implementations.ScheduledTasks ((TaskManager)TaskManager).OnTaskExecuting(this); - progress.ProgressChanged += progress_ProgressChanged; + progress.ProgressChanged += OnProgressChanged; TaskCompletionStatus status; CurrentExecutionStartTime = DateTime.UtcNow; @@ -426,7 +426,7 @@ namespace Emby.Server.Implementations.ScheduledTasks var startTime = CurrentExecutionStartTime; var endTime = DateTime.UtcNow; - progress.ProgressChanged -= progress_ProgressChanged; + progress.ProgressChanged -= OnProgressChanged; CurrentCancellationTokenSource.Dispose(); CurrentCancellationTokenSource = null; CurrentProgress = null; @@ -439,16 +439,13 @@ namespace Emby.Server.Implementations.ScheduledTasks /// /// The sender. /// The e. - void progress_ProgressChanged(object sender, double e) + private void OnProgressChanged(object sender, double e) { e = Math.Min(e, 100); CurrentProgress = e; - TaskProgress?.Invoke(this, new GenericEventArgs - { - Argument = e - }); + TaskProgress?.Invoke(this, new GenericEventArgs(e)); } /// diff --git a/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs b/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs index ecf58dbc0..f2e04d1fb 100644 --- a/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs +++ b/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs @@ -254,10 +254,7 @@ namespace Emby.Server.Implementations.ScheduledTasks /// The task. internal void OnTaskExecuting(IScheduledTaskWorker task) { - TaskExecuting?.Invoke(this, new GenericEventArgs - { - Argument = task - }); + TaskExecuting?.Invoke(this, new GenericEventArgs(task)); } /// @@ -267,11 +264,7 @@ namespace Emby.Server.Implementations.ScheduledTasks /// The result. internal void OnTaskCompleted(IScheduledTaskWorker task, TaskResult result) { - TaskCompleted?.Invoke(task, new TaskCompletionEventArgs - { - Result = result, - Task = task - }); + TaskCompleted?.Invoke(task, new TaskCompletionEventArgs(task, result)); ExecuteQueuedTasks(); } diff --git a/Emby.Server.Implementations/Updates/InstallationManager.cs b/Emby.Server.Implementations/Updates/InstallationManager.cs index c897036eb..51563fd5d 100644 --- a/Emby.Server.Implementations/Updates/InstallationManager.cs +++ b/Emby.Server.Implementations/Updates/InstallationManager.cs @@ -427,7 +427,7 @@ namespace Emby.Server.Implementations.Updates _config.SaveConfiguration(); } - PluginUninstalled?.Invoke(this, new GenericEventArgs { Argument = plugin }); + PluginUninstalled?.Invoke(this, new GenericEventArgs(plugin)); _applicationHost.NotifyPendingRestart(); } diff --git a/MediaBrowser.Api/EnvironmentService.cs b/MediaBrowser.Api/EnvironmentService.cs index 36b03f09c..10726e2aa 100644 --- a/MediaBrowser.Api/EnvironmentService.cs +++ b/MediaBrowser.Api/EnvironmentService.cs @@ -226,12 +226,7 @@ namespace MediaBrowser.Api /// IEnumerable{FileSystemEntryInfo}. private IEnumerable GetDrives() { - return _fileSystem.GetDrives().Select(d => new FileSystemEntryInfo - { - Name = d.Name, - Path = d.FullName, - Type = FileSystemEntryType.Directory - }); + return _fileSystem.GetDrives().Select(d => new FileSystemEntryInfo(d.Name, d.FullName, FileSystemEntryType.Directory)); } /// @@ -266,13 +261,7 @@ namespace MediaBrowser.Api return true; }); - return entries.Select(f => new FileSystemEntryInfo - { - Name = f.Name, - Path = f.FullName, - Type = f.IsDirectory ? FileSystemEntryType.Directory : FileSystemEntryType.File - - }); + return entries.Select(f => new FileSystemEntryInfo(f.Name, f.FullName, f.IsDirectory ? FileSystemEntryType.Directory : FileSystemEntryType.File)); } public object Get(GetParentPath request) diff --git a/MediaBrowser.Api/Images/RemoteImageService.cs b/MediaBrowser.Api/Images/RemoteImageService.cs index f03f5efd8..3e4198aae 100644 --- a/MediaBrowser.Api/Images/RemoteImageService.cs +++ b/MediaBrowser.Api/Images/RemoteImageService.cs @@ -147,9 +147,8 @@ namespace MediaBrowser.Api.Images { var item = _libraryManager.GetItemById(request.Id); - var images = await _providerManager.GetAvailableRemoteImages(item, new RemoteImageQuery + var images = await _providerManager.GetAvailableRemoteImages(item, new RemoteImageQuery(request.ProviderName) { - ProviderName = request.ProviderName, IncludeAllLanguages = request.IncludeAllLanguages, IncludeDisabledProviders = true, ImageType = request.Type diff --git a/MediaBrowser.Controller/LiveTv/TimerEventInfo.cs b/MediaBrowser.Controller/LiveTv/TimerEventInfo.cs index cfec39b4e..1b8f41db6 100644 --- a/MediaBrowser.Controller/LiveTv/TimerEventInfo.cs +++ b/MediaBrowser.Controller/LiveTv/TimerEventInfo.cs @@ -1,10 +1,19 @@ +#nullable enable +#pragma warning disable CS1591 + using System; namespace MediaBrowser.Controller.LiveTv { public class TimerEventInfo { - public string Id { get; set; } - public Guid ProgramId { get; set; } + public TimerEventInfo(string id) + { + Id = id; + } + + public string Id { get; } + + public Guid? ProgramId { get; set; } } } diff --git a/MediaBrowser.Model/Activity/ActivityLogEntry.cs b/MediaBrowser.Model/Activity/ActivityLogEntry.cs index 80f01b66e..865d07b2c 100644 --- a/MediaBrowser.Model/Activity/ActivityLogEntry.cs +++ b/MediaBrowser.Model/Activity/ActivityLogEntry.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System; diff --git a/MediaBrowser.Model/ApiClient/ServerDiscoveryInfo.cs b/MediaBrowser.Model/ApiClient/ServerDiscoveryInfo.cs index bb203f895..fcc90a1f7 100644 --- a/MediaBrowser.Model/ApiClient/ServerDiscoveryInfo.cs +++ b/MediaBrowser.Model/ApiClient/ServerDiscoveryInfo.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 namespace MediaBrowser.Model.ApiClient diff --git a/MediaBrowser.Model/Branding/BrandingOptions.cs b/MediaBrowser.Model/Branding/BrandingOptions.cs index 8ab268a64..5ddf1e7e6 100644 --- a/MediaBrowser.Model/Branding/BrandingOptions.cs +++ b/MediaBrowser.Model/Branding/BrandingOptions.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 namespace MediaBrowser.Model.Branding diff --git a/MediaBrowser.Model/Channels/ChannelFeatures.cs b/MediaBrowser.Model/Channels/ChannelFeatures.cs index c4e97ffe5..496102d83 100644 --- a/MediaBrowser.Model/Channels/ChannelFeatures.cs +++ b/MediaBrowser.Model/Channels/ChannelFeatures.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System; diff --git a/MediaBrowser.Model/Channels/ChannelInfo.cs b/MediaBrowser.Model/Channels/ChannelInfo.cs index bfb34db55..f2432aaeb 100644 --- a/MediaBrowser.Model/Channels/ChannelInfo.cs +++ b/MediaBrowser.Model/Channels/ChannelInfo.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 namespace MediaBrowser.Model.Channels diff --git a/MediaBrowser.Model/Channels/ChannelQuery.cs b/MediaBrowser.Model/Channels/ChannelQuery.cs index 88fc94a6f..d11260039 100644 --- a/MediaBrowser.Model/Channels/ChannelQuery.cs +++ b/MediaBrowser.Model/Channels/ChannelQuery.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System; @@ -13,8 +14,11 @@ namespace MediaBrowser.Model.Channels /// /// The fields. public ItemFields[] Fields { get; set; } + public bool? EnableImages { get; set; } + public int? ImageTypeLimit { get; set; } + public ImageType[] EnableImageTypes { get; set; } /// @@ -48,7 +52,9 @@ namespace MediaBrowser.Model.Channels /// /// null if [is favorite] contains no value, true if [is favorite]; otherwise, false. public bool? IsFavorite { get; set; } + public bool? IsRecordingsFolder { get; set; } + public bool RefreshLatestChannelItems { get; set; } } } diff --git a/MediaBrowser.Model/Configuration/BaseApplicationConfiguration.cs b/MediaBrowser.Model/Configuration/BaseApplicationConfiguration.cs index cc2541f74..cdd322c94 100644 --- a/MediaBrowser.Model/Configuration/BaseApplicationConfiguration.cs +++ b/MediaBrowser.Model/Configuration/BaseApplicationConfiguration.cs @@ -1,3 +1,4 @@ +#nullable disable using System; using System.Xml.Serialization; diff --git a/MediaBrowser.Model/Configuration/EncodingOptions.cs b/MediaBrowser.Model/Configuration/EncodingOptions.cs index 648568fd7..0c0e01f11 100644 --- a/MediaBrowser.Model/Configuration/EncodingOptions.cs +++ b/MediaBrowser.Model/Configuration/EncodingOptions.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 namespace MediaBrowser.Model.Configuration @@ -5,10 +6,15 @@ namespace MediaBrowser.Model.Configuration public class EncodingOptions { public int EncodingThreadCount { get; set; } + public string TranscodingTempPath { get; set; } + public double DownMixAudioBoost { get; set; } + public bool EnableThrottling { get; set; } + public int ThrottleDelaySeconds { get; set; } + public string HardwareAccelerationType { get; set; } /// @@ -20,12 +26,19 @@ namespace MediaBrowser.Model.Configuration /// The current FFmpeg path being used by the system and displayed on the transcode page. /// public string EncoderAppPathDisplay { get; set; } + public string VaapiDevice { get; set; } + public int H264Crf { get; set; } + public int H265Crf { get; set; } + public string EncoderPreset { get; set; } + public string DeinterlaceMethod { get; set; } + public bool EnableHardwareEncoding { get; set; } + public bool EnableSubtitleExtraction { get; set; } public string[] HardwareDecodingCodecs { get; set; } diff --git a/MediaBrowser.Model/Configuration/LibraryOptions.cs b/MediaBrowser.Model/Configuration/LibraryOptions.cs index 4342ccd8a..4229a4335 100644 --- a/MediaBrowser.Model/Configuration/LibraryOptions.cs +++ b/MediaBrowser.Model/Configuration/LibraryOptions.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System; diff --git a/MediaBrowser.Model/Configuration/MetadataOptions.cs b/MediaBrowser.Model/Configuration/MetadataOptions.cs index 625054b9e..e7dc3da3c 100644 --- a/MediaBrowser.Model/Configuration/MetadataOptions.cs +++ b/MediaBrowser.Model/Configuration/MetadataOptions.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System; @@ -12,12 +13,15 @@ namespace MediaBrowser.Model.Configuration public string ItemType { get; set; } public string[] DisabledMetadataSavers { get; set; } + public string[] LocalMetadataReaderOrder { get; set; } public string[] DisabledMetadataFetchers { get; set; } + public string[] MetadataFetcherOrder { get; set; } public string[] DisabledImageFetchers { get; set; } + public string[] ImageFetcherOrder { get; set; } public MetadataOptions() diff --git a/MediaBrowser.Model/Configuration/MetadataPlugin.cs b/MediaBrowser.Model/Configuration/MetadataPlugin.cs index c2b47eb9b..db8cd1875 100644 --- a/MediaBrowser.Model/Configuration/MetadataPlugin.cs +++ b/MediaBrowser.Model/Configuration/MetadataPlugin.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 namespace MediaBrowser.Model.Configuration diff --git a/MediaBrowser.Model/Configuration/MetadataPluginSummary.cs b/MediaBrowser.Model/Configuration/MetadataPluginSummary.cs index 53063810b..0c197ee02 100644 --- a/MediaBrowser.Model/Configuration/MetadataPluginSummary.cs +++ b/MediaBrowser.Model/Configuration/MetadataPluginSummary.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System; diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs index 3107ec242..333805e31 100644 --- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs +++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System; diff --git a/MediaBrowser.Model/Configuration/UserConfiguration.cs b/MediaBrowser.Model/Configuration/UserConfiguration.cs index a475c9910..289047d6b 100644 --- a/MediaBrowser.Model/Configuration/UserConfiguration.cs +++ b/MediaBrowser.Model/Configuration/UserConfiguration.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System; diff --git a/MediaBrowser.Model/Configuration/XbmcMetadataOptions.cs b/MediaBrowser.Model/Configuration/XbmcMetadataOptions.cs index d6c1295f4..c48a38192 100644 --- a/MediaBrowser.Model/Configuration/XbmcMetadataOptions.cs +++ b/MediaBrowser.Model/Configuration/XbmcMetadataOptions.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 namespace MediaBrowser.Model.Configuration diff --git a/MediaBrowser.Model/Cryptography/ICryptoProvider.cs b/MediaBrowser.Model/Cryptography/ICryptoProvider.cs index 656c04f46..d8b7d848a 100644 --- a/MediaBrowser.Model/Cryptography/ICryptoProvider.cs +++ b/MediaBrowser.Model/Cryptography/ICryptoProvider.cs @@ -10,7 +10,7 @@ namespace MediaBrowser.Model.Cryptography IEnumerable GetSupportedHashMethods(); - byte[] ComputeHash(string HashMethod, byte[] bytes, byte[] salt); + byte[] ComputeHash(string hashMethod, byte[] bytes, byte[] salt); byte[] ComputeHashWithDefaultMethod(byte[] bytes, byte[] salt); diff --git a/MediaBrowser.Model/Devices/ContentUploadHistory.cs b/MediaBrowser.Model/Devices/ContentUploadHistory.cs index c493760d5..868956df2 100644 --- a/MediaBrowser.Model/Devices/ContentUploadHistory.cs +++ b/MediaBrowser.Model/Devices/ContentUploadHistory.cs @@ -1,15 +1,19 @@ +#nullable disable #pragma warning disable CS1591 +using System; + namespace MediaBrowser.Model.Devices { public class ContentUploadHistory { public string DeviceId { get; set; } + public LocalFileInfo[] FilesUploaded { get; set; } public ContentUploadHistory() { - FilesUploaded = new LocalFileInfo[] { }; + FilesUploaded = Array.Empty(); } } } diff --git a/MediaBrowser.Model/Devices/DeviceInfo.cs b/MediaBrowser.Model/Devices/DeviceInfo.cs index d2563d1d0..0cccf931c 100644 --- a/MediaBrowser.Model/Devices/DeviceInfo.cs +++ b/MediaBrowser.Model/Devices/DeviceInfo.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System; diff --git a/MediaBrowser.Model/Devices/DevicesOptions.cs b/MediaBrowser.Model/Devices/DevicesOptions.cs index 02570650e..327b5836f 100644 --- a/MediaBrowser.Model/Devices/DevicesOptions.cs +++ b/MediaBrowser.Model/Devices/DevicesOptions.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System; @@ -7,7 +8,9 @@ namespace MediaBrowser.Model.Devices public class DevicesOptions { public string[] EnabledCameraUploadDevices { get; set; } + public string CameraUploadPath { get; set; } + public bool EnableCameraUploadSubfolders { get; set; } public DevicesOptions() diff --git a/MediaBrowser.Model/Devices/LocalFileInfo.cs b/MediaBrowser.Model/Devices/LocalFileInfo.cs index 63a8dc2aa..c3158b2f2 100644 --- a/MediaBrowser.Model/Devices/LocalFileInfo.cs +++ b/MediaBrowser.Model/Devices/LocalFileInfo.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 namespace MediaBrowser.Model.Devices @@ -5,8 +6,11 @@ namespace MediaBrowser.Model.Devices public class LocalFileInfo { public string Name { get; set; } + public string Id { get; set; } + public string Album { get; set; } + public string MimeType { get; set; } } } diff --git a/MediaBrowser.Model/Diagnostics/IProcess.cs b/MediaBrowser.Model/Diagnostics/IProcess.cs index 514d1e737..c067189a6 100644 --- a/MediaBrowser.Model/Diagnostics/IProcess.cs +++ b/MediaBrowser.Model/Diagnostics/IProcess.cs @@ -11,13 +11,21 @@ namespace MediaBrowser.Model.Diagnostics event EventHandler Exited; void Kill(); + bool WaitForExit(int timeMs); + Task WaitForExitAsync(int timeMs); + int ExitCode { get; } + void Start(); + StreamWriter StandardInput { get; } + StreamReader StandardError { get; } + StreamReader StandardOutput { get; } + ProcessOptions StartInfo { get; } } } diff --git a/MediaBrowser.Model/Diagnostics/IProcessFactory.cs b/MediaBrowser.Model/Diagnostics/IProcessFactory.cs index 57082acc5..2d15aed7e 100644 --- a/MediaBrowser.Model/Diagnostics/IProcessFactory.cs +++ b/MediaBrowser.Model/Diagnostics/IProcessFactory.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 namespace MediaBrowser.Model.Diagnostics @@ -10,15 +11,25 @@ namespace MediaBrowser.Model.Diagnostics public class ProcessOptions { public string FileName { get; set; } + public string Arguments { get; set; } + public string WorkingDirectory { get; set; } + public bool CreateNoWindow { get; set; } + public bool UseShellExecute { get; set; } + public bool EnableRaisingEvents { get; set; } + public bool ErrorDialog { get; set; } + public bool RedirectStandardError { get; set; } + public bool RedirectStandardInput { get; set; } + public bool RedirectStandardOutput { get; set; } + public bool IsHidden { get; set; } } } diff --git a/MediaBrowser.Model/Dlna/AudioOptions.cs b/MediaBrowser.Model/Dlna/AudioOptions.cs index 40081b282..fc555c5f7 100644 --- a/MediaBrowser.Model/Dlna/AudioOptions.cs +++ b/MediaBrowser.Model/Dlna/AudioOptions.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System; @@ -19,12 +20,17 @@ namespace MediaBrowser.Model.Dlna } public bool EnableDirectPlay { get; set; } + public bool EnableDirectStream { get; set; } + public bool ForceDirectPlay { get; set; } + public bool ForceDirectStream { get; set; } public Guid ItemId { get; set; } + public MediaSourceInfo[] MediaSources { get; set; } + public DeviceProfile Profile { get; set; } /// diff --git a/MediaBrowser.Model/Dlna/CodecProfile.cs b/MediaBrowser.Model/Dlna/CodecProfile.cs index 756e500dd..cc5b840c7 100644 --- a/MediaBrowser.Model/Dlna/CodecProfile.cs +++ b/MediaBrowser.Model/Dlna/CodecProfile.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System; diff --git a/MediaBrowser.Model/Dlna/ConditionProcessor.cs b/MediaBrowser.Model/Dlna/ConditionProcessor.cs index 7423efaf6..f3aaef930 100644 --- a/MediaBrowser.Model/Dlna/ConditionProcessor.cs +++ b/MediaBrowser.Model/Dlna/ConditionProcessor.cs @@ -15,7 +15,7 @@ namespace MediaBrowser.Model.Dlna int? height, int? videoBitDepth, int? videoBitrate, - string videoProfile, + string? videoProfile, double? videoLevel, float? videoFramerate, int? packetLength, @@ -25,7 +25,7 @@ namespace MediaBrowser.Model.Dlna int? refFrames, int? numVideoStreams, int? numAudioStreams, - string videoCodecTag, + string? videoCodecTag, bool? isAvc) { switch (condition.Property) @@ -103,7 +103,7 @@ namespace MediaBrowser.Model.Dlna int? audioBitrate, int? audioSampleRate, int? audioBitDepth, - string audioProfile, + string? audioProfile, bool? isSecondaryTrack) { switch (condition.Property) @@ -154,7 +154,7 @@ namespace MediaBrowser.Model.Dlna return false; } - private static bool IsConditionSatisfied(ProfileCondition condition, string currentValue) + private static bool IsConditionSatisfied(ProfileCondition condition, string? currentValue) { if (string.IsNullOrEmpty(currentValue)) { @@ -203,34 +203,6 @@ namespace MediaBrowser.Model.Dlna return false; } - private static bool IsConditionSatisfied(ProfileCondition condition, float currentValue) - { - if (currentValue <= 0) - { - // If the value is unknown, it satisfies if not marked as required - return !condition.IsRequired; - } - - if (float.TryParse(condition.Value, NumberStyles.Any, CultureInfo.InvariantCulture, out var expected)) - { - switch (condition.Condition) - { - case ProfileConditionType.Equals: - return currentValue.Equals(expected); - case ProfileConditionType.GreaterThanEqual: - return currentValue >= expected; - case ProfileConditionType.LessThanEqual: - return currentValue <= expected; - case ProfileConditionType.NotEquals: - return !currentValue.Equals(expected); - default: - throw new InvalidOperationException("Unexpected ProfileConditionType: " + condition.Condition); - } - } - - return false; - } - private static bool IsConditionSatisfied(ProfileCondition condition, double? currentValue) { if (!currentValue.HasValue) diff --git a/MediaBrowser.Model/Dlna/ContainerProfile.cs b/MediaBrowser.Model/Dlna/ContainerProfile.cs index e6691c513..1d18da6a0 100644 --- a/MediaBrowser.Model/Dlna/ContainerProfile.cs +++ b/MediaBrowser.Model/Dlna/ContainerProfile.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System; @@ -10,6 +11,7 @@ namespace MediaBrowser.Model.Dlna { [XmlAttribute("type")] public DlnaProfileType Type { get; set; } + public ProfileCondition[] Conditions { get; set; } [XmlAttribute("container")] @@ -45,7 +47,7 @@ namespace MediaBrowser.Model.Dlna public static bool ContainsContainer(string profileContainers, string inputContainer) { var isNegativeList = false; - if (profileContainers != null && profileContainers.StartsWith("-")) + if (profileContainers != null && profileContainers.StartsWith("-", StringComparison.Ordinal)) { isNegativeList = true; profileContainers = profileContainers.Substring(1); diff --git a/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs b/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs index a20f11503..b055ad41a 100644 --- a/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs +++ b/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System; @@ -32,7 +33,10 @@ namespace MediaBrowser.Model.Dlna DlnaFlags.InteractiveTransferMode | DlnaFlags.DlnaV15; - string dlnaflags = string.Format(";DLNA.ORG_FLAGS={0}", DlnaMaps.FlagsToString(flagValue)); + string dlnaflags = string.Format( + CultureInfo.InvariantCulture, + ";DLNA.ORG_FLAGS={0}", + DlnaMaps.FlagsToString(flagValue)); ResponseProfile mediaProfile = _profile.GetImageMediaProfile(container, width, diff --git a/MediaBrowser.Model/Dlna/DeviceIdentification.cs b/MediaBrowser.Model/Dlna/DeviceIdentification.cs index f1699d930..85cc9e3c1 100644 --- a/MediaBrowser.Model/Dlna/DeviceIdentification.cs +++ b/MediaBrowser.Model/Dlna/DeviceIdentification.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System; diff --git a/MediaBrowser.Model/Dlna/DeviceProfile.cs b/MediaBrowser.Model/Dlna/DeviceProfile.cs index 0cefbbe01..704d4ec37 100644 --- a/MediaBrowser.Model/Dlna/DeviceProfile.cs +++ b/MediaBrowser.Model/Dlna/DeviceProfile.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System; diff --git a/MediaBrowser.Model/Dlna/DeviceProfileInfo.cs b/MediaBrowser.Model/Dlna/DeviceProfileInfo.cs index 347583965..74c32c523 100644 --- a/MediaBrowser.Model/Dlna/DeviceProfileInfo.cs +++ b/MediaBrowser.Model/Dlna/DeviceProfileInfo.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 namespace MediaBrowser.Model.Dlna diff --git a/MediaBrowser.Model/Dlna/DirectPlayProfile.cs b/MediaBrowser.Model/Dlna/DirectPlayProfile.cs index a5947bbf4..6f4b4ab1b 100644 --- a/MediaBrowser.Model/Dlna/DirectPlayProfile.cs +++ b/MediaBrowser.Model/Dlna/DirectPlayProfile.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System.Xml.Serialization; diff --git a/MediaBrowser.Model/Dlna/HttpHeaderInfo.cs b/MediaBrowser.Model/Dlna/HttpHeaderInfo.cs index f23a24084..17c4dffcc 100644 --- a/MediaBrowser.Model/Dlna/HttpHeaderInfo.cs +++ b/MediaBrowser.Model/Dlna/HttpHeaderInfo.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System.Xml.Serialization; diff --git a/MediaBrowser.Model/Dlna/ITranscoderSupport.cs b/MediaBrowser.Model/Dlna/ITranscoderSupport.cs index 7e35cc85b..d9bd094d9 100644 --- a/MediaBrowser.Model/Dlna/ITranscoderSupport.cs +++ b/MediaBrowser.Model/Dlna/ITranscoderSupport.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 namespace MediaBrowser.Model.Dlna @@ -5,7 +6,9 @@ namespace MediaBrowser.Model.Dlna public interface ITranscoderSupport { bool CanEncodeToAudioCodec(string codec); + bool CanEncodeToSubtitleCodec(string codec); + bool CanExtractSubtitles(string codec); } @@ -15,10 +18,12 @@ namespace MediaBrowser.Model.Dlna { return true; } + public bool CanEncodeToSubtitleCodec(string codec) { return true; } + public bool CanExtractSubtitles(string codec) { return true; diff --git a/MediaBrowser.Model/Dlna/MediaFormatProfileResolver.cs b/MediaBrowser.Model/Dlna/MediaFormatProfileResolver.cs index 4cd318abb..10e9179c0 100644 --- a/MediaBrowser.Model/Dlna/MediaFormatProfileResolver.cs +++ b/MediaBrowser.Model/Dlna/MediaFormatProfileResolver.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System; @@ -21,13 +22,13 @@ namespace MediaBrowser.Model.Dlna if (string.Equals(container, "asf", StringComparison.OrdinalIgnoreCase)) { MediaFormatProfile? val = ResolveVideoASFFormat(videoCodec, audioCodec, width, height); - return val.HasValue ? new MediaFormatProfile[] { val.Value } : new MediaFormatProfile[] { }; + return val.HasValue ? new MediaFormatProfile[] { val.Value } : Array.Empty(); } if (string.Equals(container, "mp4", StringComparison.OrdinalIgnoreCase)) { MediaFormatProfile? val = ResolveVideoMP4Format(videoCodec, audioCodec, width, height); - return val.HasValue ? new MediaFormatProfile[] { val.Value } : new MediaFormatProfile[] { }; + return val.HasValue ? new MediaFormatProfile[] { val.Value } : Array.Empty(); } if (string.Equals(container, "avi", StringComparison.OrdinalIgnoreCase)) @@ -61,18 +62,18 @@ namespace MediaBrowser.Model.Dlna if (string.Equals(container, "3gp", StringComparison.OrdinalIgnoreCase)) { MediaFormatProfile? val = ResolveVideo3GPFormat(videoCodec, audioCodec); - return val.HasValue ? new MediaFormatProfile[] { val.Value } : new MediaFormatProfile[] { }; + return val.HasValue ? new MediaFormatProfile[] { val.Value } : Array.Empty(); } if (string.Equals(container, "ogv", StringComparison.OrdinalIgnoreCase) || string.Equals(container, "ogg", StringComparison.OrdinalIgnoreCase)) return new MediaFormatProfile[] { MediaFormatProfile.OGV }; - return new MediaFormatProfile[] { }; + return Array.Empty(); } private MediaFormatProfile[] ResolveVideoMPEG2TSFormat(string videoCodec, string audioCodec, int? width, int? height, TransportStreamTimestamp timestampType) { - string suffix = ""; + string suffix = string.Empty; switch (timestampType) { @@ -92,16 +93,18 @@ namespace MediaBrowser.Model.Dlna if (string.Equals(videoCodec, "mpeg2video", StringComparison.OrdinalIgnoreCase)) { - var list = new List(); - - list.Add(ValueOf("MPEG_TS_SD_NA" + suffix)); - list.Add(ValueOf("MPEG_TS_SD_EU" + suffix)); - list.Add(ValueOf("MPEG_TS_SD_KO" + suffix)); + var list = new List + { + ValueOf("MPEG_TS_SD_NA" + suffix), + ValueOf("MPEG_TS_SD_EU" + suffix), + ValueOf("MPEG_TS_SD_KO" + suffix) + }; if ((timestampType == TransportStreamTimestamp.Valid) && string.Equals(audioCodec, "aac", StringComparison.OrdinalIgnoreCase)) { list.Add(MediaFormatProfile.MPEG_TS_JP_T); } + return list.ToArray(); } if (string.Equals(videoCodec, "h264", StringComparison.OrdinalIgnoreCase)) @@ -115,6 +118,7 @@ namespace MediaBrowser.Model.Dlna { return new MediaFormatProfile[] { MediaFormatProfile.AVC_TS_HD_DTS_ISO }; } + return new MediaFormatProfile[] { MediaFormatProfile.AVC_TS_HD_DTS_T }; } diff --git a/MediaBrowser.Model/Dlna/ProfileCondition.cs b/MediaBrowser.Model/Dlna/ProfileCondition.cs index 2021038d8..f8b5dee81 100644 --- a/MediaBrowser.Model/Dlna/ProfileCondition.cs +++ b/MediaBrowser.Model/Dlna/ProfileCondition.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System.Xml.Serialization; @@ -6,18 +7,6 @@ namespace MediaBrowser.Model.Dlna { public class ProfileCondition { - [XmlAttribute("condition")] - public ProfileConditionType Condition { get; set; } - - [XmlAttribute("property")] - public ProfileConditionValue Property { get; set; } - - [XmlAttribute("value")] - public string Value { get; set; } - - [XmlAttribute("isRequired")] - public bool IsRequired { get; set; } - public ProfileCondition() { IsRequired = true; @@ -36,5 +25,17 @@ namespace MediaBrowser.Model.Dlna Value = value; IsRequired = isRequired; } + + [XmlAttribute("condition")] + public ProfileConditionType Condition { get; set; } + + [XmlAttribute("property")] + public ProfileConditionValue Property { get; set; } + + [XmlAttribute("value")] + public string Value { get; set; } + + [XmlAttribute("isRequired")] + public bool IsRequired { get; set; } } } diff --git a/MediaBrowser.Model/Dlna/ResolutionConfiguration.cs b/MediaBrowser.Model/Dlna/ResolutionConfiguration.cs index c26eeec77..30c44fbe0 100644 --- a/MediaBrowser.Model/Dlna/ResolutionConfiguration.cs +++ b/MediaBrowser.Model/Dlna/ResolutionConfiguration.cs @@ -5,6 +5,7 @@ namespace MediaBrowser.Model.Dlna public class ResolutionConfiguration { public int MaxWidth { get; set; } + public int MaxBitrate { get; set; } public ResolutionConfiguration(int maxWidth, int maxBitrate) diff --git a/MediaBrowser.Model/Dlna/ResolutionNormalizer.cs b/MediaBrowser.Model/Dlna/ResolutionNormalizer.cs index 8235b72d1..102db3b44 100644 --- a/MediaBrowser.Model/Dlna/ResolutionNormalizer.cs +++ b/MediaBrowser.Model/Dlna/ResolutionNormalizer.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System; @@ -17,7 +18,8 @@ namespace MediaBrowser.Model.Dlna new ResolutionConfiguration(3840, 35000000) }; - public static ResolutionOptions Normalize(int? inputBitrate, + public static ResolutionOptions Normalize( + int? inputBitrate, int? unused1, int? unused2, int outputBitrate, @@ -83,6 +85,7 @@ namespace MediaBrowser.Model.Dlna { return .5; } + return 1; } diff --git a/MediaBrowser.Model/Dlna/ResolutionOptions.cs b/MediaBrowser.Model/Dlna/ResolutionOptions.cs index 5ea0252cb..774592abc 100644 --- a/MediaBrowser.Model/Dlna/ResolutionOptions.cs +++ b/MediaBrowser.Model/Dlna/ResolutionOptions.cs @@ -5,6 +5,7 @@ namespace MediaBrowser.Model.Dlna public class ResolutionOptions { public int? MaxWidth { get; set; } + public int? MaxHeight { get; set; } } } diff --git a/MediaBrowser.Model/Dlna/ResponseProfile.cs b/MediaBrowser.Model/Dlna/ResponseProfile.cs index c264cb936..48f53f06c 100644 --- a/MediaBrowser.Model/Dlna/ResponseProfile.cs +++ b/MediaBrowser.Model/Dlna/ResponseProfile.cs @@ -1,5 +1,7 @@ +#nullable disable #pragma warning disable CS1591 +using System; using System.Xml.Serialization; namespace MediaBrowser.Model.Dlna @@ -28,7 +30,7 @@ namespace MediaBrowser.Model.Dlna public ResponseProfile() { - Conditions = new ProfileCondition[] { }; + Conditions = Array.Empty(); } public string[] GetContainers() diff --git a/MediaBrowser.Model/Dlna/SearchCriteria.cs b/MediaBrowser.Model/Dlna/SearchCriteria.cs index 394fb9af9..94f5bd3db 100644 --- a/MediaBrowser.Model/Dlna/SearchCriteria.cs +++ b/MediaBrowser.Model/Dlna/SearchCriteria.cs @@ -34,9 +34,9 @@ namespace MediaBrowser.Model.Dlna public SearchCriteria(string search) { - if (string.IsNullOrEmpty(search)) + if (search.Length == 0) { - throw new ArgumentNullException(nameof(search)); + throw new ArgumentException("String can't be empty.", nameof(search)); } SearchType = SearchType.Unknown; @@ -48,11 +48,10 @@ namespace MediaBrowser.Model.Dlna if (subFactors.Length == 3) { - if (string.Equals("upnp:class", subFactors[0], StringComparison.OrdinalIgnoreCase) && - (string.Equals("=", subFactors[1]) || string.Equals("derivedfrom", subFactors[1], StringComparison.OrdinalIgnoreCase))) + (string.Equals("=", subFactors[1], StringComparison.Ordinal) || string.Equals("derivedfrom", subFactors[1], StringComparison.OrdinalIgnoreCase))) { - if (string.Equals("\"object.item.imageItem\"", subFactors[2]) || string.Equals("\"object.item.imageItem.photo\"", subFactors[2], StringComparison.OrdinalIgnoreCase)) + if (string.Equals("\"object.item.imageItem\"", subFactors[2], StringComparison.Ordinal) || string.Equals("\"object.item.imageItem.photo\"", subFactors[2], StringComparison.OrdinalIgnoreCase)) { SearchType = SearchType.Image; } diff --git a/MediaBrowser.Model/Dlna/StreamBuilder.cs b/MediaBrowser.Model/Dlna/StreamBuilder.cs index 58755b171..a18ad36c5 100644 --- a/MediaBrowser.Model/Dlna/StreamBuilder.cs +++ b/MediaBrowser.Model/Dlna/StreamBuilder.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System; @@ -339,6 +340,7 @@ namespace MediaBrowser.Model.Dlna { transcodeReasons.Add(transcodeReason.Value); } + all = false; break; } diff --git a/MediaBrowser.Model/Dlna/StreamInfo.cs b/MediaBrowser.Model/Dlna/StreamInfo.cs index c9fe679e1..244463803 100644 --- a/MediaBrowser.Model/Dlna/StreamInfo.cs +++ b/MediaBrowser.Model/Dlna/StreamInfo.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System; diff --git a/MediaBrowser.Model/Dlna/SubtitleProfile.cs b/MediaBrowser.Model/Dlna/SubtitleProfile.cs index 6a8f655ac..f565fb025 100644 --- a/MediaBrowser.Model/Dlna/SubtitleProfile.cs +++ b/MediaBrowser.Model/Dlna/SubtitleProfile.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System.Xml.Serialization; diff --git a/MediaBrowser.Model/Dlna/SubtitleStreamInfo.cs b/MediaBrowser.Model/Dlna/SubtitleStreamInfo.cs index 02b3a198c..2f01836bd 100644 --- a/MediaBrowser.Model/Dlna/SubtitleStreamInfo.cs +++ b/MediaBrowser.Model/Dlna/SubtitleStreamInfo.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 namespace MediaBrowser.Model.Dlna @@ -5,13 +6,21 @@ namespace MediaBrowser.Model.Dlna public class SubtitleStreamInfo { public string Url { get; set; } + public string Language { get; set; } + public string Name { get; set; } + public bool IsForced { get; set; } + public string Format { get; set; } + public string DisplayTitle { get; set; } + public int Index { get; set; } + public SubtitleDeliveryMethod DeliveryMethod { get; set; } + public bool IsExternalUrl { get; set; } } } diff --git a/MediaBrowser.Model/Dlna/TranscodingProfile.cs b/MediaBrowser.Model/Dlna/TranscodingProfile.cs index 570ee7baa..f05e31047 100644 --- a/MediaBrowser.Model/Dlna/TranscodingProfile.cs +++ b/MediaBrowser.Model/Dlna/TranscodingProfile.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System.Xml.Serialization; diff --git a/MediaBrowser.Model/Dlna/UpnpDeviceInfo.cs b/MediaBrowser.Model/Dlna/UpnpDeviceInfo.cs index 3dc1fca36..d71013f01 100644 --- a/MediaBrowser.Model/Dlna/UpnpDeviceInfo.cs +++ b/MediaBrowser.Model/Dlna/UpnpDeviceInfo.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System; @@ -9,8 +10,11 @@ namespace MediaBrowser.Model.Dlna public class UpnpDeviceInfo { public Uri Location { get; set; } + public Dictionary Headers { get; set; } + public IPAddress LocalIpAddress { get; set; } + public int LocalPort { get; set; } } } diff --git a/MediaBrowser.Model/Dlna/VideoOptions.cs b/MediaBrowser.Model/Dlna/VideoOptions.cs index 5b12fff1c..4194f17c6 100644 --- a/MediaBrowser.Model/Dlna/VideoOptions.cs +++ b/MediaBrowser.Model/Dlna/VideoOptions.cs @@ -8,6 +8,7 @@ namespace MediaBrowser.Model.Dlna public class VideoOptions : AudioOptions { public int? AudioStreamIndex { get; set; } + public int? SubtitleStreamIndex { get; set; } } } diff --git a/MediaBrowser.Model/Dlna/XmlAttribute.cs b/MediaBrowser.Model/Dlna/XmlAttribute.cs index 31603a754..3a8939a79 100644 --- a/MediaBrowser.Model/Dlna/XmlAttribute.cs +++ b/MediaBrowser.Model/Dlna/XmlAttribute.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System.Xml.Serialization; diff --git a/MediaBrowser.Model/Drawing/DrawingUtils.cs b/MediaBrowser.Model/Drawing/DrawingUtils.cs index 0be30b0ba..1512c5233 100644 --- a/MediaBrowser.Model/Drawing/DrawingUtils.cs +++ b/MediaBrowser.Model/Drawing/DrawingUtils.cs @@ -16,7 +16,8 @@ namespace MediaBrowser.Model.Drawing /// A max fixed width, if desired. /// A max fixed height, if desired. /// A new size object. - public static ImageDimensions Resize(ImageDimensions size, + public static ImageDimensions Resize( + ImageDimensions size, int width, int height, int maxWidth, @@ -62,7 +63,7 @@ namespace MediaBrowser.Model.Drawing /// Height of the current. /// Width of the current. /// The new height. - /// the new width + /// The new width. private static int GetNewWidth(int currentHeight, int currentWidth, int newHeight) => Convert.ToInt32((double)newHeight / currentHeight * currentWidth); diff --git a/MediaBrowser.Model/Dto/BaseItemDto.cs b/MediaBrowser.Model/Dto/BaseItemDto.cs index 607355d8d..55393d32c 100644 --- a/MediaBrowser.Model/Dto/BaseItemDto.cs +++ b/MediaBrowser.Model/Dto/BaseItemDto.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System; diff --git a/MediaBrowser.Model/Dto/BaseItemPerson.cs b/MediaBrowser.Model/Dto/BaseItemPerson.cs index 5b7eefd70..b080f3e4a 100644 --- a/MediaBrowser.Model/Dto/BaseItemPerson.cs +++ b/MediaBrowser.Model/Dto/BaseItemPerson.cs @@ -1,3 +1,4 @@ +#nullable disable using System.Text.Json.Serialization; namespace MediaBrowser.Model.Dto diff --git a/MediaBrowser.Model/Dto/IHasServerId.cs b/MediaBrowser.Model/Dto/IHasServerId.cs index 8c9798c5c..c754d276c 100644 --- a/MediaBrowser.Model/Dto/IHasServerId.cs +++ b/MediaBrowser.Model/Dto/IHasServerId.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 namespace MediaBrowser.Model.Dto diff --git a/MediaBrowser.Model/Dto/ImageByNameInfo.cs b/MediaBrowser.Model/Dto/ImageByNameInfo.cs index d2e43634d..06cc3e73c 100644 --- a/MediaBrowser.Model/Dto/ImageByNameInfo.cs +++ b/MediaBrowser.Model/Dto/ImageByNameInfo.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 namespace MediaBrowser.Model.Dto diff --git a/MediaBrowser.Model/Dto/ImageInfo.cs b/MediaBrowser.Model/Dto/ImageInfo.cs index 57942ac23..1e9b47267 100644 --- a/MediaBrowser.Model/Dto/ImageInfo.cs +++ b/MediaBrowser.Model/Dto/ImageInfo.cs @@ -1,3 +1,4 @@ +#nullable disable using MediaBrowser.Model.Entities; namespace MediaBrowser.Model.Dto @@ -20,9 +21,9 @@ namespace MediaBrowser.Model.Dto public int? ImageIndex { get; set; } /// - /// The image tag + /// Gets or sets the image tag. /// - public string ImageTag; + public string ImageTag { get; set; } /// /// Gets or sets the path. diff --git a/MediaBrowser.Model/Dto/ImageOptions.cs b/MediaBrowser.Model/Dto/ImageOptions.cs index 4e672a007..158e622a8 100644 --- a/MediaBrowser.Model/Dto/ImageOptions.cs +++ b/MediaBrowser.Model/Dto/ImageOptions.cs @@ -1,3 +1,4 @@ +#nullable disable using MediaBrowser.Model.Drawing; using MediaBrowser.Model.Entities; @@ -8,6 +9,14 @@ namespace MediaBrowser.Model.Dto /// public class ImageOptions { + /// + /// Initializes a new instance of the class. + /// + public ImageOptions() + { + EnableImageEnhancers = true; + } + /// /// Gets or sets the type of the image. /// @@ -98,13 +107,5 @@ namespace MediaBrowser.Model.Dto /// /// The color of the background. public string BackgroundColor { get; set; } - - /// - /// Initializes a new instance of the class. - /// - public ImageOptions() - { - EnableImageEnhancers = true; - } } } diff --git a/MediaBrowser.Model/Dto/ItemIndex.cs b/MediaBrowser.Model/Dto/ItemIndex.cs deleted file mode 100644 index 525576d61..000000000 --- a/MediaBrowser.Model/Dto/ItemIndex.cs +++ /dev/null @@ -1,20 +0,0 @@ -namespace MediaBrowser.Model.Dto -{ - /// - /// Class ItemIndex. - /// - public class ItemIndex - { - /// - /// Gets or sets the name. - /// - /// The name. - public string Name { get; set; } - - /// - /// Gets or sets the item count. - /// - /// The item count. - public int ItemCount { get; set; } - } -} diff --git a/MediaBrowser.Model/Dto/MediaSourceInfo.cs b/MediaBrowser.Model/Dto/MediaSourceInfo.cs index 29613adbf..74c2cb4f4 100644 --- a/MediaBrowser.Model/Dto/MediaSourceInfo.cs +++ b/MediaBrowser.Model/Dto/MediaSourceInfo.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System; diff --git a/MediaBrowser.Model/Dto/MetadataEditorInfo.cs b/MediaBrowser.Model/Dto/MetadataEditorInfo.cs index 21d8a31f2..1d840a300 100644 --- a/MediaBrowser.Model/Dto/MetadataEditorInfo.cs +++ b/MediaBrowser.Model/Dto/MetadataEditorInfo.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System; diff --git a/MediaBrowser.Model/Dto/NameIdPair.cs b/MediaBrowser.Model/Dto/NameIdPair.cs index 1b4800863..efb2c157c 100644 --- a/MediaBrowser.Model/Dto/NameIdPair.cs +++ b/MediaBrowser.Model/Dto/NameIdPair.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System; diff --git a/MediaBrowser.Model/Dto/NameValuePair.cs b/MediaBrowser.Model/Dto/NameValuePair.cs index 74040c2cb..e71ff3c21 100644 --- a/MediaBrowser.Model/Dto/NameValuePair.cs +++ b/MediaBrowser.Model/Dto/NameValuePair.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 namespace MediaBrowser.Model.Dto @@ -6,7 +7,6 @@ namespace MediaBrowser.Model.Dto { public NameValuePair() { - } public NameValuePair(string name, string value) diff --git a/MediaBrowser.Model/Dto/RecommendationDto.cs b/MediaBrowser.Model/Dto/RecommendationDto.cs index bc97dd6f1..107f41540 100644 --- a/MediaBrowser.Model/Dto/RecommendationDto.cs +++ b/MediaBrowser.Model/Dto/RecommendationDto.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System; diff --git a/MediaBrowser.Model/Dto/UserDto.cs b/MediaBrowser.Model/Dto/UserDto.cs index d36706c38..40222c9dc 100644 --- a/MediaBrowser.Model/Dto/UserDto.cs +++ b/MediaBrowser.Model/Dto/UserDto.cs @@ -1,3 +1,4 @@ +#nullable disable using System; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Users; diff --git a/MediaBrowser.Model/Dto/UserItemDataDto.cs b/MediaBrowser.Model/Dto/UserItemDataDto.cs index 92f06c973..adb2cd2ab 100644 --- a/MediaBrowser.Model/Dto/UserItemDataDto.cs +++ b/MediaBrowser.Model/Dto/UserItemDataDto.cs @@ -1,3 +1,4 @@ +#nullable disable using System; namespace MediaBrowser.Model.Dto diff --git a/MediaBrowser.Model/Entities/ChapterInfo.cs b/MediaBrowser.Model/Entities/ChapterInfo.cs index bea7ec1db..45554c3dc 100644 --- a/MediaBrowser.Model/Entities/ChapterInfo.cs +++ b/MediaBrowser.Model/Entities/ChapterInfo.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System; diff --git a/MediaBrowser.Model/Entities/DisplayPreferences.cs b/MediaBrowser.Model/Entities/DisplayPreferences.cs index 2cd8bd306..0e5db01dd 100644 --- a/MediaBrowser.Model/Entities/DisplayPreferences.cs +++ b/MediaBrowser.Model/Entities/DisplayPreferences.cs @@ -1,3 +1,4 @@ +#nullable disable using System.Collections.Generic; namespace MediaBrowser.Model.Entities diff --git a/MediaBrowser.Model/Entities/IHasProviderIds.cs b/MediaBrowser.Model/Entities/IHasProviderIds.cs index c117efde9..1310f68ae 100644 --- a/MediaBrowser.Model/Entities/IHasProviderIds.cs +++ b/MediaBrowser.Model/Entities/IHasProviderIds.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; namespace MediaBrowser.Model.Entities { /// - /// Since BaseItem and DTOBaseItem both have ProviderIds, this interface helps avoid code repition by using extension methods. + /// Since BaseItem and DTOBaseItem both have ProviderIds, this interface helps avoid code repetition by using extension methods. /// public interface IHasProviderIds { diff --git a/MediaBrowser.Model/Entities/LibraryUpdateInfo.cs b/MediaBrowser.Model/Entities/LibraryUpdateInfo.cs index b98c00240..6dd6653dc 100644 --- a/MediaBrowser.Model/Entities/LibraryUpdateInfo.cs +++ b/MediaBrowser.Model/Entities/LibraryUpdateInfo.cs @@ -5,15 +5,29 @@ using System; namespace MediaBrowser.Model.Entities { /// - /// Class LibraryUpdateInfo + /// Class LibraryUpdateInfo. /// public class LibraryUpdateInfo { + /// + /// Initializes a new instance of the class. + /// + public LibraryUpdateInfo() + { + FoldersAddedTo = Array.Empty(); + FoldersRemovedFrom = Array.Empty(); + ItemsAdded = Array.Empty(); + ItemsRemoved = Array.Empty(); + ItemsUpdated = Array.Empty(); + CollectionFolders = Array.Empty(); + } + /// /// Gets or sets the folders added to. /// /// The folders added to. public string[] FoldersAddedTo { get; set; } + /// /// Gets or sets the folders removed from. /// @@ -41,18 +55,5 @@ namespace MediaBrowser.Model.Entities public string[] CollectionFolders { get; set; } public bool IsEmpty => FoldersAddedTo.Length == 0 && FoldersRemovedFrom.Length == 0 && ItemsAdded.Length == 0 && ItemsRemoved.Length == 0 && ItemsUpdated.Length == 0 && CollectionFolders.Length == 0; - - /// - /// Initializes a new instance of the class. - /// - public LibraryUpdateInfo() - { - FoldersAddedTo = Array.Empty(); - FoldersRemovedFrom = Array.Empty(); - ItemsAdded = Array.Empty(); - ItemsRemoved = Array.Empty(); - ItemsUpdated = Array.Empty(); - CollectionFolders = Array.Empty(); - } } } diff --git a/MediaBrowser.Model/Entities/MediaAttachment.cs b/MediaBrowser.Model/Entities/MediaAttachment.cs index 167be18c9..34e3eabc9 100644 --- a/MediaBrowser.Model/Entities/MediaAttachment.cs +++ b/MediaBrowser.Model/Entities/MediaAttachment.cs @@ -1,3 +1,4 @@ +#nullable disable namespace MediaBrowser.Model.Entities { /// diff --git a/MediaBrowser.Model/Entities/MediaStream.cs b/MediaBrowser.Model/Entities/MediaStream.cs index e7e8d7cec..d68f37c9c 100644 --- a/MediaBrowser.Model/Entities/MediaStream.cs +++ b/MediaBrowser.Model/Entities/MediaStream.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System; diff --git a/MediaBrowser.Model/Entities/MediaUrl.cs b/MediaBrowser.Model/Entities/MediaUrl.cs index e44143755..74f982437 100644 --- a/MediaBrowser.Model/Entities/MediaUrl.cs +++ b/MediaBrowser.Model/Entities/MediaUrl.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 namespace MediaBrowser.Model.Entities diff --git a/MediaBrowser.Model/Entities/PackageReviewInfo.cs b/MediaBrowser.Model/Entities/PackageReviewInfo.cs index a034de8ba..1ebbc3323 100644 --- a/MediaBrowser.Model/Entities/PackageReviewInfo.cs +++ b/MediaBrowser.Model/Entities/PackageReviewInfo.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System; @@ -7,32 +8,32 @@ namespace MediaBrowser.Model.Entities public class PackageReviewInfo { /// - /// The package id (database key) for this review + /// Gets or sets the package id (database key) for this review. /// public int id { get; set; } /// - /// The rating value + /// Gets or sets the rating value. /// public int rating { get; set; } /// - /// Whether or not this review recommends this item + /// Gets or sets whether or not this review recommends this item. /// public bool recommend { get; set; } /// - /// A short description of the review + /// Gets or sets a short description of the review. /// public string title { get; set; } /// - /// A full review + /// Gets or sets the full review. /// public string review { get; set; } /// - /// Time of review + /// Gets or sets the time of review. /// public DateTime timestamp { get; set; } diff --git a/MediaBrowser.Model/Entities/ParentalRating.cs b/MediaBrowser.Model/Entities/ParentalRating.cs index 4b37bd64a..17b2868a3 100644 --- a/MediaBrowser.Model/Entities/ParentalRating.cs +++ b/MediaBrowser.Model/Entities/ParentalRating.cs @@ -1,12 +1,23 @@ +#nullable disable #pragma warning disable CS1591 namespace MediaBrowser.Model.Entities { /// - /// Class ParentalRating + /// Class ParentalRating. /// public class ParentalRating { + public ParentalRating() + { + } + + public ParentalRating(string name, int value) + { + Name = name; + Value = value; + } + /// /// Gets or sets the name. /// @@ -18,16 +29,5 @@ namespace MediaBrowser.Model.Entities /// /// The value. public int Value { get; set; } - - public ParentalRating() - { - - } - - public ParentalRating(string name, int value) - { - Name = name; - Value = value; - } } } diff --git a/MediaBrowser.Model/Entities/ProviderIdsExtensions.cs b/MediaBrowser.Model/Entities/ProviderIdsExtensions.cs index cd387bd54..e089dd1e5 100644 --- a/MediaBrowser.Model/Entities/ProviderIdsExtensions.cs +++ b/MediaBrowser.Model/Entities/ProviderIdsExtensions.cs @@ -20,23 +20,23 @@ namespace MediaBrowser.Model.Entities } /// - /// Gets a provider id + /// Gets a provider id. /// /// The instance. /// The provider. /// System.String. - public static string GetProviderId(this IHasProviderIds instance, MetadataProviders provider) + public static string? GetProviderId(this IHasProviderIds instance, MetadataProviders provider) { return instance.GetProviderId(provider.ToString()); } /// - /// Gets a provider id + /// Gets a provider id. /// /// The instance. /// The name. /// System.String. - public static string GetProviderId(this IHasProviderIds instance, string name) + public static string? GetProviderId(this IHasProviderIds instance, string name) { if (instance == null) { @@ -53,7 +53,7 @@ namespace MediaBrowser.Model.Entities } /// - /// Sets a provider id + /// Sets a provider id. /// /// The instance. /// The name. @@ -89,7 +89,7 @@ namespace MediaBrowser.Model.Entities } /// - /// Sets a provider id + /// Sets a provider id. /// /// The instance. /// The provider. diff --git a/MediaBrowser.Model/Entities/VirtualFolderInfo.cs b/MediaBrowser.Model/Entities/VirtualFolderInfo.cs index dd30c9c84..2de02e403 100644 --- a/MediaBrowser.Model/Entities/VirtualFolderInfo.cs +++ b/MediaBrowser.Model/Entities/VirtualFolderInfo.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System; diff --git a/MediaBrowser.Model/Events/GenericEventArgs.cs b/MediaBrowser.Model/Events/GenericEventArgs.cs index 1ef0b25c9..44f60f811 100644 --- a/MediaBrowser.Model/Events/GenericEventArgs.cs +++ b/MediaBrowser.Model/Events/GenericEventArgs.cs @@ -22,12 +22,5 @@ namespace MediaBrowser.Model.Events { Argument = arg; } - - /// - /// Initializes a new instance of the class. - /// - public GenericEventArgs() - { - } } } diff --git a/MediaBrowser.Model/Extensions/ListHelper.cs b/MediaBrowser.Model/Extensions/ListHelper.cs index 90ce6f2e5..b893a3509 100644 --- a/MediaBrowser.Model/Extensions/ListHelper.cs +++ b/MediaBrowser.Model/Extensions/ListHelper.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System; @@ -21,6 +22,7 @@ namespace MediaBrowser.Model.Extensions return true; } } + return false; } } diff --git a/MediaBrowser.Model/Extensions/StringHelper.cs b/MediaBrowser.Model/Extensions/StringHelper.cs index f819a295c..8ffa3c4ba 100644 --- a/MediaBrowser.Model/Extensions/StringHelper.cs +++ b/MediaBrowser.Model/Extensions/StringHelper.cs @@ -12,9 +12,9 @@ namespace MediaBrowser.Model.Extensions /// The string with the first character as uppercase. public static string FirstToUpper(string str) { - if (string.IsNullOrEmpty(str)) + if (str.Length == 0) { - return string.Empty; + return str; } if (char.IsUpper(str[0])) diff --git a/MediaBrowser.Model/Globalization/CountryInfo.cs b/MediaBrowser.Model/Globalization/CountryInfo.cs index 72362f4f3..6f6979316 100644 --- a/MediaBrowser.Model/Globalization/CountryInfo.cs +++ b/MediaBrowser.Model/Globalization/CountryInfo.cs @@ -1,3 +1,4 @@ +#nullable disable namespace MediaBrowser.Model.Globalization { /// diff --git a/MediaBrowser.Model/Globalization/CultureDto.cs b/MediaBrowser.Model/Globalization/CultureDto.cs index f415840b0..6af4a872c 100644 --- a/MediaBrowser.Model/Globalization/CultureDto.cs +++ b/MediaBrowser.Model/Globalization/CultureDto.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System; diff --git a/MediaBrowser.Model/Globalization/ILocalizationManager.cs b/MediaBrowser.Model/Globalization/ILocalizationManager.cs index 613bfca69..baefeb39c 100644 --- a/MediaBrowser.Model/Globalization/ILocalizationManager.cs +++ b/MediaBrowser.Model/Globalization/ILocalizationManager.cs @@ -1,3 +1,4 @@ +#nullable disable using System.Collections.Generic; using System.Globalization; using MediaBrowser.Model.Entities; diff --git a/MediaBrowser.Model/Globalization/LocalizationOption.cs b/MediaBrowser.Model/Globalization/LocalizationOption.cs index 00caf5e11..81f47d978 100644 --- a/MediaBrowser.Model/Globalization/LocalizationOption.cs +++ b/MediaBrowser.Model/Globalization/LocalizationOption.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 namespace MediaBrowser.Model.Globalization @@ -11,6 +12,7 @@ namespace MediaBrowser.Model.Globalization } public string Name { get; set; } + public string Value { get; set; } } } diff --git a/MediaBrowser.Model/IO/FileSystemEntryInfo.cs b/MediaBrowser.Model/IO/FileSystemEntryInfo.cs index a197f0fbe..36ff5d041 100644 --- a/MediaBrowser.Model/IO/FileSystemEntryInfo.cs +++ b/MediaBrowser.Model/IO/FileSystemEntryInfo.cs @@ -1,26 +1,39 @@ namespace MediaBrowser.Model.IO { /// - /// Class FileSystemEntryInfo + /// Class FileSystemEntryInfo. /// public class FileSystemEntryInfo { /// - /// Gets or sets the name. + /// Initializes a new instance of the class. + /// + /// The filename. + /// The file path. + /// The file type. + public FileSystemEntryInfo(string name, string path, FileSystemEntryType type) + { + Name = name; + Path = path; + Type = type; + } + + /// + /// Gets the name. /// /// The name. - public string Name { get; set; } + public string Name { get; } /// - /// Gets or sets the path. + /// Gets the path. /// /// The path. - public string Path { get; set; } + public string Path { get; } /// - /// Gets or sets the type. + /// Gets the type. /// /// The type. - public FileSystemEntryType Type { get; set; } + public FileSystemEntryType Type { get; } } } diff --git a/MediaBrowser.Model/IO/FileSystemMetadata.cs b/MediaBrowser.Model/IO/FileSystemMetadata.cs index 4b9102392..b23119d08 100644 --- a/MediaBrowser.Model/IO/FileSystemMetadata.cs +++ b/MediaBrowser.Model/IO/FileSystemMetadata.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System; diff --git a/MediaBrowser.Model/IO/IFileSystem.cs b/MediaBrowser.Model/IO/IFileSystem.cs index 53f23a8e0..bba69d4b4 100644 --- a/MediaBrowser.Model/IO/IFileSystem.cs +++ b/MediaBrowser.Model/IO/IFileSystem.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System; diff --git a/MediaBrowser.Model/IO/IIsoManager.cs b/MediaBrowser.Model/IO/IIsoManager.cs index 8b6af019d..299bb0a21 100644 --- a/MediaBrowser.Model/IO/IIsoManager.cs +++ b/MediaBrowser.Model/IO/IIsoManager.cs @@ -16,7 +16,6 @@ namespace MediaBrowser.Model.IO /// The iso path. /// The cancellation token. /// IsoMount. - /// isoPath /// Unable to create mount. Task Mount(string isoPath, CancellationToken cancellationToken); diff --git a/MediaBrowser.Model/IO/IIsoMount.cs b/MediaBrowser.Model/IO/IIsoMount.cs index 72ec673ee..ea65d976a 100644 --- a/MediaBrowser.Model/IO/IIsoMount.cs +++ b/MediaBrowser.Model/IO/IIsoMount.cs @@ -8,7 +8,7 @@ namespace MediaBrowser.Model.IO public interface IIsoMount : IDisposable { /// - /// Gets or sets the iso path. + /// Gets the iso path. /// /// The iso path. string IsoPath { get; } diff --git a/MediaBrowser.Model/IO/IIsoMounter.cs b/MediaBrowser.Model/IO/IIsoMounter.cs index 83fdb5fd6..0d257395a 100644 --- a/MediaBrowser.Model/IO/IIsoMounter.cs +++ b/MediaBrowser.Model/IO/IIsoMounter.cs @@ -9,6 +9,12 @@ namespace MediaBrowser.Model.IO { public interface IIsoMounter { + /// + /// Gets the name. + /// + /// The name. + string Name { get; } + /// /// Mounts the specified iso path. /// @@ -25,11 +31,5 @@ namespace MediaBrowser.Model.IO /// The path. /// true if this instance can mount the specified path; otherwise, false. bool CanMount(string path); - - /// - /// Gets the name. - /// - /// The name. - string Name { get; } } } diff --git a/MediaBrowser.Model/IO/IStreamHelper.cs b/MediaBrowser.Model/IO/IStreamHelper.cs index e348cd725..af5ba5b17 100644 --- a/MediaBrowser.Model/IO/IStreamHelper.cs +++ b/MediaBrowser.Model/IO/IStreamHelper.cs @@ -14,6 +14,7 @@ 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/Library/UserViewQuery.cs b/MediaBrowser.Model/Library/UserViewQuery.cs index a538efd25..8a49b6863 100644 --- a/MediaBrowser.Model/Library/UserViewQuery.cs +++ b/MediaBrowser.Model/Library/UserViewQuery.cs @@ -6,6 +6,12 @@ namespace MediaBrowser.Model.Library { public class UserViewQuery { + public UserViewQuery() + { + IncludeExternalContent = true; + PresetViews = Array.Empty(); + } + /// /// Gets or sets the user identifier. /// @@ -25,11 +31,5 @@ namespace MediaBrowser.Model.Library public bool IncludeHidden { get; set; } public string[] PresetViews { get; set; } - - public UserViewQuery() - { - IncludeExternalContent = true; - PresetViews = Array.Empty(); - } } } diff --git a/MediaBrowser.Model/LiveTv/BaseTimerInfoDto.cs b/MediaBrowser.Model/LiveTv/BaseTimerInfoDto.cs index 064ce6520..45970cf6b 100644 --- a/MediaBrowser.Model/LiveTv/BaseTimerInfoDto.cs +++ b/MediaBrowser.Model/LiveTv/BaseTimerInfoDto.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System; diff --git a/MediaBrowser.Model/LiveTv/GuideInfo.cs b/MediaBrowser.Model/LiveTv/GuideInfo.cs index a224d73b7..b1cc8cfdf 100644 --- a/MediaBrowser.Model/LiveTv/GuideInfo.cs +++ b/MediaBrowser.Model/LiveTv/GuideInfo.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System; diff --git a/MediaBrowser.Model/LiveTv/LiveTvChannelQuery.cs b/MediaBrowser.Model/LiveTv/LiveTvChannelQuery.cs index 8154fbd0e..d1a94d8b3 100644 --- a/MediaBrowser.Model/LiveTv/LiveTvChannelQuery.cs +++ b/MediaBrowser.Model/LiveTv/LiveTvChannelQuery.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System; diff --git a/MediaBrowser.Model/LiveTv/LiveTvInfo.cs b/MediaBrowser.Model/LiveTv/LiveTvInfo.cs index 85b77af24..9767509d0 100644 --- a/MediaBrowser.Model/LiveTv/LiveTvInfo.cs +++ b/MediaBrowser.Model/LiveTv/LiveTvInfo.cs @@ -6,6 +6,12 @@ namespace MediaBrowser.Model.LiveTv { public class LiveTvInfo { + public LiveTvInfo() + { + Services = Array.Empty(); + EnabledUsers = Array.Empty(); + } + /// /// Gets or sets the services. /// @@ -23,11 +29,5 @@ namespace MediaBrowser.Model.LiveTv /// /// The enabled users. public string[] EnabledUsers { get; set; } - - public LiveTvInfo() - { - Services = Array.Empty(); - EnabledUsers = Array.Empty(); - } } } diff --git a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs index dc8e0f91b..69c43efd4 100644 --- a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs +++ b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System; diff --git a/MediaBrowser.Model/LiveTv/LiveTvServiceInfo.cs b/MediaBrowser.Model/LiveTv/LiveTvServiceInfo.cs index 09e900643..856f638c5 100644 --- a/MediaBrowser.Model/LiveTv/LiveTvServiceInfo.cs +++ b/MediaBrowser.Model/LiveTv/LiveTvServiceInfo.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System; diff --git a/MediaBrowser.Model/LiveTv/RecordingQuery.cs b/MediaBrowser.Model/LiveTv/RecordingQuery.cs index c75092b79..264982930 100644 --- a/MediaBrowser.Model/LiveTv/RecordingQuery.cs +++ b/MediaBrowser.Model/LiveTv/RecordingQuery.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System; diff --git a/MediaBrowser.Model/LiveTv/SeriesTimerInfoDto.cs b/MediaBrowser.Model/LiveTv/SeriesTimerInfoDto.cs index e30dd84dc..90422d19c 100644 --- a/MediaBrowser.Model/LiveTv/SeriesTimerInfoDto.cs +++ b/MediaBrowser.Model/LiveTv/SeriesTimerInfoDto.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System; @@ -14,7 +15,7 @@ namespace MediaBrowser.Model.LiveTv public SeriesTimerInfoDto() { ImageTags = new Dictionary(); - Days = new DayOfWeek[] { }; + Days = Array.Empty(); Type = "SeriesTimer"; } diff --git a/MediaBrowser.Model/LiveTv/SeriesTimerQuery.cs b/MediaBrowser.Model/LiveTv/SeriesTimerQuery.cs index bb553a576..bda46dd2b 100644 --- a/MediaBrowser.Model/LiveTv/SeriesTimerQuery.cs +++ b/MediaBrowser.Model/LiveTv/SeriesTimerQuery.cs @@ -10,7 +10,7 @@ namespace MediaBrowser.Model.LiveTv /// Gets or sets the sort by - SortName, Priority /// /// The sort by. - public string SortBy { get; set; } + public string? SortBy { get; set; } /// /// Gets or sets the sort order. diff --git a/MediaBrowser.Model/LiveTv/TimerInfoDto.cs b/MediaBrowser.Model/LiveTv/TimerInfoDto.cs index a1fbc5177..19039d448 100644 --- a/MediaBrowser.Model/LiveTv/TimerInfoDto.cs +++ b/MediaBrowser.Model/LiveTv/TimerInfoDto.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using MediaBrowser.Model.Dto; diff --git a/MediaBrowser.Model/LiveTv/TimerQuery.cs b/MediaBrowser.Model/LiveTv/TimerQuery.cs index 1ef6dd67e..367c45b9d 100644 --- a/MediaBrowser.Model/LiveTv/TimerQuery.cs +++ b/MediaBrowser.Model/LiveTv/TimerQuery.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 namespace MediaBrowser.Model.LiveTv diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj index 0fdfe5761..b24409fcc 100644 --- a/MediaBrowser.Model/MediaBrowser.Model.csproj +++ b/MediaBrowser.Model/MediaBrowser.Model.csproj @@ -12,6 +12,8 @@ false true true + enable + latest diff --git a/MediaBrowser.Model/MediaInfo/AudioCodec.cs b/MediaBrowser.Model/MediaInfo/AudioCodec.cs index dcb6fa270..8b17757b8 100644 --- a/MediaBrowser.Model/MediaInfo/AudioCodec.cs +++ b/MediaBrowser.Model/MediaInfo/AudioCodec.cs @@ -10,9 +10,9 @@ namespace MediaBrowser.Model.MediaInfo public static string GetFriendlyName(string codec) { - if (string.IsNullOrEmpty(codec)) + if (codec.Length == 0) { - return string.Empty; + return codec; } switch (codec.ToLowerInvariant()) diff --git a/MediaBrowser.Model/MediaInfo/BlurayDiscInfo.cs b/MediaBrowser.Model/MediaInfo/BlurayDiscInfo.cs index 29ba10dbb..83f982a5c 100644 --- a/MediaBrowser.Model/MediaInfo/BlurayDiscInfo.cs +++ b/MediaBrowser.Model/MediaInfo/BlurayDiscInfo.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using MediaBrowser.Model.Entities; diff --git a/MediaBrowser.Model/MediaInfo/LiveStreamRequest.cs b/MediaBrowser.Model/MediaInfo/LiveStreamRequest.cs index 52348f802..ea5d4e7d7 100644 --- a/MediaBrowser.Model/MediaInfo/LiveStreamRequest.cs +++ b/MediaBrowser.Model/MediaInfo/LiveStreamRequest.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System; @@ -7,6 +8,13 @@ namespace MediaBrowser.Model.MediaInfo { public class LiveStreamRequest { + public LiveStreamRequest() + { + EnableDirectPlay = true; + EnableDirectStream = true; + DirectPlayProtocols = new MediaProtocol[] { MediaProtocol.Http }; + } + public string OpenToken { get; set; } public Guid UserId { get; set; } public string PlaySessionId { get; set; } @@ -22,12 +30,7 @@ namespace MediaBrowser.Model.MediaInfo public bool EnableDirectStream { get; set; } public MediaProtocol[] DirectPlayProtocols { get; set; } - public LiveStreamRequest() - { - EnableDirectPlay = true; - EnableDirectStream = true; - DirectPlayProtocols = new MediaProtocol[] { MediaProtocol.Http }; - } + public LiveStreamRequest(AudioOptions options) { @@ -38,8 +41,7 @@ namespace MediaBrowser.Model.MediaInfo DirectPlayProtocols = new MediaProtocol[] { MediaProtocol.Http }; - var videoOptions = options as VideoOptions; - if (videoOptions != null) + if (options is VideoOptions videoOptions) { AudioStreamIndex = videoOptions.AudioStreamIndex; SubtitleStreamIndex = videoOptions.SubtitleStreamIndex; diff --git a/MediaBrowser.Model/MediaInfo/LiveStreamResponse.cs b/MediaBrowser.Model/MediaInfo/LiveStreamResponse.cs index 45b8fcce9..f017c1a11 100644 --- a/MediaBrowser.Model/MediaInfo/LiveStreamResponse.cs +++ b/MediaBrowser.Model/MediaInfo/LiveStreamResponse.cs @@ -6,6 +6,11 @@ namespace MediaBrowser.Model.MediaInfo { public class LiveStreamResponse { - public MediaSourceInfo MediaSource { get; set; } + public LiveStreamResponse(MediaSourceInfo mediaSource) + { + MediaSource = mediaSource; + } + + public MediaSourceInfo MediaSource { get; } } } diff --git a/MediaBrowser.Model/MediaInfo/MediaInfo.cs b/MediaBrowser.Model/MediaInfo/MediaInfo.cs index ad174f15d..97b979935 100644 --- a/MediaBrowser.Model/MediaInfo/MediaInfo.cs +++ b/MediaBrowser.Model/MediaInfo/MediaInfo.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System; diff --git a/MediaBrowser.Model/MediaInfo/PlaybackInfoRequest.cs b/MediaBrowser.Model/MediaInfo/PlaybackInfoRequest.cs index a2f163422..82e13e0eb 100644 --- a/MediaBrowser.Model/MediaInfo/PlaybackInfoRequest.cs +++ b/MediaBrowser.Model/MediaInfo/PlaybackInfoRequest.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System; diff --git a/MediaBrowser.Model/MediaInfo/PlaybackInfoResponse.cs b/MediaBrowser.Model/MediaInfo/PlaybackInfoResponse.cs index 440818c3e..273350182 100644 --- a/MediaBrowser.Model/MediaInfo/PlaybackInfoResponse.cs +++ b/MediaBrowser.Model/MediaInfo/PlaybackInfoResponse.cs @@ -20,7 +20,7 @@ namespace MediaBrowser.Model.MediaInfo /// Gets or sets the play session identifier. /// /// The play session identifier. - public string PlaySessionId { get; set; } + public string? PlaySessionId { get; set; } /// /// Gets or sets the error code. diff --git a/MediaBrowser.Model/MediaInfo/SubtitleTrackEvent.cs b/MediaBrowser.Model/MediaInfo/SubtitleTrackEvent.cs index 5b0ccb28a..72bb3d9c6 100644 --- a/MediaBrowser.Model/MediaInfo/SubtitleTrackEvent.cs +++ b/MediaBrowser.Model/MediaInfo/SubtitleTrackEvent.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 namespace MediaBrowser.Model.MediaInfo @@ -5,8 +6,11 @@ namespace MediaBrowser.Model.MediaInfo public class SubtitleTrackEvent { public string Id { get; set; } + public string Text { get; set; } + public long StartPositionTicks { get; set; } + public long EndPositionTicks { get; set; } } } diff --git a/MediaBrowser.Model/Net/EndPointInfo.cs b/MediaBrowser.Model/Net/EndPointInfo.cs index f5ac3d169..034734a9e 100644 --- a/MediaBrowser.Model/Net/EndPointInfo.cs +++ b/MediaBrowser.Model/Net/EndPointInfo.cs @@ -5,6 +5,7 @@ namespace MediaBrowser.Model.Net public class EndPointInfo { public bool IsLocal { get; set; } + public bool IsInNetwork { get; set; } } } diff --git a/MediaBrowser.Model/Net/ISocket.cs b/MediaBrowser.Model/Net/ISocket.cs index 2bfbfcb20..5b6ed92df 100644 --- a/MediaBrowser.Model/Net/ISocket.cs +++ b/MediaBrowser.Model/Net/ISocket.cs @@ -17,6 +17,7 @@ namespace MediaBrowser.Model.Net Task ReceiveAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken); IAsyncResult BeginReceive(byte[] buffer, int offset, int count, AsyncCallback callback); + SocketReceiveResult EndReceive(IAsyncResult result); /// diff --git a/MediaBrowser.Model/Net/MimeTypes.cs b/MediaBrowser.Model/Net/MimeTypes.cs index 68bcc590c..cfac4d1e2 100644 --- a/MediaBrowser.Model/Net/MimeTypes.cs +++ b/MediaBrowser.Model/Net/MimeTypes.cs @@ -8,12 +8,12 @@ using System.Linq; namespace MediaBrowser.Model.Net { /// - /// Class MimeTypes + /// Class MimeTypes. /// public static class MimeTypes { /// - /// Any extension in this list is considered a video file + /// Any extension in this list is considered a video file. /// private static readonly HashSet _videoFileExtensions = new HashSet(StringComparer.OrdinalIgnoreCase) { @@ -141,16 +141,16 @@ namespace MediaBrowser.Model.Net return dict; } - public static string GetMimeType(string path) => GetMimeType(path, true); + public static string? GetMimeType(string path) => GetMimeType(path, true); /// /// Gets the type of the MIME. /// - public static string GetMimeType(string path, bool enableStreamDefault) + public static string? GetMimeType(string path, bool enableStreamDefault) { - if (string.IsNullOrEmpty(path)) + if (path.Length == 0) { - throw new ArgumentNullException(nameof(path)); + throw new ArgumentException("String can't be empty.", nameof(path)); } var ext = Path.GetExtension(path); @@ -188,11 +188,11 @@ namespace MediaBrowser.Model.Net return enableStreamDefault ? "application/octet-stream" : null; } - public static string ToExtension(string mimeType) + public static string? ToExtension(string mimeType) { - if (string.IsNullOrEmpty(mimeType)) + if (mimeType.Length == 0) { - throw new ArgumentNullException(nameof(mimeType)); + throw new ArgumentException("String can't be empty.", nameof(mimeType)); } // handle text/html; charset=UTF-8 diff --git a/MediaBrowser.Model/Net/NetworkShare.cs b/MediaBrowser.Model/Net/NetworkShare.cs index 744c6ec14..a40cf73e4 100644 --- a/MediaBrowser.Model/Net/NetworkShare.cs +++ b/MediaBrowser.Model/Net/NetworkShare.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 namespace MediaBrowser.Model.Net diff --git a/MediaBrowser.Model/Net/SocketReceiveResult.cs b/MediaBrowser.Model/Net/SocketReceiveResult.cs index 141ae1608..54139fe9c 100644 --- a/MediaBrowser.Model/Net/SocketReceiveResult.cs +++ b/MediaBrowser.Model/Net/SocketReceiveResult.cs @@ -1,4 +1,4 @@ -#pragma warning disable CS1591 +#nullable disable using System.Net; @@ -10,12 +10,12 @@ namespace MediaBrowser.Model.Net public sealed class SocketReceiveResult { /// - /// The buffer to place received data into. + /// Gets or sets the buffer to place received data into. /// public byte[] Buffer { get; set; } /// - /// The number of bytes received. + /// Gets or sets the number of bytes received. /// public int ReceivedBytes { get; set; } @@ -23,6 +23,10 @@ namespace MediaBrowser.Model.Net /// The the data was received from. /// public IPEndPoint RemoteEndPoint { get; set; } + + /// + /// The local . + /// public IPAddress LocalIPAddress { get; set; } } } diff --git a/MediaBrowser.Model/Net/WebSocketMessage.cs b/MediaBrowser.Model/Net/WebSocketMessage.cs index 7575224d4..962b81b95 100644 --- a/MediaBrowser.Model/Net/WebSocketMessage.cs +++ b/MediaBrowser.Model/Net/WebSocketMessage.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 namespace MediaBrowser.Model.Net diff --git a/MediaBrowser.Model/Notifications/NotificationOption.cs b/MediaBrowser.Model/Notifications/NotificationOption.cs index 4fb724515..144949a3b 100644 --- a/MediaBrowser.Model/Notifications/NotificationOption.cs +++ b/MediaBrowser.Model/Notifications/NotificationOption.cs @@ -6,6 +6,15 @@ namespace MediaBrowser.Model.Notifications { public class NotificationOption { + public NotificationOption(string type) + { + Type = type; + + DisabledServices = Array.Empty(); + DisabledMonitorUsers = Array.Empty(); + SendToUsers = Array.Empty(); + } + public string Type { get; set; } /// @@ -35,12 +44,5 @@ namespace MediaBrowser.Model.Notifications /// /// The send to user mode. public SendToUserType SendToUserMode { get; set; } - - public NotificationOption() - { - DisabledServices = Array.Empty(); - DisabledMonitorUsers = Array.Empty(); - SendToUsers = Array.Empty(); - } } } diff --git a/MediaBrowser.Model/Notifications/NotificationOptions.cs b/MediaBrowser.Model/Notifications/NotificationOptions.cs index 79a128e9b..7b299b1aa 100644 --- a/MediaBrowser.Model/Notifications/NotificationOptions.cs +++ b/MediaBrowser.Model/Notifications/NotificationOptions.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System; @@ -14,63 +15,53 @@ namespace MediaBrowser.Model.Notifications { Options = new[] { - new NotificationOption + new NotificationOption(NotificationType.TaskFailed.ToString()) { - Type = NotificationType.TaskFailed.ToString(), Enabled = true, SendToUserMode = SendToUserType.Admins }, - new NotificationOption + new NotificationOption(NotificationType.ServerRestartRequired.ToString()) { - Type = NotificationType.ServerRestartRequired.ToString(), Enabled = true, SendToUserMode = SendToUserType.Admins }, - new NotificationOption + new NotificationOption(NotificationType.ApplicationUpdateAvailable.ToString()) { - Type = NotificationType.ApplicationUpdateAvailable.ToString(), Enabled = true, SendToUserMode = SendToUserType.Admins }, - new NotificationOption + new NotificationOption(NotificationType.ApplicationUpdateInstalled.ToString()) { - Type = NotificationType.ApplicationUpdateInstalled.ToString(), Enabled = true, SendToUserMode = SendToUserType.Admins }, - new NotificationOption + new NotificationOption(NotificationType.PluginUpdateInstalled.ToString()) { - Type = NotificationType.PluginUpdateInstalled.ToString(), Enabled = true, SendToUserMode = SendToUserType.Admins }, - new NotificationOption + new NotificationOption(NotificationType.PluginUninstalled.ToString()) { - Type = NotificationType.PluginUninstalled.ToString(), Enabled = true, SendToUserMode = SendToUserType.Admins }, - new NotificationOption + new NotificationOption(NotificationType.InstallationFailed.ToString()) { - Type = NotificationType.InstallationFailed.ToString(), Enabled = true, SendToUserMode = SendToUserType.Admins }, - new NotificationOption + new NotificationOption(NotificationType.PluginInstalled.ToString()) { - Type = NotificationType.PluginInstalled.ToString(), Enabled = true, SendToUserMode = SendToUserType.Admins }, - new NotificationOption + new NotificationOption(NotificationType.PluginError.ToString()) { - Type = NotificationType.PluginError.ToString(), Enabled = true, SendToUserMode = SendToUserType.Admins }, - new NotificationOption + new NotificationOption(NotificationType.UserLockedOut.ToString()) { - Type = NotificationType.UserLockedOut.ToString(), Enabled = true, SendToUserMode = SendToUserType.Admins } @@ -81,8 +72,12 @@ namespace MediaBrowser.Model.Notifications { foreach (NotificationOption i in Options) { - if (string.Equals(type, i.Type, StringComparison.OrdinalIgnoreCase)) return i; + if (string.Equals(type, i.Type, StringComparison.OrdinalIgnoreCase)) + { + return i; + } } + return null; } diff --git a/MediaBrowser.Model/Notifications/NotificationRequest.cs b/MediaBrowser.Model/Notifications/NotificationRequest.cs index ffcfab24f..febc2bc09 100644 --- a/MediaBrowser.Model/Notifications/NotificationRequest.cs +++ b/MediaBrowser.Model/Notifications/NotificationRequest.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System; diff --git a/MediaBrowser.Model/Notifications/NotificationTypeInfo.cs b/MediaBrowser.Model/Notifications/NotificationTypeInfo.cs index bfa163b40..402fbe81a 100644 --- a/MediaBrowser.Model/Notifications/NotificationTypeInfo.cs +++ b/MediaBrowser.Model/Notifications/NotificationTypeInfo.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 namespace MediaBrowser.Model.Notifications diff --git a/MediaBrowser.Model/Playlists/PlaylistCreationRequest.cs b/MediaBrowser.Model/Playlists/PlaylistCreationRequest.cs index b7003c4c8..ef435b21e 100644 --- a/MediaBrowser.Model/Playlists/PlaylistCreationRequest.cs +++ b/MediaBrowser.Model/Playlists/PlaylistCreationRequest.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System; diff --git a/MediaBrowser.Model/Playlists/PlaylistCreationResult.cs b/MediaBrowser.Model/Playlists/PlaylistCreationResult.cs index 4f2067b98..f3a1518ed 100644 --- a/MediaBrowser.Model/Playlists/PlaylistCreationResult.cs +++ b/MediaBrowser.Model/Playlists/PlaylistCreationResult.cs @@ -4,6 +4,11 @@ namespace MediaBrowser.Model.Playlists { public class PlaylistCreationResult { - public string Id { get; set; } + public PlaylistCreationResult(string id) + { + Id = id; + } + + public string Id { get; } } } diff --git a/MediaBrowser.Model/Playlists/PlaylistItemQuery.cs b/MediaBrowser.Model/Playlists/PlaylistItemQuery.cs deleted file mode 100644 index 324a38e70..000000000 --- a/MediaBrowser.Model/Playlists/PlaylistItemQuery.cs +++ /dev/null @@ -1,39 +0,0 @@ -#pragma warning disable CS1591 - -using MediaBrowser.Model.Querying; - -namespace MediaBrowser.Model.Playlists -{ - public class PlaylistItemQuery - { - /// - /// Gets or sets the identifier. - /// - /// The identifier. - public string Id { get; set; } - - /// - /// Gets or sets the user identifier. - /// - /// The user identifier. - public string UserId { get; set; } - - /// - /// Gets or sets the start index. - /// - /// The start index. - public int? StartIndex { get; set; } - - /// - /// Gets or sets the limit. - /// - /// The limit. - public int? Limit { get; set; } - - /// - /// Gets or sets the fields. - /// - /// The fields. - public ItemFields[] Fields { get; set; } - } -} diff --git a/MediaBrowser.Model/Plugins/PluginInfo.cs b/MediaBrowser.Model/Plugins/PluginInfo.cs index 9ff9ea457..c13f1a89f 100644 --- a/MediaBrowser.Model/Plugins/PluginInfo.cs +++ b/MediaBrowser.Model/Plugins/PluginInfo.cs @@ -1,3 +1,4 @@ +#nullable disable namespace MediaBrowser.Model.Plugins { /// diff --git a/MediaBrowser.Model/Plugins/PluginPageInfo.cs b/MediaBrowser.Model/Plugins/PluginPageInfo.cs index eb6a1527d..ca72e19ee 100644 --- a/MediaBrowser.Model/Plugins/PluginPageInfo.cs +++ b/MediaBrowser.Model/Plugins/PluginPageInfo.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 namespace MediaBrowser.Model.Plugins diff --git a/MediaBrowser.Model/Providers/ExternalIdInfo.cs b/MediaBrowser.Model/Providers/ExternalIdInfo.cs index 2b481ad7e..f2e6d8ef3 100644 --- a/MediaBrowser.Model/Providers/ExternalIdInfo.cs +++ b/MediaBrowser.Model/Providers/ExternalIdInfo.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 namespace MediaBrowser.Model.Providers diff --git a/MediaBrowser.Model/Providers/ExternalUrl.cs b/MediaBrowser.Model/Providers/ExternalUrl.cs index d4f4fa840..9467a2b00 100644 --- a/MediaBrowser.Model/Providers/ExternalUrl.cs +++ b/MediaBrowser.Model/Providers/ExternalUrl.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 namespace MediaBrowser.Model.Providers diff --git a/MediaBrowser.Model/Providers/ImageProviderInfo.cs b/MediaBrowser.Model/Providers/ImageProviderInfo.cs index a22ec3c07..c63a2ceda 100644 --- a/MediaBrowser.Model/Providers/ImageProviderInfo.cs +++ b/MediaBrowser.Model/Providers/ImageProviderInfo.cs @@ -10,6 +10,12 @@ namespace MediaBrowser.Model.Providers /// public class ImageProviderInfo { + public ImageProviderInfo(string name, ImageType[] supportedImages) + { + Name = name; + SupportedImages = supportedImages; + } + /// /// Gets or sets the name. /// @@ -17,10 +23,5 @@ namespace MediaBrowser.Model.Providers public string Name { get; set; } public ImageType[] SupportedImages { get; set; } - - public ImageProviderInfo() - { - SupportedImages = Array.Empty(); - } } } diff --git a/MediaBrowser.Model/Providers/RemoteImageInfo.cs b/MediaBrowser.Model/Providers/RemoteImageInfo.cs index ee2b9d8fd..78ab6c706 100644 --- a/MediaBrowser.Model/Providers/RemoteImageInfo.cs +++ b/MediaBrowser.Model/Providers/RemoteImageInfo.cs @@ -1,3 +1,4 @@ +#nullable disable using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; diff --git a/MediaBrowser.Model/Providers/RemoteImageQuery.cs b/MediaBrowser.Model/Providers/RemoteImageQuery.cs index 2873c1003..b7fad87ab 100644 --- a/MediaBrowser.Model/Providers/RemoteImageQuery.cs +++ b/MediaBrowser.Model/Providers/RemoteImageQuery.cs @@ -6,7 +6,12 @@ namespace MediaBrowser.Model.Providers { public class RemoteImageQuery { - public string ProviderName { get; set; } + public RemoteImageQuery(string providerName) + { + ProviderName = providerName; + } + + public string ProviderName { get; } public ImageType? ImageType { get; set; } diff --git a/MediaBrowser.Model/Providers/RemoteImageResult.cs b/MediaBrowser.Model/Providers/RemoteImageResult.cs index 5ca00f770..e6067ee6e 100644 --- a/MediaBrowser.Model/Providers/RemoteImageResult.cs +++ b/MediaBrowser.Model/Providers/RemoteImageResult.cs @@ -1,3 +1,4 @@ +#nullable disable namespace MediaBrowser.Model.Providers { /// diff --git a/MediaBrowser.Model/Providers/RemoteSearchResult.cs b/MediaBrowser.Model/Providers/RemoteSearchResult.cs index 161e04821..c96eb0b59 100644 --- a/MediaBrowser.Model/Providers/RemoteSearchResult.cs +++ b/MediaBrowser.Model/Providers/RemoteSearchResult.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System; @@ -8,23 +9,34 @@ namespace MediaBrowser.Model.Providers { public class RemoteSearchResult : IHasProviderIds { + public RemoteSearchResult() + { + ProviderIds = new Dictionary(StringComparer.OrdinalIgnoreCase); + Artists = Array.Empty(); + } + /// /// Gets or sets the name. /// /// The name. public string Name { get; set; } + /// /// Gets or sets the provider ids. /// /// The provider ids. public Dictionary ProviderIds { get; set; } + /// /// Gets or sets the year. /// /// The year. public int? ProductionYear { get; set; } + public int? IndexNumber { get; set; } + public int? IndexNumberEnd { get; set; } + public int? ParentIndexNumber { get; set; } public DateTime? PremiereDate { get; set; } @@ -32,15 +44,13 @@ namespace MediaBrowser.Model.Providers public string ImageUrl { get; set; } public string SearchProviderName { get; set; } + public string Overview { get; set; } public RemoteSearchResult AlbumArtist { get; set; } + public RemoteSearchResult[] Artists { get; set; } - public RemoteSearchResult() - { - ProviderIds = new Dictionary(StringComparer.OrdinalIgnoreCase); - Artists = new RemoteSearchResult[] { }; - } + } } diff --git a/MediaBrowser.Model/Providers/RemoteSubtitleInfo.cs b/MediaBrowser.Model/Providers/RemoteSubtitleInfo.cs index 06f29df3f..d9f7a852c 100644 --- a/MediaBrowser.Model/Providers/RemoteSubtitleInfo.cs +++ b/MediaBrowser.Model/Providers/RemoteSubtitleInfo.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System; diff --git a/MediaBrowser.Model/Providers/SubtitleOptions.cs b/MediaBrowser.Model/Providers/SubtitleOptions.cs index 9e6049246..c07379570 100644 --- a/MediaBrowser.Model/Providers/SubtitleOptions.cs +++ b/MediaBrowser.Model/Providers/SubtitleOptions.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System; diff --git a/MediaBrowser.Model/Providers/SubtitleProviderInfo.cs b/MediaBrowser.Model/Providers/SubtitleProviderInfo.cs index fca93d176..ee25be4b6 100644 --- a/MediaBrowser.Model/Providers/SubtitleProviderInfo.cs +++ b/MediaBrowser.Model/Providers/SubtitleProviderInfo.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 namespace MediaBrowser.Model.Providers diff --git a/MediaBrowser.Model/Querying/AllThemeMediaResult.cs b/MediaBrowser.Model/Querying/AllThemeMediaResult.cs index a264c6178..6b503ba6b 100644 --- a/MediaBrowser.Model/Querying/AllThemeMediaResult.cs +++ b/MediaBrowser.Model/Querying/AllThemeMediaResult.cs @@ -1,15 +1,10 @@ +#nullable disable #pragma warning disable CS1591 namespace MediaBrowser.Model.Querying { public class AllThemeMediaResult { - public ThemeMediaResult ThemeVideosResult { get; set; } - - public ThemeMediaResult ThemeSongsResult { get; set; } - - public ThemeMediaResult SoundtrackSongsResult { get; set; } - public AllThemeMediaResult() { ThemeVideosResult = new ThemeMediaResult(); @@ -18,5 +13,11 @@ namespace MediaBrowser.Model.Querying SoundtrackSongsResult = new ThemeMediaResult(); } + + public ThemeMediaResult ThemeVideosResult { get; set; } + + public ThemeMediaResult ThemeSongsResult { get; set; } + + public ThemeMediaResult SoundtrackSongsResult { get; set; } } } diff --git a/MediaBrowser.Model/Querying/EpisodeQuery.cs b/MediaBrowser.Model/Querying/EpisodeQuery.cs index 6fb4df676..13b1a0dcb 100644 --- a/MediaBrowser.Model/Querying/EpisodeQuery.cs +++ b/MediaBrowser.Model/Querying/EpisodeQuery.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System; diff --git a/MediaBrowser.Model/Querying/ItemCountsQuery.cs b/MediaBrowser.Model/Querying/ItemCountsQuery.cs deleted file mode 100644 index f113cf380..000000000 --- a/MediaBrowser.Model/Querying/ItemCountsQuery.cs +++ /dev/null @@ -1,20 +0,0 @@ -namespace MediaBrowser.Model.Querying -{ - /// - /// Class ItemCountsQuery. - /// - public class ItemCountsQuery - { - /// - /// Gets or sets the user id. - /// - /// The user id. - public string UserId { get; set; } - - /// - /// Gets or sets a value indicating whether this instance is favorite. - /// - /// null if [is favorite] contains no value, true if [is favorite]; otherwise, false. - public bool? IsFavorite { get; set; } - } -} diff --git a/MediaBrowser.Model/Querying/ItemSortBy.cs b/MediaBrowser.Model/Querying/ItemSortBy.cs index 15b60ad84..edf71c1a7 100644 --- a/MediaBrowser.Model/Querying/ItemSortBy.cs +++ b/MediaBrowser.Model/Querying/ItemSortBy.cs @@ -8,73 +8,99 @@ namespace MediaBrowser.Model.Querying public static class ItemSortBy { public const string AiredEpisodeOrder = "AiredEpisodeOrder"; + /// - /// The album + /// The album. /// public const string Album = "Album"; + /// - /// The album artist + /// The album artist. /// public const string AlbumArtist = "AlbumArtist"; + /// - /// The artist + /// The artist. /// public const string Artist = "Artist"; + /// - /// The date created + /// The date created. /// public const string DateCreated = "DateCreated"; + /// - /// The official rating + /// The official rating. /// public const string OfficialRating = "OfficialRating"; + /// - /// The date played + /// The date played. /// public const string DatePlayed = "DatePlayed"; + /// - /// The premiere date + /// The premiere date. /// public const string PremiereDate = "PremiereDate"; + public const string StartDate = "StartDate"; + /// - /// The sort name + /// The sort name. /// public const string SortName = "SortName"; + public const string Name = "Name"; + /// - /// The random + /// The random. /// public const string Random = "Random"; + /// - /// The runtime + /// The runtime. /// public const string Runtime = "Runtime"; + /// - /// The community rating + /// The community rating. /// public const string CommunityRating = "CommunityRating"; + /// - /// The production year + /// The production year. /// public const string ProductionYear = "ProductionYear"; + /// - /// The play count + /// The play count. /// public const string PlayCount = "PlayCount"; + /// - /// The critic rating + /// The critic rating. /// public const string CriticRating = "CriticRating"; + public const string IsFolder = "IsFolder"; + public const string IsUnplayed = "IsUnplayed"; + public const string IsPlayed = "IsPlayed"; + public const string SeriesSortName = "SeriesSortName"; + public const string VideoBitRate = "VideoBitRate"; + public const string AirTime = "AirTime"; + public const string Studio = "Studio"; + public const string IsFavoriteOrLiked = "IsFavoriteOrLiked"; + public const string DateLastContentAdded = "DateLastContentAdded"; + public const string SeriesDatePlayed = "SeriesDatePlayed"; } } diff --git a/MediaBrowser.Model/Querying/LatestItemsQuery.cs b/MediaBrowser.Model/Querying/LatestItemsQuery.cs index 84e29e76a..7954ef4b4 100644 --- a/MediaBrowser.Model/Querying/LatestItemsQuery.cs +++ b/MediaBrowser.Model/Querying/LatestItemsQuery.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System; @@ -7,8 +8,13 @@ namespace MediaBrowser.Model.Querying { public class LatestItemsQuery { + public LatestItemsQuery() + { + EnableImageTypes = Array.Empty(); + } + /// - /// The user to localize search results for + /// The user to localize search results for. /// /// The user id. public Guid UserId { get; set; } @@ -26,13 +32,13 @@ namespace MediaBrowser.Model.Querying public int? StartIndex { get; set; } /// - /// The maximum number of items to return + /// The maximum number of items to return. /// /// The limit. public int? Limit { get; set; } /// - /// Fields to return within the items, in addition to basic information + /// Fields to return within the items, in addition to basic information. /// /// The fields. public ItemFields[] Fields { get; set; } @@ -54,25 +60,23 @@ namespace MediaBrowser.Model.Querying /// /// true if [group items]; otherwise, false. public bool GroupItems { get; set; } + /// /// Gets or sets a value indicating whether [enable images]. /// /// null if [enable images] contains no value, true if [enable images]; otherwise, false. public bool? EnableImages { get; set; } + /// /// Gets or sets the image type limit. /// /// The image type limit. public int? ImageTypeLimit { get; set; } + /// /// Gets or sets the enable image types. /// /// The enable image types. public ImageType[] EnableImageTypes { get; set; } - - public LatestItemsQuery() - { - EnableImageTypes = new ImageType[] { }; - } } } diff --git a/MediaBrowser.Model/Querying/MovieRecommendationQuery.cs b/MediaBrowser.Model/Querying/MovieRecommendationQuery.cs index 93de0a8cd..1c8875890 100644 --- a/MediaBrowser.Model/Querying/MovieRecommendationQuery.cs +++ b/MediaBrowser.Model/Querying/MovieRecommendationQuery.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System; diff --git a/MediaBrowser.Model/Querying/NextUpQuery.cs b/MediaBrowser.Model/Querying/NextUpQuery.cs index 1543aea16..0df86cb22 100644 --- a/MediaBrowser.Model/Querying/NextUpQuery.cs +++ b/MediaBrowser.Model/Querying/NextUpQuery.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System; diff --git a/MediaBrowser.Model/Querying/QueryFilters.cs b/MediaBrowser.Model/Querying/QueryFilters.cs index 8d879c174..e04208f76 100644 --- a/MediaBrowser.Model/Querying/QueryFilters.cs +++ b/MediaBrowser.Model/Querying/QueryFilters.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System; diff --git a/MediaBrowser.Model/Querying/QueryResult.cs b/MediaBrowser.Model/Querying/QueryResult.cs index 266f1c7e6..42586243d 100644 --- a/MediaBrowser.Model/Querying/QueryResult.cs +++ b/MediaBrowser.Model/Querying/QueryResult.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System; diff --git a/MediaBrowser.Model/Querying/ThemeMediaResult.cs b/MediaBrowser.Model/Querying/ThemeMediaResult.cs index bae954d78..5afedeeaf 100644 --- a/MediaBrowser.Model/Querying/ThemeMediaResult.cs +++ b/MediaBrowser.Model/Querying/ThemeMediaResult.cs @@ -4,7 +4,7 @@ using MediaBrowser.Model.Dto; namespace MediaBrowser.Model.Querying { /// - /// Class ThemeMediaResult + /// Class ThemeMediaResult. /// public class ThemeMediaResult : QueryResult { diff --git a/MediaBrowser.Model/Querying/UpcomingEpisodesQuery.cs b/MediaBrowser.Model/Querying/UpcomingEpisodesQuery.cs index 123d0fad2..ed1aa7ac6 100644 --- a/MediaBrowser.Model/Querying/UpcomingEpisodesQuery.cs +++ b/MediaBrowser.Model/Querying/UpcomingEpisodesQuery.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using MediaBrowser.Model.Entities; diff --git a/MediaBrowser.Model/Search/SearchHint.cs b/MediaBrowser.Model/Search/SearchHint.cs index 6e52314fa..c7a721df6 100644 --- a/MediaBrowser.Model/Search/SearchHint.cs +++ b/MediaBrowser.Model/Search/SearchHint.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System; diff --git a/MediaBrowser.Model/Search/SearchHintResult.cs b/MediaBrowser.Model/Search/SearchHintResult.cs index 3c4fbec9e..92ba4139e 100644 --- a/MediaBrowser.Model/Search/SearchHintResult.cs +++ b/MediaBrowser.Model/Search/SearchHintResult.cs @@ -1,3 +1,4 @@ +#nullable disable namespace MediaBrowser.Model.Search { /// diff --git a/MediaBrowser.Model/Search/SearchQuery.cs b/MediaBrowser.Model/Search/SearchQuery.cs index 8a018312e..4470f1ad9 100644 --- a/MediaBrowser.Model/Search/SearchQuery.cs +++ b/MediaBrowser.Model/Search/SearchQuery.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System; diff --git a/MediaBrowser.Model/Serialization/IJsonSerializer.cs b/MediaBrowser.Model/Serialization/IJsonSerializer.cs index 6223bb559..09b6ff9b5 100644 --- a/MediaBrowser.Model/Serialization/IJsonSerializer.cs +++ b/MediaBrowser.Model/Serialization/IJsonSerializer.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System; diff --git a/MediaBrowser.Model/Serialization/IXmlSerializer.cs b/MediaBrowser.Model/Serialization/IXmlSerializer.cs index 1edd98fad..16d126ac7 100644 --- a/MediaBrowser.Model/Serialization/IXmlSerializer.cs +++ b/MediaBrowser.Model/Serialization/IXmlSerializer.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System; diff --git a/MediaBrowser.Model/Services/ApiMemberAttribute.cs b/MediaBrowser.Model/Services/ApiMemberAttribute.cs index 8e50836f4..7c23eee44 100644 --- a/MediaBrowser.Model/Services/ApiMemberAttribute.cs +++ b/MediaBrowser.Model/Services/ApiMemberAttribute.cs @@ -1,3 +1,4 @@ +#nullable disable using System; namespace MediaBrowser.Model.Services diff --git a/MediaBrowser.Model/Services/IHasRequestFilter.cs b/MediaBrowser.Model/Services/IHasRequestFilter.cs index 3d2e9c0dc..332ba113c 100644 --- a/MediaBrowser.Model/Services/IHasRequestFilter.cs +++ b/MediaBrowser.Model/Services/IHasRequestFilter.cs @@ -7,18 +7,18 @@ namespace MediaBrowser.Model.Services public interface IHasRequestFilter { /// - /// Order in which Request Filters are executed. + /// Gets the order in which Request Filters are executed. /// <0 Executed before global request filters - /// >0 Executed after global request filters + /// >0 Executed after global request filters. /// int Priority { get; } /// /// The request filter is executed before the service. /// - /// The http request wrapper - /// The http response wrapper - /// The request DTO + /// The http request wrapper. + /// The http response wrapper. + /// The request DTO. void RequestFilter(IRequest req, HttpResponse res, object requestDto); } } diff --git a/MediaBrowser.Model/Services/IHttpRequest.cs b/MediaBrowser.Model/Services/IHttpRequest.cs index 4dccd2d68..3ea65195c 100644 --- a/MediaBrowser.Model/Services/IHttpRequest.cs +++ b/MediaBrowser.Model/Services/IHttpRequest.cs @@ -5,12 +5,12 @@ namespace MediaBrowser.Model.Services public interface IHttpRequest : IRequest { /// - /// The HTTP Verb + /// Gets the HTTP Verb. /// string HttpMethod { get; } /// - /// The value of the Accept HTTP Request Header + /// Gets the value of the Accept HTTP Request Header. /// string Accept { get; } } diff --git a/MediaBrowser.Model/Services/IHttpResult.cs b/MediaBrowser.Model/Services/IHttpResult.cs index b153f15ec..abc581d8e 100644 --- a/MediaBrowser.Model/Services/IHttpResult.cs +++ b/MediaBrowser.Model/Services/IHttpResult.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System.Net; @@ -7,27 +8,27 @@ namespace MediaBrowser.Model.Services public interface IHttpResult : IHasHeaders { /// - /// The HTTP Response Status + /// The HTTP Response Status. /// int Status { get; set; } /// - /// The HTTP Response Status Code + /// The HTTP Response Status Code. /// HttpStatusCode StatusCode { get; set; } /// - /// The HTTP Response ContentType + /// The HTTP Response ContentType. /// string ContentType { get; set; } /// - /// Response DTO + /// Response DTO. /// object Response { get; set; } /// - /// Holds the request call context + /// Holds the request call context. /// IRequest RequestContext { get; set; } } diff --git a/MediaBrowser.Model/Services/IRequest.cs b/MediaBrowser.Model/Services/IRequest.cs index 3f4edced6..f413f1e17 100644 --- a/MediaBrowser.Model/Services/IRequest.cs +++ b/MediaBrowser.Model/Services/IRequest.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System; diff --git a/MediaBrowser.Model/Services/QueryParamCollection.cs b/MediaBrowser.Model/Services/QueryParamCollection.cs index 19e9e53e7..d07ff1548 100644 --- a/MediaBrowser.Model/Services/QueryParamCollection.cs +++ b/MediaBrowser.Model/Services/QueryParamCollection.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System; @@ -19,11 +20,6 @@ namespace MediaBrowser.Model.Services return StringComparison.OrdinalIgnoreCase; } - private static StringComparer GetStringComparer() - { - return StringComparer.OrdinalIgnoreCase; - } - /// /// Adds a new query parameter. /// diff --git a/MediaBrowser.Model/Services/RouteAttribute.cs b/MediaBrowser.Model/Services/RouteAttribute.cs index 197ba05e5..162576aa7 100644 --- a/MediaBrowser.Model/Services/RouteAttribute.cs +++ b/MediaBrowser.Model/Services/RouteAttribute.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System; diff --git a/MediaBrowser.Model/Session/BrowseRequest.cs b/MediaBrowser.Model/Session/BrowseRequest.cs index f485d680e..1c997d584 100644 --- a/MediaBrowser.Model/Session/BrowseRequest.cs +++ b/MediaBrowser.Model/Session/BrowseRequest.cs @@ -1,3 +1,4 @@ +#nullable disable namespace MediaBrowser.Model.Session { /// diff --git a/MediaBrowser.Model/Session/ClientCapabilities.cs b/MediaBrowser.Model/Session/ClientCapabilities.cs index 5da4998e8..51db66d21 100644 --- a/MediaBrowser.Model/Session/ClientCapabilities.cs +++ b/MediaBrowser.Model/Session/ClientCapabilities.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System; diff --git a/MediaBrowser.Model/Session/GeneralCommand.cs b/MediaBrowser.Model/Session/GeneralCommand.cs index 980e1f88b..9794bd292 100644 --- a/MediaBrowser.Model/Session/GeneralCommand.cs +++ b/MediaBrowser.Model/Session/GeneralCommand.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System; diff --git a/MediaBrowser.Model/Session/MessageCommand.cs b/MediaBrowser.Model/Session/MessageCommand.cs index 473a7bccc..09abfbb3f 100644 --- a/MediaBrowser.Model/Session/MessageCommand.cs +++ b/MediaBrowser.Model/Session/MessageCommand.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 namespace MediaBrowser.Model.Session diff --git a/MediaBrowser.Model/Session/PlayRequest.cs b/MediaBrowser.Model/Session/PlayRequest.cs index bdb2b2439..62b68b49e 100644 --- a/MediaBrowser.Model/Session/PlayRequest.cs +++ b/MediaBrowser.Model/Session/PlayRequest.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System; diff --git a/MediaBrowser.Model/Session/PlaybackProgressInfo.cs b/MediaBrowser.Model/Session/PlaybackProgressInfo.cs index 5687ba84b..6b4cfe4f0 100644 --- a/MediaBrowser.Model/Session/PlaybackProgressInfo.cs +++ b/MediaBrowser.Model/Session/PlaybackProgressInfo.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System; diff --git a/MediaBrowser.Model/Session/PlaybackStopInfo.cs b/MediaBrowser.Model/Session/PlaybackStopInfo.cs index f8cfacc20..b0827ac99 100644 --- a/MediaBrowser.Model/Session/PlaybackStopInfo.cs +++ b/MediaBrowser.Model/Session/PlaybackStopInfo.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System; diff --git a/MediaBrowser.Model/Session/PlayerStateInfo.cs b/MediaBrowser.Model/Session/PlayerStateInfo.cs index 0f9956873..0f10605ea 100644 --- a/MediaBrowser.Model/Session/PlayerStateInfo.cs +++ b/MediaBrowser.Model/Session/PlayerStateInfo.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 namespace MediaBrowser.Model.Session diff --git a/MediaBrowser.Model/Session/PlaystateRequest.cs b/MediaBrowser.Model/Session/PlaystateRequest.cs index 493a8063a..ba2c024b7 100644 --- a/MediaBrowser.Model/Session/PlaystateRequest.cs +++ b/MediaBrowser.Model/Session/PlaystateRequest.cs @@ -12,6 +12,6 @@ namespace MediaBrowser.Model.Session /// Gets or sets the controlling user identifier. /// /// The controlling user identifier. - public string ControllingUserId { get; set; } + public string? ControllingUserId { get; set; } } } diff --git a/MediaBrowser.Model/Session/SessionUserInfo.cs b/MediaBrowser.Model/Session/SessionUserInfo.cs index 42a56b92b..4d6f35efc 100644 --- a/MediaBrowser.Model/Session/SessionUserInfo.cs +++ b/MediaBrowser.Model/Session/SessionUserInfo.cs @@ -1,3 +1,4 @@ +#nullable disable using System; namespace MediaBrowser.Model.Session @@ -12,6 +13,7 @@ namespace MediaBrowser.Model.Session /// /// The user identifier. public Guid UserId { get; set; } + /// /// Gets or sets the name of the user. /// diff --git a/MediaBrowser.Model/Session/TranscodingInfo.cs b/MediaBrowser.Model/Session/TranscodingInfo.cs index 8f4e688f0..d6dc83413 100644 --- a/MediaBrowser.Model/Session/TranscodingInfo.cs +++ b/MediaBrowser.Model/Session/TranscodingInfo.cs @@ -1,5 +1,8 @@ +#nullable disable #pragma warning disable CS1591 +using System; + namespace MediaBrowser.Model.Session { public class TranscodingInfo @@ -22,7 +25,7 @@ namespace MediaBrowser.Model.Session public TranscodingInfo() { - TranscodeReasons = new TranscodeReason[] { }; + TranscodeReasons = Array.Empty(); } } diff --git a/MediaBrowser.Model/Session/UserDataChangeInfo.cs b/MediaBrowser.Model/Session/UserDataChangeInfo.cs index 0872eb4b1..0fd24edcc 100644 --- a/MediaBrowser.Model/Session/UserDataChangeInfo.cs +++ b/MediaBrowser.Model/Session/UserDataChangeInfo.cs @@ -1,3 +1,4 @@ +#nullable disable using MediaBrowser.Model.Dto; namespace MediaBrowser.Model.Session diff --git a/MediaBrowser.Model/Sync/SyncJob.cs b/MediaBrowser.Model/Sync/SyncJob.cs index 30bf27f38..3cc9ff726 100644 --- a/MediaBrowser.Model/Sync/SyncJob.cs +++ b/MediaBrowser.Model/Sync/SyncJob.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System; diff --git a/MediaBrowser.Model/Sync/SyncTarget.cs b/MediaBrowser.Model/Sync/SyncTarget.cs index 20a0c8cc7..9e6bbbc00 100644 --- a/MediaBrowser.Model/Sync/SyncTarget.cs +++ b/MediaBrowser.Model/Sync/SyncTarget.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 namespace MediaBrowser.Model.Sync diff --git a/MediaBrowser.Model/System/LogFile.cs b/MediaBrowser.Model/System/LogFile.cs index a2b701664..aec910c92 100644 --- a/MediaBrowser.Model/System/LogFile.cs +++ b/MediaBrowser.Model/System/LogFile.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System; diff --git a/MediaBrowser.Model/System/PublicSystemInfo.cs b/MediaBrowser.Model/System/PublicSystemInfo.cs index 1775470b5..b6196a43f 100644 --- a/MediaBrowser.Model/System/PublicSystemInfo.cs +++ b/MediaBrowser.Model/System/PublicSystemInfo.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 namespace MediaBrowser.Model.System diff --git a/MediaBrowser.Model/System/SystemInfo.cs b/MediaBrowser.Model/System/SystemInfo.cs index cfa7684c9..7582cb748 100644 --- a/MediaBrowser.Model/System/SystemInfo.cs +++ b/MediaBrowser.Model/System/SystemInfo.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System; @@ -34,7 +35,6 @@ namespace MediaBrowser.Model.System /// The display name of the operating system. public string OperatingSystemDisplayName { get; set; } - /// /// Get or sets the package name. /// diff --git a/MediaBrowser.Model/System/WakeOnLanInfo.cs b/MediaBrowser.Model/System/WakeOnLanInfo.cs index 534ad19ec..b2cbe737d 100644 --- a/MediaBrowser.Model/System/WakeOnLanInfo.cs +++ b/MediaBrowser.Model/System/WakeOnLanInfo.cs @@ -7,36 +7,21 @@ namespace MediaBrowser.Model.System /// public class WakeOnLanInfo { - /// - /// Returns the MAC address of the device. - /// - /// The MAC address. - public string MacAddress { get; set; } - - /// - /// Returns the wake-on-LAN port. - /// - /// The wake-on-LAN port. - public int Port { get; set; } - /// /// Initializes a new instance of the class. /// /// The MAC address. - public WakeOnLanInfo(PhysicalAddress macAddress) + public WakeOnLanInfo(PhysicalAddress macAddress) : this(macAddress.ToString()) { - MacAddress = macAddress.ToString(); - Port = 9; } /// /// Initializes a new instance of the class. /// /// The MAC address. - public WakeOnLanInfo(string macAddress) + public WakeOnLanInfo(string macAddress) : this() { MacAddress = macAddress; - Port = 9; } /// @@ -46,5 +31,17 @@ namespace MediaBrowser.Model.System { Port = 9; } + + /// + /// Gets the MAC address of the device. + /// + /// The MAC address. + public string? MacAddress { get; set; } + + /// + /// Gets or sets the wake-on-LAN port. + /// + /// The wake-on-LAN port. + public int Port { get; set; } } } diff --git a/MediaBrowser.Model/Tasks/IScheduledTask.cs b/MediaBrowser.Model/Tasks/IScheduledTask.cs index ed160e176..bf87088e4 100644 --- a/MediaBrowser.Model/Tasks/IScheduledTask.cs +++ b/MediaBrowser.Model/Tasks/IScheduledTask.cs @@ -1,5 +1,3 @@ -#pragma warning disable CS1591 - using System; using System.Collections.Generic; using System.Threading; @@ -8,16 +6,19 @@ using System.Threading.Tasks; namespace MediaBrowser.Model.Tasks { /// - /// Interface IScheduledTaskWorker + /// Interface IScheduledTaskWorker. /// public interface IScheduledTask { /// - /// Gets the name of the task + /// Gets the name of the task. /// /// The name. string Name { get; } + /// + /// Gets the key of the task. + /// string Key { get; } /// @@ -33,7 +34,7 @@ namespace MediaBrowser.Model.Tasks string Category { get; } /// - /// Executes the task + /// Executes the task. /// /// The cancellation token. /// The progress. diff --git a/MediaBrowser.Model/Tasks/IScheduledTaskWorker.cs b/MediaBrowser.Model/Tasks/IScheduledTaskWorker.cs index 4dd1bb5d0..c79d7fe75 100644 --- a/MediaBrowser.Model/Tasks/IScheduledTaskWorker.cs +++ b/MediaBrowser.Model/Tasks/IScheduledTaskWorker.cs @@ -1,3 +1,4 @@ +#nullable disable using System; using MediaBrowser.Model.Events; diff --git a/MediaBrowser.Model/Tasks/ScheduledTaskHelpers.cs b/MediaBrowser.Model/Tasks/ScheduledTaskHelpers.cs index ca0743cca..9063903ae 100644 --- a/MediaBrowser.Model/Tasks/ScheduledTaskHelpers.cs +++ b/MediaBrowser.Model/Tasks/ScheduledTaskHelpers.cs @@ -14,9 +14,7 @@ namespace MediaBrowser.Model.Tasks { var isHidden = false; - var configurableTask = task.ScheduledTask as IConfigurableScheduledTask; - - if (configurableTask != null) + if (task.ScheduledTask is IConfigurableScheduledTask configurableTask) { isHidden = configurableTask.IsHidden; } diff --git a/MediaBrowser.Model/Tasks/TaskCompletionEventArgs.cs b/MediaBrowser.Model/Tasks/TaskCompletionEventArgs.cs index cc6c2b62b..48950667e 100644 --- a/MediaBrowser.Model/Tasks/TaskCompletionEventArgs.cs +++ b/MediaBrowser.Model/Tasks/TaskCompletionEventArgs.cs @@ -6,8 +6,14 @@ namespace MediaBrowser.Model.Tasks { public class TaskCompletionEventArgs : EventArgs { - public IScheduledTaskWorker Task { get; set; } + public TaskCompletionEventArgs(IScheduledTaskWorker task, TaskResult result) + { + Task = task; + Result = result; + } - public TaskResult Result { get; set; } + public IScheduledTaskWorker Task { get; } + + public TaskResult Result { get; } } } diff --git a/MediaBrowser.Model/Tasks/TaskInfo.cs b/MediaBrowser.Model/Tasks/TaskInfo.cs index 5144c035a..77100dfe7 100644 --- a/MediaBrowser.Model/Tasks/TaskInfo.cs +++ b/MediaBrowser.Model/Tasks/TaskInfo.cs @@ -1,3 +1,4 @@ +#nullable disable using System; namespace MediaBrowser.Model.Tasks diff --git a/MediaBrowser.Model/Tasks/TaskResult.cs b/MediaBrowser.Model/Tasks/TaskResult.cs index c6f92e7ed..31001aeb2 100644 --- a/MediaBrowser.Model/Tasks/TaskResult.cs +++ b/MediaBrowser.Model/Tasks/TaskResult.cs @@ -1,3 +1,4 @@ +#nullable disable using System; namespace MediaBrowser.Model.Tasks diff --git a/MediaBrowser.Model/Tasks/TaskTriggerInfo.cs b/MediaBrowser.Model/Tasks/TaskTriggerInfo.cs index 699e0ea3a..5aeaffc2b 100644 --- a/MediaBrowser.Model/Tasks/TaskTriggerInfo.cs +++ b/MediaBrowser.Model/Tasks/TaskTriggerInfo.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System; diff --git a/MediaBrowser.Model/Updates/CheckForUpdateResult.cs b/MediaBrowser.Model/Updates/CheckForUpdateResult.cs index be1b08223..9c59a7c88 100644 --- a/MediaBrowser.Model/Updates/CheckForUpdateResult.cs +++ b/MediaBrowser.Model/Updates/CheckForUpdateResult.cs @@ -1,3 +1,4 @@ +#nullable disable namespace MediaBrowser.Model.Updates { /// diff --git a/MediaBrowser.Model/Updates/InstallationInfo.cs b/MediaBrowser.Model/Updates/InstallationInfo.cs index 42c2105f5..4651a4169 100644 --- a/MediaBrowser.Model/Updates/InstallationInfo.cs +++ b/MediaBrowser.Model/Updates/InstallationInfo.cs @@ -1,3 +1,4 @@ +#nullable disable using System; namespace MediaBrowser.Model.Updates diff --git a/MediaBrowser.Model/Updates/PackageInfo.cs b/MediaBrowser.Model/Updates/PackageInfo.cs index abbe91eff..b5a5068e7 100644 --- a/MediaBrowser.Model/Updates/PackageInfo.cs +++ b/MediaBrowser.Model/Updates/PackageInfo.cs @@ -1,3 +1,4 @@ +#nullable disable using System; using System.Collections.Generic; diff --git a/MediaBrowser.Model/Updates/PackageVersionInfo.cs b/MediaBrowser.Model/Updates/PackageVersionInfo.cs index 3eef965dd..9ef67966b 100644 --- a/MediaBrowser.Model/Updates/PackageVersionInfo.cs +++ b/MediaBrowser.Model/Updates/PackageVersionInfo.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System; diff --git a/MediaBrowser.Model/Users/ForgotPasswordResult.cs b/MediaBrowser.Model/Users/ForgotPasswordResult.cs index 368c642e8..6bb13d4c9 100644 --- a/MediaBrowser.Model/Users/ForgotPasswordResult.cs +++ b/MediaBrowser.Model/Users/ForgotPasswordResult.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System; diff --git a/MediaBrowser.Model/Users/PinRedeemResult.cs b/MediaBrowser.Model/Users/PinRedeemResult.cs index ab868cad4..7e4553bac 100644 --- a/MediaBrowser.Model/Users/PinRedeemResult.cs +++ b/MediaBrowser.Model/Users/PinRedeemResult.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 namespace MediaBrowser.Model.Users diff --git a/MediaBrowser.Model/Users/UserAction.cs b/MediaBrowser.Model/Users/UserAction.cs index f6bb6451b..36b8e6ee5 100644 --- a/MediaBrowser.Model/Users/UserAction.cs +++ b/MediaBrowser.Model/Users/UserAction.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System; diff --git a/MediaBrowser.Model/Users/UserPolicy.cs b/MediaBrowser.Model/Users/UserPolicy.cs index ae2b3fd4e..9f85022ef 100644 --- a/MediaBrowser.Model/Users/UserPolicy.cs +++ b/MediaBrowser.Model/Users/UserPolicy.cs @@ -1,3 +1,4 @@ +#nullable disable #pragma warning disable CS1591 using System; diff --git a/MediaBrowser.Providers/Manager/ItemImageProvider.cs b/MediaBrowser.Providers/Manager/ItemImageProvider.cs index 6ef0e44a2..48e1c94ad 100644 --- a/MediaBrowser.Providers/Manager/ItemImageProvider.cs +++ b/MediaBrowser.Providers/Manager/ItemImageProvider.cs @@ -230,7 +230,9 @@ namespace MediaBrowser.Providers.Manager /// The result. /// The cancellation token. /// Task. - private async Task RefreshFromProvider(BaseItem item, LibraryOptions libraryOptions, + private async Task RefreshFromProvider( + BaseItem item, + LibraryOptions libraryOptions, IRemoteImageProvider provider, ImageRefreshOptions refreshOptions, TypeOptions savedOptions, @@ -256,20 +258,24 @@ namespace MediaBrowser.Providers.Manager _logger.LogDebug("Running {0} for {1}", provider.GetType().Name, item.Path ?? item.Name); - var images = await _providerManager.GetAvailableRemoteImages(item, new RemoteImageQuery - { - ProviderName = provider.Name, - IncludeAllLanguages = false, - IncludeDisabledProviders = false, - - }, cancellationToken).ConfigureAwait(false); + var images = await _providerManager.GetAvailableRemoteImages( + item, + new RemoteImageQuery(provider.Name) + { + IncludeAllLanguages = false, + IncludeDisabledProviders = false, + }, + cancellationToken).ConfigureAwait(false); var list = images.ToList(); int minWidth; foreach (var imageType in _singularImages) { - if (!IsEnabled(savedOptions, imageType, item)) continue; + if (!IsEnabled(savedOptions, imageType, item)) + { + continue; + } if (!HasImage(item, imageType) || (refreshOptions.IsReplacingImage(imageType) && !downloadedImages.Contains(imageType))) { diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs index 7125f34c5..bf3677850 100644 --- a/MediaBrowser.Providers/Manager/ProviderManager.cs +++ b/MediaBrowser.Providers/Manager/ProviderManager.cs @@ -264,11 +264,7 @@ namespace MediaBrowser.Providers.Manager /// IEnumerable{IImageProvider}. public IEnumerable GetRemoteImageProviderInfo(BaseItem item) { - return GetRemoteImageProviders(item, true).Select(i => new ImageProviderInfo - { - Name = i.Name, - SupportedImages = i.GetSupportedImages(item).ToArray() - }); + return GetRemoteImageProviders(item, true).Select(i => new ImageProviderInfo(i.Name, i.GetSupportedImages(item).ToArray())); } public IEnumerable GetImageProviders(BaseItem item, ImageRefreshOptions refreshOptions) -- cgit v1.2.3 From 410a322fe22302eb3c8a37ea38bbe1d7e9d12aff Mon Sep 17 00:00:00 2001 From: Mark Monteiro Date: Sun, 5 Apr 2020 23:30:57 -0400 Subject: Add CanConnectWithHttps to interface --- Emby.Server.Implementations/ApplicationHost.cs | 5 +---- MediaBrowser.Controller/IServerApplicationHost.cs | 6 ++++++ 2 files changed, 7 insertions(+), 4 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index 8158b4559..9cb747171 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -1449,10 +1449,7 @@ namespace Emby.Server.Implementations /// public bool ListenWithHttps => Certificate != null && ServerConfigurationManager.Configuration.EnableHttps; - /// - /// Gets a value indicating whether a client can connect to the server over HTTPS, either directly or via a - /// reverse proxy. - /// + /// public bool CanConnectWithHttps => ListenWithHttps || ServerConfigurationManager.Configuration.IsBehindProxy; public async Task GetLocalApiUrl(CancellationToken cancellationToken) diff --git a/MediaBrowser.Controller/IServerApplicationHost.cs b/MediaBrowser.Controller/IServerApplicationHost.cs index d999f76db..7742279f7 100644 --- a/MediaBrowser.Controller/IServerApplicationHost.cs +++ b/MediaBrowser.Controller/IServerApplicationHost.cs @@ -43,6 +43,12 @@ namespace MediaBrowser.Controller /// bool ListenWithHttps { get; } + /// + /// Gets a value indicating whether a client can connect to the server over HTTPS, either directly or via a + /// reverse proxy. + /// + bool CanConnectWithHttps { get; } + /// /// Gets a value indicating whether this instance has update available. /// -- cgit v1.2.3 From 36f3e933a23d802d154c16fd304a82c3fe3f453d Mon Sep 17 00:00:00 2001 From: ConfusedPolarBear <33811686+ConfusedPolarBear@users.noreply.github.com> Date: Wed, 15 Apr 2020 14:28:42 -0500 Subject: Add quick connect --- CONTRIBUTORS.md | 1 + Emby.Server.Implementations/ApplicationHost.cs | 3 + .../QuickConnect/QuickConnectManager.cs | 262 +++++++++++++++++++++ .../Session/SessionManager.cs | 18 ++ .../QuickConnect/QuickConnectService.cs | 145 ++++++++++++ MediaBrowser.Api/UserService.cs | 34 +++ .../QuickConnect/IQuickConnect.cs | 91 +++++++ MediaBrowser.Controller/Session/ISessionManager.cs | 2 + .../QuickConnect/QuickConnectResult.cs | 50 ++++ .../QuickConnect/QuickConnectResultDto.cs | 53 +++++ .../QuickConnect/QuickConnectState.cs | 23 ++ 11 files changed, 682 insertions(+) create mode 100644 Emby.Server.Implementations/QuickConnect/QuickConnectManager.cs create mode 100644 MediaBrowser.Api/QuickConnect/QuickConnectService.cs create mode 100644 MediaBrowser.Controller/QuickConnect/IQuickConnect.cs create mode 100644 MediaBrowser.Model/QuickConnect/QuickConnectResult.cs create mode 100644 MediaBrowser.Model/QuickConnect/QuickConnectResultDto.cs create mode 100644 MediaBrowser.Model/QuickConnect/QuickConnectState.cs (limited to 'MediaBrowser.Controller') diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index ce956176e..edd33a2fb 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -15,6 +15,7 @@ - [bugfixin](https://github.com/bugfixin) - [chaosinnovator](https://github.com/chaosinnovator) - [ckcr4lyf](https://github.com/ckcr4lyf) + - [ConfusedPolarBear](https://github.com/ConfusedPolarBear) - [crankdoofus](https://github.com/crankdoofus) - [crobibero](https://github.com/crobibero) - [cromefire](https://github.com/cromefire) diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index 81a80ddb2..de044a4aa 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -74,6 +74,7 @@ using MediaBrowser.Controller.Persistence; using MediaBrowser.Controller.Playlists; using MediaBrowser.Controller.Plugins; using MediaBrowser.Controller.Providers; +using MediaBrowser.Controller.QuickConnect; using MediaBrowser.Controller.Resolvers; using MediaBrowser.Controller.Security; using MediaBrowser.Controller.Session; @@ -857,6 +858,8 @@ namespace Emby.Server.Implementations serviceCollection.AddSingleton(typeof(IAttachmentExtractor), typeof(MediaBrowser.MediaEncoding.Attachments.AttachmentExtractor)); + serviceCollection.AddSingleton(typeof(IQuickConnect), typeof(QuickConnect.QuickConnectManager)); + _displayPreferencesRepository.Initialize(); var userDataRepo = new SqliteUserDataRepository(LoggerFactory.CreateLogger(), ApplicationPaths); diff --git a/Emby.Server.Implementations/QuickConnect/QuickConnectManager.cs b/Emby.Server.Implementations/QuickConnect/QuickConnectManager.cs new file mode 100644 index 000000000..30418097c --- /dev/null +++ b/Emby.Server.Implementations/QuickConnect/QuickConnectManager.cs @@ -0,0 +1,262 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Security.Cryptography; +using MediaBrowser.Controller; +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Net; +using MediaBrowser.Controller.QuickConnect; +using MediaBrowser.Controller.Security; +using MediaBrowser.Model.Globalization; +using MediaBrowser.Model.QuickConnect; +using MediaBrowser.Model.Serialization; +using MediaBrowser.Model.Services; +using Microsoft.Extensions.Logging; + +namespace Emby.Server.Implementations.QuickConnect +{ + /// + /// Quick connect implementation. + /// + public class QuickConnectManager : IQuickConnect + { + private readonly RNGCryptoServiceProvider _rng = new RNGCryptoServiceProvider(); + private Dictionary _currentRequests = new Dictionary(); + + private ILogger _logger; + private IUserManager _userManager; + private ILocalizationManager _localizationManager; + private IJsonSerializer _jsonSerializer; + private IAuthenticationRepository _authenticationRepository; + private IAuthorizationContext _authContext; + private IServerApplicationHost _appHost; + + /// + /// Initializes a new instance of the class. + /// Should only be called at server startup when a singleton is created. + /// + /// Logger. + /// User manager. + /// Localization. + /// JSON serializer. + /// Application host. + /// Authentication context. + /// Authentication repository. + public QuickConnectManager( + ILoggerFactory loggerFactory, + IUserManager userManager, + ILocalizationManager localization, + IJsonSerializer jsonSerializer, + IServerApplicationHost appHost, + IAuthorizationContext authContext, + IAuthenticationRepository authenticationRepository) + { + _logger = loggerFactory.CreateLogger(nameof(QuickConnectManager)); + _userManager = userManager; + _localizationManager = localization; + _jsonSerializer = jsonSerializer; + _appHost = appHost; + _authContext = authContext; + _authenticationRepository = authenticationRepository; + } + + /// + public int CodeLength { get; set; } = 6; + + /// + public string TokenNamePrefix { get; set; } = "QuickConnect-"; + + /// + public QuickConnectState State { get; private set; } = QuickConnectState.Unavailable; + + /// + public int RequestExpiry { get; set; } = 30; + + /// + public void AssertActive() + { + if (State != QuickConnectState.Active) + { + throw new InvalidOperationException("Quick connect is not active on this server"); + } + } + + /// + public void SetEnabled(QuickConnectState newState) + { + _logger.LogDebug("Changed quick connect state from {0} to {1}", State, newState); + + State = newState; + } + + /// + public QuickConnectResult TryConnect(string friendlyName) + { + if (State != QuickConnectState.Active) + { + _logger.LogDebug("Refusing quick connect initiation request, current state is {0}", State); + + return new QuickConnectResult() + { + Error = "Quick connect is not active on this server" + }; + } + + _logger.LogDebug("Got new quick connect request from {friendlyName}", friendlyName); + + var lookup = GenerateSecureRandom(); + var result = new QuickConnectResult() + { + Lookup = lookup, + Secret = GenerateSecureRandom(), + FriendlyName = friendlyName, + DateAdded = DateTime.Now, + Code = GenerateCode() + }; + + _currentRequests[lookup] = result; + return result; + } + + /// + public QuickConnectResult CheckRequestStatus(string secret) + { + AssertActive(); + ExpireRequests(); + + string lookup = _currentRequests.Where(x => x.Value.Secret == secret).Select(x => x.Value.Lookup).DefaultIfEmpty(string.Empty).First(); + + _logger.LogDebug("Transformed private identifier {0} into public lookup {1}", secret, lookup); + + if (!_currentRequests.ContainsKey(lookup)) + { + throw new KeyNotFoundException("Unable to find request with provided identifier"); + } + + return _currentRequests[lookup]; + } + + /// + public List GetCurrentRequests() + { + return GetCurrentRequestsInternal().Select(x => (QuickConnectResultDto)x).ToList(); + } + + /// + public List GetCurrentRequestsInternal() + { + AssertActive(); + ExpireRequests(); + return _currentRequests.Values.ToList(); + } + + /// + public string GenerateCode() + { + // TODO: output may be biased + + int min = (int)Math.Pow(10, CodeLength - 1); + int max = (int)Math.Pow(10, CodeLength); + + uint scale = uint.MaxValue; + while (scale == uint.MaxValue) + { + byte[] raw = new byte[4]; + _rng.GetBytes(raw); + scale = BitConverter.ToUInt32(raw, 0); + } + + int code = (int)(min + (max - min) * (scale / (double)uint.MaxValue)); + return code.ToString(CultureInfo.InvariantCulture); + } + + /// + public bool AuthorizeRequest(IRequest request, string lookup) + { + AssertActive(); + + var auth = _authContext.GetAuthorizationInfo(request); + + ExpireRequests(); + + if (!_currentRequests.ContainsKey(lookup)) + { + throw new KeyNotFoundException("Unable to find request"); + } + + QuickConnectResult result = _currentRequests[lookup]; + + if (result.Authenticated) + { + throw new InvalidOperationException("Request is already authorized"); + } + + result.Authentication = Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture); + + // Advance the time on the request so it expires sooner as the client will pick up the changes in a few seconds + result.DateAdded = result.DateAdded.Subtract(new TimeSpan(0, RequestExpiry - 1, 0)); + + _authenticationRepository.Create(new AuthenticationInfo + { + AppName = TokenNamePrefix + result.FriendlyName, + AccessToken = result.Authentication, + DateCreated = DateTime.UtcNow, + DeviceId = _appHost.SystemId, + DeviceName = _appHost.FriendlyName, + AppVersion = _appHost.ApplicationVersionString, + UserId = auth.UserId + }); + + return true; + } + + /// + public int DeleteAllDevices(Guid user) + { + var raw = _authenticationRepository.Get(new AuthenticationInfoQuery() + { + DeviceId = _appHost.SystemId, + UserId = user + }); + + var tokens = raw.Items.Where(x => x.AppName.StartsWith(TokenNamePrefix, StringComparison.CurrentCulture)); + + foreach (var token in tokens) + { + _authenticationRepository.Delete(token); + _logger.LogDebug("Deleted token {0}", token.AccessToken); + } + + return tokens.Count(); + } + + private string GenerateSecureRandom(int length = 32) + { + var bytes = new byte[length]; + _rng.GetBytes(bytes); + + return string.Join(string.Empty, bytes.Select(x => x.ToString("x2", CultureInfo.InvariantCulture))); + } + + private void ExpireRequests() + { + var delete = new List(); + var values = _currentRequests.Values.ToList(); + + for (int i = 0; i < _currentRequests.Count; i++) + { + if (DateTime.Now > values[i].DateAdded.AddMinutes(RequestExpiry)) + { + delete.Add(values[i].Lookup); + } + } + + foreach (var lookup in delete) + { + _logger.LogDebug("Removing expired request {0}", lookup); + _currentRequests.Remove(lookup); + } + } + } +} diff --git a/Emby.Server.Implementations/Session/SessionManager.cs b/Emby.Server.Implementations/Session/SessionManager.cs index de768333d..2c8b2f29d 100644 --- a/Emby.Server.Implementations/Session/SessionManager.cs +++ b/Emby.Server.Implementations/Session/SessionManager.cs @@ -1386,6 +1386,24 @@ namespace Emby.Server.Implementations.Session return AuthenticateNewSessionInternal(request, false); } + public Task AuthenticateQuickConnect(AuthenticationRequest request, string token) + { + var result = _authRepo.Get(new AuthenticationInfoQuery() + { + AccessToken = token, + DeviceId = _appHost.SystemId, + Limit = 1 + }); + + if(result.TotalRecordCount < 1) + { + throw new SecurityException("Unknown quick connect token"); + } + + request.UserId = result.Items[0].UserId; + return AuthenticateNewSessionInternal(request, false); + } + private async Task AuthenticateNewSessionInternal(AuthenticationRequest request, bool enforcePassword) { CheckDisposed(); diff --git a/MediaBrowser.Api/QuickConnect/QuickConnectService.cs b/MediaBrowser.Api/QuickConnect/QuickConnectService.cs new file mode 100644 index 000000000..889a78839 --- /dev/null +++ b/MediaBrowser.Api/QuickConnect/QuickConnectService.cs @@ -0,0 +1,145 @@ +using System; +using System.Collections.Generic; +using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Net; +using MediaBrowser.Controller.QuickConnect; +using MediaBrowser.Model.QuickConnect; +using MediaBrowser.Model.Services; +using Microsoft.Extensions.Logging; + +namespace MediaBrowser.Api.QuickConnect +{ + [Route("/QuickConnect/Initiate", "GET", Summary = "Requests a new quick connect code")] + public class Initiate : IReturn + { + [ApiMember(Name = "FriendlyName", Description = "Device friendly name", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] + public string FriendlyName { get; set; } + } + + [Route("/QuickConnect/Connect", "GET", Summary = "Attempts to retrieve authentication information")] + public class Connect : IReturn + { + [ApiMember(Name = "Secret", Description = "Quick connect secret", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")] + public string Secret { get; set; } + } + + [Route("/QuickConnect/List", "GET", Summary = "Lists all quick connect requests")] + [Authenticated] + public class QuickConnectList : IReturn> + { + } + + [Route("/QuickConnect/Authorize", "POST", Summary = "Authorizes a pending quick connect request")] + [Authenticated] + public class Authorize : IReturn + { + [ApiMember(Name = "Lookup", Description = "Quick connect public lookup", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")] + public string Lookup { get; set; } + } + + [Route("/QuickConnect/Deauthorize", "POST", Summary = "Deletes all quick connect authorization tokens for the current user")] + [Authenticated] + public class Deauthorize : IReturn + { + [ApiMember(Name = "UserId", Description = "User Id", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] + public Guid UserId { get; set; } + } + + [Route("/QuickConnect/Status", "GET", Summary = "Gets the current quick connect state")] + public class QuickConnectStatus : IReturn + { + + } + + [Route("/QuickConnect/Available", "POST", Summary = "Enables or disables quick connect")] + [Authenticated(Roles = "Admin")] + public class Available : IReturn + { + [ApiMember(Name = "Status", Description = "New quick connect status", IsRequired = false, DataType = "QuickConnectState", ParameterType = "query", Verb = "GET")] + public QuickConnectState Status { get; set; } + } + + [Route("/QuickConnect/Activate", "POST", Summary = "Temporarily activates quick connect for the time period defined in the server configuration")] + [Authenticated] + public class Activate : IReturn + { + } + + public class QuickConnectService : BaseApiService + { + private IQuickConnect _quickConnect; + private IUserManager _userManager; + private IAuthorizationContext _authContext; + + public QuickConnectService( + ILogger logger, + IServerConfigurationManager serverConfigurationManager, + IHttpResultFactory httpResultFactory, + IUserManager userManager, + IAuthorizationContext authContext, + IQuickConnect quickConnect) + : base(logger, serverConfigurationManager, httpResultFactory) + { + _userManager = userManager; + _quickConnect = quickConnect; + _authContext = authContext; + } + + public object Get(Initiate request) + { + return _quickConnect.TryConnect(request.FriendlyName); + } + + public object Get(Connect request) + { + return _quickConnect.CheckRequestStatus(request.Secret); + } + + public object Get(QuickConnectList request) + { + return _quickConnect.GetCurrentRequests(); + } + + public object Get(QuickConnectStatus request) + { + return _quickConnect.State; + } + + public object Post(Deauthorize request) + { + AssertCanUpdateUser(_authContext, _userManager, request.UserId, true); + + return _quickConnect.DeleteAllDevices(request.UserId); + } + + public object Post(Authorize request) + { + bool result = _quickConnect.AuthorizeRequest(Request, request.Lookup); + + Logger.LogInformation("Result of authorizing quick connect {0}: {1}", request.Lookup[..10], result); + + return result; + } + + public object Post(Activate request) + { + if (_quickConnect.State == QuickConnectState.Available) + { + _quickConnect.SetEnabled(QuickConnectState.Active); + + string name = _authContext.GetAuthorizationInfo(Request).User.Name; + Logger.LogInformation("{name} enabled quick connect", name); + } + + return _quickConnect.State; + } + + public object Post(Available request) + { + _quickConnect.SetEnabled(request.Status); + + return _quickConnect.State; + } + } +} diff --git a/MediaBrowser.Api/UserService.cs b/MediaBrowser.Api/UserService.cs index 401514349..ebcacd2a3 100644 --- a/MediaBrowser.Api/UserService.cs +++ b/MediaBrowser.Api/UserService.cs @@ -117,6 +117,17 @@ namespace MediaBrowser.Api public string Pw { get; set; } } + [Route("/Users/AuthenticateWithQuickConnect", "POST", Summary = "Authenticates a user")] + public class AuthenticateUserQuickConnect : IReturn + { + /// + /// Gets or sets the token. + /// + /// The token + [ApiMember(Name = "Token", IsRequired = true, DataType = "string", ParameterType = "body", Verb = "POST")] + public string Token { get; set; } + } + /// /// Class UpdateUserPassword /// @@ -430,6 +441,29 @@ namespace MediaBrowser.Api } } + public async Task Post(AuthenticateUserQuickConnect request) + { + var auth = _authContext.GetAuthorizationInfo(Request); + + try + { + var result = await _sessionMananger.AuthenticateQuickConnect(new AuthenticationRequest + { + App = auth.Client, + AppVersion = auth.Version, + DeviceId = auth.DeviceId, + DeviceName = auth.Device + }, request.Token).ConfigureAwait(false); + + return ToOptimizedResult(result); + } + catch (SecurityException e) + { + // rethrow adding IP address to message + throw new SecurityException($"[{Request.RemoteIp}] {e.Message}"); + } + } + /// /// Posts the specified request. /// diff --git a/MediaBrowser.Controller/QuickConnect/IQuickConnect.cs b/MediaBrowser.Controller/QuickConnect/IQuickConnect.cs new file mode 100644 index 000000000..e4a790ffe --- /dev/null +++ b/MediaBrowser.Controller/QuickConnect/IQuickConnect.cs @@ -0,0 +1,91 @@ +using System; +using System.Collections.Generic; +using MediaBrowser.Model.QuickConnect; +using MediaBrowser.Model.Services; + +namespace MediaBrowser.Controller.QuickConnect +{ + /// + /// Quick connect standard interface. + /// + public interface IQuickConnect + { + /// + /// Gets or sets the length of user facing codes. + /// + public int CodeLength { get; set; } + + /// + /// Gets or sets the string to prefix internal access tokens with. + /// + public string TokenNamePrefix { get; set; } + + /// + /// Gets the current state of quick connect. + /// + public QuickConnectState State { get; } + + /// + /// Gets or sets the time (in minutes) before a pending request will expire. + /// + public int RequestExpiry { get; set; } + + /// + /// Assert that quick connect is currently active and throws an exception if it is not. + /// + void AssertActive(); + + /// + /// Changes the status of quick connect. + /// + /// New state to change to + void SetEnabled(QuickConnectState newState); + + /// + /// Initiates a new quick connect request. + /// + /// Friendly device name to display in the request UI. + /// A quick connect result with tokens to proceed or a descriptive error message otherwise. + QuickConnectResult TryConnect(string friendlyName); + + /// + /// Checks the status of an individual request. + /// + /// Unique secret identifier of the request. + /// Quick connect result. + QuickConnectResult CheckRequestStatus(string secret); + + /// + /// Returns all current quick connect requests as DTOs. Does not include sensitive information. + /// + /// List of all quick connect results. + List GetCurrentRequests(); + + /// + /// Returns all current quick connect requests (including sensitive information). + /// + /// List of all quick connect results. + List GetCurrentRequestsInternal(); + + /// + /// Authorizes a quick connect request to connect as the calling user. + /// + /// HTTP request object. + /// Public request lookup value. + /// A boolean indicating if the authorization completed successfully. + bool AuthorizeRequest(IRequest request, string lookup); + + /// + /// Deletes all quick connect access tokens for the provided user. + /// + /// Guid of the user to delete tokens for. + /// A count of the deleted tokens. + int DeleteAllDevices(Guid user); + + /// + /// Generates a short code to display to the user to uniquely identify this request. + /// + /// A short, unique alphanumeric string. + string GenerateCode(); + } +} diff --git a/MediaBrowser.Controller/Session/ISessionManager.cs b/MediaBrowser.Controller/Session/ISessionManager.cs index 771027103..74ffd5a18 100644 --- a/MediaBrowser.Controller/Session/ISessionManager.cs +++ b/MediaBrowser.Controller/Session/ISessionManager.cs @@ -246,6 +246,8 @@ namespace MediaBrowser.Controller.Session /// Task{SessionInfo}. Task AuthenticateNewSession(AuthenticationRequest request); + public Task AuthenticateQuickConnect(AuthenticationRequest request, string token); + /// /// Creates the new session. /// diff --git a/MediaBrowser.Model/QuickConnect/QuickConnectResult.cs b/MediaBrowser.Model/QuickConnect/QuickConnectResult.cs new file mode 100644 index 000000000..bc3fd0046 --- /dev/null +++ b/MediaBrowser.Model/QuickConnect/QuickConnectResult.cs @@ -0,0 +1,50 @@ +using System; + +namespace MediaBrowser.Model.QuickConnect +{ + /// + /// Stores the result of an incoming quick connect request. + /// + public class QuickConnectResult + { + /// + /// Gets a value indicating whether this request is authorized. + /// + public bool Authenticated => !string.IsNullOrEmpty(Authentication); + + /// + /// Gets or sets the secret value used to uniquely identify this request. Can be used to retrieve authentication information. + /// + public string Secret { get; set; } + + /// + /// Gets or sets the public value used to uniquely identify this request. Can only be used to authorize the request. + /// + public string Lookup { get; set; } + + /// + /// Gets or sets the user facing code used so the user can quickly differentiate this request from others. + /// + public string Code { get; set; } + + /// + /// Gets or sets the device friendly name. + /// + public string FriendlyName { get; set; } + + /// + /// Gets or sets the private access token. + /// + public string Authentication { get; set; } + + /// + /// Gets or sets an error message. + /// + public string Error { get; set; } + + /// + /// Gets or sets the DateTime that this request was created. + /// + public DateTime DateAdded { get; set; } + } +} diff --git a/MediaBrowser.Model/QuickConnect/QuickConnectResultDto.cs b/MediaBrowser.Model/QuickConnect/QuickConnectResultDto.cs new file mode 100644 index 000000000..671b7cc94 --- /dev/null +++ b/MediaBrowser.Model/QuickConnect/QuickConnectResultDto.cs @@ -0,0 +1,53 @@ +using System; + +namespace MediaBrowser.Model.QuickConnect +{ + /// + /// Stores the non-sensitive results of an incoming quick connect request. + /// + public class QuickConnectResultDto + { + /// + /// Gets a value indicating whether this request is authorized. + /// + public bool Authenticated { get; private set; } + + /// + /// Gets the user facing code used so the user can quickly differentiate this request from others. + /// + public string Code { get; private set; } + + /// + /// Gets the public value used to uniquely identify this request. Can only be used to authorize the request. + /// + public string Lookup { get; private set; } + + /// + /// Gets the device friendly name. + /// + public string FriendlyName { get; private set; } + + /// + /// Gets the DateTime that this request was created. + /// + public DateTime DateAdded { get; private set; } + + /// + /// Cast an internal quick connect result to a DTO by removing all sensitive properties. + /// + /// QuickConnectResult object to cast + public static implicit operator QuickConnectResultDto(QuickConnectResult result) + { + QuickConnectResultDto resultDto = new QuickConnectResultDto + { + Authenticated = result.Authenticated, + Code = result.Code, + FriendlyName = result.FriendlyName, + DateAdded = result.DateAdded, + Lookup = result.Lookup + }; + + return resultDto; + } + } +} diff --git a/MediaBrowser.Model/QuickConnect/QuickConnectState.cs b/MediaBrowser.Model/QuickConnect/QuickConnectState.cs new file mode 100644 index 000000000..9f250519b --- /dev/null +++ b/MediaBrowser.Model/QuickConnect/QuickConnectState.cs @@ -0,0 +1,23 @@ +namespace MediaBrowser.Model.QuickConnect +{ + /// + /// Quick connect state. + /// + public enum QuickConnectState + { + /// + /// This feature has not been opted into and is unavailable until the server administrator chooses to opt-in. + /// + Unavailable, + + /// + /// The feature is enabled for use on the server but is not currently accepting connection requests. + /// + Available, + + /// + /// The feature is actively accepting connection requests. + /// + Active + } +} -- cgit v1.2.3 From fee76097f44d0f11356e4a559df9178063b1bf29 Mon Sep 17 00:00:00 2001 From: Mark Monteiro Date: Thu, 16 Apr 2020 21:45:00 -0400 Subject: Remove CanConnectWithHttps Property It is only used in one place and only adds confusion by existing --- Emby.Server.Implementations/ApplicationHost.cs | 4 +--- MediaBrowser.Controller/IServerApplicationHost.cs | 6 ------ 2 files changed, 1 insertion(+), 9 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index 6a324e090..a39baa84a 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -1413,7 +1413,7 @@ namespace Emby.Server.Implementations InternalMetadataPath = ApplicationPaths.InternalMetadataPath, CachePath = ApplicationPaths.CachePath, HttpServerPortNumber = HttpPort, - SupportsHttps = CanConnectWithHttps, + SupportsHttps = ListenWithHttps || ServerConfigurationManager.Configuration.IsBehindProxy, HttpsPortNumber = HttpsPort, OperatingSystem = OperatingSystem.Id.ToString(), OperatingSystemDisplayName = OperatingSystem.Name, @@ -1455,8 +1455,6 @@ namespace Emby.Server.Implementations public bool ListenWithHttps => Certificate != null && ServerConfigurationManager.Configuration.EnableHttps; /// - public bool CanConnectWithHttps => ListenWithHttps || ServerConfigurationManager.Configuration.IsBehindProxy; - public async Task GetLocalApiUrl(CancellationToken cancellationToken) { try diff --git a/MediaBrowser.Controller/IServerApplicationHost.cs b/MediaBrowser.Controller/IServerApplicationHost.cs index 7742279f7..d999f76db 100644 --- a/MediaBrowser.Controller/IServerApplicationHost.cs +++ b/MediaBrowser.Controller/IServerApplicationHost.cs @@ -43,12 +43,6 @@ namespace MediaBrowser.Controller /// bool ListenWithHttps { get; } - /// - /// Gets a value indicating whether a client can connect to the server over HTTPS, either directly or via a - /// reverse proxy. - /// - bool CanConnectWithHttps { get; } - /// /// Gets a value indicating whether this instance has update available. /// -- cgit v1.2.3 From 00a0e013c695a3741218985afadd31265a6ddb40 Mon Sep 17 00:00:00 2001 From: Mark Monteiro Date: Thu, 16 Apr 2020 21:46:49 -0400 Subject: Update documentation for URL methods in ApplicationHost --- Emby.Server.Implementations/ApplicationHost.cs | 6 +++--- MediaBrowser.Controller/IServerApplicationHost.cs | 24 +++++++++++++---------- 2 files changed, 17 insertions(+), 13 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index a39baa84a..7699faf14 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -1510,7 +1510,7 @@ namespace Emby.Server.Implementations return GetLocalApiUrl(ipAddress.ToString()); } - /// + /// public string GetLocalApiUrl(ReadOnlySpan host) { var url = new StringBuilder(64); @@ -1559,7 +1559,7 @@ namespace Emby.Server.Implementations } } - var valid = await IsIpAddressValidAsync(address, cancellationToken).ConfigureAwait(false); + var valid = await IsLocalIpAddressValidAsync(address, cancellationToken).ConfigureAwait(false); if (valid) { resultList.Add(address); @@ -1593,7 +1593,7 @@ namespace Emby.Server.Implementations private readonly ConcurrentDictionary _validAddressResults = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); - private async Task IsIpAddressValidAsync(IPAddress address, CancellationToken cancellationToken) + private async Task IsLocalIpAddressValidAsync(IPAddress address, CancellationToken cancellationToken) { if (address.Equals(IPAddress.Loopback) || address.Equals(IPAddress.IPv6Loopback)) diff --git a/MediaBrowser.Controller/IServerApplicationHost.cs b/MediaBrowser.Controller/IServerApplicationHost.cs index d999f76db..8537e4180 100644 --- a/MediaBrowser.Controller/IServerApplicationHost.cs +++ b/MediaBrowser.Controller/IServerApplicationHost.cs @@ -56,29 +56,33 @@ namespace MediaBrowser.Controller string FriendlyName { get; } /// - /// 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. /// - /// The local ip address. + /// A cancellation token that can be used to cancel the task. + /// A list containing all the local IP addresses of the server. Task> GetLocalIpAddresses(CancellationToken cancellationToken); /// - /// 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 . /// - /// The local API URL. + /// A cancellation token that can be used to cancel the task. + /// The server URL. Task GetLocalApiUrl(CancellationToken cancellationToken); /// - /// Gets the local API URL. + /// Gets a local (LAN) URL that can be used to access the API. /// - /// The hostname. - /// The local API URL. + /// The hostname to use in the URL. + /// The API URL. string GetLocalApiUrl(ReadOnlySpan hostname); /// - /// Gets the local API URL. + /// Gets a local (LAN) URL that can be used to access the API. /// - /// The IP address. - /// The local API URL. + /// The IP address to use as the hostname in the URL. + /// The API URL. string GetLocalApiUrl(IPAddress address); /// -- cgit v1.2.3 From 387a07c6dd4792ea1e77d333e178f9b4e9c56678 Mon Sep 17 00:00:00 2001 From: ConfusedPolarBear <33811686+ConfusedPolarBear@users.noreply.github.com> Date: Sun, 19 Apr 2020 01:33:09 -0500 Subject: Add persistent setting configuration and temporary activation --- .../QuickConnect/ConfigurationExtension.cs | 30 +++++++++ .../QuickConnect/QuickConnectConfiguration.cs | 13 ++++ .../QuickConnect/QuickConnectManager.cs | 72 +++++++++++++++++++--- .../QuickConnect/QuickConnectService.cs | 40 ++++++++++-- .../QuickConnect/IQuickConnect.cs | 8 ++- 5 files changed, 149 insertions(+), 14 deletions(-) create mode 100644 Emby.Server.Implementations/QuickConnect/ConfigurationExtension.cs create mode 100644 Emby.Server.Implementations/QuickConnect/QuickConnectConfiguration.cs (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/QuickConnect/ConfigurationExtension.cs b/Emby.Server.Implementations/QuickConnect/ConfigurationExtension.cs new file mode 100644 index 000000000..0e35ba80a --- /dev/null +++ b/Emby.Server.Implementations/QuickConnect/ConfigurationExtension.cs @@ -0,0 +1,30 @@ +#pragma warning disable CS1591 + +using System.Collections.Generic; +using MediaBrowser.Common.Configuration; + +namespace Emby.Server.Implementations.QuickConnect +{ + public static class ConfigurationExtension + { + public static QuickConnectConfiguration GetQuickConnectConfiguration(this IConfigurationManager manager) + { + return manager.GetConfiguration("quickconnect"); + } + } + + public class QuickConnectConfigurationFactory : IConfigurationFactory + { + public IEnumerable GetConfigurations() + { + return new ConfigurationStore[] + { + new ConfigurationStore + { + Key = "quickconnect", + ConfigurationType = typeof(QuickConnectConfiguration) + } + }; + } + } +} diff --git a/Emby.Server.Implementations/QuickConnect/QuickConnectConfiguration.cs b/Emby.Server.Implementations/QuickConnect/QuickConnectConfiguration.cs new file mode 100644 index 000000000..befc46379 --- /dev/null +++ b/Emby.Server.Implementations/QuickConnect/QuickConnectConfiguration.cs @@ -0,0 +1,13 @@ +using MediaBrowser.Model.QuickConnect; + +namespace Emby.Server.Implementations.QuickConnect +{ + public class QuickConnectConfiguration + { + public QuickConnectConfiguration() + { + } + + public QuickConnectState State { get; set; } + } +} diff --git a/Emby.Server.Implementations/QuickConnect/QuickConnectManager.cs b/Emby.Server.Implementations/QuickConnect/QuickConnectManager.cs index 30418097c..671ddc2b9 100644 --- a/Emby.Server.Implementations/QuickConnect/QuickConnectManager.cs +++ b/Emby.Server.Implementations/QuickConnect/QuickConnectManager.cs @@ -3,7 +3,9 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Security.Cryptography; +using MediaBrowser.Common.Configuration; using MediaBrowser.Controller; +using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Net; using MediaBrowser.Controller.QuickConnect; @@ -12,6 +14,7 @@ using MediaBrowser.Model.Globalization; using MediaBrowser.Model.QuickConnect; using MediaBrowser.Model.Serialization; using MediaBrowser.Model.Services; +using MediaBrowser.Model.Tasks; using Microsoft.Extensions.Logging; namespace Emby.Server.Implementations.QuickConnect @@ -24,6 +27,7 @@ namespace Emby.Server.Implementations.QuickConnect private readonly RNGCryptoServiceProvider _rng = new RNGCryptoServiceProvider(); private Dictionary _currentRequests = new Dictionary(); + private IServerConfigurationManager _config; private ILogger _logger; private IUserManager _userManager; private ILocalizationManager _localizationManager; @@ -31,11 +35,13 @@ namespace Emby.Server.Implementations.QuickConnect private IAuthenticationRepository _authenticationRepository; private IAuthorizationContext _authContext; private IServerApplicationHost _appHost; + private ITaskManager _taskManager; /// /// Initializes a new instance of the class. /// Should only be called at server startup when a singleton is created. /// + /// Configuration. /// Logger. /// User manager. /// Localization. @@ -43,15 +49,19 @@ namespace Emby.Server.Implementations.QuickConnect /// Application host. /// Authentication context. /// Authentication repository. + /// Task scheduler. public QuickConnectManager( + IServerConfigurationManager config, ILoggerFactory loggerFactory, IUserManager userManager, ILocalizationManager localization, IJsonSerializer jsonSerializer, IServerApplicationHost appHost, IAuthorizationContext authContext, - IAuthenticationRepository authenticationRepository) + IAuthenticationRepository authenticationRepository, + ITaskManager taskManager) { + _config = config; _logger = loggerFactory.CreateLogger(nameof(QuickConnectManager)); _userManager = userManager; _localizationManager = localization; @@ -59,6 +69,16 @@ namespace Emby.Server.Implementations.QuickConnect _appHost = appHost; _authContext = authContext; _authenticationRepository = authenticationRepository; + _taskManager = taskManager; + + ReloadConfiguration(); + } + + private void ReloadConfiguration() + { + var config = _config.GetQuickConnectConfiguration(); + + State = config.State; } /// @@ -73,6 +93,10 @@ namespace Emby.Server.Implementations.QuickConnect /// public int RequestExpiry { get; set; } = 30; + private bool TemporaryActivation { get; set; } = false; + + private DateTime DateActivated { get; set; } + /// public void AssertActive() { @@ -82,17 +106,37 @@ namespace Emby.Server.Implementations.QuickConnect } } + /// + public QuickConnectResult Activate() + { + // This should not call SetEnabled since that would persist the "temporary" activation to the configuration file + State = QuickConnectState.Active; + DateActivated = DateTime.Now; + TemporaryActivation = true; + + return new QuickConnectResult(); + } + /// public void SetEnabled(QuickConnectState newState) { _logger.LogDebug("Changed quick connect state from {0} to {1}", State, newState); State = newState; + + _config.SaveConfiguration("quickconnect", new QuickConnectConfiguration() + { + State = State + }); + + _logger.LogDebug("Configuration saved"); } /// public QuickConnectResult TryConnect(string friendlyName) { + ExpireRequests(true); + if (State != QuickConnectState.Active) { _logger.LogDebug("Refusing quick connect initiation request, current state is {0}", State); @@ -122,13 +166,11 @@ namespace Emby.Server.Implementations.QuickConnect /// public QuickConnectResult CheckRequestStatus(string secret) { - AssertActive(); ExpireRequests(); + AssertActive(); string lookup = _currentRequests.Where(x => x.Value.Secret == secret).Select(x => x.Value.Lookup).DefaultIfEmpty(string.Empty).First(); - _logger.LogDebug("Transformed private identifier {0} into public lookup {1}", secret, lookup); - if (!_currentRequests.ContainsKey(lookup)) { throw new KeyNotFoundException("Unable to find request with provided identifier"); @@ -146,8 +188,8 @@ namespace Emby.Server.Implementations.QuickConnect /// public List GetCurrentRequestsInternal() { - AssertActive(); ExpireRequests(); + AssertActive(); return _currentRequests.Values.ToList(); } @@ -174,12 +216,11 @@ namespace Emby.Server.Implementations.QuickConnect /// public bool AuthorizeRequest(IRequest request, string lookup) { + ExpireRequests(); AssertActive(); var auth = _authContext.GetAuthorizationInfo(request); - ExpireRequests(); - if (!_currentRequests.ContainsKey(lookup)) { throw new KeyNotFoundException("Unable to find request"); @@ -208,6 +249,8 @@ namespace Emby.Server.Implementations.QuickConnect UserId = auth.UserId }); + _logger.LogInformation("Allowing device {0} to login as user {1} with quick connect code {2}", result.FriendlyName, auth.User.Name, result.Code); + return true; } @@ -239,8 +282,21 @@ namespace Emby.Server.Implementations.QuickConnect return string.Join(string.Empty, bytes.Select(x => x.ToString("x2", CultureInfo.InvariantCulture))); } - private void ExpireRequests() + private void ExpireRequests(bool onlyCheckTime = false) { + // check if quick connect should be deactivated + if (TemporaryActivation && DateTime.Now > DateActivated.AddMinutes(10) && State == QuickConnectState.Active) + { + _logger.LogDebug("Quick connect time expired, deactivating"); + SetEnabled(QuickConnectState.Available); + } + + if (onlyCheckTime) + { + return; + } + + // expire stale connection requests var delete = new List(); var values = _currentRequests.Values.ToList(); diff --git a/MediaBrowser.Api/QuickConnect/QuickConnectService.cs b/MediaBrowser.Api/QuickConnect/QuickConnectService.cs index 889a78839..60d6ac414 100644 --- a/MediaBrowser.Api/QuickConnect/QuickConnectService.cs +++ b/MediaBrowser.Api/QuickConnect/QuickConnectService.cs @@ -98,6 +98,11 @@ namespace MediaBrowser.Api.QuickConnect public object Get(QuickConnectList request) { + if(_quickConnect.State != QuickConnectState.Active) + { + return Array.Empty(); + } + return _quickConnect.GetCurrentRequests(); } @@ -124,15 +129,40 @@ namespace MediaBrowser.Api.QuickConnect public object Post(Activate request) { - if (_quickConnect.State == QuickConnectState.Available) + string name = _authContext.GetAuthorizationInfo(Request).User.Name; + + if(_quickConnect.State == QuickConnectState.Unavailable) + { + return new QuickConnectResult() + { + Error = "Quick connect is not enabled on this server" + }; + } + + else if(_quickConnect.State == QuickConnectState.Available) { - _quickConnect.SetEnabled(QuickConnectState.Active); + var result = _quickConnect.Activate(); - string name = _authContext.GetAuthorizationInfo(Request).User.Name; - Logger.LogInformation("{name} enabled quick connect", name); + if (string.IsNullOrEmpty(result.Error)) + { + Logger.LogInformation("{name} temporarily activated quick connect", name); + } + + return result; } - return _quickConnect.State; + else if(_quickConnect.State == QuickConnectState.Active) + { + return new QuickConnectResult() + { + Error = "" + }; + } + + return new QuickConnectResult() + { + Error = "Unknown current state" + }; } public object Post(Available request) diff --git a/MediaBrowser.Controller/QuickConnect/IQuickConnect.cs b/MediaBrowser.Controller/QuickConnect/IQuickConnect.cs index e4a790ffe..d44765e11 100644 --- a/MediaBrowser.Controller/QuickConnect/IQuickConnect.cs +++ b/MediaBrowser.Controller/QuickConnect/IQuickConnect.cs @@ -35,10 +35,16 @@ namespace MediaBrowser.Controller.QuickConnect /// void AssertActive(); + /// + /// Temporarily activates quick connect for a short amount of time. + /// + /// A quick connect result object indicating success. + QuickConnectResult Activate(); + /// /// Changes the status of quick connect. /// - /// New state to change to + /// New state to change to. void SetEnabled(QuickConnectState newState); /// -- cgit v1.2.3 From 10c2c62f07fb4088480ff580ab67c1bc10a057a4 Mon Sep 17 00:00:00 2001 From: gion Date: Wed, 1 Apr 2020 17:52:42 +0200 Subject: Implement syncplay backend --- Emby.Server.Implementations/ApplicationHost.cs | 4 + .../Session/SessionManager.cs | 17 + .../Syncplay/SyncplayController.cs | 418 +++++++++++++++++++++ .../Syncplay/SyncplayManager.cs | 248 ++++++++++++ MediaBrowser.Api/Syncplay/SyncplayService.cs | 261 +++++++++++++ MediaBrowser.Controller/Session/ISessionManager.cs | 19 + MediaBrowser.Controller/Syncplay/GroupInfo.cs | 148 ++++++++ MediaBrowser.Controller/Syncplay/GroupMember.cs | 28 ++ .../Syncplay/ISyncplayController.cs | 61 +++ .../Syncplay/ISyncplayManager.cs | 62 +++ MediaBrowser.Model/Syncplay/GroupInfoModel.cs | 38 ++ MediaBrowser.Model/Syncplay/SyncplayCommand.cs | 32 ++ MediaBrowser.Model/Syncplay/SyncplayCommandType.cs | 21 ++ MediaBrowser.Model/Syncplay/SyncplayGroupUpdate.cs | 26 ++ .../Syncplay/SyncplayGroupUpdateType.cs | 41 ++ MediaBrowser.Model/Syncplay/SyncplayRequestInfo.cs | 34 ++ MediaBrowser.Model/Syncplay/SyncplayRequestType.cs | 33 ++ 17 files changed, 1491 insertions(+) create mode 100644 Emby.Server.Implementations/Syncplay/SyncplayController.cs create mode 100644 Emby.Server.Implementations/Syncplay/SyncplayManager.cs create mode 100644 MediaBrowser.Api/Syncplay/SyncplayService.cs create mode 100644 MediaBrowser.Controller/Syncplay/GroupInfo.cs create mode 100644 MediaBrowser.Controller/Syncplay/GroupMember.cs create mode 100644 MediaBrowser.Controller/Syncplay/ISyncplayController.cs create mode 100644 MediaBrowser.Controller/Syncplay/ISyncplayManager.cs create mode 100644 MediaBrowser.Model/Syncplay/GroupInfoModel.cs create mode 100644 MediaBrowser.Model/Syncplay/SyncplayCommand.cs create mode 100644 MediaBrowser.Model/Syncplay/SyncplayCommandType.cs create mode 100644 MediaBrowser.Model/Syncplay/SyncplayGroupUpdate.cs create mode 100644 MediaBrowser.Model/Syncplay/SyncplayGroupUpdateType.cs create mode 100644 MediaBrowser.Model/Syncplay/SyncplayRequestInfo.cs create mode 100644 MediaBrowser.Model/Syncplay/SyncplayRequestType.cs (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index 4d906a1bf..8419014c2 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -47,6 +47,7 @@ using Emby.Server.Implementations.Session; using Emby.Server.Implementations.SocketSharp; using Emby.Server.Implementations.TV; using Emby.Server.Implementations.Updates; +using Emby.Server.Implementations.Syncplay; using MediaBrowser.Api; using MediaBrowser.Common; using MediaBrowser.Common.Configuration; @@ -80,6 +81,7 @@ using MediaBrowser.Controller.Session; using MediaBrowser.Controller.Sorting; using MediaBrowser.Controller.Subtitles; using MediaBrowser.Controller.TV; +using MediaBrowser.Controller.Syncplay; using MediaBrowser.LocalMetadata.Savers; using MediaBrowser.MediaEncoding.BdInfo; using MediaBrowser.Model.Activity; @@ -643,6 +645,8 @@ namespace Emby.Server.Implementations serviceCollection.AddSingleton(); + serviceCollection.AddSingleton(); + serviceCollection.AddSingleton(); serviceCollection.AddSingleton(); diff --git a/Emby.Server.Implementations/Session/SessionManager.cs b/Emby.Server.Implementations/Session/SessionManager.cs index c93c02c48..b1519b572 100644 --- a/Emby.Server.Implementations/Session/SessionManager.cs +++ b/Emby.Server.Implementations/Session/SessionManager.cs @@ -25,6 +25,7 @@ using MediaBrowser.Model.Events; using MediaBrowser.Model.Library; using MediaBrowser.Model.Querying; using MediaBrowser.Model.Session; +using MediaBrowser.Model.Syncplay; using Microsoft.Extensions.Logging; namespace Emby.Server.Implementations.Session @@ -1154,6 +1155,22 @@ namespace Emby.Server.Implementations.Session await SendMessageToSession(session, "Play", command, cancellationToken).ConfigureAwait(false); } + /// + public async Task SendSyncplayCommand(string sessionId, SyncplayCommand command, CancellationToken cancellationToken) + { + CheckDisposed(); + var session = GetSessionToRemoteControl(sessionId); + await SendMessageToSession(session, "SyncplayCommand", command, cancellationToken).ConfigureAwait(false); + } + + /// + public async Task SendSyncplayGroupUpdate(string sessionId, SyncplayGroupUpdate command, CancellationToken cancellationToken) + { + CheckDisposed(); + var session = GetSessionToRemoteControl(sessionId); + await SendMessageToSession(session, "SyncplayGroupUpdate", command, cancellationToken).ConfigureAwait(false); + } + private IEnumerable TranslateItemForPlayback(Guid id, User user) { var item = _libraryManager.GetItemById(id); diff --git a/Emby.Server.Implementations/Syncplay/SyncplayController.cs b/Emby.Server.Implementations/Syncplay/SyncplayController.cs new file mode 100644 index 000000000..4a20ceba0 --- /dev/null +++ b/Emby.Server.Implementations/Syncplay/SyncplayController.cs @@ -0,0 +1,418 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using MediaBrowser.Controller.Session; +using MediaBrowser.Controller.Syncplay; +using MediaBrowser.Model.Session; +using MediaBrowser.Model.Syncplay; +using Microsoft.Extensions.Logging; + +namespace Emby.Server.Implementations.Syncplay +{ + /// + /// Class SyncplayController. + /// + public class SyncplayController : ISyncplayController, IDisposable + { + private enum BroadcastType + { + AllGroup = 0, + SingleUser = 1, + AllExceptUser = 2, + AllReady = 3 + } + + /// + /// The logger. + /// + private readonly ILogger _logger; + + /// + /// The session manager. + /// + private readonly ISessionManager _sessionManager; + + /// + /// The syncplay manager. + /// + private readonly ISyncplayManager _syncplayManager; + + /// + /// The group to manage. + /// + private readonly GroupInfo _group = new GroupInfo(); + + /// + public Guid GetGroupId() => _group.GroupId; + + /// + public Guid GetPlayingItemId() => _group.PlayingItem.Id; + + /// + public bool IsGroupEmpty() => _group.IsEmpty(); + + private bool _disposed = false; + + public SyncplayController( + ILogger logger, + ISessionManager sessionManager, + ISyncplayManager syncplayManager) + { + _logger = logger; + _sessionManager = sessionManager; + _syncplayManager = syncplayManager; + } + + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + /// + /// Releases unmanaged and optionally managed resources. + /// + /// true to release both managed and unmanaged resources; false to release only unmanaged resources. + protected virtual void Dispose(bool disposing) + { + if (_disposed) + { + return; + } + + _disposed = true; + } + + // TODO: use this somewhere + private void CheckDisposed() + { + if (_disposed) + { + throw new ObjectDisposedException(GetType().Name); + } + } + + private SessionInfo[] FilterUsers(SessionInfo from, BroadcastType type) + { + if (type == BroadcastType.SingleUser) + { + return new SessionInfo[] { from }; + } + else if (type == BroadcastType.AllGroup) + { + return _group.Partecipants.Values.Select( + user => user.Session + ).ToArray(); + } + else if (type == BroadcastType.AllExceptUser) + { + return _group.Partecipants.Values.Select( + user => user.Session + ).Where( + user => !user.Id.Equals(from.Id) + ).ToArray(); + } + else if (type == BroadcastType.AllReady) + { + return _group.Partecipants.Values.Where( + user => !user.IsBuffering + ).Select( + user => user.Session + ).ToArray(); + } + else + { + return new SessionInfo[] {}; + } + } + + private Task SendGroupUpdate(SessionInfo from, BroadcastType type, SyncplayGroupUpdate message) + { + IEnumerable GetTasks() + { + SessionInfo[] users = FilterUsers(from, type); + foreach (var user in users) + { + yield return _sessionManager.SendSyncplayGroupUpdate(user.Id.ToString(), message, CancellationToken.None); + } + } + + return Task.WhenAll(GetTasks()); + } + + private Task SendCommand(SessionInfo from, BroadcastType type, SyncplayCommand message) + { + IEnumerable GetTasks() + { + SessionInfo[] users = FilterUsers(from, type); + foreach (var user in users) + { + yield return _sessionManager.SendSyncplayCommand(user.Id.ToString(), message, CancellationToken.None); + } + } + + return Task.WhenAll(GetTasks()); + } + + private SyncplayCommand NewSyncplayCommand(SyncplayCommandType type) { + var command = new SyncplayCommand(); + command.GroupId = _group.GroupId.ToString(); + command.Command = type; + command.PositionTicks = _group.PositionTicks; + command.When = _group.LastActivity.ToUniversalTime().ToString("o"); + return command; + } + + private SyncplayGroupUpdate NewSyncplayGroupUpdate(SyncplayGroupUpdateType type, T data) + { + var command = new SyncplayGroupUpdate(); + command.GroupId = _group.GroupId.ToString(); + command.Type = type; + command.Data = data; + return command; + } + + /// + public void InitGroup(SessionInfo user) + { + _group.AddUser(user); + _syncplayManager.MapUserToGroup(user, this); + + _group.PlayingItem = user.FullNowPlayingItem; + _group.IsPaused = true; + _group.PositionTicks = user.PlayState.PositionTicks ??= 0; + _group.LastActivity = DateTime.UtcNow; + + var updateUser = NewSyncplayGroupUpdate(SyncplayGroupUpdateType.GroupJoined, DateTime.UtcNow.ToUniversalTime().ToString("o")); + SendGroupUpdate(user, BroadcastType.SingleUser, updateUser); + var pauseCommand = NewSyncplayCommand(SyncplayCommandType.Pause); + SendCommand(user, BroadcastType.SingleUser, pauseCommand); + } + + /// + public void UserJoin(SessionInfo user) + { + if (user.NowPlayingItem != null && user.NowPlayingItem.Id.Equals(_group.PlayingItem.Id)) + { + _group.AddUser(user); + _syncplayManager.MapUserToGroup(user, this); + + var updateUser = NewSyncplayGroupUpdate(SyncplayGroupUpdateType.GroupJoined, _group.PositionTicks); + SendGroupUpdate(user, BroadcastType.SingleUser, updateUser); + + var updateOthers = NewSyncplayGroupUpdate(SyncplayGroupUpdateType.UserJoined, user.UserName); + SendGroupUpdate(user, BroadcastType.AllExceptUser, updateOthers); + + // Client join and play, syncing will happen client side + if (!_group.IsPaused) + { + var playCommand = NewSyncplayCommand(SyncplayCommandType.Play); + SendCommand(user, BroadcastType.SingleUser, playCommand); + } + else + { + var pauseCommand = NewSyncplayCommand(SyncplayCommandType.Pause); + SendCommand(user, BroadcastType.SingleUser, pauseCommand); + } + } + else + { + var playRequest = new PlayRequest(); + playRequest.ItemIds = new Guid[] { _group.PlayingItem.Id }; + playRequest.StartPositionTicks = _group.PositionTicks; + var update = NewSyncplayGroupUpdate(SyncplayGroupUpdateType.PrepareSession, playRequest); + SendGroupUpdate(user, BroadcastType.SingleUser, update); + } + } + + /// + public void UserLeave(SessionInfo user) + { + _group.RemoveUser(user); + _syncplayManager.UnmapUserFromGroup(user, this); + + var updateUser = NewSyncplayGroupUpdate(SyncplayGroupUpdateType.GroupLeft, _group.PositionTicks); + SendGroupUpdate(user, BroadcastType.SingleUser, updateUser); + + var updateOthers = NewSyncplayGroupUpdate(SyncplayGroupUpdateType.UserLeft, user.UserName); + SendGroupUpdate(user, BroadcastType.AllExceptUser, updateOthers); + } + + /// + public void HandleRequest(SessionInfo user, SyncplayRequestInfo request) + { + if (request.Type.Equals(SyncplayRequestType.Play)) + { + if (_group.IsPaused) + { + var delay = _group.GetHighestPing() * 2; + delay = delay < _group.DefaulPing ? _group.DefaulPing : delay; + + _group.IsPaused = false; + _group.LastActivity = DateTime.UtcNow.AddMilliseconds( + delay + ); + + var command = NewSyncplayCommand(SyncplayCommandType.Play); + SendCommand(user, BroadcastType.AllGroup, command); + } + else + { + // Client got lost + var command = NewSyncplayCommand(SyncplayCommandType.Play); + SendCommand(user, BroadcastType.SingleUser, command); + } + } + else if (request.Type.Equals(SyncplayRequestType.Pause)) + { + if (!_group.IsPaused) + { + _group.IsPaused = true; + var currentTime = DateTime.UtcNow; + var elapsedTime = currentTime - _group.LastActivity; + _group.LastActivity = currentTime; + _group.PositionTicks += elapsedTime.Ticks > 0 ? elapsedTime.Ticks : 0; + + var command = NewSyncplayCommand(SyncplayCommandType.Pause); + SendCommand(user, BroadcastType.AllGroup, command); + } + else + { + var command = NewSyncplayCommand(SyncplayCommandType.Pause); + SendCommand(user, BroadcastType.SingleUser, command); + } + } + else if (request.Type.Equals(SyncplayRequestType.Seek)) + { + // Sanitize PositionTicks + var ticks = request.PositionTicks ??= 0; + ticks = ticks >= 0 ? ticks : 0; + if (_group.PlayingItem.RunTimeTicks != null) + { + var runTimeTicks = _group.PlayingItem.RunTimeTicks ??= 0; + ticks = ticks > runTimeTicks ? runTimeTicks : ticks; + } + + _group.IsPaused = true; + _group.PositionTicks = ticks; + _group.LastActivity = DateTime.UtcNow; + + var command = NewSyncplayCommand(SyncplayCommandType.Seek); + SendCommand(user, BroadcastType.AllGroup, command); + } + // TODO: client does not implement this yet + else if (request.Type.Equals(SyncplayRequestType.Buffering)) + { + if (!_group.IsPaused) + { + _group.IsPaused = true; + var currentTime = DateTime.UtcNow; + var elapsedTime = currentTime - _group.LastActivity; + _group.LastActivity = currentTime; + _group.PositionTicks += elapsedTime.Ticks > 0 ? elapsedTime.Ticks : 0; + + _group.SetBuffering(user, true); + + // Send pause command to all non-buffering users + var command = NewSyncplayCommand(SyncplayCommandType.Pause); + SendCommand(user, BroadcastType.AllReady, command); + + var updateOthers = NewSyncplayGroupUpdate(SyncplayGroupUpdateType.GroupWait, user.UserName); + SendGroupUpdate(user, BroadcastType.AllExceptUser, updateOthers); + } + else + { + var command = NewSyncplayCommand(SyncplayCommandType.Pause); + SendCommand(user, BroadcastType.SingleUser, command); + } + } + // TODO: client does not implement this yet + else if (request.Type.Equals(SyncplayRequestType.BufferingComplete)) + { + if (_group.IsPaused) + { + _group.SetBuffering(user, false); + + if (_group.IsBuffering()) { + // Others are buffering, tell this client to pause when ready + var when = request.When ??= DateTime.UtcNow; + var currentTime = DateTime.UtcNow; + var elapsedTime = currentTime - when; + var clientPosition = TimeSpan.FromTicks(request.PositionTicks ??= 0) + elapsedTime; + var delay = _group.PositionTicks - clientPosition.Ticks; + + var command = NewSyncplayCommand(SyncplayCommandType.Pause); + command.When = currentTime.AddMilliseconds( + delay + ).ToUniversalTime().ToString("o"); + SendCommand(user, BroadcastType.SingleUser, command); + } + else + { + // Let other clients resume as soon as the buffering client catches up + var when = request.When ??= DateTime.UtcNow; + var currentTime = DateTime.UtcNow; + var elapsedTime = currentTime - when; + var clientPosition = TimeSpan.FromTicks(request.PositionTicks ??= 0) + elapsedTime; + var delay = _group.PositionTicks - clientPosition.Ticks; + + _group.IsPaused = false; + + if (delay > _group.GetHighestPing() * 2) + { + // Client that was buffering is recovering, notifying others to resume + _group.LastActivity = currentTime.AddMilliseconds( + delay + ); + var command = NewSyncplayCommand(SyncplayCommandType.Play); + SendCommand(user, BroadcastType.AllExceptUser, command); + } + else + { + // Client, that was buffering, resumed playback but did not update others in time + delay = _group.GetHighestPing() * 2; + delay = delay < _group.DefaulPing ? _group.DefaulPing : delay; + + _group.LastActivity = currentTime.AddMilliseconds( + delay + ); + + var command = NewSyncplayCommand(SyncplayCommandType.Play); + SendCommand(user, BroadcastType.AllGroup, command); + } + } + } + else + { + // Make sure client has latest group state + var command = NewSyncplayCommand(SyncplayCommandType.Play); + SendCommand(user, BroadcastType.SingleUser, command); + } + } + else if (request.Type.Equals(SyncplayRequestType.KeepAlive)) + { + _group.UpdatePing(user, request.Ping ??= _group.DefaulPing); + + var keepAlive = new SyncplayGroupUpdate(); + keepAlive.GroupId = _group.GroupId.ToString(); + keepAlive.Type = SyncplayGroupUpdateType.KeepAlive; + SendGroupUpdate(user, BroadcastType.SingleUser, keepAlive); + } + } + + /// + public GroupInfoView GetInfo() + { + var info = new GroupInfoView(); + info.GroupId = GetGroupId().ToString(); + info.PlayingItemName = _group.PlayingItem.Name; + info.PlayingItemId = _group.PlayingItem.Id.ToString(); + info.PositionTicks = _group.PositionTicks; + info.Partecipants = _group.Partecipants.Values.Select(user => user.Session.UserName).ToArray(); + return info; + } + } +} diff --git a/Emby.Server.Implementations/Syncplay/SyncplayManager.cs b/Emby.Server.Implementations/Syncplay/SyncplayManager.cs new file mode 100644 index 000000000..6bfd6aa9b --- /dev/null +++ b/Emby.Server.Implementations/Syncplay/SyncplayManager.cs @@ -0,0 +1,248 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using Microsoft.Extensions.Logging; +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Session; +using MediaBrowser.Controller.Syncplay; +using MediaBrowser.Model.Syncplay; + +namespace Emby.Server.Implementations.Syncplay +{ + /// + /// Class SyncplayManager. + /// + public class SyncplayManager : ISyncplayManager, IDisposable + { + /// + /// The logger. + /// + private readonly ILogger _logger; + + /// + /// The session manager. + /// + private readonly ISessionManager _sessionManager; + + /// + /// The map between users and groups. + /// + private readonly ConcurrentDictionary _userToGroupMap = + new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); + + /// + /// The groups. + /// + private readonly ConcurrentDictionary _groups = + new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); + + private bool _disposed = false; + + public SyncplayManager( + ILogger logger, + ISessionManager sessionManager) + { + _logger = logger; + _sessionManager = sessionManager; + + _sessionManager.SessionEnded += _sessionManager_SessionEnded; + _sessionManager.PlaybackStopped += _sessionManager_PlaybackStopped; + } + + /// + /// Gets all groups. + /// + /// All groups. + public IEnumerable Groups => _groups.Values; + + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + /// + /// Releases unmanaged and optionally managed resources. + /// + /// true to release both managed and unmanaged resources; false to release only unmanaged resources. + protected virtual void Dispose(bool disposing) + { + if (_disposed) + { + return; + } + + _sessionManager.SessionEnded -= _sessionManager_SessionEnded; + _sessionManager.PlaybackStopped -= _sessionManager_PlaybackStopped; + + _disposed = true; + } + + private void CheckDisposed() + { + if (_disposed) + { + throw new ObjectDisposedException(GetType().Name); + } + } + + void _sessionManager_SessionEnded(object sender, SessionEventArgs e) + { + LeaveGroup(e.SessionInfo); + } + + void _sessionManager_PlaybackStopped(object sender, PlaybackStopEventArgs e) + { + LeaveGroup(e.Session); + } + + private bool IsUserInGroup(SessionInfo user) + { + return _userToGroupMap.ContainsKey(user.Id); + } + + private Guid? GetUserGroup(SessionInfo user) + { + ISyncplayController group; + _userToGroupMap.TryGetValue(user.Id, out group); + if (group != null) + { + return group.GetGroupId(); + } + else + { + return null; + } + } + + /// + public void NewGroup(SessionInfo user) + { + if (IsUserInGroup(user)) + { + LeaveGroup(user); + } + + var group = new SyncplayController(_logger, _sessionManager, this); + _groups[group.GetGroupId().ToString()] = group; + + group.InitGroup(user); + } + + /// + public void JoinGroup(SessionInfo user, string groupId) + { + if (IsUserInGroup(user)) + { + if (GetUserGroup(user).Equals(groupId)) return; + LeaveGroup(user); + } + + ISyncplayController group; + _groups.TryGetValue(groupId, out group); + + if (group == null) + { + _logger.LogError("Syncplaymanager JoinGroup: " + groupId + " does not exist."); + + var update = new SyncplayGroupUpdate(); + update.Type = SyncplayGroupUpdateType.NotInGroup; + _sessionManager.SendSyncplayGroupUpdate(user.Id.ToString(), update, CancellationToken.None); + return; + } + group.UserJoin(user); + } + + /// + public void LeaveGroup(SessionInfo user) + { + ISyncplayController group; + _userToGroupMap.TryGetValue(user.Id, out group); + + if (group == null) + { + _logger.LogWarning("Syncplaymanager HandleRequest: " + user.Id + " not in group."); + + var update = new SyncplayGroupUpdate(); + update.Type = SyncplayGroupUpdateType.NotInGroup; + _sessionManager.SendSyncplayGroupUpdate(user.Id.ToString(), update, CancellationToken.None); + return; + } + group.UserLeave(user); + + if (group.IsGroupEmpty()) + { + _groups.Remove(group.GetGroupId().ToString(), out _); + } + } + + /// + public List ListGroups(SessionInfo user) + { + // Filter by playing item if the user is viewing something already + if (user.NowPlayingItem != null) + { + return _groups.Values.Where( + group => group.GetPlayingItemId().Equals(user.FullNowPlayingItem.Id) + ).Select( + group => group.GetInfo() + ).ToList(); + } + // Otherwise show all available groups + else + { + return _groups.Values.Select( + group => group.GetInfo() + ).ToList(); + } + } + + /// + public void HandleRequest(SessionInfo user, SyncplayRequestInfo request) + { + ISyncplayController group; + _userToGroupMap.TryGetValue(user.Id, out group); + + if (group == null) + { + _logger.LogWarning("Syncplaymanager HandleRequest: " + user.Id + " not in group."); + + var update = new SyncplayGroupUpdate(); + update.Type = SyncplayGroupUpdateType.NotInGroup; + _sessionManager.SendSyncplayGroupUpdate(user.Id.ToString(), update, CancellationToken.None); + return; + } + group.HandleRequest(user, request); + } + + /// + public void MapUserToGroup(SessionInfo user, ISyncplayController group) + { + if (IsUserInGroup(user)) + { + throw new InvalidOperationException("User in other group already!"); + } + _userToGroupMap[user.Id] = group; + } + + /// + public void UnmapUserFromGroup(SessionInfo user, ISyncplayController group) + { + if (!IsUserInGroup(user)) + { + throw new InvalidOperationException("User not in any group!"); + } + + ISyncplayController tempGroup; + _userToGroupMap.Remove(user.Id, out tempGroup); + + if (!tempGroup.GetGroupId().Equals(group.GetGroupId())) + { + throw new InvalidOperationException("User was in wrong group!"); + } + } + } +} diff --git a/MediaBrowser.Api/Syncplay/SyncplayService.cs b/MediaBrowser.Api/Syncplay/SyncplayService.cs new file mode 100644 index 000000000..f17cca9ee --- /dev/null +++ b/MediaBrowser.Api/Syncplay/SyncplayService.cs @@ -0,0 +1,261 @@ +using System; +using System.Collections.Generic; +using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Net; +using MediaBrowser.Controller.Session; +using MediaBrowser.Controller.Syncplay; +using MediaBrowser.Model.Services; +using MediaBrowser.Model.Syncplay; +using Microsoft.Extensions.Logging; + +namespace MediaBrowser.Api.Syncplay +{ + [Route("/Syncplay/{SessionId}/NewGroup", "POST", Summary = "Create a new Syncplay group")] + [Authenticated] + public class SyncplayNewGroup : IReturnVoid + { + [ApiMember(Name = "SessionId", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] + public string SessionId { get; set; } + } + + [Route("/Syncplay/{SessionId}/JoinGroup", "POST", Summary = "Join an existing Syncplay group")] + [Authenticated] + public class SyncplayJoinGroup : IReturnVoid + { + [ApiMember(Name = "SessionId", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] + public string SessionId { get; set; } + + /// + /// Gets or sets the Group id. + /// + /// The Group id to join. + [ApiMember(Name = "GroupId", Description = "Group Id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")] + public string GroupId { get; set; } + } + + [Route("/Syncplay/{SessionId}/LeaveGroup", "POST", Summary = "Leave joined Syncplay group")] + [Authenticated] + public class SyncplayLeaveGroup : IReturnVoid + { + [ApiMember(Name = "SessionId", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] + public string SessionId { get; set; } + } + + [Route("/Syncplay/{SessionId}/ListGroups", "POST", Summary = "List Syncplay groups playing same item")] + [Authenticated] + public class SyncplayListGroups : IReturnVoid + { + [ApiMember(Name = "SessionId", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] + public string SessionId { get; set; } + } + + [Route("/Syncplay/{SessionId}/PlayRequest", "POST", Summary = "Request play in Syncplay group")] + [Authenticated] + public class SyncplayPlayRequest : IReturnVoid + { + [ApiMember(Name = "SessionId", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] + public string SessionId { get; set; } + } + + [Route("/Syncplay/{SessionId}/PauseRequest", "POST", Summary = "Request pause in Syncplay group")] + [Authenticated] + public class SyncplayPauseRequest : IReturnVoid + { + [ApiMember(Name = "SessionId", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] + public string SessionId { get; set; } + } + + [Route("/Syncplay/{SessionId}/SeekRequest", "POST", Summary = "Request seek in Syncplay group")] + [Authenticated] + public class SyncplaySeekRequest : IReturnVoid + { + [ApiMember(Name = "SessionId", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] + public string SessionId { get; set; } + + [ApiMember(Name = "PositionTicks", IsRequired = true, DataType = "long", ParameterType = "query", Verb = "POST")] + public long PositionTicks { get; set; } + } + + [Route("/Syncplay/{SessionId}/BufferingRequest", "POST", Summary = "Request group wait in Syncplay group while buffering")] + [Authenticated] + public class SyncplayBufferingRequest : IReturnVoid + { + [ApiMember(Name = "SessionId", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] + public string SessionId { get; set; } + + [ApiMember(Name = "When", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")] + public string When { get; set; } + + [ApiMember(Name = "PositionTicks", IsRequired = true, DataType = "long", ParameterType = "query", Verb = "POST")] + public long PositionTicks { get; set; } + + [ApiMember(Name = "Resume", IsRequired = true, DataType = "bool", ParameterType = "query", Verb = "POST")] + public bool Resume { get; set; } + } + + [Route("/Syncplay/{SessionId}/KeepAlive", "POST", Summary = "Keep session alive")] + [Authenticated] + public class SyncplayKeepAlive : IReturnVoid + { + [ApiMember(Name = "SessionId", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] + public string SessionId { get; set; } + + [ApiMember(Name = "Ping", IsRequired = true, DataType = "double", ParameterType = "query", Verb = "POST")] + public double Ping { get; set; } + } + + [Route("/Syncplay/{SessionId}/GetUtcTime", "POST", Summary = "Get UtcTime")] + [Authenticated] + public class SyncplayGetUtcTime : IReturnVoid + { + [ApiMember(Name = "SessionId", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] + public string SessionId { get; set; } + } + + /// + /// Class SyncplayService. + /// + public class SyncplayService : BaseApiService + { + /// + /// The session manager. + /// + private readonly ISessionManager _sessionManager; + + private readonly ISessionContext _sessionContext; + + /// + /// The Syncplay manager. + /// + private readonly ISyncplayManager _syncplayManager; + + public SyncplayService( + ILogger logger, + IServerConfigurationManager serverConfigurationManager, + IHttpResultFactory httpResultFactory, + ISessionManager sessionManager, + ISessionContext sessionContext, + ISyncplayManager syncplayManager) + : base(logger, serverConfigurationManager, httpResultFactory) + { + _sessionManager = sessionManager; + _sessionContext = sessionContext; + _syncplayManager = syncplayManager; + } + + /// + /// Handles the specified request. + /// + /// The request. + public void Post(SyncplayNewGroup request) + { + var currentSession = GetSession(_sessionContext); + _syncplayManager.NewGroup(currentSession); + } + + /// + /// Handles the specified request. + /// + /// The request. + public void Post(SyncplayJoinGroup request) + { + var currentSession = GetSession(_sessionContext); + _syncplayManager.JoinGroup(currentSession, request.GroupId); + } + + /// + /// Handles the specified request. + /// + /// The request. + public void Post(SyncplayLeaveGroup request) + { + var currentSession = GetSession(_sessionContext); + _syncplayManager.LeaveGroup(currentSession); + } + + /// + /// Handles the specified request. + /// + /// The request. + /// The requested list of groups. + public List Post(SyncplayListGroups request) + { + var currentSession = GetSession(_sessionContext); + return _syncplayManager.ListGroups(currentSession); + } + + /// + /// Handles the specified request. + /// + /// The request. + public void Post(SyncplayPlayRequest request) + { + var currentSession = GetSession(_sessionContext); + var syncplayRequest = new SyncplayRequestInfo(); + syncplayRequest.Type = SyncplayRequestType.Play; + _syncplayManager.HandleRequest(currentSession, syncplayRequest); + } + + /// + /// Handles the specified request. + /// + /// The request. + public void Post(SyncplayPauseRequest request) + { + var currentSession = GetSession(_sessionContext); + var syncplayRequest = new SyncplayRequestInfo(); + syncplayRequest.Type = SyncplayRequestType.Pause; + _syncplayManager.HandleRequest(currentSession, syncplayRequest); + } + + /// + /// Handles the specified request. + /// + /// The request. + public void Post(SyncplaySeekRequest request) + { + var currentSession = GetSession(_sessionContext); + var syncplayRequest = new SyncplayRequestInfo(); + syncplayRequest.Type = SyncplayRequestType.Seek; + syncplayRequest.PositionTicks = request.PositionTicks; + _syncplayManager.HandleRequest(currentSession, syncplayRequest); + } + + /// + /// Handles the specified request. + /// + /// The request. + public void Post(SyncplayBufferingRequest request) + { + var currentSession = GetSession(_sessionContext); + var syncplayRequest = new SyncplayRequestInfo(); + syncplayRequest.Type = request.Resume ? SyncplayRequestType.BufferingComplete : SyncplayRequestType.Buffering; + syncplayRequest.When = DateTime.Parse(request.When); + syncplayRequest.PositionTicks = request.PositionTicks; + _syncplayManager.HandleRequest(currentSession, syncplayRequest); + } + + /// + /// Handles the specified request. + /// + /// The request. + public void Post(SyncplayKeepAlive request) + { + var currentSession = GetSession(_sessionContext); + var syncplayRequest = new SyncplayRequestInfo(); + syncplayRequest.Type = SyncplayRequestType.KeepAlive; + syncplayRequest.Ping = Convert.ToInt64(request.Ping); + _syncplayManager.HandleRequest(currentSession, syncplayRequest); + } + + /// + /// Handles the specified request. + /// + /// The request. + /// The current UTC time. + public string Post(SyncplayGetUtcTime request) + { + return DateTime.UtcNow.ToUniversalTime().ToString("o"); + } + } +} diff --git a/MediaBrowser.Controller/Session/ISessionManager.cs b/MediaBrowser.Controller/Session/ISessionManager.cs index 771027103..4bfc0c73f 100644 --- a/MediaBrowser.Controller/Session/ISessionManager.cs +++ b/MediaBrowser.Controller/Session/ISessionManager.cs @@ -9,6 +9,7 @@ using MediaBrowser.Controller.Security; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Events; using MediaBrowser.Model.Session; +using MediaBrowser.Model.Syncplay; namespace MediaBrowser.Controller.Session { @@ -140,6 +141,24 @@ namespace MediaBrowser.Controller.Session /// Task. Task SendPlayCommand(string controllingSessionId, string sessionId, PlayRequest command, CancellationToken cancellationToken); + /// + /// Sends the SyncplayCommand. + /// + /// The session id. + /// The command. + /// The cancellation token. + /// Task. + Task SendSyncplayCommand(string sessionId, SyncplayCommand command, CancellationToken cancellationToken); + + /// + /// Sends the SyncplayGroupUpdate. + /// + /// The session id. + /// The group update. + /// The cancellation token. + /// Task. + Task SendSyncplayGroupUpdate(string sessionId, SyncplayGroupUpdate command, CancellationToken cancellationToken); + /// /// Sends the browse command. /// diff --git a/MediaBrowser.Controller/Syncplay/GroupInfo.cs b/MediaBrowser.Controller/Syncplay/GroupInfo.cs new file mode 100644 index 000000000..d37e8563b --- /dev/null +++ b/MediaBrowser.Controller/Syncplay/GroupInfo.cs @@ -0,0 +1,148 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Session; + +namespace MediaBrowser.Controller.Syncplay +{ + /// + /// Class GroupInfo. + /// + public class GroupInfo + { + /// + /// Default ping value used for users. + /// + public readonly long DefaulPing = 500; + /// + /// Gets or sets the group identifier. + /// + /// The group identifier. + public readonly Guid GroupId = Guid.NewGuid(); + + /// + /// Gets or sets the playing item. + /// + /// The playing item. + public BaseItem PlayingItem { get; set; } + + /// + /// Gets or sets whether playback is paused. + /// + /// Playback is paused. + public bool IsPaused { get; set; } + + /// + /// Gets or sets the position ticks. + /// + /// The position ticks. + public long PositionTicks { get; set; } + + /// + /// Gets or sets the last activity. + /// + /// The last activity. + public DateTime LastActivity { get; set; } + + /// + /// Gets the partecipants. + /// + /// The partecipants. + public readonly ConcurrentDictionary Partecipants = + new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); + + /// + /// Checks if a user is in this group. + /// + /// true if the user is in this group; false otherwise. + public bool ContainsUser(string sessionId) + { + return Partecipants.ContainsKey(sessionId); + } + + /// + /// Adds the user to the group. + /// + /// The session. + public void AddUser(SessionInfo user) + { + if (ContainsUser(user.Id.ToString())) return; + var member = new GroupMember(); + member.Session = user; + member.Ping = DefaulPing; + member.IsBuffering = false; + Partecipants[user.Id.ToString()] = member; + } + + /// + /// Removes the user from the group. + /// + /// The session. + + public void RemoveUser(SessionInfo user) + { + if (!ContainsUser(user.Id.ToString())) return; + GroupMember member; + Partecipants.Remove(user.Id.ToString(), out member); + } + + /// + /// Updates the ping of a user. + /// + /// The session. + /// The ping. + public void UpdatePing(SessionInfo user, long ping) + { + if (!ContainsUser(user.Id.ToString())) return; + Partecipants[user.Id.ToString()].Ping = ping; + } + + /// + /// Gets the highest ping in the group. + /// + /// The highest ping in the group. + public long GetHighestPing() + { + long max = Int64.MinValue; + foreach (var user in Partecipants.Values) + { + max = Math.Max(max, user.Ping); + } + return max; + } + + /// + /// Sets the user's buffering state. + /// + /// The session. + /// The state. + public void SetBuffering(SessionInfo user, bool isBuffering) + { + if (!ContainsUser(user.Id.ToString())) return; + Partecipants[user.Id.ToString()].IsBuffering = isBuffering; + } + + /// + /// Gets the group buffering state. + /// + /// true if there is a user buffering in the group; false otherwise. + public bool IsBuffering() + { + foreach (var user in Partecipants.Values) + { + if (user.IsBuffering) return true; + } + return false; + } + + /// + /// Checks if the group is empty. + /// + /// true if the group is empty; false otherwise. + public bool IsEmpty() + { + return Partecipants.Count == 0; + } + } +} diff --git a/MediaBrowser.Controller/Syncplay/GroupMember.cs b/MediaBrowser.Controller/Syncplay/GroupMember.cs new file mode 100644 index 000000000..7630428d7 --- /dev/null +++ b/MediaBrowser.Controller/Syncplay/GroupMember.cs @@ -0,0 +1,28 @@ +using MediaBrowser.Controller.Session; + +namespace MediaBrowser.Controller.Syncplay +{ + /// + /// Class GroupMember. + /// + public class GroupMember + { + /// + /// Gets or sets whether this member is buffering. + /// + /// true if member is buffering; false otherwise. + public bool IsBuffering { get; set; } + + /// + /// Gets or sets the session. + /// + /// The session. + public SessionInfo Session { get; set; } + + /// + /// Gets or sets the ping. + /// + /// The ping. + public long Ping { get; set; } + } +} diff --git a/MediaBrowser.Controller/Syncplay/ISyncplayController.cs b/MediaBrowser.Controller/Syncplay/ISyncplayController.cs new file mode 100644 index 000000000..c9465b27a --- /dev/null +++ b/MediaBrowser.Controller/Syncplay/ISyncplayController.cs @@ -0,0 +1,61 @@ +using System; +using MediaBrowser.Controller.Session; +using MediaBrowser.Model.Syncplay; + +namespace MediaBrowser.Controller.Syncplay +{ + /// + /// Interface ISyncplayController. + /// + public interface ISyncplayController + { + /// + /// Gets the group id. + /// + /// The group id. + Guid GetGroupId(); + + /// + /// Gets the playing item id. + /// + /// The playing item id. + Guid GetPlayingItemId(); + + /// + /// Checks if the group is empty. + /// + /// If the group is empty. + bool IsGroupEmpty(); + + /// + /// Initializes the group with the user's info. + /// + /// The session. + void InitGroup(SessionInfo user); + + /// + /// Adds the user to the group. + /// + /// The session. + void UserJoin(SessionInfo user); + + /// + /// Removes the user from the group. + /// + /// The session. + void UserLeave(SessionInfo user); + + /// + /// Handles the requested action by the user. + /// + /// The session. + /// The requested action. + void HandleRequest(SessionInfo user, SyncplayRequestInfo request); + + /// + /// Gets the info about the group for the clients. + /// + /// The group info for the clients. + GroupInfoView GetInfo(); + } +} \ No newline at end of file diff --git a/MediaBrowser.Controller/Syncplay/ISyncplayManager.cs b/MediaBrowser.Controller/Syncplay/ISyncplayManager.cs new file mode 100644 index 000000000..ec91ea69d --- /dev/null +++ b/MediaBrowser.Controller/Syncplay/ISyncplayManager.cs @@ -0,0 +1,62 @@ +using System; +using System.Collections.Generic; +using MediaBrowser.Controller.Session; +using MediaBrowser.Model.Syncplay; + +namespace MediaBrowser.Controller.Syncplay +{ + /// + /// Interface ISyncplayManager. + /// + public interface ISyncplayManager + { + /// + /// Creates a new group. + /// + /// The user that's creating the group. + void NewGroup(SessionInfo user); + + /// + /// Adds the user to a group. + /// + /// The session. + /// The group id. + void JoinGroup(SessionInfo user, string groupId); + + /// + /// Removes the user from a group. + /// + /// The session. + void LeaveGroup(SessionInfo user); + + /// + /// Gets list of available groups for a user. + /// + /// The user. + /// The list of available groups. + List ListGroups(SessionInfo user); + + /// + /// Handle a request by a user in a group. + /// + /// The session. + /// The request. + void HandleRequest(SessionInfo user, SyncplayRequestInfo request); + + /// + /// Maps a user to a group. + /// + /// The user. + /// The group. + /// + void MapUserToGroup(SessionInfo user, ISyncplayController group); + + /// + /// Unmaps a user from a group. + /// + /// The user. + /// The group. + /// + void UnmapUserFromGroup(SessionInfo user, ISyncplayController group); + } +} diff --git a/MediaBrowser.Model/Syncplay/GroupInfoModel.cs b/MediaBrowser.Model/Syncplay/GroupInfoModel.cs new file mode 100644 index 000000000..599c0dbfc --- /dev/null +++ b/MediaBrowser.Model/Syncplay/GroupInfoModel.cs @@ -0,0 +1,38 @@ +namespace MediaBrowser.Model.Syncplay +{ + /// + /// Class GroupInfoModel. + /// + public class GroupInfoView + { + /// + /// Gets or sets the group identifier. + /// + /// The group identifier. + public string GroupId { get; set; } + + /// + /// Gets or sets the playing item id. + /// + /// The playing item id. + public string PlayingItemId { get; set; } + + /// + /// Gets or sets the playing item name. + /// + /// The playing item name. + public string PlayingItemName { get; set; } + + /// + /// Gets or sets the position ticks. + /// + /// The position ticks. + public long PositionTicks { get; set; } + + /// + /// Gets or sets the partecipants. + /// + /// The partecipants. + public string[] Partecipants { get; set; } + } +} diff --git a/MediaBrowser.Model/Syncplay/SyncplayCommand.cs b/MediaBrowser.Model/Syncplay/SyncplayCommand.cs new file mode 100644 index 000000000..769316e80 --- /dev/null +++ b/MediaBrowser.Model/Syncplay/SyncplayCommand.cs @@ -0,0 +1,32 @@ +namespace MediaBrowser.Model.Syncplay +{ + /// + /// Class SyncplayCommand. + /// + public class SyncplayCommand + { + /// + /// Gets or sets the group identifier. + /// + /// The group identifier. + public string GroupId { get; set; } + + /// + /// Gets or sets the UTC time when to execute the command. + /// + /// The UTC time when to execute the command. + public string When { get; set; } + + /// + /// Gets or sets the position ticks. + /// + /// The position ticks. + public long? PositionTicks { get; set; } + + /// + /// Gets or sets the command. + /// + /// The command. + public SyncplayCommandType Command { get; set; } + } +} diff --git a/MediaBrowser.Model/Syncplay/SyncplayCommandType.cs b/MediaBrowser.Model/Syncplay/SyncplayCommandType.cs new file mode 100644 index 000000000..87b9ad66d --- /dev/null +++ b/MediaBrowser.Model/Syncplay/SyncplayCommandType.cs @@ -0,0 +1,21 @@ +namespace MediaBrowser.Model.Syncplay +{ + /// + /// Enum SyncplayCommandType. + /// + public enum SyncplayCommandType + { + /// + /// The play command. Instructs users to start playback. + /// + Play = 0, + /// + /// The pause command. Instructs users to pause playback. + /// + Pause = 1, + /// + /// The seek command. Instructs users to seek to a specified time. + /// + Seek = 2 + } +} diff --git a/MediaBrowser.Model/Syncplay/SyncplayGroupUpdate.cs b/MediaBrowser.Model/Syncplay/SyncplayGroupUpdate.cs new file mode 100644 index 000000000..c5c2f3540 --- /dev/null +++ b/MediaBrowser.Model/Syncplay/SyncplayGroupUpdate.cs @@ -0,0 +1,26 @@ +namespace MediaBrowser.Model.Syncplay +{ + /// + /// Class SyncplayGroupUpdate. + /// + public class SyncplayGroupUpdate + { + /// + /// Gets or sets the group identifier. + /// + /// The group identifier. + public string GroupId { get; set; } + + /// + /// Gets or sets the update type. + /// + /// The update type. + public SyncplayGroupUpdateType Type { get; set; } + + /// + /// Gets or sets the data. + /// + /// The data. + public T Data { get; set; } + } +} diff --git a/MediaBrowser.Model/Syncplay/SyncplayGroupUpdateType.cs b/MediaBrowser.Model/Syncplay/SyncplayGroupUpdateType.cs new file mode 100644 index 000000000..c7c5f534d --- /dev/null +++ b/MediaBrowser.Model/Syncplay/SyncplayGroupUpdateType.cs @@ -0,0 +1,41 @@ +namespace MediaBrowser.Model.Syncplay +{ + /// + /// Enum SyncplayGroupUpdateType + /// + public enum SyncplayGroupUpdateType + { + /// + /// The user-joined update. Tells members of a group about a new user. + /// + UserJoined = 0, + /// + /// The user-left update. Tells members of a group that a user left. + /// + UserLeft = 1, + /// + /// The group-joined update. Tells a user that the group has been joined. + /// + GroupJoined = 2, + /// + /// The group-left update. Tells a user that the group has been left. + /// + GroupLeft = 3, + /// + /// The group-wait update. Tells members of the group that a user is buffering. + /// + GroupWait = 4, + /// + /// The prepare-session update. Tells a user to load some content. + /// + PrepareSession = 5, + /// + /// The keep-alive update. An update to keep alive the socket. + /// + KeepAlive = 6, + /// + /// The not-in-group update. Tells a user that no group has been joined. + /// + NotInGroup = 7 + } +} diff --git a/MediaBrowser.Model/Syncplay/SyncplayRequestInfo.cs b/MediaBrowser.Model/Syncplay/SyncplayRequestInfo.cs new file mode 100644 index 000000000..7dba74ae9 --- /dev/null +++ b/MediaBrowser.Model/Syncplay/SyncplayRequestInfo.cs @@ -0,0 +1,34 @@ +using System; + +namespace MediaBrowser.Model.Syncplay +{ + /// + /// Class SyncplayRequestInfo. + /// + public class SyncplayRequestInfo + { + /// + /// Gets or sets the request type. + /// + /// The request type. + public SyncplayRequestType Type; + + /// + /// Gets or sets when the request has been made by the client. + /// + /// The date of the request. + public DateTime? When { get; set; } + + /// + /// Gets or sets the position ticks. + /// + /// The position ticks. + public long? PositionTicks { get; set; } + + /// + /// Gets or sets the ping time. + /// + /// The ping time. + public long? Ping { get; set; } + } +} diff --git a/MediaBrowser.Model/Syncplay/SyncplayRequestType.cs b/MediaBrowser.Model/Syncplay/SyncplayRequestType.cs new file mode 100644 index 000000000..44d7a0af2 --- /dev/null +++ b/MediaBrowser.Model/Syncplay/SyncplayRequestType.cs @@ -0,0 +1,33 @@ +namespace MediaBrowser.Model.Syncplay +{ + /// + /// Enum SyncplayRequestType + /// + public enum SyncplayRequestType + { + /// + /// A user is requesting a play command for the group. + /// + Play = 0, + /// + /// A user is requesting a pause command for the group. + /// + Pause = 1, + /// + /// A user is requesting a seek command for the group. + /// + Seek = 2, + /// + /// A user is signaling that playback is buffering. + /// + Buffering = 3, + /// + /// A user is signaling that playback resumed. + /// + BufferingComplete = 4, + /// + /// A user is reporting its ping. + /// + KeepAlive = 5 + } +} -- cgit v1.2.3 From f273995f5bd89f12322d80f3009ad6d8d20b8e81 Mon Sep 17 00:00:00 2001 From: gion Date: Sat, 4 Apr 2020 17:56:21 +0200 Subject: Refactor: rename user to session --- .../Syncplay/SyncplayController.cs | 124 ++++++++++----------- .../Syncplay/SyncplayManager.cs | 88 +++++++-------- MediaBrowser.Controller/Syncplay/GroupInfo.cs | 62 +++++------ .../Syncplay/ISyncplayController.cs | 24 ++-- .../Syncplay/ISyncplayManager.cs | 40 +++---- 5 files changed, 169 insertions(+), 169 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/Syncplay/SyncplayController.cs b/Emby.Server.Implementations/Syncplay/SyncplayController.cs index 4a20ceba0..b156e5a87 100644 --- a/Emby.Server.Implementations/Syncplay/SyncplayController.cs +++ b/Emby.Server.Implementations/Syncplay/SyncplayController.cs @@ -19,8 +19,8 @@ namespace Emby.Server.Implementations.Syncplay private enum BroadcastType { AllGroup = 0, - SingleUser = 1, - AllExceptUser = 2, + SingleSession = 1, + AllExceptSession = 2, AllReady = 3 } @@ -95,32 +95,32 @@ namespace Emby.Server.Implementations.Syncplay } } - private SessionInfo[] FilterUsers(SessionInfo from, BroadcastType type) + private SessionInfo[] FilterSessions(SessionInfo from, BroadcastType type) { - if (type == BroadcastType.SingleUser) + if (type == BroadcastType.SingleSession) { return new SessionInfo[] { from }; } else if (type == BroadcastType.AllGroup) { return _group.Partecipants.Values.Select( - user => user.Session + session => session.Session ).ToArray(); } - else if (type == BroadcastType.AllExceptUser) + else if (type == BroadcastType.AllExceptSession) { return _group.Partecipants.Values.Select( - user => user.Session + session => session.Session ).Where( - user => !user.Id.Equals(from.Id) + session => !session.Id.Equals(from.Id) ).ToArray(); } else if (type == BroadcastType.AllReady) { return _group.Partecipants.Values.Where( - user => !user.IsBuffering + session => !session.IsBuffering ).Select( - user => user.Session + session => session.Session ).ToArray(); } else @@ -133,10 +133,10 @@ namespace Emby.Server.Implementations.Syncplay { IEnumerable GetTasks() { - SessionInfo[] users = FilterUsers(from, type); - foreach (var user in users) + SessionInfo[] sessions = FilterSessions(from, type); + foreach (var session in sessions) { - yield return _sessionManager.SendSyncplayGroupUpdate(user.Id.ToString(), message, CancellationToken.None); + yield return _sessionManager.SendSyncplayGroupUpdate(session.Id.ToString(), message, CancellationToken.None); } } @@ -147,10 +147,10 @@ namespace Emby.Server.Implementations.Syncplay { IEnumerable GetTasks() { - SessionInfo[] users = FilterUsers(from, type); - foreach (var user in users) + SessionInfo[] sessions = FilterSessions(from, type); + foreach (var session in sessions) { - yield return _sessionManager.SendSyncplayCommand(user.Id.ToString(), message, CancellationToken.None); + yield return _sessionManager.SendSyncplayCommand(session.Id.ToString(), message, CancellationToken.None); } } @@ -176,46 +176,46 @@ namespace Emby.Server.Implementations.Syncplay } /// - public void InitGroup(SessionInfo user) + public void InitGroup(SessionInfo session) { - _group.AddUser(user); - _syncplayManager.MapUserToGroup(user, this); + _group.AddSession(session); + _syncplayManager.MapSessionToGroup(session, this); - _group.PlayingItem = user.FullNowPlayingItem; + _group.PlayingItem = session.FullNowPlayingItem; _group.IsPaused = true; - _group.PositionTicks = user.PlayState.PositionTicks ??= 0; + _group.PositionTicks = session.PlayState.PositionTicks ??= 0; _group.LastActivity = DateTime.UtcNow; - var updateUser = NewSyncplayGroupUpdate(SyncplayGroupUpdateType.GroupJoined, DateTime.UtcNow.ToUniversalTime().ToString("o")); - SendGroupUpdate(user, BroadcastType.SingleUser, updateUser); + var updateSession = NewSyncplayGroupUpdate(SyncplayGroupUpdateType.GroupJoined, DateTime.UtcNow.ToUniversalTime().ToString("o")); + SendGroupUpdate(session, BroadcastType.SingleSession, updateSession); var pauseCommand = NewSyncplayCommand(SyncplayCommandType.Pause); - SendCommand(user, BroadcastType.SingleUser, pauseCommand); + SendCommand(session, BroadcastType.SingleSession, pauseCommand); } /// - public void UserJoin(SessionInfo user) + public void SessionJoin(SessionInfo session) { - if (user.NowPlayingItem != null && user.NowPlayingItem.Id.Equals(_group.PlayingItem.Id)) + if (session.NowPlayingItem != null && session.NowPlayingItem.Id.Equals(_group.PlayingItem.Id)) { - _group.AddUser(user); - _syncplayManager.MapUserToGroup(user, this); + _group.AddSession(session); + _syncplayManager.MapSessionToGroup(session, this); - var updateUser = NewSyncplayGroupUpdate(SyncplayGroupUpdateType.GroupJoined, _group.PositionTicks); - SendGroupUpdate(user, BroadcastType.SingleUser, updateUser); + var updateSession = NewSyncplayGroupUpdate(SyncplayGroupUpdateType.GroupJoined, _group.PositionTicks); + SendGroupUpdate(session, BroadcastType.SingleSession, updateSession); - var updateOthers = NewSyncplayGroupUpdate(SyncplayGroupUpdateType.UserJoined, user.UserName); - SendGroupUpdate(user, BroadcastType.AllExceptUser, updateOthers); + var updateOthers = NewSyncplayGroupUpdate(SyncplayGroupUpdateType.UserJoined, session.UserName); + SendGroupUpdate(session, BroadcastType.AllExceptSession, updateOthers); // Client join and play, syncing will happen client side if (!_group.IsPaused) { var playCommand = NewSyncplayCommand(SyncplayCommandType.Play); - SendCommand(user, BroadcastType.SingleUser, playCommand); + SendCommand(session, BroadcastType.SingleSession, playCommand); } else { var pauseCommand = NewSyncplayCommand(SyncplayCommandType.Pause); - SendCommand(user, BroadcastType.SingleUser, pauseCommand); + SendCommand(session, BroadcastType.SingleSession, pauseCommand); } } else @@ -224,25 +224,25 @@ namespace Emby.Server.Implementations.Syncplay playRequest.ItemIds = new Guid[] { _group.PlayingItem.Id }; playRequest.StartPositionTicks = _group.PositionTicks; var update = NewSyncplayGroupUpdate(SyncplayGroupUpdateType.PrepareSession, playRequest); - SendGroupUpdate(user, BroadcastType.SingleUser, update); + SendGroupUpdate(session, BroadcastType.SingleSession, update); } } /// - public void UserLeave(SessionInfo user) + public void SessionLeave(SessionInfo session) { - _group.RemoveUser(user); - _syncplayManager.UnmapUserFromGroup(user, this); + _group.RemoveSession(session); + _syncplayManager.UnmapSessionFromGroup(session, this); - var updateUser = NewSyncplayGroupUpdate(SyncplayGroupUpdateType.GroupLeft, _group.PositionTicks); - SendGroupUpdate(user, BroadcastType.SingleUser, updateUser); + var updateSession = NewSyncplayGroupUpdate(SyncplayGroupUpdateType.GroupLeft, _group.PositionTicks); + SendGroupUpdate(session, BroadcastType.SingleSession, updateSession); - var updateOthers = NewSyncplayGroupUpdate(SyncplayGroupUpdateType.UserLeft, user.UserName); - SendGroupUpdate(user, BroadcastType.AllExceptUser, updateOthers); + var updateOthers = NewSyncplayGroupUpdate(SyncplayGroupUpdateType.UserLeft, session.UserName); + SendGroupUpdate(session, BroadcastType.AllExceptSession, updateOthers); } /// - public void HandleRequest(SessionInfo user, SyncplayRequestInfo request) + public void HandleRequest(SessionInfo session, SyncplayRequestInfo request) { if (request.Type.Equals(SyncplayRequestType.Play)) { @@ -257,13 +257,13 @@ namespace Emby.Server.Implementations.Syncplay ); var command = NewSyncplayCommand(SyncplayCommandType.Play); - SendCommand(user, BroadcastType.AllGroup, command); + SendCommand(session, BroadcastType.AllGroup, command); } else { // Client got lost var command = NewSyncplayCommand(SyncplayCommandType.Play); - SendCommand(user, BroadcastType.SingleUser, command); + SendCommand(session, BroadcastType.SingleSession, command); } } else if (request.Type.Equals(SyncplayRequestType.Pause)) @@ -277,12 +277,12 @@ namespace Emby.Server.Implementations.Syncplay _group.PositionTicks += elapsedTime.Ticks > 0 ? elapsedTime.Ticks : 0; var command = NewSyncplayCommand(SyncplayCommandType.Pause); - SendCommand(user, BroadcastType.AllGroup, command); + SendCommand(session, BroadcastType.AllGroup, command); } else { var command = NewSyncplayCommand(SyncplayCommandType.Pause); - SendCommand(user, BroadcastType.SingleUser, command); + SendCommand(session, BroadcastType.SingleSession, command); } } else if (request.Type.Equals(SyncplayRequestType.Seek)) @@ -301,7 +301,7 @@ namespace Emby.Server.Implementations.Syncplay _group.LastActivity = DateTime.UtcNow; var command = NewSyncplayCommand(SyncplayCommandType.Seek); - SendCommand(user, BroadcastType.AllGroup, command); + SendCommand(session, BroadcastType.AllGroup, command); } // TODO: client does not implement this yet else if (request.Type.Equals(SyncplayRequestType.Buffering)) @@ -314,19 +314,19 @@ namespace Emby.Server.Implementations.Syncplay _group.LastActivity = currentTime; _group.PositionTicks += elapsedTime.Ticks > 0 ? elapsedTime.Ticks : 0; - _group.SetBuffering(user, true); + _group.SetBuffering(session, true); - // Send pause command to all non-buffering users + // Send pause command to all non-buffering sessions var command = NewSyncplayCommand(SyncplayCommandType.Pause); - SendCommand(user, BroadcastType.AllReady, command); + SendCommand(session, BroadcastType.AllReady, command); - var updateOthers = NewSyncplayGroupUpdate(SyncplayGroupUpdateType.GroupWait, user.UserName); - SendGroupUpdate(user, BroadcastType.AllExceptUser, updateOthers); + var updateOthers = NewSyncplayGroupUpdate(SyncplayGroupUpdateType.GroupWait, session.UserName); + SendGroupUpdate(session, BroadcastType.AllExceptSession, updateOthers); } else { var command = NewSyncplayCommand(SyncplayCommandType.Pause); - SendCommand(user, BroadcastType.SingleUser, command); + SendCommand(session, BroadcastType.SingleSession, command); } } // TODO: client does not implement this yet @@ -334,7 +334,7 @@ namespace Emby.Server.Implementations.Syncplay { if (_group.IsPaused) { - _group.SetBuffering(user, false); + _group.SetBuffering(session, false); if (_group.IsBuffering()) { // Others are buffering, tell this client to pause when ready @@ -348,7 +348,7 @@ namespace Emby.Server.Implementations.Syncplay command.When = currentTime.AddMilliseconds( delay ).ToUniversalTime().ToString("o"); - SendCommand(user, BroadcastType.SingleUser, command); + SendCommand(session, BroadcastType.SingleSession, command); } else { @@ -368,7 +368,7 @@ namespace Emby.Server.Implementations.Syncplay delay ); var command = NewSyncplayCommand(SyncplayCommandType.Play); - SendCommand(user, BroadcastType.AllExceptUser, command); + SendCommand(session, BroadcastType.AllExceptSession, command); } else { @@ -381,7 +381,7 @@ namespace Emby.Server.Implementations.Syncplay ); var command = NewSyncplayCommand(SyncplayCommandType.Play); - SendCommand(user, BroadcastType.AllGroup, command); + SendCommand(session, BroadcastType.AllGroup, command); } } } @@ -389,17 +389,17 @@ namespace Emby.Server.Implementations.Syncplay { // Make sure client has latest group state var command = NewSyncplayCommand(SyncplayCommandType.Play); - SendCommand(user, BroadcastType.SingleUser, command); + SendCommand(session, BroadcastType.SingleSession, command); } } else if (request.Type.Equals(SyncplayRequestType.KeepAlive)) { - _group.UpdatePing(user, request.Ping ??= _group.DefaulPing); + _group.UpdatePing(session, request.Ping ??= _group.DefaulPing); var keepAlive = new SyncplayGroupUpdate(); keepAlive.GroupId = _group.GroupId.ToString(); keepAlive.Type = SyncplayGroupUpdateType.KeepAlive; - SendGroupUpdate(user, BroadcastType.SingleUser, keepAlive); + SendGroupUpdate(session, BroadcastType.SingleSession, keepAlive); } } @@ -411,7 +411,7 @@ namespace Emby.Server.Implementations.Syncplay info.PlayingItemName = _group.PlayingItem.Name; info.PlayingItemId = _group.PlayingItem.Id.ToString(); info.PositionTicks = _group.PositionTicks; - info.Partecipants = _group.Partecipants.Values.Select(user => user.Session.UserName).ToArray(); + info.Partecipants = _group.Partecipants.Values.Select(session => session.Session.UserName).ToArray(); return info; } } diff --git a/Emby.Server.Implementations/Syncplay/SyncplayManager.cs b/Emby.Server.Implementations/Syncplay/SyncplayManager.cs index 7583793bb..f76d243d5 100644 --- a/Emby.Server.Implementations/Syncplay/SyncplayManager.cs +++ b/Emby.Server.Implementations/Syncplay/SyncplayManager.cs @@ -27,9 +27,9 @@ namespace Emby.Server.Implementations.Syncplay private readonly ISessionManager _sessionManager; /// - /// The map between users and groups. + /// The map between sessions and groups. /// - private readonly ConcurrentDictionary _userToGroupMap = + private readonly ConcurrentDictionary _sessionToGroupMap = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); /// @@ -91,27 +91,27 @@ namespace Emby.Server.Implementations.Syncplay void _sessionManager_SessionEnded(object sender, SessionEventArgs e) { - var user = e.SessionInfo; - if (!IsUserInGroup(user)) return; - LeaveGroup(user); + var session = e.SessionInfo; + if (!IsSessionInGroup(session)) return; + LeaveGroup(session); } void _sessionManager_PlaybackStopped(object sender, PlaybackStopEventArgs e) { - var user = e.Session; - if (!IsUserInGroup(user)) return; - LeaveGroup(user); + var session = e.Session; + if (!IsSessionInGroup(session)) return; + LeaveGroup(session); } - private bool IsUserInGroup(SessionInfo user) + private bool IsSessionInGroup(SessionInfo session) { - return _userToGroupMap.ContainsKey(user.Id); + return _sessionToGroupMap.ContainsKey(session.Id); } - private Guid? GetUserGroup(SessionInfo user) + private Guid? GetSessionGroup(SessionInfo session) { ISyncplayController group; - _userToGroupMap.TryGetValue(user.Id, out group); + _sessionToGroupMap.TryGetValue(session.Id, out group); if (group != null) { return group.GetGroupId(); @@ -123,26 +123,26 @@ namespace Emby.Server.Implementations.Syncplay } /// - public void NewGroup(SessionInfo user) + public void NewGroup(SessionInfo session) { - if (IsUserInGroup(user)) { - LeaveGroup(user); + if (IsSessionInGroup(session)) + LeaveGroup(session); } var group = new SyncplayController(_logger, _sessionManager, this); _groups[group.GetGroupId().ToString()] = group; - group.InitGroup(user); + group.InitGroup(session); } /// - public void JoinGroup(SessionInfo user, string groupId) + public void JoinGroup(SessionInfo session, string groupId) { - if (IsUserInGroup(user)) + if (IsSessionInGroup(session)) { - if (GetUserGroup(user).Equals(groupId)) return; - LeaveGroup(user); + if (GetSessionGroup(session).Equals(groupId)) return; + LeaveGroup(session); } ISyncplayController group; @@ -154,28 +154,28 @@ namespace Emby.Server.Implementations.Syncplay var update = new SyncplayGroupUpdate(); update.Type = SyncplayGroupUpdateType.NotInGroup; - _sessionManager.SendSyncplayGroupUpdate(user.Id.ToString(), update, CancellationToken.None); + _sessionManager.SendSyncplayGroupUpdate(session.Id.ToString(), update, CancellationToken.None); return; } - group.UserJoin(user); + group.SessionJoin(session); } /// - public void LeaveGroup(SessionInfo user) + public void LeaveGroup(SessionInfo session) { ISyncplayController group; - _userToGroupMap.TryGetValue(user.Id, out group); + _sessionToGroupMap.TryGetValue(session.Id, out group); if (group == null) { - _logger.LogWarning("Syncplaymanager HandleRequest: " + user.Id + " not in group."); + _logger.LogWarning("Syncplaymanager HandleRequest: " + session.Id + " not in group."); var update = new SyncplayGroupUpdate(); update.Type = SyncplayGroupUpdateType.NotInGroup; - _sessionManager.SendSyncplayGroupUpdate(user.Id.ToString(), update, CancellationToken.None); + _sessionManager.SendSyncplayGroupUpdate(session.Id.ToString(), update, CancellationToken.None); return; } - group.UserLeave(user); + group.SessionLeave(session); if (group.IsGroupEmpty()) { @@ -184,13 +184,13 @@ namespace Emby.Server.Implementations.Syncplay } /// - public List ListGroups(SessionInfo user) + public List ListGroups(SessionInfo session) { // Filter by playing item if the user is viewing something already - if (user.NowPlayingItem != null) + if (session.NowPlayingItem != null) { return _groups.Values.Where( - group => group.GetPlayingItemId().Equals(user.FullNowPlayingItem.Id) + group => group.GetPlayingItemId().Equals(session.FullNowPlayingItem.Id) ).Select( group => group.GetInfo() ).ToList(); @@ -205,47 +205,47 @@ namespace Emby.Server.Implementations.Syncplay } /// - public void HandleRequest(SessionInfo user, SyncplayRequestInfo request) + public void HandleRequest(SessionInfo session, SyncplayRequestInfo request) { ISyncplayController group; - _userToGroupMap.TryGetValue(user.Id, out group); + _sessionToGroupMap.TryGetValue(session.Id, out group); if (group == null) { - _logger.LogWarning("Syncplaymanager HandleRequest: " + user.Id + " not in group."); + _logger.LogWarning("Syncplaymanager HandleRequest: " + session.Id + " not in group."); var update = new SyncplayGroupUpdate(); update.Type = SyncplayGroupUpdateType.NotInGroup; - _sessionManager.SendSyncplayGroupUpdate(user.Id.ToString(), update, CancellationToken.None); + _sessionManager.SendSyncplayGroupUpdate(session.Id.ToString(), update, CancellationToken.None); return; } - group.HandleRequest(user, request); + group.HandleRequest(session, request); } /// - public void MapUserToGroup(SessionInfo user, ISyncplayController group) + public void MapSessionToGroup(SessionInfo session, ISyncplayController group) { - if (IsUserInGroup(user)) + if (IsSessionInGroup(session)) { - throw new InvalidOperationException("User in other group already!"); + throw new InvalidOperationException("Session in other group already!"); } - _userToGroupMap[user.Id] = group; + _sessionToGroupMap[session.Id] = group; } /// - public void UnmapUserFromGroup(SessionInfo user, ISyncplayController group) + public void UnmapSessionFromGroup(SessionInfo session, ISyncplayController group) { - if (!IsUserInGroup(user)) + if (!IsSessionInGroup(session)) { - throw new InvalidOperationException("User not in any group!"); + throw new InvalidOperationException("Session not in any group!"); } ISyncplayController tempGroup; - _userToGroupMap.Remove(user.Id, out tempGroup); + _sessionToGroupMap.Remove(session.Id, out tempGroup); if (!tempGroup.GetGroupId().Equals(group.GetGroupId())) { - throw new InvalidOperationException("User was in wrong group!"); + throw new InvalidOperationException("Session was in wrong group!"); } } } diff --git a/MediaBrowser.Controller/Syncplay/GroupInfo.cs b/MediaBrowser.Controller/Syncplay/GroupInfo.cs index d37e8563b..42e85ef86 100644 --- a/MediaBrowser.Controller/Syncplay/GroupInfo.cs +++ b/MediaBrowser.Controller/Syncplay/GroupInfo.cs @@ -12,7 +12,7 @@ namespace MediaBrowser.Controller.Syncplay public class GroupInfo { /// - /// Default ping value used for users. + /// Default ping value used for sessions. /// public readonly long DefaulPing = 500; /// @@ -53,85 +53,85 @@ namespace MediaBrowser.Controller.Syncplay new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); /// - /// Checks if a user is in this group. + /// Checks if a session is in this group. /// - /// true if the user is in this group; false otherwise. - public bool ContainsUser(string sessionId) + /// true if the session is in this group; false otherwise. + public bool ContainsSession(string sessionId) { return Partecipants.ContainsKey(sessionId); } /// - /// Adds the user to the group. + /// Adds the session to the group. /// - /// The session. - public void AddUser(SessionInfo user) + /// The session. + public void AddSession(SessionInfo session) { - if (ContainsUser(user.Id.ToString())) return; + if (ContainsSession(session.Id.ToString())) return; var member = new GroupMember(); - member.Session = user; + member.Session = session; member.Ping = DefaulPing; member.IsBuffering = false; - Partecipants[user.Id.ToString()] = member; + Partecipants[session.Id.ToString()] = member; } /// - /// Removes the user from the group. + /// Removes the session from the group. /// - /// The session. + /// The session. - public void RemoveUser(SessionInfo user) + public void RemoveSession(SessionInfo session) { - if (!ContainsUser(user.Id.ToString())) return; + if (!ContainsSession(session.Id.ToString())) return; GroupMember member; - Partecipants.Remove(user.Id.ToString(), out member); + Partecipants.Remove(session.Id.ToString(), out member); } /// - /// Updates the ping of a user. + /// Updates the ping of a session. /// - /// The session. + /// The session. /// The ping. - public void UpdatePing(SessionInfo user, long ping) + public void UpdatePing(SessionInfo session, long ping) { - if (!ContainsUser(user.Id.ToString())) return; - Partecipants[user.Id.ToString()].Ping = ping; + if (!ContainsSession(session.Id.ToString())) return; + Partecipants[session.Id.ToString()].Ping = ping; } /// /// Gets the highest ping in the group. /// - /// The highest ping in the group. + /// The highest ping in the group. public long GetHighestPing() { long max = Int64.MinValue; - foreach (var user in Partecipants.Values) + foreach (var session in Partecipants.Values) { - max = Math.Max(max, user.Ping); + max = Math.Max(max, session.Ping); } return max; } /// - /// Sets the user's buffering state. + /// Sets the session's buffering state. /// - /// The session. + /// The session. /// The state. - public void SetBuffering(SessionInfo user, bool isBuffering) + public void SetBuffering(SessionInfo session, bool isBuffering) { - if (!ContainsUser(user.Id.ToString())) return; - Partecipants[user.Id.ToString()].IsBuffering = isBuffering; + if (!ContainsSession(session.Id.ToString())) return; + Partecipants[session.Id.ToString()].IsBuffering = isBuffering; } /// /// Gets the group buffering state. /// - /// true if there is a user buffering in the group; false otherwise. + /// true if there is a session buffering in the group; false otherwise. public bool IsBuffering() { - foreach (var user in Partecipants.Values) + foreach (var session in Partecipants.Values) { - if (user.IsBuffering) return true; + if (session.IsBuffering) return true; } return false; } diff --git a/MediaBrowser.Controller/Syncplay/ISyncplayController.cs b/MediaBrowser.Controller/Syncplay/ISyncplayController.cs index c9465b27a..d35ae3101 100644 --- a/MediaBrowser.Controller/Syncplay/ISyncplayController.cs +++ b/MediaBrowser.Controller/Syncplay/ISyncplayController.cs @@ -28,29 +28,29 @@ namespace MediaBrowser.Controller.Syncplay bool IsGroupEmpty(); /// - /// Initializes the group with the user's info. + /// Initializes the group with the session's info. /// - /// The session. - void InitGroup(SessionInfo user); + /// The session. + void InitGroup(SessionInfo session); /// - /// Adds the user to the group. + /// Adds the session to the group. /// - /// The session. - void UserJoin(SessionInfo user); + /// The session. + void SessionJoin(SessionInfo session); /// - /// Removes the user from the group. + /// Removes the session from the group. /// - /// The session. - void UserLeave(SessionInfo user); + /// The session. + void SessionLeave(SessionInfo session); /// - /// Handles the requested action by the user. + /// Handles the requested action by the session. /// - /// The session. + /// The session. /// The requested action. - void HandleRequest(SessionInfo user, SyncplayRequestInfo request); + void HandleRequest(SessionInfo session, SyncplayRequestInfo request); /// /// Gets the info about the group for the clients. diff --git a/MediaBrowser.Controller/Syncplay/ISyncplayManager.cs b/MediaBrowser.Controller/Syncplay/ISyncplayManager.cs index ec91ea69d..09920a19f 100644 --- a/MediaBrowser.Controller/Syncplay/ISyncplayManager.cs +++ b/MediaBrowser.Controller/Syncplay/ISyncplayManager.cs @@ -13,50 +13,50 @@ namespace MediaBrowser.Controller.Syncplay /// /// Creates a new group. /// - /// The user that's creating the group. - void NewGroup(SessionInfo user); + /// The session that's creating the group. + void NewGroup(SessionInfo session); /// - /// Adds the user to a group. + /// Adds the session to a group. /// - /// The session. + /// The session. /// The group id. - void JoinGroup(SessionInfo user, string groupId); + void JoinGroup(SessionInfo session, string groupId); /// - /// Removes the user from a group. + /// Removes the session from a group. /// - /// The session. - void LeaveGroup(SessionInfo user); + /// The session. + void LeaveGroup(SessionInfo session); /// - /// Gets list of available groups for a user. + /// Gets list of available groups for a session. /// - /// The user. + /// The session. /// The list of available groups. - List ListGroups(SessionInfo user); + List ListGroups(SessionInfo session); /// - /// Handle a request by a user in a group. + /// Handle a request by a session in a group. /// - /// The session. + /// The session. /// The request. - void HandleRequest(SessionInfo user, SyncplayRequestInfo request); + void HandleRequest(SessionInfo session, SyncplayRequestInfo request); /// - /// Maps a user to a group. + /// Maps a session to a group. /// - /// The user. + /// The session. /// The group. /// - void MapUserToGroup(SessionInfo user, ISyncplayController group); + void MapSessionToGroup(SessionInfo session, ISyncplayController group); /// - /// Unmaps a user from a group. + /// Unmaps a session from a group. /// - /// The user. + /// The session. /// The group. /// - void UnmapUserFromGroup(SessionInfo user, ISyncplayController group); + void UnmapSessionFromGroup(SessionInfo session, ISyncplayController group); } } -- cgit v1.2.3 From 84d92ba9cea4fdd97a8d1580e67706dc4577871a Mon Sep 17 00:00:00 2001 From: gion Date: Wed, 15 Apr 2020 18:03:58 +0200 Subject: Check that client is playing the right item Send date when playback command is emitted Rename some classes --- .../Session/SessionManager.cs | 4 +- .../Syncplay/SyncplayController.cs | 80 ++++++++++++---------- .../Syncplay/SyncplayManager.cs | 28 ++++---- MediaBrowser.Api/Syncplay/SyncplayService.cs | 43 +++++++++--- MediaBrowser.Controller/Session/ISessionManager.cs | 4 +- .../Syncplay/ISyncplayController.cs | 5 +- .../Syncplay/ISyncplayManager.cs | 5 +- MediaBrowser.Model/Syncplay/GroupUpdate.cs | 26 +++++++ MediaBrowser.Model/Syncplay/GroupUpdateType.cs | 41 +++++++++++ MediaBrowser.Model/Syncplay/JoinGroupRequest.cs | 22 ++++++ MediaBrowser.Model/Syncplay/PlaybackRequest.cs | 34 +++++++++ MediaBrowser.Model/Syncplay/PlaybackRequestType.cs | 33 +++++++++ MediaBrowser.Model/Syncplay/SendCommand.cs | 38 ++++++++++ MediaBrowser.Model/Syncplay/SendCommandType.cs | 21 ++++++ MediaBrowser.Model/Syncplay/SyncplayCommand.cs | 32 --------- MediaBrowser.Model/Syncplay/SyncplayCommandType.cs | 21 ------ MediaBrowser.Model/Syncplay/SyncplayGroupUpdate.cs | 26 ------- .../Syncplay/SyncplayGroupUpdateType.cs | 41 ----------- MediaBrowser.Model/Syncplay/SyncplayRequestInfo.cs | 34 --------- MediaBrowser.Model/Syncplay/SyncplayRequestType.cs | 33 --------- 20 files changed, 313 insertions(+), 258 deletions(-) create mode 100644 MediaBrowser.Model/Syncplay/GroupUpdate.cs create mode 100644 MediaBrowser.Model/Syncplay/GroupUpdateType.cs create mode 100644 MediaBrowser.Model/Syncplay/JoinGroupRequest.cs create mode 100644 MediaBrowser.Model/Syncplay/PlaybackRequest.cs create mode 100644 MediaBrowser.Model/Syncplay/PlaybackRequestType.cs create mode 100644 MediaBrowser.Model/Syncplay/SendCommand.cs create mode 100644 MediaBrowser.Model/Syncplay/SendCommandType.cs delete mode 100644 MediaBrowser.Model/Syncplay/SyncplayCommand.cs delete mode 100644 MediaBrowser.Model/Syncplay/SyncplayCommandType.cs delete mode 100644 MediaBrowser.Model/Syncplay/SyncplayGroupUpdate.cs delete mode 100644 MediaBrowser.Model/Syncplay/SyncplayGroupUpdateType.cs delete mode 100644 MediaBrowser.Model/Syncplay/SyncplayRequestInfo.cs delete mode 100644 MediaBrowser.Model/Syncplay/SyncplayRequestType.cs (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/Session/SessionManager.cs b/Emby.Server.Implementations/Session/SessionManager.cs index b1519b572..6a64209c1 100644 --- a/Emby.Server.Implementations/Session/SessionManager.cs +++ b/Emby.Server.Implementations/Session/SessionManager.cs @@ -1156,7 +1156,7 @@ namespace Emby.Server.Implementations.Session } /// - public async Task SendSyncplayCommand(string sessionId, SyncplayCommand command, CancellationToken cancellationToken) + public async Task SendSyncplayCommand(string sessionId, SendCommand command, CancellationToken cancellationToken) { CheckDisposed(); var session = GetSessionToRemoteControl(sessionId); @@ -1164,7 +1164,7 @@ namespace Emby.Server.Implementations.Session } /// - public async Task SendSyncplayGroupUpdate(string sessionId, SyncplayGroupUpdate command, CancellationToken cancellationToken) + public async Task SendSyncplayGroupUpdate(string sessionId, GroupUpdate command, CancellationToken cancellationToken) { CheckDisposed(); var session = GetSessionToRemoteControl(sessionId); diff --git a/Emby.Server.Implementations/Syncplay/SyncplayController.cs b/Emby.Server.Implementations/Syncplay/SyncplayController.cs index b156e5a87..fb37b2fb6 100644 --- a/Emby.Server.Implementations/Syncplay/SyncplayController.cs +++ b/Emby.Server.Implementations/Syncplay/SyncplayController.cs @@ -129,7 +129,7 @@ namespace Emby.Server.Implementations.Syncplay } } - private Task SendGroupUpdate(SessionInfo from, BroadcastType type, SyncplayGroupUpdate message) + private Task SendGroupUpdate(SessionInfo from, BroadcastType type, GroupUpdate message) { IEnumerable GetTasks() { @@ -143,7 +143,7 @@ namespace Emby.Server.Implementations.Syncplay return Task.WhenAll(GetTasks()); } - private Task SendCommand(SessionInfo from, BroadcastType type, SyncplayCommand message) + private Task SendCommand(SessionInfo from, BroadcastType type, SendCommand message) { IEnumerable GetTasks() { @@ -157,18 +157,20 @@ namespace Emby.Server.Implementations.Syncplay return Task.WhenAll(GetTasks()); } - private SyncplayCommand NewSyncplayCommand(SyncplayCommandType type) { - var command = new SyncplayCommand(); + private SendCommand NewSyncplayCommand(SendCommandType type) + { + var command = new SendCommand(); command.GroupId = _group.GroupId.ToString(); command.Command = type; command.PositionTicks = _group.PositionTicks; command.When = _group.LastActivity.ToUniversalTime().ToString("o"); + command.EmittedAt = DateTime.UtcNow.ToUniversalTime().ToString("o"); return command; } - private SyncplayGroupUpdate NewSyncplayGroupUpdate(SyncplayGroupUpdateType type, T data) + private GroupUpdate NewSyncplayGroupUpdate(GroupUpdateType type, T data) { - var command = new SyncplayGroupUpdate(); + var command = new GroupUpdate(); command.GroupId = _group.GroupId.ToString(); command.Type = type; command.Data = data; @@ -186,35 +188,37 @@ namespace Emby.Server.Implementations.Syncplay _group.PositionTicks = session.PlayState.PositionTicks ??= 0; _group.LastActivity = DateTime.UtcNow; - var updateSession = NewSyncplayGroupUpdate(SyncplayGroupUpdateType.GroupJoined, DateTime.UtcNow.ToUniversalTime().ToString("o")); + var updateSession = NewSyncplayGroupUpdate(GroupUpdateType.GroupJoined, DateTime.UtcNow.ToUniversalTime().ToString("o")); SendGroupUpdate(session, BroadcastType.SingleSession, updateSession); - var pauseCommand = NewSyncplayCommand(SyncplayCommandType.Pause); + var pauseCommand = NewSyncplayCommand(SendCommandType.Pause); SendCommand(session, BroadcastType.SingleSession, pauseCommand); } /// - public void SessionJoin(SessionInfo session) + public void SessionJoin(SessionInfo session, JoinGroupRequest request) { - if (session.NowPlayingItem != null && session.NowPlayingItem.Id.Equals(_group.PlayingItem.Id)) + if (session.NowPlayingItem != null && + session.NowPlayingItem.Id.Equals(_group.PlayingItem.Id) && + request.PlayingItemId.Equals(_group.PlayingItem.Id)) { _group.AddSession(session); _syncplayManager.MapSessionToGroup(session, this); - var updateSession = NewSyncplayGroupUpdate(SyncplayGroupUpdateType.GroupJoined, _group.PositionTicks); + var updateSession = NewSyncplayGroupUpdate(GroupUpdateType.GroupJoined, DateTime.UtcNow.ToUniversalTime().ToString("o")); SendGroupUpdate(session, BroadcastType.SingleSession, updateSession); - var updateOthers = NewSyncplayGroupUpdate(SyncplayGroupUpdateType.UserJoined, session.UserName); + var updateOthers = NewSyncplayGroupUpdate(GroupUpdateType.UserJoined, session.UserName); SendGroupUpdate(session, BroadcastType.AllExceptSession, updateOthers); // Client join and play, syncing will happen client side if (!_group.IsPaused) { - var playCommand = NewSyncplayCommand(SyncplayCommandType.Play); + var playCommand = NewSyncplayCommand(SendCommandType.Play); SendCommand(session, BroadcastType.SingleSession, playCommand); } else { - var pauseCommand = NewSyncplayCommand(SyncplayCommandType.Pause); + var pauseCommand = NewSyncplayCommand(SendCommandType.Pause); SendCommand(session, BroadcastType.SingleSession, pauseCommand); } } @@ -223,7 +227,7 @@ namespace Emby.Server.Implementations.Syncplay var playRequest = new PlayRequest(); playRequest.ItemIds = new Guid[] { _group.PlayingItem.Id }; playRequest.StartPositionTicks = _group.PositionTicks; - var update = NewSyncplayGroupUpdate(SyncplayGroupUpdateType.PrepareSession, playRequest); + var update = NewSyncplayGroupUpdate(GroupUpdateType.PrepareSession, playRequest); SendGroupUpdate(session, BroadcastType.SingleSession, update); } } @@ -234,17 +238,17 @@ namespace Emby.Server.Implementations.Syncplay _group.RemoveSession(session); _syncplayManager.UnmapSessionFromGroup(session, this); - var updateSession = NewSyncplayGroupUpdate(SyncplayGroupUpdateType.GroupLeft, _group.PositionTicks); + var updateSession = NewSyncplayGroupUpdate(GroupUpdateType.GroupLeft, _group.PositionTicks); SendGroupUpdate(session, BroadcastType.SingleSession, updateSession); - var updateOthers = NewSyncplayGroupUpdate(SyncplayGroupUpdateType.UserLeft, session.UserName); + var updateOthers = NewSyncplayGroupUpdate(GroupUpdateType.UserLeft, session.UserName); SendGroupUpdate(session, BroadcastType.AllExceptSession, updateOthers); } /// - public void HandleRequest(SessionInfo session, SyncplayRequestInfo request) + public void HandleRequest(SessionInfo session, PlaybackRequest request) { - if (request.Type.Equals(SyncplayRequestType.Play)) + if (request.Type.Equals(PlaybackRequestType.Play)) { if (_group.IsPaused) { @@ -256,17 +260,17 @@ namespace Emby.Server.Implementations.Syncplay delay ); - var command = NewSyncplayCommand(SyncplayCommandType.Play); + var command = NewSyncplayCommand(SendCommandType.Play); SendCommand(session, BroadcastType.AllGroup, command); } else { // Client got lost - var command = NewSyncplayCommand(SyncplayCommandType.Play); + var command = NewSyncplayCommand(SendCommandType.Play); SendCommand(session, BroadcastType.SingleSession, command); } } - else if (request.Type.Equals(SyncplayRequestType.Pause)) + else if (request.Type.Equals(PlaybackRequestType.Pause)) { if (!_group.IsPaused) { @@ -276,16 +280,16 @@ namespace Emby.Server.Implementations.Syncplay _group.LastActivity = currentTime; _group.PositionTicks += elapsedTime.Ticks > 0 ? elapsedTime.Ticks : 0; - var command = NewSyncplayCommand(SyncplayCommandType.Pause); + var command = NewSyncplayCommand(SendCommandType.Pause); SendCommand(session, BroadcastType.AllGroup, command); } else { - var command = NewSyncplayCommand(SyncplayCommandType.Pause); + var command = NewSyncplayCommand(SendCommandType.Pause); SendCommand(session, BroadcastType.SingleSession, command); } } - else if (request.Type.Equals(SyncplayRequestType.Seek)) + else if (request.Type.Equals(PlaybackRequestType.Seek)) { // Sanitize PositionTicks var ticks = request.PositionTicks ??= 0; @@ -300,11 +304,11 @@ namespace Emby.Server.Implementations.Syncplay _group.PositionTicks = ticks; _group.LastActivity = DateTime.UtcNow; - var command = NewSyncplayCommand(SyncplayCommandType.Seek); + var command = NewSyncplayCommand(SendCommandType.Seek); SendCommand(session, BroadcastType.AllGroup, command); } // TODO: client does not implement this yet - else if (request.Type.Equals(SyncplayRequestType.Buffering)) + else if (request.Type.Equals(PlaybackRequestType.Buffering)) { if (!_group.IsPaused) { @@ -317,20 +321,20 @@ namespace Emby.Server.Implementations.Syncplay _group.SetBuffering(session, true); // Send pause command to all non-buffering sessions - var command = NewSyncplayCommand(SyncplayCommandType.Pause); + var command = NewSyncplayCommand(SendCommandType.Pause); SendCommand(session, BroadcastType.AllReady, command); - var updateOthers = NewSyncplayGroupUpdate(SyncplayGroupUpdateType.GroupWait, session.UserName); + var updateOthers = NewSyncplayGroupUpdate(GroupUpdateType.GroupWait, session.UserName); SendGroupUpdate(session, BroadcastType.AllExceptSession, updateOthers); } else { - var command = NewSyncplayCommand(SyncplayCommandType.Pause); + var command = NewSyncplayCommand(SendCommandType.Pause); SendCommand(session, BroadcastType.SingleSession, command); } } // TODO: client does not implement this yet - else if (request.Type.Equals(SyncplayRequestType.BufferingComplete)) + else if (request.Type.Equals(PlaybackRequestType.BufferingComplete)) { if (_group.IsPaused) { @@ -344,7 +348,7 @@ namespace Emby.Server.Implementations.Syncplay var clientPosition = TimeSpan.FromTicks(request.PositionTicks ??= 0) + elapsedTime; var delay = _group.PositionTicks - clientPosition.Ticks; - var command = NewSyncplayCommand(SyncplayCommandType.Pause); + var command = NewSyncplayCommand(SendCommandType.Pause); command.When = currentTime.AddMilliseconds( delay ).ToUniversalTime().ToString("o"); @@ -367,7 +371,7 @@ namespace Emby.Server.Implementations.Syncplay _group.LastActivity = currentTime.AddMilliseconds( delay ); - var command = NewSyncplayCommand(SyncplayCommandType.Play); + var command = NewSyncplayCommand(SendCommandType.Play); SendCommand(session, BroadcastType.AllExceptSession, command); } else @@ -380,7 +384,7 @@ namespace Emby.Server.Implementations.Syncplay delay ); - var command = NewSyncplayCommand(SyncplayCommandType.Play); + var command = NewSyncplayCommand(SendCommandType.Play); SendCommand(session, BroadcastType.AllGroup, command); } } @@ -388,17 +392,17 @@ namespace Emby.Server.Implementations.Syncplay else { // Make sure client has latest group state - var command = NewSyncplayCommand(SyncplayCommandType.Play); + var command = NewSyncplayCommand(SendCommandType.Play); SendCommand(session, BroadcastType.SingleSession, command); } } - else if (request.Type.Equals(SyncplayRequestType.KeepAlive)) + else if (request.Type.Equals(PlaybackRequestType.KeepAlive)) { _group.UpdatePing(session, request.Ping ??= _group.DefaulPing); - var keepAlive = new SyncplayGroupUpdate(); + var keepAlive = new GroupUpdate(); keepAlive.GroupId = _group.GroupId.ToString(); - keepAlive.Type = SyncplayGroupUpdateType.KeepAlive; + keepAlive.Type = GroupUpdateType.KeepAlive; SendGroupUpdate(session, BroadcastType.SingleSession, keepAlive); } } diff --git a/Emby.Server.Implementations/Syncplay/SyncplayManager.cs b/Emby.Server.Implementations/Syncplay/SyncplayManager.cs index 5c44326f5..60d70e5fd 100644 --- a/Emby.Server.Implementations/Syncplay/SyncplayManager.cs +++ b/Emby.Server.Implementations/Syncplay/SyncplayManager.cs @@ -166,7 +166,7 @@ namespace Emby.Server.Implementations.Syncplay if (user.Policy.SyncplayAccess != SyncplayAccess.CreateAndJoinGroups) { // TODO: shall an error message be sent back to the client? - return; + throw new ArgumentException("User does not have permission to create groups"); } if (IsSessionInGroup(session)) @@ -181,14 +181,14 @@ namespace Emby.Server.Implementations.Syncplay } /// - public void JoinGroup(SessionInfo session, string groupId) + public void JoinGroup(SessionInfo session, string groupId, JoinGroupRequest request) { var user = _userManager.GetUserById(session.UserId); if (user.Policy.SyncplayAccess == SyncplayAccess.None) { // TODO: shall an error message be sent back to the client? - return; + throw new ArgumentException("User does not have access to syncplay"); } if (IsSessionInGroup(session)) @@ -204,18 +204,18 @@ namespace Emby.Server.Implementations.Syncplay { _logger.LogError("Syncplaymanager JoinGroup: " + groupId + " does not exist."); - var update = new SyncplayGroupUpdate(); - update.Type = SyncplayGroupUpdateType.NotInGroup; + var update = new GroupUpdate(); + update.Type = GroupUpdateType.NotInGroup; _sessionManager.SendSyncplayGroupUpdate(session.Id.ToString(), update, CancellationToken.None); return; } if (!HasAccessToItem(user, group.GetPlayingItemId())) { - return; + throw new ArgumentException("User does not have access to playing item"); } - group.SessionJoin(session); + group.SessionJoin(session, request); } /// @@ -230,8 +230,8 @@ namespace Emby.Server.Implementations.Syncplay { _logger.LogWarning("Syncplaymanager HandleRequest: " + session.Id + " not in group."); - var update = new SyncplayGroupUpdate(); - update.Type = SyncplayGroupUpdateType.NotInGroup; + var update = new GroupUpdate(); + update.Type = GroupUpdateType.NotInGroup; _sessionManager.SendSyncplayGroupUpdate(session.Id.ToString(), update, CancellationToken.None); return; } @@ -276,14 +276,14 @@ namespace Emby.Server.Implementations.Syncplay } /// - public void HandleRequest(SessionInfo session, SyncplayRequestInfo request) + public void HandleRequest(SessionInfo session, PlaybackRequest request) { var user = _userManager.GetUserById(session.UserId); if (user.Policy.SyncplayAccess == SyncplayAccess.None) { // TODO: same as LeaveGroup - return; + throw new ArgumentException("User does not have access to syncplay"); } ISyncplayController group; @@ -293,14 +293,14 @@ namespace Emby.Server.Implementations.Syncplay { _logger.LogWarning("Syncplaymanager HandleRequest: " + session.Id + " not in group."); - var update = new SyncplayGroupUpdate(); - update.Type = SyncplayGroupUpdateType.NotInGroup; + var update = new GroupUpdate(); + update.Type = GroupUpdateType.NotInGroup; _sessionManager.SendSyncplayGroupUpdate(session.Id.ToString(), update, CancellationToken.None); return; } group.HandleRequest(session, request); } - + /// public void MapSessionToGroup(SessionInfo session, ISyncplayController group) { diff --git a/MediaBrowser.Api/Syncplay/SyncplayService.cs b/MediaBrowser.Api/Syncplay/SyncplayService.cs index f17cca9ee..0f9d1b733 100644 --- a/MediaBrowser.Api/Syncplay/SyncplayService.cs +++ b/MediaBrowser.Api/Syncplay/SyncplayService.cs @@ -31,6 +31,13 @@ namespace MediaBrowser.Api.Syncplay /// The Group id to join. [ApiMember(Name = "GroupId", Description = "Group Id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")] public string GroupId { get; set; } + + /// + /// Gets or sets the playing item id. + /// + /// The client's currently playing item id. + [ApiMember(Name = "PlayingItemId", Description = "Client's playing item id", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")] + public string PlayingItemId { get; set; } } [Route("/Syncplay/{SessionId}/LeaveGroup", "POST", Summary = "Leave joined Syncplay group")] @@ -160,7 +167,21 @@ namespace MediaBrowser.Api.Syncplay public void Post(SyncplayJoinGroup request) { var currentSession = GetSession(_sessionContext); - _syncplayManager.JoinGroup(currentSession, request.GroupId); + var joinRequest = new JoinGroupRequest(); + joinRequest.GroupId = Guid.Parse(request.GroupId); + try + { + joinRequest.PlayingItemId = Guid.Parse(request.PlayingItemId); + } + catch (ArgumentNullException) + { + // Do nothing + } + catch (FormatException) + { + // Do nothing + } + _syncplayManager.JoinGroup(currentSession, request.GroupId, joinRequest); } /// @@ -191,8 +212,8 @@ namespace MediaBrowser.Api.Syncplay public void Post(SyncplayPlayRequest request) { var currentSession = GetSession(_sessionContext); - var syncplayRequest = new SyncplayRequestInfo(); - syncplayRequest.Type = SyncplayRequestType.Play; + var syncplayRequest = new PlaybackRequest(); + syncplayRequest.Type = PlaybackRequestType.Play; _syncplayManager.HandleRequest(currentSession, syncplayRequest); } @@ -203,8 +224,8 @@ namespace MediaBrowser.Api.Syncplay public void Post(SyncplayPauseRequest request) { var currentSession = GetSession(_sessionContext); - var syncplayRequest = new SyncplayRequestInfo(); - syncplayRequest.Type = SyncplayRequestType.Pause; + var syncplayRequest = new PlaybackRequest(); + syncplayRequest.Type = PlaybackRequestType.Pause; _syncplayManager.HandleRequest(currentSession, syncplayRequest); } @@ -215,8 +236,8 @@ namespace MediaBrowser.Api.Syncplay public void Post(SyncplaySeekRequest request) { var currentSession = GetSession(_sessionContext); - var syncplayRequest = new SyncplayRequestInfo(); - syncplayRequest.Type = SyncplayRequestType.Seek; + var syncplayRequest = new PlaybackRequest(); + syncplayRequest.Type = PlaybackRequestType.Seek; syncplayRequest.PositionTicks = request.PositionTicks; _syncplayManager.HandleRequest(currentSession, syncplayRequest); } @@ -228,8 +249,8 @@ namespace MediaBrowser.Api.Syncplay public void Post(SyncplayBufferingRequest request) { var currentSession = GetSession(_sessionContext); - var syncplayRequest = new SyncplayRequestInfo(); - syncplayRequest.Type = request.Resume ? SyncplayRequestType.BufferingComplete : SyncplayRequestType.Buffering; + var syncplayRequest = new PlaybackRequest(); + syncplayRequest.Type = request.Resume ? PlaybackRequestType.BufferingComplete : PlaybackRequestType.Buffering; syncplayRequest.When = DateTime.Parse(request.When); syncplayRequest.PositionTicks = request.PositionTicks; _syncplayManager.HandleRequest(currentSession, syncplayRequest); @@ -242,8 +263,8 @@ namespace MediaBrowser.Api.Syncplay public void Post(SyncplayKeepAlive request) { var currentSession = GetSession(_sessionContext); - var syncplayRequest = new SyncplayRequestInfo(); - syncplayRequest.Type = SyncplayRequestType.KeepAlive; + var syncplayRequest = new PlaybackRequest(); + syncplayRequest.Type = PlaybackRequestType.KeepAlive; syncplayRequest.Ping = Convert.ToInt64(request.Ping); _syncplayManager.HandleRequest(currentSession, syncplayRequest); } diff --git a/MediaBrowser.Controller/Session/ISessionManager.cs b/MediaBrowser.Controller/Session/ISessionManager.cs index 4bfc0c73f..39c065b89 100644 --- a/MediaBrowser.Controller/Session/ISessionManager.cs +++ b/MediaBrowser.Controller/Session/ISessionManager.cs @@ -148,7 +148,7 @@ namespace MediaBrowser.Controller.Session /// The command. /// The cancellation token. /// Task. - Task SendSyncplayCommand(string sessionId, SyncplayCommand command, CancellationToken cancellationToken); + Task SendSyncplayCommand(string sessionId, SendCommand command, CancellationToken cancellationToken); /// /// Sends the SyncplayGroupUpdate. @@ -157,7 +157,7 @@ namespace MediaBrowser.Controller.Session /// The group update. /// The cancellation token. /// Task. - Task SendSyncplayGroupUpdate(string sessionId, SyncplayGroupUpdate command, CancellationToken cancellationToken); + Task SendSyncplayGroupUpdate(string sessionId, GroupUpdate command, CancellationToken cancellationToken); /// /// Sends the browse command. diff --git a/MediaBrowser.Controller/Syncplay/ISyncplayController.cs b/MediaBrowser.Controller/Syncplay/ISyncplayController.cs index d35ae3101..5b08eac0a 100644 --- a/MediaBrowser.Controller/Syncplay/ISyncplayController.cs +++ b/MediaBrowser.Controller/Syncplay/ISyncplayController.cs @@ -37,7 +37,8 @@ namespace MediaBrowser.Controller.Syncplay /// Adds the session to the group. /// /// The session. - void SessionJoin(SessionInfo session); + /// The request. + void SessionJoin(SessionInfo session, JoinGroupRequest request); /// /// Removes the session from the group. @@ -50,7 +51,7 @@ namespace MediaBrowser.Controller.Syncplay /// /// The session. /// The requested action. - void HandleRequest(SessionInfo session, SyncplayRequestInfo request); + void HandleRequest(SessionInfo session, PlaybackRequest request); /// /// Gets the info about the group for the clients. diff --git a/MediaBrowser.Controller/Syncplay/ISyncplayManager.cs b/MediaBrowser.Controller/Syncplay/ISyncplayManager.cs index 09920a19f..d0cf8fa9c 100644 --- a/MediaBrowser.Controller/Syncplay/ISyncplayManager.cs +++ b/MediaBrowser.Controller/Syncplay/ISyncplayManager.cs @@ -21,7 +21,8 @@ namespace MediaBrowser.Controller.Syncplay /// /// The session. /// The group id. - void JoinGroup(SessionInfo session, string groupId); + /// The request. + void JoinGroup(SessionInfo session, string groupId, JoinGroupRequest request); /// /// Removes the session from a group. @@ -41,7 +42,7 @@ namespace MediaBrowser.Controller.Syncplay /// /// The session. /// The request. - void HandleRequest(SessionInfo session, SyncplayRequestInfo request); + void HandleRequest(SessionInfo session, PlaybackRequest request); /// /// Maps a session to a group. diff --git a/MediaBrowser.Model/Syncplay/GroupUpdate.cs b/MediaBrowser.Model/Syncplay/GroupUpdate.cs new file mode 100644 index 000000000..cc49e92a9 --- /dev/null +++ b/MediaBrowser.Model/Syncplay/GroupUpdate.cs @@ -0,0 +1,26 @@ +namespace MediaBrowser.Model.Syncplay +{ + /// + /// Class GroupUpdate. + /// + public class GroupUpdate + { + /// + /// Gets or sets the group identifier. + /// + /// The group identifier. + public string GroupId { get; set; } + + /// + /// Gets or sets the update type. + /// + /// The update type. + public GroupUpdateType Type { get; set; } + + /// + /// Gets or sets the data. + /// + /// The data. + public T Data { get; set; } + } +} diff --git a/MediaBrowser.Model/Syncplay/GroupUpdateType.cs b/MediaBrowser.Model/Syncplay/GroupUpdateType.cs new file mode 100644 index 000000000..ceb778b36 --- /dev/null +++ b/MediaBrowser.Model/Syncplay/GroupUpdateType.cs @@ -0,0 +1,41 @@ +namespace MediaBrowser.Model.Syncplay +{ + /// + /// Enum GroupUpdateType + /// + public enum GroupUpdateType + { + /// + /// The user-joined update. Tells members of a group about a new user. + /// + UserJoined = 0, + /// + /// The user-left update. Tells members of a group that a user left. + /// + UserLeft = 1, + /// + /// The group-joined update. Tells a user that the group has been joined. + /// + GroupJoined = 2, + /// + /// The group-left update. Tells a user that the group has been left. + /// + GroupLeft = 3, + /// + /// The group-wait update. Tells members of the group that a user is buffering. + /// + GroupWait = 4, + /// + /// The prepare-session update. Tells a user to load some content. + /// + PrepareSession = 5, + /// + /// The keep-alive update. An update to keep alive the socket. + /// + KeepAlive = 6, + /// + /// The not-in-group update. Tells a user that no group has been joined. + /// + NotInGroup = 7 + } +} diff --git a/MediaBrowser.Model/Syncplay/JoinGroupRequest.cs b/MediaBrowser.Model/Syncplay/JoinGroupRequest.cs new file mode 100644 index 000000000..8d8a2646a --- /dev/null +++ b/MediaBrowser.Model/Syncplay/JoinGroupRequest.cs @@ -0,0 +1,22 @@ +using System; + +namespace MediaBrowser.Model.Syncplay +{ + /// + /// Class JoinGroupRequest. + /// + public class JoinGroupRequest + { + /// + /// Gets or sets the Group id. + /// + /// The Group id to join. + public Guid GroupId { get; set; } + + /// + /// Gets or sets the playing item id. + /// + /// The client's currently playing item id. + public Guid PlayingItemId { get; set; } + } +} diff --git a/MediaBrowser.Model/Syncplay/PlaybackRequest.cs b/MediaBrowser.Model/Syncplay/PlaybackRequest.cs new file mode 100644 index 000000000..cae769db0 --- /dev/null +++ b/MediaBrowser.Model/Syncplay/PlaybackRequest.cs @@ -0,0 +1,34 @@ +using System; + +namespace MediaBrowser.Model.Syncplay +{ + /// + /// Class PlaybackRequest. + /// + public class PlaybackRequest + { + /// + /// Gets or sets the request type. + /// + /// The request type. + public PlaybackRequestType Type; + + /// + /// Gets or sets when the request has been made by the client. + /// + /// The date of the request. + public DateTime? When { get; set; } + + /// + /// Gets or sets the position ticks. + /// + /// The position ticks. + public long? PositionTicks { get; set; } + + /// + /// Gets or sets the ping time. + /// + /// The ping time. + public long? Ping { get; set; } + } +} diff --git a/MediaBrowser.Model/Syncplay/PlaybackRequestType.cs b/MediaBrowser.Model/Syncplay/PlaybackRequestType.cs new file mode 100644 index 000000000..da770736c --- /dev/null +++ b/MediaBrowser.Model/Syncplay/PlaybackRequestType.cs @@ -0,0 +1,33 @@ +namespace MediaBrowser.Model.Syncplay +{ + /// + /// Enum PlaybackRequestType + /// + public enum PlaybackRequestType + { + /// + /// A user is requesting a play command for the group. + /// + Play = 0, + /// + /// A user is requesting a pause command for the group. + /// + Pause = 1, + /// + /// A user is requesting a seek command for the group. + /// + Seek = 2, + /// + /// A user is signaling that playback is buffering. + /// + Buffering = 3, + /// + /// A user is signaling that playback resumed. + /// + BufferingComplete = 4, + /// + /// A user is reporting its ping. + /// + KeepAlive = 5 + } +} diff --git a/MediaBrowser.Model/Syncplay/SendCommand.cs b/MediaBrowser.Model/Syncplay/SendCommand.cs new file mode 100644 index 000000000..d9f391403 --- /dev/null +++ b/MediaBrowser.Model/Syncplay/SendCommand.cs @@ -0,0 +1,38 @@ +namespace MediaBrowser.Model.Syncplay +{ + /// + /// Class SendCommand. + /// + public class SendCommand + { + /// + /// Gets or sets the group identifier. + /// + /// The group identifier. + public string GroupId { get; set; } + + /// + /// Gets or sets the UTC time when to execute the command. + /// + /// The UTC time when to execute the command. + public string When { get; set; } + + /// + /// Gets or sets the position ticks. + /// + /// The position ticks. + public long? PositionTicks { get; set; } + + /// + /// Gets or sets the command. + /// + /// The command. + public SendCommandType Command { get; set; } + + /// + /// Gets or sets the UTC time when this command has been emitted. + /// + /// The UTC time when this command has been emitted. + public string EmittedAt { get; set; } + } +} diff --git a/MediaBrowser.Model/Syncplay/SendCommandType.cs b/MediaBrowser.Model/Syncplay/SendCommandType.cs new file mode 100644 index 000000000..02e4774d0 --- /dev/null +++ b/MediaBrowser.Model/Syncplay/SendCommandType.cs @@ -0,0 +1,21 @@ +namespace MediaBrowser.Model.Syncplay +{ + /// + /// Enum SendCommandType. + /// + public enum SendCommandType + { + /// + /// The play command. Instructs users to start playback. + /// + Play = 0, + /// + /// The pause command. Instructs users to pause playback. + /// + Pause = 1, + /// + /// The seek command. Instructs users to seek to a specified time. + /// + Seek = 2 + } +} diff --git a/MediaBrowser.Model/Syncplay/SyncplayCommand.cs b/MediaBrowser.Model/Syncplay/SyncplayCommand.cs deleted file mode 100644 index 769316e80..000000000 --- a/MediaBrowser.Model/Syncplay/SyncplayCommand.cs +++ /dev/null @@ -1,32 +0,0 @@ -namespace MediaBrowser.Model.Syncplay -{ - /// - /// Class SyncplayCommand. - /// - public class SyncplayCommand - { - /// - /// Gets or sets the group identifier. - /// - /// The group identifier. - public string GroupId { get; set; } - - /// - /// Gets or sets the UTC time when to execute the command. - /// - /// The UTC time when to execute the command. - public string When { get; set; } - - /// - /// Gets or sets the position ticks. - /// - /// The position ticks. - public long? PositionTicks { get; set; } - - /// - /// Gets or sets the command. - /// - /// The command. - public SyncplayCommandType Command { get; set; } - } -} diff --git a/MediaBrowser.Model/Syncplay/SyncplayCommandType.cs b/MediaBrowser.Model/Syncplay/SyncplayCommandType.cs deleted file mode 100644 index 87b9ad66d..000000000 --- a/MediaBrowser.Model/Syncplay/SyncplayCommandType.cs +++ /dev/null @@ -1,21 +0,0 @@ -namespace MediaBrowser.Model.Syncplay -{ - /// - /// Enum SyncplayCommandType. - /// - public enum SyncplayCommandType - { - /// - /// The play command. Instructs users to start playback. - /// - Play = 0, - /// - /// The pause command. Instructs users to pause playback. - /// - Pause = 1, - /// - /// The seek command. Instructs users to seek to a specified time. - /// - Seek = 2 - } -} diff --git a/MediaBrowser.Model/Syncplay/SyncplayGroupUpdate.cs b/MediaBrowser.Model/Syncplay/SyncplayGroupUpdate.cs deleted file mode 100644 index c5c2f3540..000000000 --- a/MediaBrowser.Model/Syncplay/SyncplayGroupUpdate.cs +++ /dev/null @@ -1,26 +0,0 @@ -namespace MediaBrowser.Model.Syncplay -{ - /// - /// Class SyncplayGroupUpdate. - /// - public class SyncplayGroupUpdate - { - /// - /// Gets or sets the group identifier. - /// - /// The group identifier. - public string GroupId { get; set; } - - /// - /// Gets or sets the update type. - /// - /// The update type. - public SyncplayGroupUpdateType Type { get; set; } - - /// - /// Gets or sets the data. - /// - /// The data. - public T Data { get; set; } - } -} diff --git a/MediaBrowser.Model/Syncplay/SyncplayGroupUpdateType.cs b/MediaBrowser.Model/Syncplay/SyncplayGroupUpdateType.cs deleted file mode 100644 index c7c5f534d..000000000 --- a/MediaBrowser.Model/Syncplay/SyncplayGroupUpdateType.cs +++ /dev/null @@ -1,41 +0,0 @@ -namespace MediaBrowser.Model.Syncplay -{ - /// - /// Enum SyncplayGroupUpdateType - /// - public enum SyncplayGroupUpdateType - { - /// - /// The user-joined update. Tells members of a group about a new user. - /// - UserJoined = 0, - /// - /// The user-left update. Tells members of a group that a user left. - /// - UserLeft = 1, - /// - /// The group-joined update. Tells a user that the group has been joined. - /// - GroupJoined = 2, - /// - /// The group-left update. Tells a user that the group has been left. - /// - GroupLeft = 3, - /// - /// The group-wait update. Tells members of the group that a user is buffering. - /// - GroupWait = 4, - /// - /// The prepare-session update. Tells a user to load some content. - /// - PrepareSession = 5, - /// - /// The keep-alive update. An update to keep alive the socket. - /// - KeepAlive = 6, - /// - /// The not-in-group update. Tells a user that no group has been joined. - /// - NotInGroup = 7 - } -} diff --git a/MediaBrowser.Model/Syncplay/SyncplayRequestInfo.cs b/MediaBrowser.Model/Syncplay/SyncplayRequestInfo.cs deleted file mode 100644 index 7dba74ae9..000000000 --- a/MediaBrowser.Model/Syncplay/SyncplayRequestInfo.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System; - -namespace MediaBrowser.Model.Syncplay -{ - /// - /// Class SyncplayRequestInfo. - /// - public class SyncplayRequestInfo - { - /// - /// Gets or sets the request type. - /// - /// The request type. - public SyncplayRequestType Type; - - /// - /// Gets or sets when the request has been made by the client. - /// - /// The date of the request. - public DateTime? When { get; set; } - - /// - /// Gets or sets the position ticks. - /// - /// The position ticks. - public long? PositionTicks { get; set; } - - /// - /// Gets or sets the ping time. - /// - /// The ping time. - public long? Ping { get; set; } - } -} diff --git a/MediaBrowser.Model/Syncplay/SyncplayRequestType.cs b/MediaBrowser.Model/Syncplay/SyncplayRequestType.cs deleted file mode 100644 index 44d7a0af2..000000000 --- a/MediaBrowser.Model/Syncplay/SyncplayRequestType.cs +++ /dev/null @@ -1,33 +0,0 @@ -namespace MediaBrowser.Model.Syncplay -{ - /// - /// Enum SyncplayRequestType - /// - public enum SyncplayRequestType - { - /// - /// A user is requesting a play command for the group. - /// - Play = 0, - /// - /// A user is requesting a pause command for the group. - /// - Pause = 1, - /// - /// A user is requesting a seek command for the group. - /// - Seek = 2, - /// - /// A user is signaling that playback is buffering. - /// - Buffering = 3, - /// - /// A user is signaling that playback resumed. - /// - BufferingComplete = 4, - /// - /// A user is reporting its ping. - /// - KeepAlive = 5 - } -} -- cgit v1.2.3 From aad5058d25b3c295e9ea5b4330dde219034ba8c8 Mon Sep 17 00:00:00 2001 From: gion Date: Fri, 17 Apr 2020 13:47:00 +0200 Subject: Implement KeepAlive for WebSockets --- .../HttpServer/WebSocketConnection.cs | 27 +++- .../Session/SessionWebSocketListener.cs | 156 +++++++++++++++++++++ .../Net/IWebSocketConnection.cs | 6 + 3 files changed, 183 insertions(+), 6 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs b/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs index 2292d86a4..171047e65 100644 --- a/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs +++ b/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs @@ -94,6 +94,9 @@ namespace Emby.Server.Implementations.HttpServer /// The last activity date. public DateTime LastActivityDate { get; private set; } + /// + public DateTime LastKeepAliveDate { get; set; } + /// /// Gets the id. /// @@ -158,11 +161,6 @@ namespace Emby.Server.Implementations.HttpServer return; } - if (OnReceive == null) - { - return; - } - try { var stub = (WebSocketMessage)_jsonSerializer.DeserializeFromString(message, typeof(WebSocketMessage)); @@ -174,7 +172,15 @@ namespace Emby.Server.Implementations.HttpServer Connection = this }; - OnReceive(info); + if (info.MessageType.Equals("KeepAlive", StringComparison.Ordinal)) + { + SendKeepAliveResponse(); + } + + if (OnReceive != null) + { + OnReceive(info); + } } catch (Exception ex) { @@ -233,6 +239,15 @@ namespace Emby.Server.Implementations.HttpServer return _socket.SendAsync(text, true, cancellationToken); } + private Task SendKeepAliveResponse() + { + LastKeepAliveDate = DateTime.UtcNow; + return SendAsync(new WebSocketMessage + { + MessageType = "KeepAlive" + }, CancellationToken.None); + } + /// public void Dispose() { diff --git a/Emby.Server.Implementations/Session/SessionWebSocketListener.cs b/Emby.Server.Implementations/Session/SessionWebSocketListener.cs index 930f2d35d..d8e02ef39 100644 --- a/Emby.Server.Implementations/Session/SessionWebSocketListener.cs +++ b/Emby.Server.Implementations/Session/SessionWebSocketListener.cs @@ -1,8 +1,13 @@ using System; +using System.Collections.Concurrent; +using System.Linq; +using System.Net.WebSockets; +using System.Threading; using System.Threading.Tasks; using MediaBrowser.Controller.Net; using MediaBrowser.Controller.Session; using MediaBrowser.Model.Events; +using MediaBrowser.Model.Net; using MediaBrowser.Model.Serialization; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; @@ -14,6 +19,21 @@ namespace Emby.Server.Implementations.Session /// public class SessionWebSocketListener : IWebSocketListener, IDisposable { + /// + /// The timeout in seconds after which a WebSocket is considered to be lost. + /// + public readonly int WebSocketLostTimeout = 60; + + /// + /// The timer factor; controls the frequency of the timer. + /// + public readonly double TimerFactor = 0.2; + + /// + /// The ForceKeepAlive factor; controls when a ForceKeepAlive is sent. + /// + public readonly double ForceKeepAliveFactor = 0.75; + /// /// The _session manager /// @@ -31,6 +51,15 @@ namespace Emby.Server.Implementations.Session private readonly IHttpServer _httpServer; + /// + /// The KeepAlive timer. + /// + private Timer _keepAliveTimer; + + /// + /// The WebSocket watchlist. + /// + private readonly ConcurrentDictionary _webSockets = new ConcurrentDictionary(); /// /// Initializes a new instance of the class. @@ -55,6 +84,7 @@ namespace Emby.Server.Implementations.Session if (session != null) { EnsureController(session, e.Argument); + KeepAliveWebSocket(e.Argument); } else { @@ -82,6 +112,7 @@ namespace Emby.Server.Implementations.Session public void Dispose() { _httpServer.WebSocketConnected -= _serverManager_WebSocketConnected; + StopKeepAliveTimer(); } /// @@ -99,5 +130,130 @@ namespace Emby.Server.Implementations.Session var controller = (WebSocketController)controllerInfo.Item1; controller.AddWebSocket(connection); } + + /// + /// Called when a WebSocket is closed. + /// + /// The WebSocket. + /// The event arguments. + private void _webSocket_Closed(object sender, EventArgs e) + { + var webSocket = (IWebSocketConnection) sender; + webSocket.Closed -= _webSocket_Closed; + _webSockets.TryRemove(webSocket, out _); + } + + /// + /// Adds a WebSocket to the KeepAlive watchlist. + /// + /// The WebSocket to monitor. + private async void KeepAliveWebSocket(IWebSocketConnection webSocket) + { + _webSockets.TryAdd(webSocket, 0); + webSocket.Closed += _webSocket_Closed; + webSocket.LastKeepAliveDate = DateTime.UtcNow; + + // Notify WebSocket about timeout + try + { + await SendForceKeepAlive(webSocket); + } + catch (WebSocketException exception) + { + _logger.LogDebug(exception, "Error sending ForceKeepAlive message to WebSocket."); + } + + StartKeepAliveTimer(); + } + + /// + /// Starts the KeepAlive timer. + /// + private void StartKeepAliveTimer() + { + if (_keepAliveTimer == null) + { + _keepAliveTimer = new Timer( + KeepAliveSockets, + null, + TimeSpan.FromSeconds(WebSocketLostTimeout * TimerFactor), + TimeSpan.FromSeconds(WebSocketLostTimeout * TimerFactor) + ); + } + } + + /// + /// Stops the KeepAlive timer. + /// + private void StopKeepAliveTimer() + { + if (_keepAliveTimer != null) + { + _keepAliveTimer.Dispose(); + _keepAliveTimer = null; + } + + foreach (var pair in _webSockets) + { + pair.Key.Closed -= _webSocket_Closed; + } + } + + /// + /// Checks status of KeepAlive of WebSockets. + /// + /// The state. + private async void KeepAliveSockets(object state) + { + var inactive = _webSockets.Keys.Where(i => + { + var elapsed = (DateTime.UtcNow - i.LastKeepAliveDate).TotalSeconds; + return (elapsed > WebSocketLostTimeout * ForceKeepAliveFactor) && (elapsed < WebSocketLostTimeout); + }); + var lost = _webSockets.Keys.Where(i => (DateTime.UtcNow - i.LastKeepAliveDate).TotalSeconds >= WebSocketLostTimeout); + + if (inactive.Any()) + { + _logger.LogDebug("Sending ForceKeepAlive message to {0} WebSockets.", inactive.Count()); + } + + foreach (var webSocket in inactive) + { + try + { + await SendForceKeepAlive(webSocket); + } + catch (WebSocketException exception) + { + _logger.LogDebug(exception, "Error sending ForceKeepAlive message to WebSocket."); + lost.Append(webSocket); + } + } + + if (lost.Any()) + { + // TODO: handle lost webSockets + _logger.LogDebug("Lost {0} WebSockets.", lost.Count()); + } + + if (!_webSockets.Any()) + { + StopKeepAliveTimer(); + } + } + + /// + /// Sends a ForceKeepAlive message to a WebSocket. + /// + /// The WebSocket. + /// Task. + private Task SendForceKeepAlive(IWebSocketConnection webSocket) + { + return webSocket.SendAsync(new WebSocketMessage + { + MessageType = "ForceKeepAlive", + Data = WebSocketLostTimeout + }, CancellationToken.None); + } } } diff --git a/MediaBrowser.Controller/Net/IWebSocketConnection.cs b/MediaBrowser.Controller/Net/IWebSocketConnection.cs index 31eb7ccb7..fb766ab57 100644 --- a/MediaBrowser.Controller/Net/IWebSocketConnection.cs +++ b/MediaBrowser.Controller/Net/IWebSocketConnection.cs @@ -26,6 +26,12 @@ namespace MediaBrowser.Controller.Net /// The last activity date. DateTime LastActivityDate { get; } + /// + /// Gets or sets the date of last Keeplive received. + /// + /// The date of last Keeplive received. + public DateTime LastKeepAliveDate { get; set; } + /// /// Gets or sets the URL. /// -- cgit v1.2.3 From 083d3272d09395e2b7d73d886377017573e63686 Mon Sep 17 00:00:00 2001 From: gion Date: Tue, 21 Apr 2020 23:37:37 +0200 Subject: Refactor and other minor changes --- .../HttpServer/WebSocketConnection.cs | 5 +- .../Session/SessionWebSocketListener.cs | 42 +- .../Syncplay/SyncplayController.cs | 485 +++++++++++++-------- .../Syncplay/SyncplayManager.cs | 50 +-- MediaBrowser.Api/Syncplay/SyncplayService.cs | 52 ++- MediaBrowser.Api/Syncplay/TimeSyncService.cs | 1 - MediaBrowser.Controller/Syncplay/GroupInfo.cs | 24 +- .../Syncplay/ISyncplayManager.cs | 4 +- MediaBrowser.Model/Syncplay/GroupInfoModel.cs | 38 -- MediaBrowser.Model/Syncplay/GroupInfoView.cs | 38 ++ MediaBrowser.Model/Syncplay/PlaybackRequestType.cs | 2 +- 11 files changed, 441 insertions(+), 300 deletions(-) delete mode 100644 MediaBrowser.Model/Syncplay/GroupInfoModel.cs create mode 100644 MediaBrowser.Model/Syncplay/GroupInfoView.cs (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs b/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs index 171047e65..c819c163a 100644 --- a/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs +++ b/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs @@ -176,10 +176,9 @@ namespace Emby.Server.Implementations.HttpServer { SendKeepAliveResponse(); } - - if (OnReceive != null) + else { - OnReceive(info); + OnReceive?.Invoke(info); } } catch (Exception ex) diff --git a/Emby.Server.Implementations/Session/SessionWebSocketListener.cs b/Emby.Server.Implementations/Session/SessionWebSocketListener.cs index d8e02ef39..b0c6d0aa0 100644 --- a/Emby.Server.Implementations/Session/SessionWebSocketListener.cs +++ b/Emby.Server.Implementations/Session/SessionWebSocketListener.cs @@ -1,3 +1,4 @@ +using System.Collections.Generic; using System; using System.Collections.Concurrent; using System.Linq; @@ -25,7 +26,7 @@ namespace Emby.Server.Implementations.Session public readonly int WebSocketLostTimeout = 60; /// - /// The timer factor; controls the frequency of the timer. + /// The keep-alive timer factor; controls how often the timer will check on the status of the WebSockets. /// public readonly double TimerFactor = 0.2; @@ -136,11 +137,10 @@ namespace Emby.Server.Implementations.Session /// /// The WebSocket. /// The event arguments. - private void _webSocket_Closed(object sender, EventArgs e) + private void OnWebSocketClosed(object sender, EventArgs e) { var webSocket = (IWebSocketConnection) sender; - webSocket.Closed -= _webSocket_Closed; - _webSockets.TryRemove(webSocket, out _); + RemoveWebSocket(webSocket); } /// @@ -149,8 +149,12 @@ namespace Emby.Server.Implementations.Session /// The WebSocket to monitor. private async void KeepAliveWebSocket(IWebSocketConnection webSocket) { - _webSockets.TryAdd(webSocket, 0); - webSocket.Closed += _webSocket_Closed; + if (!_webSockets.TryAdd(webSocket, 0)) + { + _logger.LogWarning("Multiple attempts to keep alive single WebSocket {0}", webSocket); + return; + } + webSocket.Closed += OnWebSocketClosed; webSocket.LastKeepAliveDate = DateTime.UtcNow; // Notify WebSocket about timeout @@ -160,12 +164,22 @@ namespace Emby.Server.Implementations.Session } catch (WebSocketException exception) { - _logger.LogDebug(exception, "Error sending ForceKeepAlive message to WebSocket."); + _logger.LogWarning(exception, "Error sending ForceKeepAlive message to WebSocket."); } StartKeepAliveTimer(); } + /// + /// Removes a WebSocket from the KeepAlive watchlist. + /// + /// The WebSocket to remove. + private void RemoveWebSocket(IWebSocketConnection webSocket) + { + webSocket.Closed -= OnWebSocketClosed; + _webSockets.TryRemove(webSocket, out _); + } + /// /// Starts the KeepAlive timer. /// @@ -195,7 +209,7 @@ namespace Emby.Server.Implementations.Session foreach (var pair in _webSockets) { - pair.Key.Closed -= _webSocket_Closed; + pair.Key.Closed -= OnWebSocketClosed; } } @@ -214,7 +228,7 @@ namespace Emby.Server.Implementations.Session if (inactive.Any()) { - _logger.LogDebug("Sending ForceKeepAlive message to {0} WebSockets.", inactive.Count()); + _logger.LogDebug("Sending ForceKeepAlive message to {0} inactive WebSockets.", inactive.Count()); } foreach (var webSocket in inactive) @@ -225,15 +239,19 @@ namespace Emby.Server.Implementations.Session } catch (WebSocketException exception) { - _logger.LogDebug(exception, "Error sending ForceKeepAlive message to WebSocket."); + _logger.LogInformation(exception, "Error sending ForceKeepAlive message to WebSocket."); lost.Append(webSocket); } } if (lost.Any()) { - // TODO: handle lost webSockets - _logger.LogDebug("Lost {0} WebSockets.", lost.Count()); + _logger.LogInformation("Lost {0} WebSockets.", lost.Count()); + foreach (var webSocket in lost) + { + // TODO: handle session relative to the lost webSocket + RemoveWebSocket(webSocket); + } } if (!_webSockets.Any()) diff --git a/Emby.Server.Implementations/Syncplay/SyncplayController.cs b/Emby.Server.Implementations/Syncplay/SyncplayController.cs index 83b477944..02cf08cd7 100644 --- a/Emby.Server.Implementations/Syncplay/SyncplayController.cs +++ b/Emby.Server.Implementations/Syncplay/SyncplayController.cs @@ -16,11 +16,26 @@ namespace Emby.Server.Implementations.Syncplay /// public class SyncplayController : ISyncplayController, IDisposable { + /// + /// Used to filter the sessions of a group. + /// private enum BroadcastType { + /// + /// All sessions will receive the message. + /// AllGroup = 0, - SingleSession = 1, - AllExceptSession = 2, + /// + /// Only the specified session will receive the message. + /// + CurrentSession = 1, + /// + /// All sessions, except the current one, will receive the message. + /// + AllExceptCurrentSession = 2, + /// + /// Only sessions that are not buffering will receive the message. + /// AllReady = 3 } @@ -95,40 +110,46 @@ namespace Emby.Server.Implementations.Syncplay } } + /// + /// Filters sessions of this group. + /// + /// The current session. + /// The filtering type. + /// The array of sessions matching the filter. private SessionInfo[] FilterSessions(SessionInfo from, BroadcastType type) { - if (type == BroadcastType.SingleSession) - { - return new SessionInfo[] { from }; - } - else if (type == BroadcastType.AllGroup) - { - return _group.Partecipants.Values.Select( - session => session.Session - ).ToArray(); - } - else if (type == BroadcastType.AllExceptSession) - { - return _group.Partecipants.Values.Select( - session => session.Session - ).Where( - session => !session.Id.Equals(from.Id) - ).ToArray(); - } - else if (type == BroadcastType.AllReady) + switch (type) { - return _group.Partecipants.Values.Where( - session => !session.IsBuffering - ).Select( - session => session.Session - ).ToArray(); - } - else - { - return new SessionInfo[] {}; + case BroadcastType.CurrentSession: + return new SessionInfo[] { from }; + case BroadcastType.AllGroup: + return _group.Participants.Values.Select( + session => session.Session + ).ToArray(); + case BroadcastType.AllExceptCurrentSession: + return _group.Participants.Values.Select( + session => session.Session + ).Where( + session => !session.Id.Equals(from.Id) + ).ToArray(); + case BroadcastType.AllReady: + return _group.Participants.Values.Where( + session => !session.IsBuffering + ).Select( + session => session.Session + ).ToArray(); + default: + return new SessionInfo[] { }; } } + /// + /// Sends a GroupUpdate message to the interested sessions. + /// + /// The current session. + /// The filtering type. + /// The message to send. + /// The task. private Task SendGroupUpdate(SessionInfo from, BroadcastType type, GroupUpdate message) { IEnumerable GetTasks() @@ -143,6 +164,13 @@ namespace Emby.Server.Implementations.Syncplay return Task.WhenAll(GetTasks()); } + /// + /// Sends a playback command to the interested sessions. + /// + /// The current session. + /// The filtering type. + /// The message to send. + /// The task. private Task SendCommand(SessionInfo from, BroadcastType type, SendCommand message) { IEnumerable GetTasks() @@ -157,31 +185,44 @@ namespace Emby.Server.Implementations.Syncplay return Task.WhenAll(GetTasks()); } + /// + /// Builds a new playback command with some default values. + /// + /// The command type. + /// The SendCommand. private SendCommand NewSyncplayCommand(SendCommandType type) { - var command = new SendCommand(); - command.GroupId = _group.GroupId.ToString(); - command.Command = type; - command.PositionTicks = _group.PositionTicks; - command.When = _group.LastActivity.ToUniversalTime().ToString("o"); - command.EmittedAt = DateTime.UtcNow.ToUniversalTime().ToString("o"); - return command; + return new SendCommand() + { + GroupId = _group.GroupId.ToString(), + Command = type, + PositionTicks = _group.PositionTicks, + When = _group.LastActivity.ToUniversalTime().ToString("o"), + EmittedAt = DateTime.UtcNow.ToUniversalTime().ToString("o") + }; } + /// + /// Builds a new group update message. + /// + /// The update type. + /// The data to send. + /// The GroupUpdate. private GroupUpdate NewSyncplayGroupUpdate(GroupUpdateType type, T data) { - var command = new GroupUpdate(); - command.GroupId = _group.GroupId.ToString(); - command.Type = type; - command.Data = data; - return command; + return new GroupUpdate() + { + GroupId = _group.GroupId.ToString(), + Type = type, + Data = data + }; } /// public void InitGroup(SessionInfo session) { _group.AddSession(session); - _syncplayManager.MapSessionToGroup(session, this); + _syncplayManager.AddSessionToGroup(session, this); _group.PlayingItem = session.FullNowPlayingItem; _group.IsPaused = true; @@ -189,37 +230,35 @@ namespace Emby.Server.Implementations.Syncplay _group.LastActivity = DateTime.UtcNow; var updateSession = NewSyncplayGroupUpdate(GroupUpdateType.GroupJoined, DateTime.UtcNow.ToUniversalTime().ToString("o")); - SendGroupUpdate(session, BroadcastType.SingleSession, updateSession); + SendGroupUpdate(session, BroadcastType.CurrentSession, updateSession); var pauseCommand = NewSyncplayCommand(SendCommandType.Pause); - SendCommand(session, BroadcastType.SingleSession, pauseCommand); + SendCommand(session, BroadcastType.CurrentSession, pauseCommand); } /// public void SessionJoin(SessionInfo session, JoinGroupRequest request) { - if (session.NowPlayingItem != null && - session.NowPlayingItem.Id.Equals(_group.PlayingItem.Id) && - request.PlayingItemId.Equals(_group.PlayingItem.Id)) + if (session.NowPlayingItem?.Id == _group.PlayingItem.Id && request.PlayingItemId == _group.PlayingItem.Id) { _group.AddSession(session); - _syncplayManager.MapSessionToGroup(session, this); + _syncplayManager.AddSessionToGroup(session, this); var updateSession = NewSyncplayGroupUpdate(GroupUpdateType.GroupJoined, DateTime.UtcNow.ToUniversalTime().ToString("o")); - SendGroupUpdate(session, BroadcastType.SingleSession, updateSession); + SendGroupUpdate(session, BroadcastType.CurrentSession, updateSession); var updateOthers = NewSyncplayGroupUpdate(GroupUpdateType.UserJoined, session.UserName); - SendGroupUpdate(session, BroadcastType.AllExceptSession, updateOthers); + SendGroupUpdate(session, BroadcastType.AllExceptCurrentSession, updateOthers); // Client join and play, syncing will happen client side if (!_group.IsPaused) { var playCommand = NewSyncplayCommand(SendCommandType.Play); - SendCommand(session, BroadcastType.SingleSession, playCommand); + SendCommand(session, BroadcastType.CurrentSession, playCommand); } else { var pauseCommand = NewSyncplayCommand(SendCommandType.Pause); - SendCommand(session, BroadcastType.SingleSession, pauseCommand); + SendCommand(session, BroadcastType.CurrentSession, pauseCommand); } } else @@ -228,7 +267,7 @@ namespace Emby.Server.Implementations.Syncplay playRequest.ItemIds = new Guid[] { _group.PlayingItem.Id }; playRequest.StartPositionTicks = _group.PositionTicks; var update = NewSyncplayGroupUpdate(GroupUpdateType.PrepareSession, playRequest); - SendGroupUpdate(session, BroadcastType.SingleSession, update); + SendGroupUpdate(session, BroadcastType.CurrentSession, update); } } @@ -236,182 +275,250 @@ namespace Emby.Server.Implementations.Syncplay public void SessionLeave(SessionInfo session) { _group.RemoveSession(session); - _syncplayManager.UnmapSessionFromGroup(session, this); + _syncplayManager.RemoveSessionFromGroup(session, this); var updateSession = NewSyncplayGroupUpdate(GroupUpdateType.GroupLeft, _group.PositionTicks); - SendGroupUpdate(session, BroadcastType.SingleSession, updateSession); + SendGroupUpdate(session, BroadcastType.CurrentSession, updateSession); var updateOthers = NewSyncplayGroupUpdate(GroupUpdateType.UserLeft, session.UserName); - SendGroupUpdate(session, BroadcastType.AllExceptSession, updateOthers); + SendGroupUpdate(session, BroadcastType.AllExceptCurrentSession, updateOthers); } /// public void HandleRequest(SessionInfo session, PlaybackRequest request) { - if (request.Type.Equals(PlaybackRequestType.Play)) + // The server's job is to mantain a consistent state to which clients refer to, + // as also to notify clients of state changes. + // The actual syncing of media playback happens client side. + // Clients are aware of the server's time and use it to sync. + switch (request.Type) { - if (_group.IsPaused) - { - var delay = _group.GetHighestPing() * 2; - delay = delay < _group.DefaulPing ? _group.DefaulPing : delay; - - _group.IsPaused = false; - _group.LastActivity = DateTime.UtcNow.AddMilliseconds( - delay - ); + case PlaybackRequestType.Play: + HandlePlayRequest(session, request); + break; + case PlaybackRequestType.Pause: + HandlePauseRequest(session, request); + break; + case PlaybackRequestType.Seek: + HandleSeekRequest(session, request); + break; + case PlaybackRequestType.Buffering: + HandleBufferingRequest(session, request); + break; + case PlaybackRequestType.BufferingDone: + HandleBufferingDoneRequest(session, request); + break; + case PlaybackRequestType.UpdatePing: + HandlePingUpdateRequest(session, request); + break; + } + } - var command = NewSyncplayCommand(SendCommandType.Play); - SendCommand(session, BroadcastType.AllGroup, command); - } - else - { - // Client got lost - var command = NewSyncplayCommand(SendCommandType.Play); - SendCommand(session, BroadcastType.SingleSession, command); - } + /// + /// Handles a play action requested by a session. + /// + /// The session. + /// The play action. + private void HandlePlayRequest(SessionInfo session, PlaybackRequest request) + { + if (_group.IsPaused) + { + // Pick a suitable time that accounts for latency + var delay = _group.GetHighestPing() * 2; + delay = delay < _group.DefaulPing ? _group.DefaulPing : delay; + + // Unpause group and set starting point in future + // Clients will start playback at LastActivity (datetime) from PositionTicks (playback position) + // The added delay does not guarantee, of course, that the command will be received in time + // Playback synchronization will mainly happen client side + _group.IsPaused = false; + _group.LastActivity = DateTime.UtcNow.AddMilliseconds( + delay + ); + + var command = NewSyncplayCommand(SendCommandType.Play); + SendCommand(session, BroadcastType.AllGroup, command); } - else if (request.Type.Equals(PlaybackRequestType.Pause)) + else { - if (!_group.IsPaused) - { - _group.IsPaused = true; - var currentTime = DateTime.UtcNow; - var elapsedTime = currentTime - _group.LastActivity; - _group.LastActivity = currentTime; - _group.PositionTicks += elapsedTime.Ticks > 0 ? elapsedTime.Ticks : 0; + // Client got lost, sending current state + var command = NewSyncplayCommand(SendCommandType.Play); + SendCommand(session, BroadcastType.CurrentSession, command); + } + } - var command = NewSyncplayCommand(SendCommandType.Pause); - SendCommand(session, BroadcastType.AllGroup, command); - } - else - { - var command = NewSyncplayCommand(SendCommandType.Pause); - SendCommand(session, BroadcastType.SingleSession, command); - } + /// + /// Handles a pause action requested by a session. + /// + /// The session. + /// The pause action. + private void HandlePauseRequest(SessionInfo session, PlaybackRequest request) + { + if (!_group.IsPaused) + { + // Pause group and compute the media playback position + _group.IsPaused = true; + var currentTime = DateTime.UtcNow; + var elapsedTime = currentTime - _group.LastActivity; + _group.LastActivity = currentTime; + // Seek only if playback actually started + // (a pause request may be issued during the delay added to account for latency) + _group.PositionTicks += elapsedTime.Ticks > 0 ? elapsedTime.Ticks : 0; + + var command = NewSyncplayCommand(SendCommandType.Pause); + SendCommand(session, BroadcastType.AllGroup, command); } - else if (request.Type.Equals(PlaybackRequestType.Seek)) + else { - // Sanitize PositionTicks - var ticks = request.PositionTicks ??= 0; - ticks = ticks >= 0 ? ticks : 0; - if (_group.PlayingItem.RunTimeTicks != null) - { - var runTimeTicks = _group.PlayingItem.RunTimeTicks ??= 0; - ticks = ticks > runTimeTicks ? runTimeTicks : ticks; - } + // Client got lost, sending current state + var command = NewSyncplayCommand(SendCommandType.Pause); + SendCommand(session, BroadcastType.CurrentSession, command); + } + } + + /// + /// Handles a seek action requested by a session. + /// + /// The session. + /// The seek action. + private void HandleSeekRequest(SessionInfo session, PlaybackRequest request) + { + // Sanitize PositionTicks + var ticks = request.PositionTicks ??= 0; + ticks = ticks >= 0 ? ticks : 0; + if (_group.PlayingItem.RunTimeTicks != null) + { + var runTimeTicks = _group.PlayingItem.RunTimeTicks ??= 0; + ticks = ticks > runTimeTicks ? runTimeTicks : ticks; + } + + // Pause and seek + _group.IsPaused = true; + _group.PositionTicks = ticks; + _group.LastActivity = DateTime.UtcNow; + + var command = NewSyncplayCommand(SendCommandType.Seek); + SendCommand(session, BroadcastType.AllGroup, command); + } + /// + /// Handles a buffering action requested by a session. + /// + /// The session. + /// The buffering action. + private void HandleBufferingRequest(SessionInfo session, PlaybackRequest request) + { + if (!_group.IsPaused) + { + // Pause group and compute the media playback position _group.IsPaused = true; - _group.PositionTicks = ticks; - _group.LastActivity = DateTime.UtcNow; + var currentTime = DateTime.UtcNow; + var elapsedTime = currentTime - _group.LastActivity; + _group.LastActivity = currentTime; + _group.PositionTicks += elapsedTime.Ticks > 0 ? elapsedTime.Ticks : 0; - var command = NewSyncplayCommand(SendCommandType.Seek); - SendCommand(session, BroadcastType.AllGroup, command); + _group.SetBuffering(session, true); + + // Send pause command to all non-buffering sessions + var command = NewSyncplayCommand(SendCommandType.Pause); + SendCommand(session, BroadcastType.AllReady, command); + + var updateOthers = NewSyncplayGroupUpdate(GroupUpdateType.GroupWait, session.UserName); + SendGroupUpdate(session, BroadcastType.AllExceptCurrentSession, updateOthers); } - // TODO: client does not implement this yet - else if (request.Type.Equals(PlaybackRequestType.Buffering)) + else { - if (!_group.IsPaused) - { - _group.IsPaused = true; - var currentTime = DateTime.UtcNow; - var elapsedTime = currentTime - _group.LastActivity; - _group.LastActivity = currentTime; - _group.PositionTicks += elapsedTime.Ticks > 0 ? elapsedTime.Ticks : 0; + // Client got lost, sending current state + var command = NewSyncplayCommand(SendCommandType.Pause); + SendCommand(session, BroadcastType.CurrentSession, command); + } + } - _group.SetBuffering(session, true); + /// + /// Handles a buffering-done action requested by a session. + /// + /// The session. + /// The buffering-done action. + private void HandleBufferingDoneRequest(SessionInfo session, PlaybackRequest request) + { + if (_group.IsPaused) + { + _group.SetBuffering(session, false); - // Send pause command to all non-buffering sessions - var command = NewSyncplayCommand(SendCommandType.Pause); - SendCommand(session, BroadcastType.AllReady, command); + var when = request.When ??= DateTime.UtcNow; + var currentTime = DateTime.UtcNow; + var elapsedTime = currentTime - when; + var clientPosition = TimeSpan.FromTicks(request.PositionTicks ??= 0) + elapsedTime; + var delay = _group.PositionTicks - clientPosition.Ticks; - var updateOthers = NewSyncplayGroupUpdate(GroupUpdateType.GroupWait, session.UserName); - SendGroupUpdate(session, BroadcastType.AllExceptSession, updateOthers); - } - else + if (_group.IsBuffering()) { + // Others are buffering, tell this client to pause when ready var command = NewSyncplayCommand(SendCommandType.Pause); - SendCommand(session, BroadcastType.SingleSession, command); + command.When = currentTime.AddMilliseconds( + delay + ).ToUniversalTime().ToString("o"); + SendCommand(session, BroadcastType.CurrentSession, command); } - } - // TODO: client does not implement this yet - else if (request.Type.Equals(PlaybackRequestType.BufferingComplete)) - { - if (_group.IsPaused) + else { - _group.SetBuffering(session, false); - - if (_group.IsBuffering()) { - // Others are buffering, tell this client to pause when ready - var when = request.When ??= DateTime.UtcNow; - var currentTime = DateTime.UtcNow; - var elapsedTime = currentTime - when; - var clientPosition = TimeSpan.FromTicks(request.PositionTicks ??= 0) + elapsedTime; - var delay = _group.PositionTicks - clientPosition.Ticks; - - var command = NewSyncplayCommand(SendCommandType.Pause); - command.When = currentTime.AddMilliseconds( + // Let other clients resume as soon as the buffering client catches up + _group.IsPaused = false; + + if (delay > _group.GetHighestPing() * 2) + { + // Client that was buffering is recovering, notifying others to resume + _group.LastActivity = currentTime.AddMilliseconds( delay - ).ToUniversalTime().ToString("o"); - SendCommand(session, BroadcastType.SingleSession, command); + ); + var command = NewSyncplayCommand(SendCommandType.Play); + SendCommand(session, BroadcastType.AllExceptCurrentSession, command); } else { - // Let other clients resume as soon as the buffering client catches up - var when = request.When ??= DateTime.UtcNow; - var currentTime = DateTime.UtcNow; - var elapsedTime = currentTime - when; - var clientPosition = TimeSpan.FromTicks(request.PositionTicks ??= 0) + elapsedTime; - var delay = _group.PositionTicks - clientPosition.Ticks; - - _group.IsPaused = false; - - if (delay > _group.GetHighestPing() * 2) - { - // Client that was buffering is recovering, notifying others to resume - _group.LastActivity = currentTime.AddMilliseconds( - delay - ); - var command = NewSyncplayCommand(SendCommandType.Play); - SendCommand(session, BroadcastType.AllExceptSession, command); - } - else - { - // Client, that was buffering, resumed playback but did not update others in time - delay = _group.GetHighestPing() * 2; - delay = delay < _group.DefaulPing ? _group.DefaulPing : delay; - - _group.LastActivity = currentTime.AddMilliseconds( - delay - ); - - var command = NewSyncplayCommand(SendCommandType.Play); - SendCommand(session, BroadcastType.AllGroup, command); - } - } - } - else - { - // Make sure client has latest group state - var command = NewSyncplayCommand(SendCommandType.Play); - SendCommand(session, BroadcastType.SingleSession, command); + // Client, that was buffering, resumed playback but did not update others in time + delay = _group.GetHighestPing() * 2; + delay = delay < _group.DefaulPing ? _group.DefaulPing : delay; + + _group.LastActivity = currentTime.AddMilliseconds( + delay + ); + + var command = NewSyncplayCommand(SendCommandType.Play); + SendCommand(session, BroadcastType.AllGroup, command); + } } } - else if (request.Type.Equals(PlaybackRequestType.UpdatePing)) + else { - _group.UpdatePing(session, request.Ping ??= _group.DefaulPing); + // Group was not waiting, make sure client has latest state + var command = NewSyncplayCommand(SendCommandType.Play); + SendCommand(session, BroadcastType.CurrentSession, command); } } + /// + /// Updates ping of a session. + /// + /// The session. + /// The update. + private void HandlePingUpdateRequest(SessionInfo session, PlaybackRequest request) + { + // Collected pings are used to account for network latency when unpausing playback + _group.UpdatePing(session, request.Ping ??= _group.DefaulPing); + } + /// public GroupInfoView GetInfo() { - var info = new GroupInfoView(); - info.GroupId = GetGroupId().ToString(); - info.PlayingItemName = _group.PlayingItem.Name; - info.PlayingItemId = _group.PlayingItem.Id.ToString(); - info.PositionTicks = _group.PositionTicks; - info.Partecipants = _group.Partecipants.Values.Select(session => session.Session.UserName).ToArray(); - return info; + return new GroupInfoView() + { + GroupId = GetGroupId().ToString(), + PlayingItemName = _group.PlayingItem.Name, + PlayingItemId = _group.PlayingItem.Id.ToString(), + PositionTicks = _group.PositionTicks, + Participants = _group.Participants.Values.Select(session => session.Session.UserName).ToArray() + }; } } } diff --git a/Emby.Server.Implementations/Syncplay/SyncplayManager.cs b/Emby.Server.Implementations/Syncplay/SyncplayManager.cs index 60d70e5fd..e7df8925e 100644 --- a/Emby.Server.Implementations/Syncplay/SyncplayManager.cs +++ b/Emby.Server.Implementations/Syncplay/SyncplayManager.cs @@ -49,7 +49,7 @@ namespace Emby.Server.Implementations.Syncplay /// The groups. /// private readonly ConcurrentDictionary _groups = - new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); + new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); private bool _disposed = false; @@ -64,8 +64,8 @@ namespace Emby.Server.Implementations.Syncplay _sessionManager = sessionManager; _libraryManager = libraryManager; - _sessionManager.SessionEnded += _sessionManager_SessionEnded; - _sessionManager.PlaybackStopped += _sessionManager_PlaybackStopped; + _sessionManager.SessionEnded += OnSessionManagerSessionEnded; + _sessionManager.PlaybackStopped += OnSessionManagerPlaybackStopped; } /// @@ -92,8 +92,8 @@ namespace Emby.Server.Implementations.Syncplay return; } - _sessionManager.SessionEnded -= _sessionManager_SessionEnded; - _sessionManager.PlaybackStopped -= _sessionManager_PlaybackStopped; + _sessionManager.SessionEnded -= OnSessionManagerSessionEnded; + _sessionManager.PlaybackStopped -= OnSessionManagerPlaybackStopped; _disposed = true; } @@ -106,14 +106,14 @@ namespace Emby.Server.Implementations.Syncplay } } - void _sessionManager_SessionEnded(object sender, SessionEventArgs e) + private void OnSessionManagerSessionEnded(object sender, SessionEventArgs e) { var session = e.SessionInfo; if (!IsSessionInGroup(session)) return; LeaveGroup(session); } - void _sessionManager_PlaybackStopped(object sender, PlaybackStopEventArgs e) + private void OnSessionManagerPlaybackStopped(object sender, PlaybackStopEventArgs e) { var session = e.Session; if (!IsSessionInGroup(session)) return; @@ -130,13 +130,13 @@ namespace Emby.Server.Implementations.Syncplay var item = _libraryManager.GetItemById(itemId); var hasParentalRatingAccess = user.Policy.MaxParentalRating.HasValue ? item.InheritedParentalRatingValue <= user.Policy.MaxParentalRating : true; - if (!user.Policy.EnableAllFolders) + if (!user.Policy.EnableAllFolders && hasParentalRatingAccess) { var collections = _libraryManager.GetCollectionFolders(item).Select( folder => folder.Id.ToString("N", CultureInfo.InvariantCulture) ); var intersect = collections.Intersect(user.Policy.EnabledFolders); - return intersect.Count() > 0 && hasParentalRatingAccess; + return intersect.Count() > 0; } else { @@ -165,7 +165,7 @@ namespace Emby.Server.Implementations.Syncplay if (user.Policy.SyncplayAccess != SyncplayAccess.CreateAndJoinGroups) { - // TODO: shall an error message be sent back to the client? + // TODO: report the error to the client throw new ArgumentException("User does not have permission to create groups"); } @@ -187,22 +187,16 @@ namespace Emby.Server.Implementations.Syncplay if (user.Policy.SyncplayAccess == SyncplayAccess.None) { - // TODO: shall an error message be sent back to the client? + // TODO: report the error to the client throw new ArgumentException("User does not have access to syncplay"); } - if (IsSessionInGroup(session)) - { - if (GetSessionGroup(session).Equals(groupId)) return; - LeaveGroup(session); - } - ISyncplayController group; _groups.TryGetValue(groupId, out group); if (group == null) { - _logger.LogError("Syncplaymanager JoinGroup: " + groupId + " does not exist."); + _logger.LogWarning("Syncplaymanager JoinGroup: {0} does not exist.", groupId); var update = new GroupUpdate(); update.Type = GroupUpdateType.NotInGroup; @@ -215,20 +209,26 @@ namespace Emby.Server.Implementations.Syncplay throw new ArgumentException("User does not have access to playing item"); } + if (IsSessionInGroup(session)) + { + if (GetSessionGroup(session).Equals(groupId)) return; + LeaveGroup(session); + } + group.SessionJoin(session, request); } /// public void LeaveGroup(SessionInfo session) { - // TODO: what happens to users that are in a group and get their permissions revoked? + // TODO: determine what happens to users that are in a group and get their permissions revoked ISyncplayController group; _sessionToGroupMap.TryGetValue(session.Id, out group); if (group == null) { - _logger.LogWarning("Syncplaymanager HandleRequest: " + session.Id + " not in group."); + _logger.LogWarning("Syncplaymanager LeaveGroup: {0} does not belong to any group.", session.Id); var update = new GroupUpdate(); update.Type = GroupUpdateType.NotInGroup; @@ -257,9 +257,7 @@ namespace Emby.Server.Implementations.Syncplay if (session.NowPlayingItem != null) { return _groups.Values.Where( - group => HasAccessToItem(user, group.GetPlayingItemId()) - ).Where( - group => group.GetPlayingItemId().Equals(session.FullNowPlayingItem.Id) + group => group.GetPlayingItemId().Equals(session.FullNowPlayingItem.Id) && HasAccessToItem(user, group.GetPlayingItemId()) ).Select( group => group.GetInfo() ).ToList(); @@ -291,7 +289,7 @@ namespace Emby.Server.Implementations.Syncplay if (group == null) { - _logger.LogWarning("Syncplaymanager HandleRequest: " + session.Id + " not in group."); + _logger.LogWarning("Syncplaymanager HandleRequest: {0} not in a group.", session.Id); var update = new GroupUpdate(); update.Type = GroupUpdateType.NotInGroup; @@ -302,7 +300,7 @@ namespace Emby.Server.Implementations.Syncplay } /// - public void MapSessionToGroup(SessionInfo session, ISyncplayController group) + public void AddSessionToGroup(SessionInfo session, ISyncplayController group) { if (IsSessionInGroup(session)) { @@ -312,7 +310,7 @@ namespace Emby.Server.Implementations.Syncplay } /// - public void UnmapSessionFromGroup(SessionInfo session, ISyncplayController group) + public void RemoveSessionFromGroup(SessionInfo session, ISyncplayController group) { if (!IsSessionInGroup(session)) { diff --git a/MediaBrowser.Api/Syncplay/SyncplayService.cs b/MediaBrowser.Api/Syncplay/SyncplayService.cs index af220ed81..2eaf9ce83 100644 --- a/MediaBrowser.Api/Syncplay/SyncplayService.cs +++ b/MediaBrowser.Api/Syncplay/SyncplayService.cs @@ -90,12 +90,20 @@ namespace MediaBrowser.Api.Syncplay [ApiMember(Name = "SessionId", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] public string SessionId { get; set; } + /// + /// Gets or sets the date used to pin PositionTicks in time. + /// + /// The date related to PositionTicks. [ApiMember(Name = "When", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")] public string When { get; set; } [ApiMember(Name = "PositionTicks", IsRequired = true, DataType = "long", ParameterType = "query", Verb = "POST")] public long PositionTicks { get; set; } + /// + /// Gets or sets whether this is a buffering or a buffering-done request. + /// + /// true if buffering is complete; false otherwise. [ApiMember(Name = "Resume", IsRequired = true, DataType = "bool", ParameterType = "query", Verb = "POST")] public bool Resume { get; set; } } @@ -162,8 +170,10 @@ namespace MediaBrowser.Api.Syncplay public void Post(SyncplayJoinGroup request) { var currentSession = GetSession(_sessionContext); - var joinRequest = new JoinGroupRequest(); - joinRequest.GroupId = Guid.Parse(request.GroupId); + var joinRequest = new JoinGroupRequest() + { + GroupId = Guid.Parse(request.GroupId) + }; try { joinRequest.PlayingItemId = Guid.Parse(request.PlayingItemId); @@ -207,8 +217,10 @@ namespace MediaBrowser.Api.Syncplay public void Post(SyncplayPlayRequest request) { var currentSession = GetSession(_sessionContext); - var syncplayRequest = new PlaybackRequest(); - syncplayRequest.Type = PlaybackRequestType.Play; + var syncplayRequest = new PlaybackRequest() + { + Type = PlaybackRequestType.Play + }; _syncplayManager.HandleRequest(currentSession, syncplayRequest); } @@ -219,8 +231,10 @@ namespace MediaBrowser.Api.Syncplay public void Post(SyncplayPauseRequest request) { var currentSession = GetSession(_sessionContext); - var syncplayRequest = new PlaybackRequest(); - syncplayRequest.Type = PlaybackRequestType.Pause; + var syncplayRequest = new PlaybackRequest() + { + Type = PlaybackRequestType.Pause + }; _syncplayManager.HandleRequest(currentSession, syncplayRequest); } @@ -231,9 +245,11 @@ namespace MediaBrowser.Api.Syncplay public void Post(SyncplaySeekRequest request) { var currentSession = GetSession(_sessionContext); - var syncplayRequest = new PlaybackRequest(); - syncplayRequest.Type = PlaybackRequestType.Seek; - syncplayRequest.PositionTicks = request.PositionTicks; + var syncplayRequest = new PlaybackRequest() + { + Type = PlaybackRequestType.Seek, + PositionTicks = request.PositionTicks + }; _syncplayManager.HandleRequest(currentSession, syncplayRequest); } @@ -244,10 +260,12 @@ namespace MediaBrowser.Api.Syncplay public void Post(SyncplayBufferingRequest request) { var currentSession = GetSession(_sessionContext); - var syncplayRequest = new PlaybackRequest(); - syncplayRequest.Type = request.Resume ? PlaybackRequestType.BufferingComplete : PlaybackRequestType.Buffering; - syncplayRequest.When = DateTime.Parse(request.When); - syncplayRequest.PositionTicks = request.PositionTicks; + var syncplayRequest = new PlaybackRequest() + { + Type = request.Resume ? PlaybackRequestType.BufferingDone : PlaybackRequestType.Buffering, + When = DateTime.Parse(request.When), + PositionTicks = request.PositionTicks + }; _syncplayManager.HandleRequest(currentSession, syncplayRequest); } @@ -258,9 +276,11 @@ namespace MediaBrowser.Api.Syncplay public void Post(SyncplayUpdatePing request) { var currentSession = GetSession(_sessionContext); - var syncplayRequest = new PlaybackRequest(); - syncplayRequest.Type = PlaybackRequestType.UpdatePing; - syncplayRequest.Ping = Convert.ToInt64(request.Ping); + var syncplayRequest = new PlaybackRequest() + { + Type = PlaybackRequestType.UpdatePing, + Ping = Convert.ToInt64(request.Ping) + }; _syncplayManager.HandleRequest(currentSession, syncplayRequest); } } diff --git a/MediaBrowser.Api/Syncplay/TimeSyncService.cs b/MediaBrowser.Api/Syncplay/TimeSyncService.cs index a69e0e293..897413015 100644 --- a/MediaBrowser.Api/Syncplay/TimeSyncService.cs +++ b/MediaBrowser.Api/Syncplay/TimeSyncService.cs @@ -54,7 +54,6 @@ namespace MediaBrowser.Api.Syncplay var response = new UtcTimeResponse(); response.RequestReceptionTime = requestReceptionTime; - var currentSession = GetSession(_sessionContext); // Important to keep the following two lines at the end var responseTransmissionTime = DateTime.UtcNow.ToUniversalTime().ToString("o"); diff --git a/MediaBrowser.Controller/Syncplay/GroupInfo.cs b/MediaBrowser.Controller/Syncplay/GroupInfo.cs index 42e85ef86..8e886a2cb 100644 --- a/MediaBrowser.Controller/Syncplay/GroupInfo.cs +++ b/MediaBrowser.Controller/Syncplay/GroupInfo.cs @@ -46,11 +46,11 @@ namespace MediaBrowser.Controller.Syncplay public DateTime LastActivity { get; set; } /// - /// Gets the partecipants. + /// Gets the participants. /// - /// The partecipants. - public readonly ConcurrentDictionary Partecipants = - new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); + /// The participants, or members of the group. + public readonly ConcurrentDictionary Participants = + new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); /// /// Checks if a session is in this group. @@ -58,7 +58,7 @@ namespace MediaBrowser.Controller.Syncplay /// true if the session is in this group; false otherwise. public bool ContainsSession(string sessionId) { - return Partecipants.ContainsKey(sessionId); + return Participants.ContainsKey(sessionId); } /// @@ -72,7 +72,7 @@ namespace MediaBrowser.Controller.Syncplay member.Session = session; member.Ping = DefaulPing; member.IsBuffering = false; - Partecipants[session.Id.ToString()] = member; + Participants[session.Id.ToString()] = member; } /// @@ -84,7 +84,7 @@ namespace MediaBrowser.Controller.Syncplay { if (!ContainsSession(session.Id.ToString())) return; GroupMember member; - Partecipants.Remove(session.Id.ToString(), out member); + Participants.Remove(session.Id.ToString(), out member); } /// @@ -95,7 +95,7 @@ namespace MediaBrowser.Controller.Syncplay public void UpdatePing(SessionInfo session, long ping) { if (!ContainsSession(session.Id.ToString())) return; - Partecipants[session.Id.ToString()].Ping = ping; + Participants[session.Id.ToString()].Ping = ping; } /// @@ -105,7 +105,7 @@ namespace MediaBrowser.Controller.Syncplay public long GetHighestPing() { long max = Int64.MinValue; - foreach (var session in Partecipants.Values) + foreach (var session in Participants.Values) { max = Math.Max(max, session.Ping); } @@ -120,7 +120,7 @@ namespace MediaBrowser.Controller.Syncplay public void SetBuffering(SessionInfo session, bool isBuffering) { if (!ContainsSession(session.Id.ToString())) return; - Partecipants[session.Id.ToString()].IsBuffering = isBuffering; + Participants[session.Id.ToString()].IsBuffering = isBuffering; } /// @@ -129,7 +129,7 @@ namespace MediaBrowser.Controller.Syncplay /// true if there is a session buffering in the group; false otherwise. public bool IsBuffering() { - foreach (var session in Partecipants.Values) + foreach (var session in Participants.Values) { if (session.IsBuffering) return true; } @@ -142,7 +142,7 @@ namespace MediaBrowser.Controller.Syncplay /// true if the group is empty; false otherwise. public bool IsEmpty() { - return Partecipants.Count == 0; + return Participants.Count == 0; } } } diff --git a/MediaBrowser.Controller/Syncplay/ISyncplayManager.cs b/MediaBrowser.Controller/Syncplay/ISyncplayManager.cs index d0cf8fa9c..433d6d8bc 100644 --- a/MediaBrowser.Controller/Syncplay/ISyncplayManager.cs +++ b/MediaBrowser.Controller/Syncplay/ISyncplayManager.cs @@ -50,7 +50,7 @@ namespace MediaBrowser.Controller.Syncplay /// The session. /// The group. /// - void MapSessionToGroup(SessionInfo session, ISyncplayController group); + void AddSessionToGroup(SessionInfo session, ISyncplayController group); /// /// Unmaps a session from a group. @@ -58,6 +58,6 @@ namespace MediaBrowser.Controller.Syncplay /// The session. /// The group. /// - void UnmapSessionFromGroup(SessionInfo session, ISyncplayController group); + void RemoveSessionFromGroup(SessionInfo session, ISyncplayController group); } } diff --git a/MediaBrowser.Model/Syncplay/GroupInfoModel.cs b/MediaBrowser.Model/Syncplay/GroupInfoModel.cs deleted file mode 100644 index 599c0dbfc..000000000 --- a/MediaBrowser.Model/Syncplay/GroupInfoModel.cs +++ /dev/null @@ -1,38 +0,0 @@ -namespace MediaBrowser.Model.Syncplay -{ - /// - /// Class GroupInfoModel. - /// - public class GroupInfoView - { - /// - /// Gets or sets the group identifier. - /// - /// The group identifier. - public string GroupId { get; set; } - - /// - /// Gets or sets the playing item id. - /// - /// The playing item id. - public string PlayingItemId { get; set; } - - /// - /// Gets or sets the playing item name. - /// - /// The playing item name. - public string PlayingItemName { get; set; } - - /// - /// Gets or sets the position ticks. - /// - /// The position ticks. - public long PositionTicks { get; set; } - - /// - /// Gets or sets the partecipants. - /// - /// The partecipants. - public string[] Partecipants { get; set; } - } -} diff --git a/MediaBrowser.Model/Syncplay/GroupInfoView.cs b/MediaBrowser.Model/Syncplay/GroupInfoView.cs new file mode 100644 index 000000000..50ad70630 --- /dev/null +++ b/MediaBrowser.Model/Syncplay/GroupInfoView.cs @@ -0,0 +1,38 @@ +namespace MediaBrowser.Model.Syncplay +{ + /// + /// Class GroupInfoView. + /// + public class GroupInfoView + { + /// + /// Gets or sets the group identifier. + /// + /// The group identifier. + public string GroupId { get; set; } + + /// + /// Gets or sets the playing item id. + /// + /// The playing item id. + public string PlayingItemId { get; set; } + + /// + /// Gets or sets the playing item name. + /// + /// The playing item name. + public string PlayingItemName { get; set; } + + /// + /// Gets or sets the position ticks. + /// + /// The position ticks. + public long PositionTicks { get; set; } + + /// + /// Gets or sets the participants. + /// + /// The participants. + public string[] Participants { get; set; } + } +} diff --git a/MediaBrowser.Model/Syncplay/PlaybackRequestType.cs b/MediaBrowser.Model/Syncplay/PlaybackRequestType.cs index 3d99b2718..b3d49d09e 100644 --- a/MediaBrowser.Model/Syncplay/PlaybackRequestType.cs +++ b/MediaBrowser.Model/Syncplay/PlaybackRequestType.cs @@ -24,7 +24,7 @@ namespace MediaBrowser.Model.Syncplay /// /// A user is signaling that playback resumed. /// - BufferingComplete = 4, + BufferingDone = 4, /// /// A user is reporting its ping. /// -- cgit v1.2.3 From 3623aafcb60dec4f4f5055046717d895b7597b60 Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Sat, 2 May 2020 01:30:04 +0200 Subject: Make SonarCloud happy --- Emby.Server.Implementations/ApplicationHost.cs | 5 +---- .../HttpServer/HttpListenerHost.cs | 25 +--------------------- .../HttpServer/WebSocketConnection.cs | 8 ------- .../Session/WebSocketController.cs | 2 +- MediaBrowser.Controller/Net/IHttpServer.cs | 5 ++--- 5 files changed, 5 insertions(+), 40 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index 6279ce5d0..11fed24f7 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -93,7 +93,6 @@ using MediaBrowser.Model.Serialization; using MediaBrowser.Model.Services; using MediaBrowser.Model.System; using MediaBrowser.Model.Tasks; -using MediaBrowser.Model.Updates; using MediaBrowser.Providers.Chapters; using MediaBrowser.Providers.Manager; using MediaBrowser.Providers.Plugins.TheTvdb; @@ -101,12 +100,10 @@ using MediaBrowser.Providers.Subtitles; using MediaBrowser.WebDashboard.Api; using MediaBrowser.XbmcMetadata.Providers; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.Extensions; -using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; -using OperatingSystem = MediaBrowser.Common.System.OperatingSystem; using Prometheus.DotNetRuntime; +using OperatingSystem = MediaBrowser.Common.System.OperatingSystem; namespace Emby.Server.Implementations { diff --git a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs index e75140d6c..7358c1a81 100644 --- a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs +++ b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs @@ -28,12 +28,11 @@ using Microsoft.AspNetCore.WebUtilities; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; -using Microsoft.Net.Http.Headers; using ServiceStack.Text.Jsv; namespace Emby.Server.Implementations.HttpServer { - public class HttpListenerHost : IHttpServer, IDisposable + public class HttpListenerHost : IHttpServer { /// /// The key for a setting that specifies the default redirect path @@ -699,28 +698,6 @@ namespace Emby.Server.Implementations.HttpServer return _baseUrlPrefix + NormalizeUrlPath(path); } - /// - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - protected virtual void Dispose(bool disposing) - { - if (_disposed) - { - return; - } - - if (disposing) - { - // TODO: - } - - _disposed = true; - } - /// /// Processes the web socket message received. /// diff --git a/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs b/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs index 1af748ebc..095725c50 100644 --- a/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs +++ b/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs @@ -36,8 +36,6 @@ namespace Emby.Server.Implementations.HttpServer /// private readonly WebSocket _socket; - private bool _disposed = false; - /// /// Initializes a new instance of the class. /// @@ -221,12 +219,6 @@ namespace Emby.Server.Implementations.HttpServer }; await OnReceive(info).ConfigureAwait(false); - - // Stop reading if there's no more data coming - if (result.IsCompleted) - { - return; - } } } } diff --git a/Emby.Server.Implementations/Session/WebSocketController.cs b/Emby.Server.Implementations/Session/WebSocketController.cs index c7ef9b1ce..a0274acd2 100644 --- a/Emby.Server.Implementations/Session/WebSocketController.cs +++ b/Emby.Server.Implementations/Session/WebSocketController.cs @@ -21,7 +21,7 @@ namespace Emby.Server.Implementations.Session private readonly ISessionManager _sessionManager; private readonly SessionInfo _session; - private List _sockets; + private readonly List _sockets; private bool _disposed = false; public WebSocketController( diff --git a/MediaBrowser.Controller/Net/IHttpServer.cs b/MediaBrowser.Controller/Net/IHttpServer.cs index 666ac1cfe..f1c441761 100644 --- a/MediaBrowser.Controller/Net/IHttpServer.cs +++ b/MediaBrowser.Controller/Net/IHttpServer.cs @@ -2,15 +2,14 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; using MediaBrowser.Model.Events; -using MediaBrowser.Model.Services; using Microsoft.AspNetCore.Http; namespace MediaBrowser.Controller.Net { /// - /// Interface IHttpServer + /// Interface IHttpServer. /// - public interface IHttpServer : IDisposable + public interface IHttpServer { /// /// Gets the URL prefix. -- cgit v1.2.3 From 6e22e9222b68ad117550c02a8cbce2d65878f50b Mon Sep 17 00:00:00 2001 From: gion Date: Mon, 4 May 2020 19:46:02 +0200 Subject: Fix code issues --- .../HttpServer/WebSocketConnection.cs | 4 +- .../Session/SessionWebSocketListener.cs | 127 +++++++++-------- .../Syncplay/SyncplayController.cs | 158 ++++++++++++--------- .../Syncplay/SyncplayManager.cs | 61 ++++---- MediaBrowser.Api/Syncplay/SyncplayService.cs | 85 +++++++---- MediaBrowser.Api/Syncplay/TimeSyncService.cs | 13 +- MediaBrowser.Controller/Syncplay/GroupInfo.cs | 8 +- .../Syncplay/ISyncplayController.cs | 13 +- .../Syncplay/ISyncplayManager.cs | 16 ++- MediaBrowser.Model/Syncplay/GroupUpdateType.cs | 6 +- MediaBrowser.Model/Syncplay/PlaybackRequest.cs | 2 +- 11 files changed, 281 insertions(+), 212 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs b/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs index c819c163a..4c33ff71b 100644 --- a/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs +++ b/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs @@ -238,10 +238,10 @@ namespace Emby.Server.Implementations.HttpServer return _socket.SendAsync(text, true, cancellationToken); } - private Task SendKeepAliveResponse() + private void SendKeepAliveResponse() { LastKeepAliveDate = DateTime.UtcNow; - return SendAsync(new WebSocketMessage + SendAsync(new WebSocketMessage { MessageType = "KeepAlive" }, CancellationToken.None); diff --git a/Emby.Server.Implementations/Session/SessionWebSocketListener.cs b/Emby.Server.Implementations/Session/SessionWebSocketListener.cs index 7a316b070..d1ee22ea8 100644 --- a/Emby.Server.Implementations/Session/SessionWebSocketListener.cs +++ b/Emby.Server.Implementations/Session/SessionWebSocketListener.cs @@ -84,10 +84,10 @@ namespace Emby.Server.Implementations.Session _logger = loggerFactory.CreateLogger(GetType().Name); _json = json; _httpServer = httpServer; - httpServer.WebSocketConnected += _serverManager_WebSocketConnected; + httpServer.WebSocketConnected += OnServerManagerWebSocketConnected; } - void _serverManager_WebSocketConnected(object sender, GenericEventArgs e) + void OnServerManagerWebSocketConnected(object sender, GenericEventArgs e) { var session = GetSession(e.Argument.QueryString, e.Argument.RemoteEndPoint); @@ -121,7 +121,7 @@ namespace Emby.Server.Implementations.Session public void Dispose() { - _httpServer.WebSocketConnected -= _serverManager_WebSocketConnected; + _httpServer.WebSocketConnected -= OnServerManagerWebSocketConnected; StopKeepAlive(); } @@ -149,7 +149,7 @@ namespace Emby.Server.Implementations.Session private void OnWebSocketClosed(object sender, EventArgs e) { var webSocket = (IWebSocketConnection) sender; - _logger.LogDebug("WebSockets {0} closed.", webSocket); + _logger.LogDebug("WebSocket {0} is closed.", webSocket); RemoveWebSocket(webSocket); } @@ -157,7 +157,7 @@ namespace Emby.Server.Implementations.Session /// Adds a WebSocket to the KeepAlive watchlist. /// /// The WebSocket to monitor. - private async Task KeepAliveWebSocket(IWebSocketConnection webSocket) + private void KeepAliveWebSocket(IWebSocketConnection webSocket) { lock (_webSocketsLock) { @@ -175,11 +175,11 @@ namespace Emby.Server.Implementations.Session // Notify WebSocket about timeout try { - await SendForceKeepAlive(webSocket); + SendForceKeepAlive(webSocket).Wait(); } catch (WebSocketException exception) { - _logger.LogWarning(exception, "Error sending ForceKeepAlive message to WebSocket {0}.", webSocket); + _logger.LogWarning(exception, "Cannot send ForceKeepAlive message to WebSocket {0}.", webSocket); } } @@ -213,7 +213,8 @@ namespace Emby.Server.Implementations.Session { _keepAliveCancellationToken = new CancellationTokenSource(); // Start KeepAlive watcher - KeepAliveSockets( + var task = RepeatAsyncCallbackEvery( + KeepAliveSockets, TimeSpan.FromSeconds(WebSocketLostTimeout * IntervalFactor), _keepAliveCancellationToken.Token); } @@ -245,73 +246,58 @@ namespace Emby.Server.Implementations.Session } /// - /// Checks status of KeepAlive of WebSockets once every the specified interval time. + /// Checks status of KeepAlive of WebSockets. /// - /// The interval. - /// The cancellation token. - private async Task KeepAliveSockets(TimeSpan interval, CancellationToken cancellationToken) + private async Task KeepAliveSockets() { - while (true) + IEnumerable inactive; + IEnumerable lost; + + lock (_webSocketsLock) { - _logger.LogDebug("Watching {0} WebSockets.", _webSockets.Count()); + _logger.LogDebug("Watching {0} WebSockets.", _webSockets.Count); - IEnumerable inactive; - IEnumerable lost; - lock (_webSocketsLock) + inactive = _webSockets.Where(i => { - inactive = _webSockets.Where(i => - { - var elapsed = (DateTime.UtcNow - i.LastKeepAliveDate).TotalSeconds; - return (elapsed > WebSocketLostTimeout * ForceKeepAliveFactor) && (elapsed < WebSocketLostTimeout); - }); - lost = _webSockets.Where(i => (DateTime.UtcNow - i.LastKeepAliveDate).TotalSeconds >= WebSocketLostTimeout); - } + var elapsed = (DateTime.UtcNow - i.LastKeepAliveDate).TotalSeconds; + return (elapsed > WebSocketLostTimeout * ForceKeepAliveFactor) && (elapsed < WebSocketLostTimeout); + }); + lost = _webSockets.Where(i => (DateTime.UtcNow - i.LastKeepAliveDate).TotalSeconds >= WebSocketLostTimeout); + } - if (inactive.Any()) + if (inactive.Any()) + { + _logger.LogInformation("Sending ForceKeepAlive message to {0} inactive WebSockets.", inactive.Count()); + } + + foreach (var webSocket in inactive) + { + try { - _logger.LogInformation("Sending ForceKeepAlive message to {0} inactive WebSockets.", inactive.Count()); + await SendForceKeepAlive(webSocket); } - - foreach (var webSocket in inactive) + catch (WebSocketException exception) { - try - { - await SendForceKeepAlive(webSocket); - } - catch (WebSocketException exception) - { - _logger.LogInformation(exception, "Error sending ForceKeepAlive message to WebSocket."); - lost = lost.Append(webSocket); - } + _logger.LogInformation(exception, "Error sending ForceKeepAlive message to WebSocket."); + lost = lost.Append(webSocket); } + } - lock (_webSocketsLock) + lock (_webSocketsLock) + { + if (lost.Any()) { - if (lost.Any()) - { - _logger.LogInformation("Lost {0} WebSockets.", lost.Count()); - foreach (var webSocket in lost.ToList()) - { - // TODO: handle session relative to the lost webSocket - RemoveWebSocket(webSocket); - } - } - - if (!_webSockets.Any()) + _logger.LogInformation("Lost {0} WebSockets.", lost.Count()); + foreach (var webSocket in lost.ToList()) { - StopKeepAlive(); + // TODO: handle session relative to the lost webSocket + RemoveWebSocket(webSocket); } } - // Wait for next interval - Task task = Task.Delay(interval, cancellationToken); - try + if (!_webSockets.Any()) { - await task; - } - catch (TaskCanceledException) - { - return; + StopKeepAlive(); } } } @@ -329,5 +315,30 @@ namespace Emby.Server.Implementations.Session Data = WebSocketLostTimeout }, CancellationToken.None); } + + /// + /// Runs a given async callback once every specified interval time, until cancelled. + /// + /// The async callback. + /// The interval time. + /// The cancellation token. + /// Task. + private async Task RepeatAsyncCallbackEvery(Func callback, TimeSpan interval, CancellationToken cancellationToken) + { + while (!cancellationToken.IsCancellationRequested) + { + await callback(); + Task task = Task.Delay(interval, cancellationToken); + + try + { + await task; + } + catch (TaskCanceledException) + { + return; + } + } + } } } diff --git a/Emby.Server.Implementations/Syncplay/SyncplayController.cs b/Emby.Server.Implementations/Syncplay/SyncplayController.cs index 02cf08cd7..8cc3d1fac 100644 --- a/Emby.Server.Implementations/Syncplay/SyncplayController.cs +++ b/Emby.Server.Implementations/Syncplay/SyncplayController.cs @@ -7,13 +7,15 @@ using MediaBrowser.Controller.Session; using MediaBrowser.Controller.Syncplay; using MediaBrowser.Model.Session; using MediaBrowser.Model.Syncplay; -using Microsoft.Extensions.Logging; namespace Emby.Server.Implementations.Syncplay { /// /// Class SyncplayController. /// + /// + /// Class is not thread-safe, external locking is required when accessing methods. + /// public class SyncplayController : ISyncplayController, IDisposable { /// @@ -39,11 +41,6 @@ namespace Emby.Server.Implementations.Syncplay AllReady = 3 } - /// - /// The logger. - /// - private readonly ILogger _logger; - /// /// The session manager. /// @@ -71,11 +68,9 @@ namespace Emby.Server.Implementations.Syncplay private bool _disposed = false; public SyncplayController( - ILogger logger, ISessionManager sessionManager, ISyncplayManager syncplayManager) { - _logger = logger; _sessionManager = sessionManager; _syncplayManager = syncplayManager; } @@ -110,6 +105,16 @@ namespace Emby.Server.Implementations.Syncplay } } + /// + /// Converts DateTime to UTC string. + /// + /// The date to convert. + /// The UTC string. + private string DateToUTCString(DateTime date) + { + return date.ToUniversalTime().ToString("o"); + } + /// /// Filters sessions of this group. /// @@ -149,15 +154,16 @@ namespace Emby.Server.Implementations.Syncplay /// The current session. /// The filtering type. /// The message to send. + /// The cancellation token. /// The task. - private Task SendGroupUpdate(SessionInfo from, BroadcastType type, GroupUpdate message) + private Task SendGroupUpdate(SessionInfo from, BroadcastType type, GroupUpdate message, CancellationToken cancellationToken) { IEnumerable GetTasks() { SessionInfo[] sessions = FilterSessions(from, type); foreach (var session in sessions) { - yield return _sessionManager.SendSyncplayGroupUpdate(session.Id.ToString(), message, CancellationToken.None); + yield return _sessionManager.SendSyncplayGroupUpdate(session.Id.ToString(), message, cancellationToken); } } @@ -170,15 +176,16 @@ namespace Emby.Server.Implementations.Syncplay /// The current session. /// The filtering type. /// The message to send. + /// The cancellation token. /// The task. - private Task SendCommand(SessionInfo from, BroadcastType type, SendCommand message) + private Task SendCommand(SessionInfo from, BroadcastType type, SendCommand message, CancellationToken cancellationToken) { IEnumerable GetTasks() { SessionInfo[] sessions = FilterSessions(from, type); foreach (var session in sessions) { - yield return _sessionManager.SendSyncplayCommand(session.Id.ToString(), message, CancellationToken.None); + yield return _sessionManager.SendSyncplayCommand(session.Id.ToString(), message, cancellationToken); } } @@ -197,8 +204,8 @@ namespace Emby.Server.Implementations.Syncplay GroupId = _group.GroupId.ToString(), Command = type, PositionTicks = _group.PositionTicks, - When = _group.LastActivity.ToUniversalTime().ToString("o"), - EmittedAt = DateTime.UtcNow.ToUniversalTime().ToString("o") + When = DateToUTCString(_group.LastActivity), + EmittedAt = DateToUTCString(DateTime.UtcNow) }; } @@ -219,46 +226,46 @@ namespace Emby.Server.Implementations.Syncplay } /// - public void InitGroup(SessionInfo session) + public void InitGroup(SessionInfo session, CancellationToken cancellationToken) { _group.AddSession(session); _syncplayManager.AddSessionToGroup(session, this); _group.PlayingItem = session.FullNowPlayingItem; _group.IsPaused = true; - _group.PositionTicks = session.PlayState.PositionTicks ??= 0; + _group.PositionTicks = session.PlayState.PositionTicks ?? 0; _group.LastActivity = DateTime.UtcNow; - var updateSession = NewSyncplayGroupUpdate(GroupUpdateType.GroupJoined, DateTime.UtcNow.ToUniversalTime().ToString("o")); - SendGroupUpdate(session, BroadcastType.CurrentSession, updateSession); + var updateSession = NewSyncplayGroupUpdate(GroupUpdateType.GroupJoined, DateToUTCString(DateTime.UtcNow)); + SendGroupUpdate(session, BroadcastType.CurrentSession, updateSession, cancellationToken); var pauseCommand = NewSyncplayCommand(SendCommandType.Pause); - SendCommand(session, BroadcastType.CurrentSession, pauseCommand); + SendCommand(session, BroadcastType.CurrentSession, pauseCommand, cancellationToken); } /// - public void SessionJoin(SessionInfo session, JoinGroupRequest request) + public void SessionJoin(SessionInfo session, JoinGroupRequest request, CancellationToken cancellationToken) { if (session.NowPlayingItem?.Id == _group.PlayingItem.Id && request.PlayingItemId == _group.PlayingItem.Id) { _group.AddSession(session); _syncplayManager.AddSessionToGroup(session, this); - var updateSession = NewSyncplayGroupUpdate(GroupUpdateType.GroupJoined, DateTime.UtcNow.ToUniversalTime().ToString("o")); - SendGroupUpdate(session, BroadcastType.CurrentSession, updateSession); + var updateSession = NewSyncplayGroupUpdate(GroupUpdateType.GroupJoined, DateToUTCString(DateTime.UtcNow)); + SendGroupUpdate(session, BroadcastType.CurrentSession, updateSession, cancellationToken); var updateOthers = NewSyncplayGroupUpdate(GroupUpdateType.UserJoined, session.UserName); - SendGroupUpdate(session, BroadcastType.AllExceptCurrentSession, updateOthers); + SendGroupUpdate(session, BroadcastType.AllExceptCurrentSession, updateOthers, cancellationToken); // Client join and play, syncing will happen client side if (!_group.IsPaused) { var playCommand = NewSyncplayCommand(SendCommandType.Play); - SendCommand(session, BroadcastType.CurrentSession, playCommand); + SendCommand(session, BroadcastType.CurrentSession, playCommand, cancellationToken); } else { var pauseCommand = NewSyncplayCommand(SendCommandType.Pause); - SendCommand(session, BroadcastType.CurrentSession, pauseCommand); + SendCommand(session, BroadcastType.CurrentSession, pauseCommand, cancellationToken); } } else @@ -267,25 +274,25 @@ namespace Emby.Server.Implementations.Syncplay playRequest.ItemIds = new Guid[] { _group.PlayingItem.Id }; playRequest.StartPositionTicks = _group.PositionTicks; var update = NewSyncplayGroupUpdate(GroupUpdateType.PrepareSession, playRequest); - SendGroupUpdate(session, BroadcastType.CurrentSession, update); + SendGroupUpdate(session, BroadcastType.CurrentSession, update, cancellationToken); } } /// - public void SessionLeave(SessionInfo session) + public void SessionLeave(SessionInfo session, CancellationToken cancellationToken) { _group.RemoveSession(session); _syncplayManager.RemoveSessionFromGroup(session, this); var updateSession = NewSyncplayGroupUpdate(GroupUpdateType.GroupLeft, _group.PositionTicks); - SendGroupUpdate(session, BroadcastType.CurrentSession, updateSession); + SendGroupUpdate(session, BroadcastType.CurrentSession, updateSession, cancellationToken); var updateOthers = NewSyncplayGroupUpdate(GroupUpdateType.UserLeft, session.UserName); - SendGroupUpdate(session, BroadcastType.AllExceptCurrentSession, updateOthers); + SendGroupUpdate(session, BroadcastType.AllExceptCurrentSession, updateOthers, cancellationToken); } /// - public void HandleRequest(SessionInfo session, PlaybackRequest request) + public void HandleRequest(SessionInfo session, PlaybackRequest request, CancellationToken cancellationToken) { // The server's job is to mantain a consistent state to which clients refer to, // as also to notify clients of state changes. @@ -294,19 +301,19 @@ namespace Emby.Server.Implementations.Syncplay switch (request.Type) { case PlaybackRequestType.Play: - HandlePlayRequest(session, request); + HandlePlayRequest(session, request, cancellationToken); break; case PlaybackRequestType.Pause: - HandlePauseRequest(session, request); + HandlePauseRequest(session, request, cancellationToken); break; case PlaybackRequestType.Seek: - HandleSeekRequest(session, request); + HandleSeekRequest(session, request, cancellationToken); break; case PlaybackRequestType.Buffering: - HandleBufferingRequest(session, request); + HandleBufferingRequest(session, request, cancellationToken); break; case PlaybackRequestType.BufferingDone: - HandleBufferingDoneRequest(session, request); + HandleBufferingDoneRequest(session, request, cancellationToken); break; case PlaybackRequestType.UpdatePing: HandlePingUpdateRequest(session, request); @@ -319,7 +326,8 @@ namespace Emby.Server.Implementations.Syncplay /// /// The session. /// The play action. - private void HandlePlayRequest(SessionInfo session, PlaybackRequest request) + /// The cancellation token. + private void HandlePlayRequest(SessionInfo session, PlaybackRequest request, CancellationToken cancellationToken) { if (_group.IsPaused) { @@ -337,13 +345,13 @@ namespace Emby.Server.Implementations.Syncplay ); var command = NewSyncplayCommand(SendCommandType.Play); - SendCommand(session, BroadcastType.AllGroup, command); + SendCommand(session, BroadcastType.AllGroup, command, cancellationToken); } else { // Client got lost, sending current state var command = NewSyncplayCommand(SendCommandType.Play); - SendCommand(session, BroadcastType.CurrentSession, command); + SendCommand(session, BroadcastType.CurrentSession, command, cancellationToken); } } @@ -352,7 +360,8 @@ namespace Emby.Server.Implementations.Syncplay /// /// The session. /// The pause action. - private void HandlePauseRequest(SessionInfo session, PlaybackRequest request) + /// The cancellation token. + private void HandlePauseRequest(SessionInfo session, PlaybackRequest request, CancellationToken cancellationToken) { if (!_group.IsPaused) { @@ -366,13 +375,13 @@ namespace Emby.Server.Implementations.Syncplay _group.PositionTicks += elapsedTime.Ticks > 0 ? elapsedTime.Ticks : 0; var command = NewSyncplayCommand(SendCommandType.Pause); - SendCommand(session, BroadcastType.AllGroup, command); + SendCommand(session, BroadcastType.AllGroup, command, cancellationToken); } else { // Client got lost, sending current state var command = NewSyncplayCommand(SendCommandType.Pause); - SendCommand(session, BroadcastType.CurrentSession, command); + SendCommand(session, BroadcastType.CurrentSession, command, cancellationToken); } } @@ -381,16 +390,11 @@ namespace Emby.Server.Implementations.Syncplay /// /// The session. /// The seek action. - private void HandleSeekRequest(SessionInfo session, PlaybackRequest request) + /// The cancellation token. + private void HandleSeekRequest(SessionInfo session, PlaybackRequest request, CancellationToken cancellationToken) { // Sanitize PositionTicks - var ticks = request.PositionTicks ??= 0; - ticks = ticks >= 0 ? ticks : 0; - if (_group.PlayingItem.RunTimeTicks != null) - { - var runTimeTicks = _group.PlayingItem.RunTimeTicks ??= 0; - ticks = ticks > runTimeTicks ? runTimeTicks : ticks; - } + var ticks = SanitizePositionTicks(request.PositionTicks); // Pause and seek _group.IsPaused = true; @@ -398,7 +402,7 @@ namespace Emby.Server.Implementations.Syncplay _group.LastActivity = DateTime.UtcNow; var command = NewSyncplayCommand(SendCommandType.Seek); - SendCommand(session, BroadcastType.AllGroup, command); + SendCommand(session, BroadcastType.AllGroup, command, cancellationToken); } /// @@ -406,7 +410,8 @@ namespace Emby.Server.Implementations.Syncplay /// /// The session. /// The buffering action. - private void HandleBufferingRequest(SessionInfo session, PlaybackRequest request) + /// The cancellation token. + private void HandleBufferingRequest(SessionInfo session, PlaybackRequest request, CancellationToken cancellationToken) { if (!_group.IsPaused) { @@ -421,16 +426,16 @@ namespace Emby.Server.Implementations.Syncplay // Send pause command to all non-buffering sessions var command = NewSyncplayCommand(SendCommandType.Pause); - SendCommand(session, BroadcastType.AllReady, command); + SendCommand(session, BroadcastType.AllReady, command, cancellationToken); var updateOthers = NewSyncplayGroupUpdate(GroupUpdateType.GroupWait, session.UserName); - SendGroupUpdate(session, BroadcastType.AllExceptCurrentSession, updateOthers); + SendGroupUpdate(session, BroadcastType.AllExceptCurrentSession, updateOthers, cancellationToken); } else { // Client got lost, sending current state var command = NewSyncplayCommand(SendCommandType.Pause); - SendCommand(session, BroadcastType.CurrentSession, command); + SendCommand(session, BroadcastType.CurrentSession, command, cancellationToken); } } @@ -439,26 +444,28 @@ namespace Emby.Server.Implementations.Syncplay /// /// The session. /// The buffering-done action. - private void HandleBufferingDoneRequest(SessionInfo session, PlaybackRequest request) + /// The cancellation token. + private void HandleBufferingDoneRequest(SessionInfo session, PlaybackRequest request, CancellationToken cancellationToken) { if (_group.IsPaused) { _group.SetBuffering(session, false); - var when = request.When ??= DateTime.UtcNow; + var requestTicks = SanitizePositionTicks(request.PositionTicks); + + var when = request.When ?? DateTime.UtcNow; var currentTime = DateTime.UtcNow; var elapsedTime = currentTime - when; - var clientPosition = TimeSpan.FromTicks(request.PositionTicks ??= 0) + elapsedTime; + var clientPosition = TimeSpan.FromTicks(requestTicks) + elapsedTime; var delay = _group.PositionTicks - clientPosition.Ticks; if (_group.IsBuffering()) { - // Others are buffering, tell this client to pause when ready + // Others are still buffering, tell this client to pause when ready var command = NewSyncplayCommand(SendCommandType.Pause); - command.When = currentTime.AddMilliseconds( - delay - ).ToUniversalTime().ToString("o"); - SendCommand(session, BroadcastType.CurrentSession, command); + var pauseAtTime = currentTime.AddMilliseconds(delay); + command.When = DateToUTCString(pauseAtTime); + SendCommand(session, BroadcastType.CurrentSession, command, cancellationToken); } else { @@ -472,7 +479,7 @@ namespace Emby.Server.Implementations.Syncplay delay ); var command = NewSyncplayCommand(SendCommandType.Play); - SendCommand(session, BroadcastType.AllExceptCurrentSession, command); + SendCommand(session, BroadcastType.AllExceptCurrentSession, command, cancellationToken); } else { @@ -485,7 +492,7 @@ namespace Emby.Server.Implementations.Syncplay ); var command = NewSyncplayCommand(SendCommandType.Play); - SendCommand(session, BroadcastType.AllGroup, command); + SendCommand(session, BroadcastType.AllGroup, command, cancellationToken); } } } @@ -493,8 +500,25 @@ namespace Emby.Server.Implementations.Syncplay { // Group was not waiting, make sure client has latest state var command = NewSyncplayCommand(SendCommandType.Play); - SendCommand(session, BroadcastType.CurrentSession, command); + SendCommand(session, BroadcastType.CurrentSession, command, cancellationToken); + } + } + + /// + /// Sanitizes the PositionTicks, considers the current playing item when available. + /// + /// The PositionTicks. + /// The sanitized PositionTicks. + private long SanitizePositionTicks(long? positionTicks) + { + var ticks = positionTicks ?? 0; + ticks = ticks >= 0 ? ticks : 0; + if (_group.PlayingItem != null) + { + var runTimeTicks = _group.PlayingItem.RunTimeTicks ?? 0; + ticks = ticks > runTimeTicks ? runTimeTicks : ticks; } + return ticks; } /// @@ -505,7 +529,7 @@ namespace Emby.Server.Implementations.Syncplay private void HandlePingUpdateRequest(SessionInfo session, PlaybackRequest request) { // Collected pings are used to account for network latency when unpausing playback - _group.UpdatePing(session, request.Ping ??= _group.DefaulPing); + _group.UpdatePing(session, request.Ping ?? _group.DefaulPing); } /// @@ -517,7 +541,7 @@ namespace Emby.Server.Implementations.Syncplay PlayingItemName = _group.PlayingItem.Name, PlayingItemId = _group.PlayingItem.Id.ToString(), PositionTicks = _group.PositionTicks, - Participants = _group.Participants.Values.Select(session => session.Session.UserName).ToArray() + Participants = _group.Participants.Values.Select(session => session.Session.UserName).Distinct().ToArray() }; } } diff --git a/Emby.Server.Implementations/Syncplay/SyncplayManager.cs b/Emby.Server.Implementations/Syncplay/SyncplayManager.cs index eb61da7f3..7074e2225 100644 --- a/Emby.Server.Implementations/Syncplay/SyncplayManager.cs +++ b/Emby.Server.Implementations/Syncplay/SyncplayManager.cs @@ -114,14 +114,14 @@ namespace Emby.Server.Implementations.Syncplay { var session = e.SessionInfo; if (!IsSessionInGroup(session)) return; - LeaveGroup(session); + LeaveGroup(session, CancellationToken.None); } private void OnSessionManagerPlaybackStopped(object sender, PlaybackStopEventArgs e) { var session = e.Session; if (!IsSessionInGroup(session)) return; - LeaveGroup(session); + LeaveGroup(session, CancellationToken.None); } private bool IsSessionInGroup(SessionInfo session) @@ -132,7 +132,13 @@ namespace Emby.Server.Implementations.Syncplay private bool HasAccessToItem(User user, Guid itemId) { var item = _libraryManager.GetItemById(itemId); - var hasParentalRatingAccess = user.Policy.MaxParentalRating.HasValue ? item.InheritedParentalRatingValue <= user.Policy.MaxParentalRating : true; + + // Check ParentalRating access + var hasParentalRatingAccess = true; + if (user.Policy.MaxParentalRating.HasValue) + { + hasParentalRatingAccess = item.InheritedParentalRatingValue <= user.Policy.MaxParentalRating; + } if (!user.Policy.EnableAllFolders && hasParentalRatingAccess) { @@ -140,7 +146,7 @@ namespace Emby.Server.Implementations.Syncplay folder => folder.Id.ToString("N", CultureInfo.InvariantCulture) ); var intersect = collections.Intersect(user.Policy.EnabledFolders); - return intersect.Count() > 0; + return intersect.Any(); } else { @@ -163,13 +169,13 @@ namespace Emby.Server.Implementations.Syncplay } /// - public void NewGroup(SessionInfo session) + public void NewGroup(SessionInfo session, CancellationToken cancellationToken) { var user = _userManager.GetUserById(session.UserId); if (user.Policy.SyncplayAccess != SyncplayAccess.CreateAndJoinGroups) { - _logger.LogWarning("Syncplaymanager NewGroup: {0} does not have permission to create groups.", session.Id); + _logger.LogWarning("NewGroup: {0} does not have permission to create groups.", session.Id); var error = new GroupUpdate() { @@ -183,24 +189,24 @@ namespace Emby.Server.Implementations.Syncplay { if (IsSessionInGroup(session)) { - LeaveGroup(session); + LeaveGroup(session, cancellationToken); } - var group = new SyncplayController(_logger, _sessionManager, this); + var group = new SyncplayController(_sessionManager, this); _groups[group.GetGroupId().ToString()] = group; - group.InitGroup(session); + group.InitGroup(session, cancellationToken); } } /// - public void JoinGroup(SessionInfo session, string groupId, JoinGroupRequest request) + public void JoinGroup(SessionInfo session, string groupId, JoinGroupRequest request, CancellationToken cancellationToken) { var user = _userManager.GetUserById(session.UserId); if (user.Policy.SyncplayAccess == SyncplayAccess.None) { - _logger.LogWarning("Syncplaymanager JoinGroup: {0} does not have access to Syncplay.", session.Id); + _logger.LogWarning("JoinGroup: {0} does not have access to Syncplay.", session.Id); var error = new GroupUpdate() { @@ -217,11 +223,11 @@ namespace Emby.Server.Implementations.Syncplay if (group == null) { - _logger.LogWarning("Syncplaymanager JoinGroup: {0} tried to join group {0} that does not exist.", session.Id, groupId); + _logger.LogWarning("JoinGroup: {0} tried to join group {0} that does not exist.", session.Id, groupId); var error = new GroupUpdate() { - Type = GroupUpdateType.GroupNotJoined + Type = GroupUpdateType.GroupDoesNotExist }; _sessionManager.SendSyncplayGroupUpdate(session.Id.ToString(), error, CancellationToken.None); return; @@ -229,7 +235,7 @@ namespace Emby.Server.Implementations.Syncplay if (!HasAccessToItem(user, group.GetPlayingItemId())) { - _logger.LogWarning("Syncplaymanager JoinGroup: {0} does not have access to {1}.", session.Id, group.GetPlayingItemId()); + _logger.LogWarning("JoinGroup: {0} does not have access to {1}.", session.Id, group.GetPlayingItemId()); var error = new GroupUpdate() { @@ -243,15 +249,15 @@ namespace Emby.Server.Implementations.Syncplay if (IsSessionInGroup(session)) { if (GetSessionGroup(session).Equals(groupId)) return; - LeaveGroup(session); + LeaveGroup(session, cancellationToken); } - group.SessionJoin(session, request); + group.SessionJoin(session, request, cancellationToken); } } /// - public void LeaveGroup(SessionInfo session) + public void LeaveGroup(SessionInfo session, CancellationToken cancellationToken) { // TODO: determine what happens to users that are in a group and get their permissions revoked lock (_groupsLock) @@ -261,7 +267,7 @@ namespace Emby.Server.Implementations.Syncplay if (group == null) { - _logger.LogWarning("Syncplaymanager LeaveGroup: {0} does not belong to any group.", session.Id); + _logger.LogWarning("LeaveGroup: {0} does not belong to any group.", session.Id); var error = new GroupUpdate() { @@ -271,17 +277,18 @@ namespace Emby.Server.Implementations.Syncplay return; } - group.SessionLeave(session); + group.SessionLeave(session, cancellationToken); if (group.IsGroupEmpty()) { + _logger.LogInformation("LeaveGroup: removing empty group {0}.", group.GetGroupId()); _groups.Remove(group.GetGroupId().ToString(), out _); } } } /// - public List ListGroups(SessionInfo session) + public List ListGroups(SessionInfo session, Guid filterItemId) { var user = _userManager.GetUserById(session.UserId); @@ -290,11 +297,11 @@ namespace Emby.Server.Implementations.Syncplay return new List(); } - // Filter by playing item if the user is viewing something already - if (session.NowPlayingItem != null) + // Filter by item if requested + if (!filterItemId.Equals(Guid.Empty)) { return _groups.Values.Where( - group => group.GetPlayingItemId().Equals(session.FullNowPlayingItem.Id) && HasAccessToItem(user, group.GetPlayingItemId()) + group => group.GetPlayingItemId().Equals(filterItemId) && HasAccessToItem(user, group.GetPlayingItemId()) ).Select( group => group.GetInfo() ).ToList(); @@ -311,13 +318,13 @@ namespace Emby.Server.Implementations.Syncplay } /// - public void HandleRequest(SessionInfo session, PlaybackRequest request) + public void HandleRequest(SessionInfo session, PlaybackRequest request, CancellationToken cancellationToken) { var user = _userManager.GetUserById(session.UserId); if (user.Policy.SyncplayAccess == SyncplayAccess.None) { - _logger.LogWarning("Syncplaymanager HandleRequest: {0} does not have access to Syncplay.", session.Id); + _logger.LogWarning("HandleRequest: {0} does not have access to Syncplay.", session.Id); var error = new GroupUpdate() { @@ -334,7 +341,7 @@ namespace Emby.Server.Implementations.Syncplay if (group == null) { - _logger.LogWarning("Syncplaymanager HandleRequest: {0} does not belong to any group.", session.Id); + _logger.LogWarning("HandleRequest: {0} does not belong to any group.", session.Id); var error = new GroupUpdate() { @@ -344,7 +351,7 @@ namespace Emby.Server.Implementations.Syncplay return; } - group.HandleRequest(session, request); + group.HandleRequest(session, request, cancellationToken); } } diff --git a/MediaBrowser.Api/Syncplay/SyncplayService.cs b/MediaBrowser.Api/Syncplay/SyncplayService.cs index 2eaf9ce83..4b6e16762 100644 --- a/MediaBrowser.Api/Syncplay/SyncplayService.cs +++ b/MediaBrowser.Api/Syncplay/SyncplayService.cs @@ -1,3 +1,4 @@ +using System.Threading; using System; using System.Collections.Generic; using MediaBrowser.Controller.Configuration; @@ -48,12 +49,19 @@ namespace MediaBrowser.Api.Syncplay public string SessionId { get; set; } } - [Route("/Syncplay/{SessionId}/ListGroups", "POST", Summary = "List Syncplay groups playing same item")] + [Route("/Syncplay/{SessionId}/ListGroups", "POST", Summary = "List Syncplay groups")] [Authenticated] public class SyncplayListGroups : IReturnVoid { [ApiMember(Name = "SessionId", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] public string SessionId { get; set; } + + /// + /// Gets or sets the filter item id. + /// + /// The filter item id. + [ApiMember(Name = "FilterItemId", Description = "Filter by item id", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")] + public string FilterItemId { get; set; } } [Route("/Syncplay/{SessionId}/PlayRequest", "POST", Summary = "Request play in Syncplay group")] @@ -104,8 +112,8 @@ namespace MediaBrowser.Api.Syncplay /// Gets or sets whether this is a buffering or a buffering-done request. /// /// true if buffering is complete; false otherwise. - [ApiMember(Name = "Resume", IsRequired = true, DataType = "bool", ParameterType = "query", Verb = "POST")] - public bool Resume { get; set; } + [ApiMember(Name = "BufferingDone", IsRequired = true, DataType = "bool", ParameterType = "query", Verb = "POST")] + public bool BufferingDone { get; set; } } [Route("/Syncplay/{SessionId}/UpdatePing", "POST", Summary = "Update session ping")] @@ -124,11 +132,6 @@ namespace MediaBrowser.Api.Syncplay /// public class SyncplayService : BaseApiService { - /// - /// The session manager. - /// - private readonly ISessionManager _sessionManager; - /// /// The session context. /// @@ -143,12 +146,10 @@ namespace MediaBrowser.Api.Syncplay ILogger logger, IServerConfigurationManager serverConfigurationManager, IHttpResultFactory httpResultFactory, - ISessionManager sessionManager, ISessionContext sessionContext, ISyncplayManager syncplayManager) : base(logger, serverConfigurationManager, httpResultFactory) { - _sessionManager = sessionManager; _sessionContext = sessionContext; _syncplayManager = syncplayManager; } @@ -160,7 +161,7 @@ namespace MediaBrowser.Api.Syncplay public void Post(SyncplayNewGroup request) { var currentSession = GetSession(_sessionContext); - _syncplayManager.NewGroup(currentSession); + _syncplayManager.NewGroup(currentSession, CancellationToken.None); } /// @@ -174,19 +175,27 @@ namespace MediaBrowser.Api.Syncplay { GroupId = Guid.Parse(request.GroupId) }; - try - { - joinRequest.PlayingItemId = Guid.Parse(request.PlayingItemId); - } - catch (ArgumentNullException) - { - // Do nothing - } - catch (FormatException) + + // Both null and empty strings mean that client isn't playing anything + if (!String.IsNullOrEmpty(request.PlayingItemId)) { - // Do nothing + try + { + joinRequest.PlayingItemId = Guid.Parse(request.PlayingItemId); + } + catch (ArgumentNullException) + { + // Should never happen, but just in case + Logger.LogError("JoinGroup: null value for PlayingItemId. Ignoring request."); + return; + } + catch (FormatException) + { + Logger.LogError("JoinGroup: {0} is not a valid format for PlayingItemId. Ignoring request.", request.PlayingItemId); + return; + } } - _syncplayManager.JoinGroup(currentSession, request.GroupId, joinRequest); + _syncplayManager.JoinGroup(currentSession, request.GroupId, joinRequest, CancellationToken.None); } /// @@ -196,7 +205,7 @@ namespace MediaBrowser.Api.Syncplay public void Post(SyncplayLeaveGroup request) { var currentSession = GetSession(_sessionContext); - _syncplayManager.LeaveGroup(currentSession); + _syncplayManager.LeaveGroup(currentSession, CancellationToken.None); } /// @@ -207,7 +216,23 @@ namespace MediaBrowser.Api.Syncplay public List Post(SyncplayListGroups request) { var currentSession = GetSession(_sessionContext); - return _syncplayManager.ListGroups(currentSession); + var filterItemId = Guid.Empty; + if (!String.IsNullOrEmpty(request.FilterItemId)) + { + try + { + filterItemId = Guid.Parse(request.FilterItemId); + } + catch (ArgumentNullException) + { + Logger.LogWarning("ListGroups: null value for FilterItemId. Ignoring filter."); + } + catch (FormatException) + { + Logger.LogWarning("ListGroups: {0} is not a valid format for FilterItemId. Ignoring filter.", request.FilterItemId); + } + } + return _syncplayManager.ListGroups(currentSession, filterItemId); } /// @@ -221,7 +246,7 @@ namespace MediaBrowser.Api.Syncplay { Type = PlaybackRequestType.Play }; - _syncplayManager.HandleRequest(currentSession, syncplayRequest); + _syncplayManager.HandleRequest(currentSession, syncplayRequest, CancellationToken.None); } /// @@ -235,7 +260,7 @@ namespace MediaBrowser.Api.Syncplay { Type = PlaybackRequestType.Pause }; - _syncplayManager.HandleRequest(currentSession, syncplayRequest); + _syncplayManager.HandleRequest(currentSession, syncplayRequest, CancellationToken.None); } /// @@ -250,7 +275,7 @@ namespace MediaBrowser.Api.Syncplay Type = PlaybackRequestType.Seek, PositionTicks = request.PositionTicks }; - _syncplayManager.HandleRequest(currentSession, syncplayRequest); + _syncplayManager.HandleRequest(currentSession, syncplayRequest, CancellationToken.None); } /// @@ -262,11 +287,11 @@ namespace MediaBrowser.Api.Syncplay var currentSession = GetSession(_sessionContext); var syncplayRequest = new PlaybackRequest() { - Type = request.Resume ? PlaybackRequestType.BufferingDone : PlaybackRequestType.Buffering, + Type = request.BufferingDone ? PlaybackRequestType.BufferingDone : PlaybackRequestType.Buffering, When = DateTime.Parse(request.When), PositionTicks = request.PositionTicks }; - _syncplayManager.HandleRequest(currentSession, syncplayRequest); + _syncplayManager.HandleRequest(currentSession, syncplayRequest, CancellationToken.None); } /// @@ -281,7 +306,7 @@ namespace MediaBrowser.Api.Syncplay Type = PlaybackRequestType.UpdatePing, Ping = Convert.ToInt64(request.Ping) }; - _syncplayManager.HandleRequest(currentSession, syncplayRequest); + _syncplayManager.HandleRequest(currentSession, syncplayRequest, CancellationToken.None); } } } diff --git a/MediaBrowser.Api/Syncplay/TimeSyncService.cs b/MediaBrowser.Api/Syncplay/TimeSyncService.cs index 930968d9f..9a26ffd99 100644 --- a/MediaBrowser.Api/Syncplay/TimeSyncService.cs +++ b/MediaBrowser.Api/Syncplay/TimeSyncService.cs @@ -1,7 +1,6 @@ using System; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Net; -using MediaBrowser.Controller.Session; using MediaBrowser.Model.Services; using MediaBrowser.Model.Syncplay; using Microsoft.Extensions.Logging; @@ -19,16 +18,6 @@ namespace MediaBrowser.Api.Syncplay /// public class TimeSyncService : BaseApiService { - /// - /// The session manager. - /// - private readonly ISessionManager _sessionManager; - - /// - /// The session context. - /// - private readonly ISessionContext _sessionContext; - public TimeSyncService( ILogger logger, IServerConfigurationManager serverConfigurationManager, @@ -55,7 +44,7 @@ namespace MediaBrowser.Api.Syncplay var responseTransmissionTime = DateTime.UtcNow.ToUniversalTime().ToString("o"); response.ResponseTransmissionTime = responseTransmissionTime; - // Implementing NTP on such a high level results in this useless + // Implementing NTP on such a high level results in this useless // information being sent. On the other hand it enables future additions. return response; } diff --git a/MediaBrowser.Controller/Syncplay/GroupInfo.cs b/MediaBrowser.Controller/Syncplay/GroupInfo.cs index 8e886a2cb..c01fead83 100644 --- a/MediaBrowser.Controller/Syncplay/GroupInfo.cs +++ b/MediaBrowser.Controller/Syncplay/GroupInfo.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Concurrent; using System.Collections.Generic; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Session; @@ -9,6 +8,9 @@ namespace MediaBrowser.Controller.Syncplay /// /// Class GroupInfo. /// + /// + /// Class is not thread-safe, external locking is required when accessing methods. + /// public class GroupInfo { /// @@ -49,8 +51,8 @@ namespace MediaBrowser.Controller.Syncplay /// Gets the participants. /// /// The participants, or members of the group. - public readonly ConcurrentDictionary Participants = - new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); + public readonly Dictionary Participants = + new Dictionary(StringComparer.OrdinalIgnoreCase); /// /// Checks if a session is in this group. diff --git a/MediaBrowser.Controller/Syncplay/ISyncplayController.cs b/MediaBrowser.Controller/Syncplay/ISyncplayController.cs index 5b08eac0a..34eae4062 100644 --- a/MediaBrowser.Controller/Syncplay/ISyncplayController.cs +++ b/MediaBrowser.Controller/Syncplay/ISyncplayController.cs @@ -1,4 +1,5 @@ using System; +using System.Threading; using MediaBrowser.Controller.Session; using MediaBrowser.Model.Syncplay; @@ -31,27 +32,31 @@ namespace MediaBrowser.Controller.Syncplay /// Initializes the group with the session's info. /// /// The session. - void InitGroup(SessionInfo session); + /// The cancellation token. + void InitGroup(SessionInfo session, CancellationToken cancellationToken); /// /// Adds the session to the group. /// /// The session. /// The request. - void SessionJoin(SessionInfo session, JoinGroupRequest request); + /// The cancellation token. + void SessionJoin(SessionInfo session, JoinGroupRequest request, CancellationToken cancellationToken); /// /// Removes the session from the group. /// /// The session. - void SessionLeave(SessionInfo session); + /// The cancellation token. + void SessionLeave(SessionInfo session, CancellationToken cancellationToken); /// /// Handles the requested action by the session. /// /// The session. /// The requested action. - void HandleRequest(SessionInfo session, PlaybackRequest request); + /// The cancellation token. + void HandleRequest(SessionInfo session, PlaybackRequest request, CancellationToken cancellationToken); /// /// Gets the info about the group for the clients. diff --git a/MediaBrowser.Controller/Syncplay/ISyncplayManager.cs b/MediaBrowser.Controller/Syncplay/ISyncplayManager.cs index 433d6d8bc..fbc208d27 100644 --- a/MediaBrowser.Controller/Syncplay/ISyncplayManager.cs +++ b/MediaBrowser.Controller/Syncplay/ISyncplayManager.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Threading; using MediaBrowser.Controller.Session; using MediaBrowser.Model.Syncplay; @@ -14,7 +15,8 @@ namespace MediaBrowser.Controller.Syncplay /// Creates a new group. /// /// The session that's creating the group. - void NewGroup(SessionInfo session); + /// The cancellation token. + void NewGroup(SessionInfo session, CancellationToken cancellationToken); /// /// Adds the session to a group. @@ -22,27 +24,31 @@ namespace MediaBrowser.Controller.Syncplay /// The session. /// The group id. /// The request. - void JoinGroup(SessionInfo session, string groupId, JoinGroupRequest request); + /// The cancellation token. + void JoinGroup(SessionInfo session, string groupId, JoinGroupRequest request, CancellationToken cancellationToken); /// /// Removes the session from a group. /// /// The session. - void LeaveGroup(SessionInfo session); + /// The cancellation token. + void LeaveGroup(SessionInfo session, CancellationToken cancellationToken); /// /// Gets list of available groups for a session. /// /// The session. + /// The item id to filter by. /// The list of available groups. - List ListGroups(SessionInfo session); + List ListGroups(SessionInfo session, Guid filterItemId); /// /// Handle a request by a session in a group. /// /// The session. /// The request. - void HandleRequest(SessionInfo session, PlaybackRequest request); + /// The cancellation token. + void HandleRequest(SessionInfo session, PlaybackRequest request, CancellationToken cancellationToken); /// /// Maps a session to a group. diff --git a/MediaBrowser.Model/Syncplay/GroupUpdateType.cs b/MediaBrowser.Model/Syncplay/GroupUpdateType.cs index 20e76932d..9f40f9577 100644 --- a/MediaBrowser.Model/Syncplay/GroupUpdateType.cs +++ b/MediaBrowser.Model/Syncplay/GroupUpdateType.cs @@ -30,13 +30,13 @@ namespace MediaBrowser.Model.Syncplay /// PrepareSession, /// - /// The not-in-group error. Tells a user that it doesn't belong to a group. + /// The not-in-group error. Tells a user that they don't belong to a group. /// NotInGroup, /// - /// The group-not-joined error. Sent when a request to join a group fails. + /// The group-does-not-exist error. Sent when trying to join a non-existing group. /// - GroupNotJoined, + GroupDoesNotExist, /// /// The create-group-denied error. Sent when a user tries to create a group without required permissions. /// diff --git a/MediaBrowser.Model/Syncplay/PlaybackRequest.cs b/MediaBrowser.Model/Syncplay/PlaybackRequest.cs index cae769db0..ba97641f6 100644 --- a/MediaBrowser.Model/Syncplay/PlaybackRequest.cs +++ b/MediaBrowser.Model/Syncplay/PlaybackRequest.cs @@ -11,7 +11,7 @@ namespace MediaBrowser.Model.Syncplay /// Gets or sets the request type. /// /// The request type. - public PlaybackRequestType Type; + public PlaybackRequestType Type { get; set; } /// /// Gets or sets when the request has been made by the client. -- cgit v1.2.3 From 8a6ec2fb713cb77e91d2fceea8b4fce8e7d17395 Mon Sep 17 00:00:00 2001 From: gion Date: Wed, 6 May 2020 23:42:53 +0200 Subject: Rename Syncplay to SyncPlay --- Emby.Server.Implementations/ApplicationHost.cs | 6 +- .../Session/SessionManager.cs | 10 +- .../SyncPlay/SyncPlayController.cs | 548 +++++++++++++++++++++ .../SyncPlay/SyncPlayManager.cs | 385 +++++++++++++++ .../Syncplay/SyncplayController.cs | 548 --------------------- .../Syncplay/SyncplayManager.cs | 385 --------------- MediaBrowser.Api/SyncPlay/SyncPlayService.cs | 312 ++++++++++++ MediaBrowser.Api/SyncPlay/TimeSyncService.cs | 52 ++ MediaBrowser.Api/Syncplay/SyncplayService.cs | 312 ------------ MediaBrowser.Api/Syncplay/TimeSyncService.cs | 52 -- MediaBrowser.Controller/Session/ISessionManager.cs | 10 +- MediaBrowser.Controller/SyncPlay/GroupInfo.cs | 150 ++++++ MediaBrowser.Controller/SyncPlay/GroupMember.cs | 28 ++ .../SyncPlay/ISyncPlayController.cs | 67 +++ .../SyncPlay/ISyncPlayManager.cs | 69 +++ MediaBrowser.Controller/Syncplay/GroupInfo.cs | 150 ------ MediaBrowser.Controller/Syncplay/GroupMember.cs | 28 -- .../Syncplay/ISyncplayController.cs | 67 --- .../Syncplay/ISyncplayManager.cs | 69 --- MediaBrowser.Model/Configuration/SyncplayAccess.cs | 6 +- MediaBrowser.Model/SyncPlay/GroupInfoView.cs | 38 ++ MediaBrowser.Model/SyncPlay/GroupUpdate.cs | 26 + MediaBrowser.Model/SyncPlay/GroupUpdateType.cs | 53 ++ MediaBrowser.Model/SyncPlay/JoinGroupRequest.cs | 22 + MediaBrowser.Model/SyncPlay/PlaybackRequest.cs | 34 ++ MediaBrowser.Model/SyncPlay/PlaybackRequestType.cs | 33 ++ MediaBrowser.Model/SyncPlay/SendCommand.cs | 38 ++ MediaBrowser.Model/SyncPlay/SendCommandType.cs | 21 + MediaBrowser.Model/SyncPlay/UtcTimeResponse.cs | 20 + MediaBrowser.Model/Syncplay/GroupInfoView.cs | 38 -- MediaBrowser.Model/Syncplay/GroupUpdate.cs | 26 - MediaBrowser.Model/Syncplay/GroupUpdateType.cs | 53 -- MediaBrowser.Model/Syncplay/JoinGroupRequest.cs | 22 - MediaBrowser.Model/Syncplay/PlaybackRequest.cs | 34 -- MediaBrowser.Model/Syncplay/PlaybackRequestType.cs | 33 -- MediaBrowser.Model/Syncplay/SendCommand.cs | 38 -- MediaBrowser.Model/Syncplay/SendCommandType.cs | 21 - MediaBrowser.Model/Syncplay/UtcTimeResponse.cs | 20 - MediaBrowser.Model/Users/UserPolicy.cs | 8 +- 39 files changed, 1916 insertions(+), 1916 deletions(-) create mode 100644 Emby.Server.Implementations/SyncPlay/SyncPlayController.cs create mode 100644 Emby.Server.Implementations/SyncPlay/SyncPlayManager.cs delete mode 100644 Emby.Server.Implementations/Syncplay/SyncplayController.cs delete mode 100644 Emby.Server.Implementations/Syncplay/SyncplayManager.cs create mode 100644 MediaBrowser.Api/SyncPlay/SyncPlayService.cs create mode 100644 MediaBrowser.Api/SyncPlay/TimeSyncService.cs delete mode 100644 MediaBrowser.Api/Syncplay/SyncplayService.cs delete mode 100644 MediaBrowser.Api/Syncplay/TimeSyncService.cs create mode 100644 MediaBrowser.Controller/SyncPlay/GroupInfo.cs create mode 100644 MediaBrowser.Controller/SyncPlay/GroupMember.cs create mode 100644 MediaBrowser.Controller/SyncPlay/ISyncPlayController.cs create mode 100644 MediaBrowser.Controller/SyncPlay/ISyncPlayManager.cs delete mode 100644 MediaBrowser.Controller/Syncplay/GroupInfo.cs delete mode 100644 MediaBrowser.Controller/Syncplay/GroupMember.cs delete mode 100644 MediaBrowser.Controller/Syncplay/ISyncplayController.cs delete mode 100644 MediaBrowser.Controller/Syncplay/ISyncplayManager.cs create mode 100644 MediaBrowser.Model/SyncPlay/GroupInfoView.cs create mode 100644 MediaBrowser.Model/SyncPlay/GroupUpdate.cs create mode 100644 MediaBrowser.Model/SyncPlay/GroupUpdateType.cs create mode 100644 MediaBrowser.Model/SyncPlay/JoinGroupRequest.cs create mode 100644 MediaBrowser.Model/SyncPlay/PlaybackRequest.cs create mode 100644 MediaBrowser.Model/SyncPlay/PlaybackRequestType.cs create mode 100644 MediaBrowser.Model/SyncPlay/SendCommand.cs create mode 100644 MediaBrowser.Model/SyncPlay/SendCommandType.cs create mode 100644 MediaBrowser.Model/SyncPlay/UtcTimeResponse.cs delete mode 100644 MediaBrowser.Model/Syncplay/GroupInfoView.cs delete mode 100644 MediaBrowser.Model/Syncplay/GroupUpdate.cs delete mode 100644 MediaBrowser.Model/Syncplay/GroupUpdateType.cs delete mode 100644 MediaBrowser.Model/Syncplay/JoinGroupRequest.cs delete mode 100644 MediaBrowser.Model/Syncplay/PlaybackRequest.cs delete mode 100644 MediaBrowser.Model/Syncplay/PlaybackRequestType.cs delete mode 100644 MediaBrowser.Model/Syncplay/SendCommand.cs delete mode 100644 MediaBrowser.Model/Syncplay/SendCommandType.cs delete mode 100644 MediaBrowser.Model/Syncplay/UtcTimeResponse.cs (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index 8419014c2..730323c22 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -47,7 +47,7 @@ using Emby.Server.Implementations.Session; using Emby.Server.Implementations.SocketSharp; using Emby.Server.Implementations.TV; using Emby.Server.Implementations.Updates; -using Emby.Server.Implementations.Syncplay; +using Emby.Server.Implementations.SyncPlay; using MediaBrowser.Api; using MediaBrowser.Common; using MediaBrowser.Common.Configuration; @@ -81,7 +81,7 @@ using MediaBrowser.Controller.Session; using MediaBrowser.Controller.Sorting; using MediaBrowser.Controller.Subtitles; using MediaBrowser.Controller.TV; -using MediaBrowser.Controller.Syncplay; +using MediaBrowser.Controller.SyncPlay; using MediaBrowser.LocalMetadata.Savers; using MediaBrowser.MediaEncoding.BdInfo; using MediaBrowser.Model.Activity; @@ -645,7 +645,7 @@ namespace Emby.Server.Implementations serviceCollection.AddSingleton(); - serviceCollection.AddSingleton(); + serviceCollection.AddSingleton(); serviceCollection.AddSingleton(); serviceCollection.AddSingleton(); diff --git a/Emby.Server.Implementations/Session/SessionManager.cs b/Emby.Server.Implementations/Session/SessionManager.cs index 6a64209c1..aab745de4 100644 --- a/Emby.Server.Implementations/Session/SessionManager.cs +++ b/Emby.Server.Implementations/Session/SessionManager.cs @@ -25,7 +25,7 @@ using MediaBrowser.Model.Events; using MediaBrowser.Model.Library; using MediaBrowser.Model.Querying; using MediaBrowser.Model.Session; -using MediaBrowser.Model.Syncplay; +using MediaBrowser.Model.SyncPlay; using Microsoft.Extensions.Logging; namespace Emby.Server.Implementations.Session @@ -1156,19 +1156,19 @@ namespace Emby.Server.Implementations.Session } /// - public async Task SendSyncplayCommand(string sessionId, SendCommand command, CancellationToken cancellationToken) + public async Task SendSyncPlayCommand(string sessionId, SendCommand command, CancellationToken cancellationToken) { CheckDisposed(); var session = GetSessionToRemoteControl(sessionId); - await SendMessageToSession(session, "SyncplayCommand", command, cancellationToken).ConfigureAwait(false); + await SendMessageToSession(session, "SyncPlayCommand", command, cancellationToken).ConfigureAwait(false); } /// - public async Task SendSyncplayGroupUpdate(string sessionId, GroupUpdate command, CancellationToken cancellationToken) + public async Task SendSyncPlayGroupUpdate(string sessionId, GroupUpdate command, CancellationToken cancellationToken) { CheckDisposed(); var session = GetSessionToRemoteControl(sessionId); - await SendMessageToSession(session, "SyncplayGroupUpdate", command, cancellationToken).ConfigureAwait(false); + await SendMessageToSession(session, "SyncPlayGroupUpdate", command, cancellationToken).ConfigureAwait(false); } private IEnumerable TranslateItemForPlayback(Guid id, User user) diff --git a/Emby.Server.Implementations/SyncPlay/SyncPlayController.cs b/Emby.Server.Implementations/SyncPlay/SyncPlayController.cs new file mode 100644 index 000000000..9c9758de1 --- /dev/null +++ b/Emby.Server.Implementations/SyncPlay/SyncPlayController.cs @@ -0,0 +1,548 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using MediaBrowser.Controller.Session; +using MediaBrowser.Controller.SyncPlay; +using MediaBrowser.Model.Session; +using MediaBrowser.Model.SyncPlay; + +namespace Emby.Server.Implementations.SyncPlay +{ + /// + /// Class SyncPlayController. + /// + /// + /// Class is not thread-safe, external locking is required when accessing methods. + /// + public class SyncPlayController : ISyncPlayController, IDisposable + { + /// + /// Used to filter the sessions of a group. + /// + private enum BroadcastType + { + /// + /// All sessions will receive the message. + /// + AllGroup = 0, + /// + /// Only the specified session will receive the message. + /// + CurrentSession = 1, + /// + /// All sessions, except the current one, will receive the message. + /// + AllExceptCurrentSession = 2, + /// + /// Only sessions that are not buffering will receive the message. + /// + AllReady = 3 + } + + /// + /// The session manager. + /// + private readonly ISessionManager _sessionManager; + + /// + /// The SyncPlay manager. + /// + private readonly ISyncPlayManager _syncPlayManager; + + /// + /// The group to manage. + /// + private readonly GroupInfo _group = new GroupInfo(); + + /// + public Guid GetGroupId() => _group.GroupId; + + /// + public Guid GetPlayingItemId() => _group.PlayingItem.Id; + + /// + public bool IsGroupEmpty() => _group.IsEmpty(); + + private bool _disposed = false; + + public SyncPlayController( + ISessionManager sessionManager, + ISyncPlayManager syncPlayManager) + { + _sessionManager = sessionManager; + _syncPlayManager = syncPlayManager; + } + + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + /// + /// Releases unmanaged and optionally managed resources. + /// + /// true to release both managed and unmanaged resources; false to release only unmanaged resources. + protected virtual void Dispose(bool disposing) + { + if (_disposed) + { + return; + } + + _disposed = true; + } + + // TODO: use this somewhere + private void CheckDisposed() + { + if (_disposed) + { + throw new ObjectDisposedException(GetType().Name); + } + } + + /// + /// Converts DateTime to UTC string. + /// + /// The date to convert. + /// The UTC string. + private string DateToUTCString(DateTime date) + { + return date.ToUniversalTime().ToString("o"); + } + + /// + /// Filters sessions of this group. + /// + /// The current session. + /// The filtering type. + /// The array of sessions matching the filter. + private SessionInfo[] FilterSessions(SessionInfo from, BroadcastType type) + { + switch (type) + { + case BroadcastType.CurrentSession: + return new SessionInfo[] { from }; + case BroadcastType.AllGroup: + return _group.Participants.Values.Select( + session => session.Session + ).ToArray(); + case BroadcastType.AllExceptCurrentSession: + return _group.Participants.Values.Select( + session => session.Session + ).Where( + session => !session.Id.Equals(from.Id) + ).ToArray(); + case BroadcastType.AllReady: + return _group.Participants.Values.Where( + session => !session.IsBuffering + ).Select( + session => session.Session + ).ToArray(); + default: + return new SessionInfo[] { }; + } + } + + /// + /// Sends a GroupUpdate message to the interested sessions. + /// + /// The current session. + /// The filtering type. + /// The message to send. + /// The cancellation token. + /// The task. + private Task SendGroupUpdate(SessionInfo from, BroadcastType type, GroupUpdate message, CancellationToken cancellationToken) + { + IEnumerable GetTasks() + { + SessionInfo[] sessions = FilterSessions(from, type); + foreach (var session in sessions) + { + yield return _sessionManager.SendSyncPlayGroupUpdate(session.Id.ToString(), message, cancellationToken); + } + } + + return Task.WhenAll(GetTasks()); + } + + /// + /// Sends a playback command to the interested sessions. + /// + /// The current session. + /// The filtering type. + /// The message to send. + /// The cancellation token. + /// The task. + private Task SendCommand(SessionInfo from, BroadcastType type, SendCommand message, CancellationToken cancellationToken) + { + IEnumerable GetTasks() + { + SessionInfo[] sessions = FilterSessions(from, type); + foreach (var session in sessions) + { + yield return _sessionManager.SendSyncPlayCommand(session.Id.ToString(), message, cancellationToken); + } + } + + return Task.WhenAll(GetTasks()); + } + + /// + /// Builds a new playback command with some default values. + /// + /// The command type. + /// The SendCommand. + private SendCommand NewSyncPlayCommand(SendCommandType type) + { + return new SendCommand() + { + GroupId = _group.GroupId.ToString(), + Command = type, + PositionTicks = _group.PositionTicks, + When = DateToUTCString(_group.LastActivity), + EmittedAt = DateToUTCString(DateTime.UtcNow) + }; + } + + /// + /// Builds a new group update message. + /// + /// The update type. + /// The data to send. + /// The GroupUpdate. + private GroupUpdate NewSyncPlayGroupUpdate(GroupUpdateType type, T data) + { + return new GroupUpdate() + { + GroupId = _group.GroupId.ToString(), + Type = type, + Data = data + }; + } + + /// + public void InitGroup(SessionInfo session, CancellationToken cancellationToken) + { + _group.AddSession(session); + _syncPlayManager.AddSessionToGroup(session, this); + + _group.PlayingItem = session.FullNowPlayingItem; + _group.IsPaused = true; + _group.PositionTicks = session.PlayState.PositionTicks ?? 0; + _group.LastActivity = DateTime.UtcNow; + + var updateSession = NewSyncPlayGroupUpdate(GroupUpdateType.GroupJoined, DateToUTCString(DateTime.UtcNow)); + SendGroupUpdate(session, BroadcastType.CurrentSession, updateSession, cancellationToken); + var pauseCommand = NewSyncPlayCommand(SendCommandType.Pause); + SendCommand(session, BroadcastType.CurrentSession, pauseCommand, cancellationToken); + } + + /// + public void SessionJoin(SessionInfo session, JoinGroupRequest request, CancellationToken cancellationToken) + { + if (session.NowPlayingItem?.Id == _group.PlayingItem.Id && request.PlayingItemId == _group.PlayingItem.Id) + { + _group.AddSession(session); + _syncPlayManager.AddSessionToGroup(session, this); + + var updateSession = NewSyncPlayGroupUpdate(GroupUpdateType.GroupJoined, DateToUTCString(DateTime.UtcNow)); + SendGroupUpdate(session, BroadcastType.CurrentSession, updateSession, cancellationToken); + + var updateOthers = NewSyncPlayGroupUpdate(GroupUpdateType.UserJoined, session.UserName); + SendGroupUpdate(session, BroadcastType.AllExceptCurrentSession, updateOthers, cancellationToken); + + // Client join and play, syncing will happen client side + if (!_group.IsPaused) + { + var playCommand = NewSyncPlayCommand(SendCommandType.Play); + SendCommand(session, BroadcastType.CurrentSession, playCommand, cancellationToken); + } + else + { + var pauseCommand = NewSyncPlayCommand(SendCommandType.Pause); + SendCommand(session, BroadcastType.CurrentSession, pauseCommand, cancellationToken); + } + } + else + { + var playRequest = new PlayRequest(); + playRequest.ItemIds = new Guid[] { _group.PlayingItem.Id }; + playRequest.StartPositionTicks = _group.PositionTicks; + var update = NewSyncPlayGroupUpdate(GroupUpdateType.PrepareSession, playRequest); + SendGroupUpdate(session, BroadcastType.CurrentSession, update, cancellationToken); + } + } + + /// + public void SessionLeave(SessionInfo session, CancellationToken cancellationToken) + { + _group.RemoveSession(session); + _syncPlayManager.RemoveSessionFromGroup(session, this); + + var updateSession = NewSyncPlayGroupUpdate(GroupUpdateType.GroupLeft, _group.PositionTicks); + SendGroupUpdate(session, BroadcastType.CurrentSession, updateSession, cancellationToken); + + var updateOthers = NewSyncPlayGroupUpdate(GroupUpdateType.UserLeft, session.UserName); + SendGroupUpdate(session, BroadcastType.AllExceptCurrentSession, updateOthers, cancellationToken); + } + + /// + public void HandleRequest(SessionInfo session, PlaybackRequest request, CancellationToken cancellationToken) + { + // The server's job is to mantain a consistent state to which clients refer to, + // as also to notify clients of state changes. + // The actual syncing of media playback happens client side. + // Clients are aware of the server's time and use it to sync. + switch (request.Type) + { + case PlaybackRequestType.Play: + HandlePlayRequest(session, request, cancellationToken); + break; + case PlaybackRequestType.Pause: + HandlePauseRequest(session, request, cancellationToken); + break; + case PlaybackRequestType.Seek: + HandleSeekRequest(session, request, cancellationToken); + break; + case PlaybackRequestType.Buffering: + HandleBufferingRequest(session, request, cancellationToken); + break; + case PlaybackRequestType.BufferingDone: + HandleBufferingDoneRequest(session, request, cancellationToken); + break; + case PlaybackRequestType.UpdatePing: + HandlePingUpdateRequest(session, request); + break; + } + } + + /// + /// Handles a play action requested by a session. + /// + /// The session. + /// The play action. + /// The cancellation token. + private void HandlePlayRequest(SessionInfo session, PlaybackRequest request, CancellationToken cancellationToken) + { + if (_group.IsPaused) + { + // Pick a suitable time that accounts for latency + var delay = _group.GetHighestPing() * 2; + delay = delay < _group.DefaulPing ? _group.DefaulPing : delay; + + // Unpause group and set starting point in future + // Clients will start playback at LastActivity (datetime) from PositionTicks (playback position) + // The added delay does not guarantee, of course, that the command will be received in time + // Playback synchronization will mainly happen client side + _group.IsPaused = false; + _group.LastActivity = DateTime.UtcNow.AddMilliseconds( + delay + ); + + var command = NewSyncPlayCommand(SendCommandType.Play); + SendCommand(session, BroadcastType.AllGroup, command, cancellationToken); + } + else + { + // Client got lost, sending current state + var command = NewSyncPlayCommand(SendCommandType.Play); + SendCommand(session, BroadcastType.CurrentSession, command, cancellationToken); + } + } + + /// + /// Handles a pause action requested by a session. + /// + /// The session. + /// The pause action. + /// The cancellation token. + private void HandlePauseRequest(SessionInfo session, PlaybackRequest request, CancellationToken cancellationToken) + { + if (!_group.IsPaused) + { + // Pause group and compute the media playback position + _group.IsPaused = true; + var currentTime = DateTime.UtcNow; + var elapsedTime = currentTime - _group.LastActivity; + _group.LastActivity = currentTime; + // Seek only if playback actually started + // (a pause request may be issued during the delay added to account for latency) + _group.PositionTicks += elapsedTime.Ticks > 0 ? elapsedTime.Ticks : 0; + + var command = NewSyncPlayCommand(SendCommandType.Pause); + SendCommand(session, BroadcastType.AllGroup, command, cancellationToken); + } + else + { + // Client got lost, sending current state + var command = NewSyncPlayCommand(SendCommandType.Pause); + SendCommand(session, BroadcastType.CurrentSession, command, cancellationToken); + } + } + + /// + /// Handles a seek action requested by a session. + /// + /// The session. + /// The seek action. + /// The cancellation token. + private void HandleSeekRequest(SessionInfo session, PlaybackRequest request, CancellationToken cancellationToken) + { + // Sanitize PositionTicks + var ticks = SanitizePositionTicks(request.PositionTicks); + + // Pause and seek + _group.IsPaused = true; + _group.PositionTicks = ticks; + _group.LastActivity = DateTime.UtcNow; + + var command = NewSyncPlayCommand(SendCommandType.Seek); + SendCommand(session, BroadcastType.AllGroup, command, cancellationToken); + } + + /// + /// Handles a buffering action requested by a session. + /// + /// The session. + /// The buffering action. + /// The cancellation token. + private void HandleBufferingRequest(SessionInfo session, PlaybackRequest request, CancellationToken cancellationToken) + { + if (!_group.IsPaused) + { + // Pause group and compute the media playback position + _group.IsPaused = true; + var currentTime = DateTime.UtcNow; + var elapsedTime = currentTime - _group.LastActivity; + _group.LastActivity = currentTime; + _group.PositionTicks += elapsedTime.Ticks > 0 ? elapsedTime.Ticks : 0; + + _group.SetBuffering(session, true); + + // Send pause command to all non-buffering sessions + var command = NewSyncPlayCommand(SendCommandType.Pause); + SendCommand(session, BroadcastType.AllReady, command, cancellationToken); + + var updateOthers = NewSyncPlayGroupUpdate(GroupUpdateType.GroupWait, session.UserName); + SendGroupUpdate(session, BroadcastType.AllExceptCurrentSession, updateOthers, cancellationToken); + } + else + { + // Client got lost, sending current state + var command = NewSyncPlayCommand(SendCommandType.Pause); + SendCommand(session, BroadcastType.CurrentSession, command, cancellationToken); + } + } + + /// + /// Handles a buffering-done action requested by a session. + /// + /// The session. + /// The buffering-done action. + /// The cancellation token. + private void HandleBufferingDoneRequest(SessionInfo session, PlaybackRequest request, CancellationToken cancellationToken) + { + if (_group.IsPaused) + { + _group.SetBuffering(session, false); + + var requestTicks = SanitizePositionTicks(request.PositionTicks); + + var when = request.When ?? DateTime.UtcNow; + var currentTime = DateTime.UtcNow; + var elapsedTime = currentTime - when; + var clientPosition = TimeSpan.FromTicks(requestTicks) + elapsedTime; + var delay = _group.PositionTicks - clientPosition.Ticks; + + if (_group.IsBuffering()) + { + // Others are still buffering, tell this client to pause when ready + var command = NewSyncPlayCommand(SendCommandType.Pause); + var pauseAtTime = currentTime.AddMilliseconds(delay); + command.When = DateToUTCString(pauseAtTime); + SendCommand(session, BroadcastType.CurrentSession, command, cancellationToken); + } + else + { + // Let other clients resume as soon as the buffering client catches up + _group.IsPaused = false; + + if (delay > _group.GetHighestPing() * 2) + { + // Client that was buffering is recovering, notifying others to resume + _group.LastActivity = currentTime.AddMilliseconds( + delay + ); + var command = NewSyncPlayCommand(SendCommandType.Play); + SendCommand(session, BroadcastType.AllExceptCurrentSession, command, cancellationToken); + } + else + { + // Client, that was buffering, resumed playback but did not update others in time + delay = _group.GetHighestPing() * 2; + delay = delay < _group.DefaulPing ? _group.DefaulPing : delay; + + _group.LastActivity = currentTime.AddMilliseconds( + delay + ); + + var command = NewSyncPlayCommand(SendCommandType.Play); + SendCommand(session, BroadcastType.AllGroup, command, cancellationToken); + } + } + } + else + { + // Group was not waiting, make sure client has latest state + var command = NewSyncPlayCommand(SendCommandType.Play); + SendCommand(session, BroadcastType.CurrentSession, command, cancellationToken); + } + } + + /// + /// Sanitizes the PositionTicks, considers the current playing item when available. + /// + /// The PositionTicks. + /// The sanitized PositionTicks. + private long SanitizePositionTicks(long? positionTicks) + { + var ticks = positionTicks ?? 0; + ticks = ticks >= 0 ? ticks : 0; + if (_group.PlayingItem != null) + { + var runTimeTicks = _group.PlayingItem.RunTimeTicks ?? 0; + ticks = ticks > runTimeTicks ? runTimeTicks : ticks; + } + return ticks; + } + + /// + /// Updates ping of a session. + /// + /// The session. + /// The update. + private void HandlePingUpdateRequest(SessionInfo session, PlaybackRequest request) + { + // Collected pings are used to account for network latency when unpausing playback + _group.UpdatePing(session, request.Ping ?? _group.DefaulPing); + } + + /// + public GroupInfoView GetInfo() + { + return new GroupInfoView() + { + GroupId = GetGroupId().ToString(), + PlayingItemName = _group.PlayingItem.Name, + PlayingItemId = _group.PlayingItem.Id.ToString(), + PositionTicks = _group.PositionTicks, + Participants = _group.Participants.Values.Select(session => session.Session.UserName).Distinct().ToArray() + }; + } + } +} diff --git a/Emby.Server.Implementations/SyncPlay/SyncPlayManager.cs b/Emby.Server.Implementations/SyncPlay/SyncPlayManager.cs new file mode 100644 index 000000000..d3197d97b --- /dev/null +++ b/Emby.Server.Implementations/SyncPlay/SyncPlayManager.cs @@ -0,0 +1,385 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Threading; +using Microsoft.Extensions.Logging; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Session; +using MediaBrowser.Controller.SyncPlay; +using MediaBrowser.Model.Configuration; +using MediaBrowser.Model.SyncPlay; + +namespace Emby.Server.Implementations.SyncPlay +{ + /// + /// Class SyncPlayManager. + /// + public class SyncPlayManager : ISyncPlayManager, IDisposable + { + /// + /// The logger. + /// + private readonly ILogger _logger; + + /// + /// The user manager. + /// + private readonly IUserManager _userManager; + + /// + /// The session manager. + /// + private readonly ISessionManager _sessionManager; + + /// + /// The library manager. + /// + private readonly ILibraryManager _libraryManager; + + /// + /// The map between sessions and groups. + /// + private readonly Dictionary _sessionToGroupMap = + new Dictionary(StringComparer.OrdinalIgnoreCase); + + /// + /// The groups. + /// + private readonly Dictionary _groups = + new Dictionary(StringComparer.OrdinalIgnoreCase); + + /// + /// Lock used for accesing any group. + /// + private readonly object _groupsLock = new object(); + + private bool _disposed = false; + + public SyncPlayManager( + ILogger logger, + IUserManager userManager, + ISessionManager sessionManager, + ILibraryManager libraryManager) + { + _logger = logger; + _userManager = userManager; + _sessionManager = sessionManager; + _libraryManager = libraryManager; + + _sessionManager.SessionEnded += OnSessionManagerSessionEnded; + _sessionManager.PlaybackStopped += OnSessionManagerPlaybackStopped; + } + + /// + /// Gets all groups. + /// + /// All groups. + public IEnumerable Groups => _groups.Values; + + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + /// + /// Releases unmanaged and optionally managed resources. + /// + /// true to release both managed and unmanaged resources; false to release only unmanaged resources. + protected virtual void Dispose(bool disposing) + { + if (_disposed) + { + return; + } + + _sessionManager.SessionEnded -= OnSessionManagerSessionEnded; + _sessionManager.PlaybackStopped -= OnSessionManagerPlaybackStopped; + + _disposed = true; + } + + private void CheckDisposed() + { + if (_disposed) + { + throw new ObjectDisposedException(GetType().Name); + } + } + + private void OnSessionManagerSessionEnded(object sender, SessionEventArgs e) + { + var session = e.SessionInfo; + if (!IsSessionInGroup(session)) return; + LeaveGroup(session, CancellationToken.None); + } + + private void OnSessionManagerPlaybackStopped(object sender, PlaybackStopEventArgs e) + { + var session = e.Session; + if (!IsSessionInGroup(session)) return; + LeaveGroup(session, CancellationToken.None); + } + + private bool IsSessionInGroup(SessionInfo session) + { + return _sessionToGroupMap.ContainsKey(session.Id); + } + + private bool HasAccessToItem(User user, Guid itemId) + { + var item = _libraryManager.GetItemById(itemId); + + // Check ParentalRating access + var hasParentalRatingAccess = true; + if (user.Policy.MaxParentalRating.HasValue) + { + hasParentalRatingAccess = item.InheritedParentalRatingValue <= user.Policy.MaxParentalRating; + } + + if (!user.Policy.EnableAllFolders && hasParentalRatingAccess) + { + var collections = _libraryManager.GetCollectionFolders(item).Select( + folder => folder.Id.ToString("N", CultureInfo.InvariantCulture) + ); + var intersect = collections.Intersect(user.Policy.EnabledFolders); + return intersect.Any(); + } + else + { + return hasParentalRatingAccess; + } + } + + private Guid? GetSessionGroup(SessionInfo session) + { + ISyncPlayController group; + _sessionToGroupMap.TryGetValue(session.Id, out group); + if (group != null) + { + return group.GetGroupId(); + } + else + { + return null; + } + } + + /// + public void NewGroup(SessionInfo session, CancellationToken cancellationToken) + { + var user = _userManager.GetUserById(session.UserId); + + if (user.Policy.SyncPlayAccess != SyncPlayAccess.CreateAndJoinGroups) + { + _logger.LogWarning("NewGroup: {0} does not have permission to create groups.", session.Id); + + var error = new GroupUpdate() + { + Type = GroupUpdateType.CreateGroupDenied + }; + _sessionManager.SendSyncPlayGroupUpdate(session.Id.ToString(), error, CancellationToken.None); + return; + } + + lock (_groupsLock) + { + if (IsSessionInGroup(session)) + { + LeaveGroup(session, cancellationToken); + } + + var group = new SyncPlayController(_sessionManager, this); + _groups[group.GetGroupId().ToString()] = group; + + group.InitGroup(session, cancellationToken); + } + } + + /// + public void JoinGroup(SessionInfo session, string groupId, JoinGroupRequest request, CancellationToken cancellationToken) + { + var user = _userManager.GetUserById(session.UserId); + + if (user.Policy.SyncPlayAccess == SyncPlayAccess.None) + { + _logger.LogWarning("JoinGroup: {0} does not have access to SyncPlay.", session.Id); + + var error = new GroupUpdate() + { + Type = GroupUpdateType.JoinGroupDenied + }; + _sessionManager.SendSyncPlayGroupUpdate(session.Id.ToString(), error, CancellationToken.None); + return; + } + + lock (_groupsLock) + { + ISyncPlayController group; + _groups.TryGetValue(groupId, out group); + + if (group == null) + { + _logger.LogWarning("JoinGroup: {0} tried to join group {0} that does not exist.", session.Id, groupId); + + var error = new GroupUpdate() + { + Type = GroupUpdateType.GroupDoesNotExist + }; + _sessionManager.SendSyncPlayGroupUpdate(session.Id.ToString(), error, CancellationToken.None); + return; + } + + if (!HasAccessToItem(user, group.GetPlayingItemId())) + { + _logger.LogWarning("JoinGroup: {0} does not have access to {1}.", session.Id, group.GetPlayingItemId()); + + var error = new GroupUpdate() + { + GroupId = group.GetGroupId().ToString(), + Type = GroupUpdateType.LibraryAccessDenied + }; + _sessionManager.SendSyncPlayGroupUpdate(session.Id.ToString(), error, CancellationToken.None); + return; + } + + if (IsSessionInGroup(session)) + { + if (GetSessionGroup(session).Equals(groupId)) return; + LeaveGroup(session, cancellationToken); + } + + group.SessionJoin(session, request, cancellationToken); + } + } + + /// + public void LeaveGroup(SessionInfo session, CancellationToken cancellationToken) + { + // TODO: determine what happens to users that are in a group and get their permissions revoked + lock (_groupsLock) + { + ISyncPlayController group; + _sessionToGroupMap.TryGetValue(session.Id, out group); + + if (group == null) + { + _logger.LogWarning("LeaveGroup: {0} does not belong to any group.", session.Id); + + var error = new GroupUpdate() + { + Type = GroupUpdateType.NotInGroup + }; + _sessionManager.SendSyncPlayGroupUpdate(session.Id.ToString(), error, CancellationToken.None); + return; + } + + group.SessionLeave(session, cancellationToken); + + if (group.IsGroupEmpty()) + { + _logger.LogInformation("LeaveGroup: removing empty group {0}.", group.GetGroupId()); + _groups.Remove(group.GetGroupId().ToString(), out _); + } + } + } + + /// + public List ListGroups(SessionInfo session, Guid filterItemId) + { + var user = _userManager.GetUserById(session.UserId); + + if (user.Policy.SyncPlayAccess == SyncPlayAccess.None) + { + return new List(); + } + + // Filter by item if requested + if (!filterItemId.Equals(Guid.Empty)) + { + return _groups.Values.Where( + group => group.GetPlayingItemId().Equals(filterItemId) && HasAccessToItem(user, group.GetPlayingItemId()) + ).Select( + group => group.GetInfo() + ).ToList(); + } + // Otherwise show all available groups + else + { + return _groups.Values.Where( + group => HasAccessToItem(user, group.GetPlayingItemId()) + ).Select( + group => group.GetInfo() + ).ToList(); + } + } + + /// + public void HandleRequest(SessionInfo session, PlaybackRequest request, CancellationToken cancellationToken) + { + var user = _userManager.GetUserById(session.UserId); + + if (user.Policy.SyncPlayAccess == SyncPlayAccess.None) + { + _logger.LogWarning("HandleRequest: {0} does not have access to SyncPlay.", session.Id); + + var error = new GroupUpdate() + { + Type = GroupUpdateType.JoinGroupDenied + }; + _sessionManager.SendSyncPlayGroupUpdate(session.Id.ToString(), error, CancellationToken.None); + return; + } + + lock (_groupsLock) + { + ISyncPlayController group; + _sessionToGroupMap.TryGetValue(session.Id, out group); + + if (group == null) + { + _logger.LogWarning("HandleRequest: {0} does not belong to any group.", session.Id); + + var error = new GroupUpdate() + { + Type = GroupUpdateType.NotInGroup + }; + _sessionManager.SendSyncPlayGroupUpdate(session.Id.ToString(), error, CancellationToken.None); + return; + } + + group.HandleRequest(session, request, cancellationToken); + } + } + + /// + public void AddSessionToGroup(SessionInfo session, ISyncPlayController group) + { + if (IsSessionInGroup(session)) + { + throw new InvalidOperationException("Session in other group already!"); + } + _sessionToGroupMap[session.Id] = group; + } + + /// + public void RemoveSessionFromGroup(SessionInfo session, ISyncPlayController group) + { + if (!IsSessionInGroup(session)) + { + throw new InvalidOperationException("Session not in any group!"); + } + + ISyncPlayController tempGroup; + _sessionToGroupMap.Remove(session.Id, out tempGroup); + + if (!tempGroup.GetGroupId().Equals(group.GetGroupId())) + { + throw new InvalidOperationException("Session was in wrong group!"); + } + } + } +} diff --git a/Emby.Server.Implementations/Syncplay/SyncplayController.cs b/Emby.Server.Implementations/Syncplay/SyncplayController.cs deleted file mode 100644 index 8cc3d1fac..000000000 --- a/Emby.Server.Implementations/Syncplay/SyncplayController.cs +++ /dev/null @@ -1,548 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using MediaBrowser.Controller.Session; -using MediaBrowser.Controller.Syncplay; -using MediaBrowser.Model.Session; -using MediaBrowser.Model.Syncplay; - -namespace Emby.Server.Implementations.Syncplay -{ - /// - /// Class SyncplayController. - /// - /// - /// Class is not thread-safe, external locking is required when accessing methods. - /// - public class SyncplayController : ISyncplayController, IDisposable - { - /// - /// Used to filter the sessions of a group. - /// - private enum BroadcastType - { - /// - /// All sessions will receive the message. - /// - AllGroup = 0, - /// - /// Only the specified session will receive the message. - /// - CurrentSession = 1, - /// - /// All sessions, except the current one, will receive the message. - /// - AllExceptCurrentSession = 2, - /// - /// Only sessions that are not buffering will receive the message. - /// - AllReady = 3 - } - - /// - /// The session manager. - /// - private readonly ISessionManager _sessionManager; - - /// - /// The syncplay manager. - /// - private readonly ISyncplayManager _syncplayManager; - - /// - /// The group to manage. - /// - private readonly GroupInfo _group = new GroupInfo(); - - /// - public Guid GetGroupId() => _group.GroupId; - - /// - public Guid GetPlayingItemId() => _group.PlayingItem.Id; - - /// - public bool IsGroupEmpty() => _group.IsEmpty(); - - private bool _disposed = false; - - public SyncplayController( - ISessionManager sessionManager, - ISyncplayManager syncplayManager) - { - _sessionManager = sessionManager; - _syncplayManager = syncplayManager; - } - - /// - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - /// - /// Releases unmanaged and optionally managed resources. - /// - /// true to release both managed and unmanaged resources; false to release only unmanaged resources. - protected virtual void Dispose(bool disposing) - { - if (_disposed) - { - return; - } - - _disposed = true; - } - - // TODO: use this somewhere - private void CheckDisposed() - { - if (_disposed) - { - throw new ObjectDisposedException(GetType().Name); - } - } - - /// - /// Converts DateTime to UTC string. - /// - /// The date to convert. - /// The UTC string. - private string DateToUTCString(DateTime date) - { - return date.ToUniversalTime().ToString("o"); - } - - /// - /// Filters sessions of this group. - /// - /// The current session. - /// The filtering type. - /// The array of sessions matching the filter. - private SessionInfo[] FilterSessions(SessionInfo from, BroadcastType type) - { - switch (type) - { - case BroadcastType.CurrentSession: - return new SessionInfo[] { from }; - case BroadcastType.AllGroup: - return _group.Participants.Values.Select( - session => session.Session - ).ToArray(); - case BroadcastType.AllExceptCurrentSession: - return _group.Participants.Values.Select( - session => session.Session - ).Where( - session => !session.Id.Equals(from.Id) - ).ToArray(); - case BroadcastType.AllReady: - return _group.Participants.Values.Where( - session => !session.IsBuffering - ).Select( - session => session.Session - ).ToArray(); - default: - return new SessionInfo[] { }; - } - } - - /// - /// Sends a GroupUpdate message to the interested sessions. - /// - /// The current session. - /// The filtering type. - /// The message to send. - /// The cancellation token. - /// The task. - private Task SendGroupUpdate(SessionInfo from, BroadcastType type, GroupUpdate message, CancellationToken cancellationToken) - { - IEnumerable GetTasks() - { - SessionInfo[] sessions = FilterSessions(from, type); - foreach (var session in sessions) - { - yield return _sessionManager.SendSyncplayGroupUpdate(session.Id.ToString(), message, cancellationToken); - } - } - - return Task.WhenAll(GetTasks()); - } - - /// - /// Sends a playback command to the interested sessions. - /// - /// The current session. - /// The filtering type. - /// The message to send. - /// The cancellation token. - /// The task. - private Task SendCommand(SessionInfo from, BroadcastType type, SendCommand message, CancellationToken cancellationToken) - { - IEnumerable GetTasks() - { - SessionInfo[] sessions = FilterSessions(from, type); - foreach (var session in sessions) - { - yield return _sessionManager.SendSyncplayCommand(session.Id.ToString(), message, cancellationToken); - } - } - - return Task.WhenAll(GetTasks()); - } - - /// - /// Builds a new playback command with some default values. - /// - /// The command type. - /// The SendCommand. - private SendCommand NewSyncplayCommand(SendCommandType type) - { - return new SendCommand() - { - GroupId = _group.GroupId.ToString(), - Command = type, - PositionTicks = _group.PositionTicks, - When = DateToUTCString(_group.LastActivity), - EmittedAt = DateToUTCString(DateTime.UtcNow) - }; - } - - /// - /// Builds a new group update message. - /// - /// The update type. - /// The data to send. - /// The GroupUpdate. - private GroupUpdate NewSyncplayGroupUpdate(GroupUpdateType type, T data) - { - return new GroupUpdate() - { - GroupId = _group.GroupId.ToString(), - Type = type, - Data = data - }; - } - - /// - public void InitGroup(SessionInfo session, CancellationToken cancellationToken) - { - _group.AddSession(session); - _syncplayManager.AddSessionToGroup(session, this); - - _group.PlayingItem = session.FullNowPlayingItem; - _group.IsPaused = true; - _group.PositionTicks = session.PlayState.PositionTicks ?? 0; - _group.LastActivity = DateTime.UtcNow; - - var updateSession = NewSyncplayGroupUpdate(GroupUpdateType.GroupJoined, DateToUTCString(DateTime.UtcNow)); - SendGroupUpdate(session, BroadcastType.CurrentSession, updateSession, cancellationToken); - var pauseCommand = NewSyncplayCommand(SendCommandType.Pause); - SendCommand(session, BroadcastType.CurrentSession, pauseCommand, cancellationToken); - } - - /// - public void SessionJoin(SessionInfo session, JoinGroupRequest request, CancellationToken cancellationToken) - { - if (session.NowPlayingItem?.Id == _group.PlayingItem.Id && request.PlayingItemId == _group.PlayingItem.Id) - { - _group.AddSession(session); - _syncplayManager.AddSessionToGroup(session, this); - - var updateSession = NewSyncplayGroupUpdate(GroupUpdateType.GroupJoined, DateToUTCString(DateTime.UtcNow)); - SendGroupUpdate(session, BroadcastType.CurrentSession, updateSession, cancellationToken); - - var updateOthers = NewSyncplayGroupUpdate(GroupUpdateType.UserJoined, session.UserName); - SendGroupUpdate(session, BroadcastType.AllExceptCurrentSession, updateOthers, cancellationToken); - - // Client join and play, syncing will happen client side - if (!_group.IsPaused) - { - var playCommand = NewSyncplayCommand(SendCommandType.Play); - SendCommand(session, BroadcastType.CurrentSession, playCommand, cancellationToken); - } - else - { - var pauseCommand = NewSyncplayCommand(SendCommandType.Pause); - SendCommand(session, BroadcastType.CurrentSession, pauseCommand, cancellationToken); - } - } - else - { - var playRequest = new PlayRequest(); - playRequest.ItemIds = new Guid[] { _group.PlayingItem.Id }; - playRequest.StartPositionTicks = _group.PositionTicks; - var update = NewSyncplayGroupUpdate(GroupUpdateType.PrepareSession, playRequest); - SendGroupUpdate(session, BroadcastType.CurrentSession, update, cancellationToken); - } - } - - /// - public void SessionLeave(SessionInfo session, CancellationToken cancellationToken) - { - _group.RemoveSession(session); - _syncplayManager.RemoveSessionFromGroup(session, this); - - var updateSession = NewSyncplayGroupUpdate(GroupUpdateType.GroupLeft, _group.PositionTicks); - SendGroupUpdate(session, BroadcastType.CurrentSession, updateSession, cancellationToken); - - var updateOthers = NewSyncplayGroupUpdate(GroupUpdateType.UserLeft, session.UserName); - SendGroupUpdate(session, BroadcastType.AllExceptCurrentSession, updateOthers, cancellationToken); - } - - /// - public void HandleRequest(SessionInfo session, PlaybackRequest request, CancellationToken cancellationToken) - { - // The server's job is to mantain a consistent state to which clients refer to, - // as also to notify clients of state changes. - // The actual syncing of media playback happens client side. - // Clients are aware of the server's time and use it to sync. - switch (request.Type) - { - case PlaybackRequestType.Play: - HandlePlayRequest(session, request, cancellationToken); - break; - case PlaybackRequestType.Pause: - HandlePauseRequest(session, request, cancellationToken); - break; - case PlaybackRequestType.Seek: - HandleSeekRequest(session, request, cancellationToken); - break; - case PlaybackRequestType.Buffering: - HandleBufferingRequest(session, request, cancellationToken); - break; - case PlaybackRequestType.BufferingDone: - HandleBufferingDoneRequest(session, request, cancellationToken); - break; - case PlaybackRequestType.UpdatePing: - HandlePingUpdateRequest(session, request); - break; - } - } - - /// - /// Handles a play action requested by a session. - /// - /// The session. - /// The play action. - /// The cancellation token. - private void HandlePlayRequest(SessionInfo session, PlaybackRequest request, CancellationToken cancellationToken) - { - if (_group.IsPaused) - { - // Pick a suitable time that accounts for latency - var delay = _group.GetHighestPing() * 2; - delay = delay < _group.DefaulPing ? _group.DefaulPing : delay; - - // Unpause group and set starting point in future - // Clients will start playback at LastActivity (datetime) from PositionTicks (playback position) - // The added delay does not guarantee, of course, that the command will be received in time - // Playback synchronization will mainly happen client side - _group.IsPaused = false; - _group.LastActivity = DateTime.UtcNow.AddMilliseconds( - delay - ); - - var command = NewSyncplayCommand(SendCommandType.Play); - SendCommand(session, BroadcastType.AllGroup, command, cancellationToken); - } - else - { - // Client got lost, sending current state - var command = NewSyncplayCommand(SendCommandType.Play); - SendCommand(session, BroadcastType.CurrentSession, command, cancellationToken); - } - } - - /// - /// Handles a pause action requested by a session. - /// - /// The session. - /// The pause action. - /// The cancellation token. - private void HandlePauseRequest(SessionInfo session, PlaybackRequest request, CancellationToken cancellationToken) - { - if (!_group.IsPaused) - { - // Pause group and compute the media playback position - _group.IsPaused = true; - var currentTime = DateTime.UtcNow; - var elapsedTime = currentTime - _group.LastActivity; - _group.LastActivity = currentTime; - // Seek only if playback actually started - // (a pause request may be issued during the delay added to account for latency) - _group.PositionTicks += elapsedTime.Ticks > 0 ? elapsedTime.Ticks : 0; - - var command = NewSyncplayCommand(SendCommandType.Pause); - SendCommand(session, BroadcastType.AllGroup, command, cancellationToken); - } - else - { - // Client got lost, sending current state - var command = NewSyncplayCommand(SendCommandType.Pause); - SendCommand(session, BroadcastType.CurrentSession, command, cancellationToken); - } - } - - /// - /// Handles a seek action requested by a session. - /// - /// The session. - /// The seek action. - /// The cancellation token. - private void HandleSeekRequest(SessionInfo session, PlaybackRequest request, CancellationToken cancellationToken) - { - // Sanitize PositionTicks - var ticks = SanitizePositionTicks(request.PositionTicks); - - // Pause and seek - _group.IsPaused = true; - _group.PositionTicks = ticks; - _group.LastActivity = DateTime.UtcNow; - - var command = NewSyncplayCommand(SendCommandType.Seek); - SendCommand(session, BroadcastType.AllGroup, command, cancellationToken); - } - - /// - /// Handles a buffering action requested by a session. - /// - /// The session. - /// The buffering action. - /// The cancellation token. - private void HandleBufferingRequest(SessionInfo session, PlaybackRequest request, CancellationToken cancellationToken) - { - if (!_group.IsPaused) - { - // Pause group and compute the media playback position - _group.IsPaused = true; - var currentTime = DateTime.UtcNow; - var elapsedTime = currentTime - _group.LastActivity; - _group.LastActivity = currentTime; - _group.PositionTicks += elapsedTime.Ticks > 0 ? elapsedTime.Ticks : 0; - - _group.SetBuffering(session, true); - - // Send pause command to all non-buffering sessions - var command = NewSyncplayCommand(SendCommandType.Pause); - SendCommand(session, BroadcastType.AllReady, command, cancellationToken); - - var updateOthers = NewSyncplayGroupUpdate(GroupUpdateType.GroupWait, session.UserName); - SendGroupUpdate(session, BroadcastType.AllExceptCurrentSession, updateOthers, cancellationToken); - } - else - { - // Client got lost, sending current state - var command = NewSyncplayCommand(SendCommandType.Pause); - SendCommand(session, BroadcastType.CurrentSession, command, cancellationToken); - } - } - - /// - /// Handles a buffering-done action requested by a session. - /// - /// The session. - /// The buffering-done action. - /// The cancellation token. - private void HandleBufferingDoneRequest(SessionInfo session, PlaybackRequest request, CancellationToken cancellationToken) - { - if (_group.IsPaused) - { - _group.SetBuffering(session, false); - - var requestTicks = SanitizePositionTicks(request.PositionTicks); - - var when = request.When ?? DateTime.UtcNow; - var currentTime = DateTime.UtcNow; - var elapsedTime = currentTime - when; - var clientPosition = TimeSpan.FromTicks(requestTicks) + elapsedTime; - var delay = _group.PositionTicks - clientPosition.Ticks; - - if (_group.IsBuffering()) - { - // Others are still buffering, tell this client to pause when ready - var command = NewSyncplayCommand(SendCommandType.Pause); - var pauseAtTime = currentTime.AddMilliseconds(delay); - command.When = DateToUTCString(pauseAtTime); - SendCommand(session, BroadcastType.CurrentSession, command, cancellationToken); - } - else - { - // Let other clients resume as soon as the buffering client catches up - _group.IsPaused = false; - - if (delay > _group.GetHighestPing() * 2) - { - // Client that was buffering is recovering, notifying others to resume - _group.LastActivity = currentTime.AddMilliseconds( - delay - ); - var command = NewSyncplayCommand(SendCommandType.Play); - SendCommand(session, BroadcastType.AllExceptCurrentSession, command, cancellationToken); - } - else - { - // Client, that was buffering, resumed playback but did not update others in time - delay = _group.GetHighestPing() * 2; - delay = delay < _group.DefaulPing ? _group.DefaulPing : delay; - - _group.LastActivity = currentTime.AddMilliseconds( - delay - ); - - var command = NewSyncplayCommand(SendCommandType.Play); - SendCommand(session, BroadcastType.AllGroup, command, cancellationToken); - } - } - } - else - { - // Group was not waiting, make sure client has latest state - var command = NewSyncplayCommand(SendCommandType.Play); - SendCommand(session, BroadcastType.CurrentSession, command, cancellationToken); - } - } - - /// - /// Sanitizes the PositionTicks, considers the current playing item when available. - /// - /// The PositionTicks. - /// The sanitized PositionTicks. - private long SanitizePositionTicks(long? positionTicks) - { - var ticks = positionTicks ?? 0; - ticks = ticks >= 0 ? ticks : 0; - if (_group.PlayingItem != null) - { - var runTimeTicks = _group.PlayingItem.RunTimeTicks ?? 0; - ticks = ticks > runTimeTicks ? runTimeTicks : ticks; - } - return ticks; - } - - /// - /// Updates ping of a session. - /// - /// The session. - /// The update. - private void HandlePingUpdateRequest(SessionInfo session, PlaybackRequest request) - { - // Collected pings are used to account for network latency when unpausing playback - _group.UpdatePing(session, request.Ping ?? _group.DefaulPing); - } - - /// - public GroupInfoView GetInfo() - { - return new GroupInfoView() - { - GroupId = GetGroupId().ToString(), - PlayingItemName = _group.PlayingItem.Name, - PlayingItemId = _group.PlayingItem.Id.ToString(), - PositionTicks = _group.PositionTicks, - Participants = _group.Participants.Values.Select(session => session.Session.UserName).Distinct().ToArray() - }; - } - } -} diff --git a/Emby.Server.Implementations/Syncplay/SyncplayManager.cs b/Emby.Server.Implementations/Syncplay/SyncplayManager.cs deleted file mode 100644 index 7074e2225..000000000 --- a/Emby.Server.Implementations/Syncplay/SyncplayManager.cs +++ /dev/null @@ -1,385 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Threading; -using Microsoft.Extensions.Logging; -using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Library; -using MediaBrowser.Controller.Session; -using MediaBrowser.Controller.Syncplay; -using MediaBrowser.Model.Configuration; -using MediaBrowser.Model.Syncplay; - -namespace Emby.Server.Implementations.Syncplay -{ - /// - /// Class SyncplayManager. - /// - public class SyncplayManager : ISyncplayManager, IDisposable - { - /// - /// The logger. - /// - private readonly ILogger _logger; - - /// - /// The user manager. - /// - private readonly IUserManager _userManager; - - /// - /// The session manager. - /// - private readonly ISessionManager _sessionManager; - - /// - /// The library manager. - /// - private readonly ILibraryManager _libraryManager; - - /// - /// The map between sessions and groups. - /// - private readonly Dictionary _sessionToGroupMap = - new Dictionary(StringComparer.OrdinalIgnoreCase); - - /// - /// The groups. - /// - private readonly Dictionary _groups = - new Dictionary(StringComparer.OrdinalIgnoreCase); - - /// - /// Lock used for accesing any group. - /// - private readonly object _groupsLock = new object(); - - private bool _disposed = false; - - public SyncplayManager( - ILogger logger, - IUserManager userManager, - ISessionManager sessionManager, - ILibraryManager libraryManager) - { - _logger = logger; - _userManager = userManager; - _sessionManager = sessionManager; - _libraryManager = libraryManager; - - _sessionManager.SessionEnded += OnSessionManagerSessionEnded; - _sessionManager.PlaybackStopped += OnSessionManagerPlaybackStopped; - } - - /// - /// Gets all groups. - /// - /// All groups. - public IEnumerable Groups => _groups.Values; - - /// - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - /// - /// Releases unmanaged and optionally managed resources. - /// - /// true to release both managed and unmanaged resources; false to release only unmanaged resources. - protected virtual void Dispose(bool disposing) - { - if (_disposed) - { - return; - } - - _sessionManager.SessionEnded -= OnSessionManagerSessionEnded; - _sessionManager.PlaybackStopped -= OnSessionManagerPlaybackStopped; - - _disposed = true; - } - - private void CheckDisposed() - { - if (_disposed) - { - throw new ObjectDisposedException(GetType().Name); - } - } - - private void OnSessionManagerSessionEnded(object sender, SessionEventArgs e) - { - var session = e.SessionInfo; - if (!IsSessionInGroup(session)) return; - LeaveGroup(session, CancellationToken.None); - } - - private void OnSessionManagerPlaybackStopped(object sender, PlaybackStopEventArgs e) - { - var session = e.Session; - if (!IsSessionInGroup(session)) return; - LeaveGroup(session, CancellationToken.None); - } - - private bool IsSessionInGroup(SessionInfo session) - { - return _sessionToGroupMap.ContainsKey(session.Id); - } - - private bool HasAccessToItem(User user, Guid itemId) - { - var item = _libraryManager.GetItemById(itemId); - - // Check ParentalRating access - var hasParentalRatingAccess = true; - if (user.Policy.MaxParentalRating.HasValue) - { - hasParentalRatingAccess = item.InheritedParentalRatingValue <= user.Policy.MaxParentalRating; - } - - if (!user.Policy.EnableAllFolders && hasParentalRatingAccess) - { - var collections = _libraryManager.GetCollectionFolders(item).Select( - folder => folder.Id.ToString("N", CultureInfo.InvariantCulture) - ); - var intersect = collections.Intersect(user.Policy.EnabledFolders); - return intersect.Any(); - } - else - { - return hasParentalRatingAccess; - } - } - - private Guid? GetSessionGroup(SessionInfo session) - { - ISyncplayController group; - _sessionToGroupMap.TryGetValue(session.Id, out group); - if (group != null) - { - return group.GetGroupId(); - } - else - { - return null; - } - } - - /// - public void NewGroup(SessionInfo session, CancellationToken cancellationToken) - { - var user = _userManager.GetUserById(session.UserId); - - if (user.Policy.SyncplayAccess != SyncplayAccess.CreateAndJoinGroups) - { - _logger.LogWarning("NewGroup: {0} does not have permission to create groups.", session.Id); - - var error = new GroupUpdate() - { - Type = GroupUpdateType.CreateGroupDenied - }; - _sessionManager.SendSyncplayGroupUpdate(session.Id.ToString(), error, CancellationToken.None); - return; - } - - lock (_groupsLock) - { - if (IsSessionInGroup(session)) - { - LeaveGroup(session, cancellationToken); - } - - var group = new SyncplayController(_sessionManager, this); - _groups[group.GetGroupId().ToString()] = group; - - group.InitGroup(session, cancellationToken); - } - } - - /// - public void JoinGroup(SessionInfo session, string groupId, JoinGroupRequest request, CancellationToken cancellationToken) - { - var user = _userManager.GetUserById(session.UserId); - - if (user.Policy.SyncplayAccess == SyncplayAccess.None) - { - _logger.LogWarning("JoinGroup: {0} does not have access to Syncplay.", session.Id); - - var error = new GroupUpdate() - { - Type = GroupUpdateType.JoinGroupDenied - }; - _sessionManager.SendSyncplayGroupUpdate(session.Id.ToString(), error, CancellationToken.None); - return; - } - - lock (_groupsLock) - { - ISyncplayController group; - _groups.TryGetValue(groupId, out group); - - if (group == null) - { - _logger.LogWarning("JoinGroup: {0} tried to join group {0} that does not exist.", session.Id, groupId); - - var error = new GroupUpdate() - { - Type = GroupUpdateType.GroupDoesNotExist - }; - _sessionManager.SendSyncplayGroupUpdate(session.Id.ToString(), error, CancellationToken.None); - return; - } - - if (!HasAccessToItem(user, group.GetPlayingItemId())) - { - _logger.LogWarning("JoinGroup: {0} does not have access to {1}.", session.Id, group.GetPlayingItemId()); - - var error = new GroupUpdate() - { - GroupId = group.GetGroupId().ToString(), - Type = GroupUpdateType.LibraryAccessDenied - }; - _sessionManager.SendSyncplayGroupUpdate(session.Id.ToString(), error, CancellationToken.None); - return; - } - - if (IsSessionInGroup(session)) - { - if (GetSessionGroup(session).Equals(groupId)) return; - LeaveGroup(session, cancellationToken); - } - - group.SessionJoin(session, request, cancellationToken); - } - } - - /// - public void LeaveGroup(SessionInfo session, CancellationToken cancellationToken) - { - // TODO: determine what happens to users that are in a group and get their permissions revoked - lock (_groupsLock) - { - ISyncplayController group; - _sessionToGroupMap.TryGetValue(session.Id, out group); - - if (group == null) - { - _logger.LogWarning("LeaveGroup: {0} does not belong to any group.", session.Id); - - var error = new GroupUpdate() - { - Type = GroupUpdateType.NotInGroup - }; - _sessionManager.SendSyncplayGroupUpdate(session.Id.ToString(), error, CancellationToken.None); - return; - } - - group.SessionLeave(session, cancellationToken); - - if (group.IsGroupEmpty()) - { - _logger.LogInformation("LeaveGroup: removing empty group {0}.", group.GetGroupId()); - _groups.Remove(group.GetGroupId().ToString(), out _); - } - } - } - - /// - public List ListGroups(SessionInfo session, Guid filterItemId) - { - var user = _userManager.GetUserById(session.UserId); - - if (user.Policy.SyncplayAccess == SyncplayAccess.None) - { - return new List(); - } - - // Filter by item if requested - if (!filterItemId.Equals(Guid.Empty)) - { - return _groups.Values.Where( - group => group.GetPlayingItemId().Equals(filterItemId) && HasAccessToItem(user, group.GetPlayingItemId()) - ).Select( - group => group.GetInfo() - ).ToList(); - } - // Otherwise show all available groups - else - { - return _groups.Values.Where( - group => HasAccessToItem(user, group.GetPlayingItemId()) - ).Select( - group => group.GetInfo() - ).ToList(); - } - } - - /// - public void HandleRequest(SessionInfo session, PlaybackRequest request, CancellationToken cancellationToken) - { - var user = _userManager.GetUserById(session.UserId); - - if (user.Policy.SyncplayAccess == SyncplayAccess.None) - { - _logger.LogWarning("HandleRequest: {0} does not have access to Syncplay.", session.Id); - - var error = new GroupUpdate() - { - Type = GroupUpdateType.JoinGroupDenied - }; - _sessionManager.SendSyncplayGroupUpdate(session.Id.ToString(), error, CancellationToken.None); - return; - } - - lock (_groupsLock) - { - ISyncplayController group; - _sessionToGroupMap.TryGetValue(session.Id, out group); - - if (group == null) - { - _logger.LogWarning("HandleRequest: {0} does not belong to any group.", session.Id); - - var error = new GroupUpdate() - { - Type = GroupUpdateType.NotInGroup - }; - _sessionManager.SendSyncplayGroupUpdate(session.Id.ToString(), error, CancellationToken.None); - return; - } - - group.HandleRequest(session, request, cancellationToken); - } - } - - /// - public void AddSessionToGroup(SessionInfo session, ISyncplayController group) - { - if (IsSessionInGroup(session)) - { - throw new InvalidOperationException("Session in other group already!"); - } - _sessionToGroupMap[session.Id] = group; - } - - /// - public void RemoveSessionFromGroup(SessionInfo session, ISyncplayController group) - { - if (!IsSessionInGroup(session)) - { - throw new InvalidOperationException("Session not in any group!"); - } - - ISyncplayController tempGroup; - _sessionToGroupMap.Remove(session.Id, out tempGroup); - - if (!tempGroup.GetGroupId().Equals(group.GetGroupId())) - { - throw new InvalidOperationException("Session was in wrong group!"); - } - } - } -} diff --git a/MediaBrowser.Api/SyncPlay/SyncPlayService.cs b/MediaBrowser.Api/SyncPlay/SyncPlayService.cs new file mode 100644 index 000000000..bcdc833e4 --- /dev/null +++ b/MediaBrowser.Api/SyncPlay/SyncPlayService.cs @@ -0,0 +1,312 @@ +using System.Threading; +using System; +using System.Collections.Generic; +using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Net; +using MediaBrowser.Controller.Session; +using MediaBrowser.Controller.SyncPlay; +using MediaBrowser.Model.Services; +using MediaBrowser.Model.SyncPlay; +using Microsoft.Extensions.Logging; + +namespace MediaBrowser.Api.SyncPlay +{ + [Route("/SyncPlay/{SessionId}/NewGroup", "POST", Summary = "Create a new SyncPlay group")] + [Authenticated] + public class SyncPlayNewGroup : IReturnVoid + { + [ApiMember(Name = "SessionId", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] + public string SessionId { get; set; } + } + + [Route("/SyncPlay/{SessionId}/JoinGroup", "POST", Summary = "Join an existing SyncPlay group")] + [Authenticated] + public class SyncPlayJoinGroup : IReturnVoid + { + [ApiMember(Name = "SessionId", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] + public string SessionId { get; set; } + + /// + /// Gets or sets the Group id. + /// + /// The Group id to join. + [ApiMember(Name = "GroupId", Description = "Group Id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")] + public string GroupId { get; set; } + + /// + /// Gets or sets the playing item id. + /// + /// The client's currently playing item id. + [ApiMember(Name = "PlayingItemId", Description = "Client's playing item id", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")] + public string PlayingItemId { get; set; } + } + + [Route("/SyncPlay/{SessionId}/LeaveGroup", "POST", Summary = "Leave joined SyncPlay group")] + [Authenticated] + public class SyncPlayLeaveGroup : IReturnVoid + { + [ApiMember(Name = "SessionId", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] + public string SessionId { get; set; } + } + + [Route("/SyncPlay/{SessionId}/ListGroups", "POST", Summary = "List SyncPlay groups")] + [Authenticated] + public class SyncPlayListGroups : IReturnVoid + { + [ApiMember(Name = "SessionId", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] + public string SessionId { get; set; } + + /// + /// Gets or sets the filter item id. + /// + /// The filter item id. + [ApiMember(Name = "FilterItemId", Description = "Filter by item id", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")] + public string FilterItemId { get; set; } + } + + [Route("/SyncPlay/{SessionId}/PlayRequest", "POST", Summary = "Request play in SyncPlay group")] + [Authenticated] + public class SyncPlayPlayRequest : IReturnVoid + { + [ApiMember(Name = "SessionId", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] + public string SessionId { get; set; } + } + + [Route("/SyncPlay/{SessionId}/PauseRequest", "POST", Summary = "Request pause in SyncPlay group")] + [Authenticated] + public class SyncPlayPauseRequest : IReturnVoid + { + [ApiMember(Name = "SessionId", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] + public string SessionId { get; set; } + } + + [Route("/SyncPlay/{SessionId}/SeekRequest", "POST", Summary = "Request seek in SyncPlay group")] + [Authenticated] + public class SyncPlaySeekRequest : IReturnVoid + { + [ApiMember(Name = "SessionId", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] + public string SessionId { get; set; } + + [ApiMember(Name = "PositionTicks", IsRequired = true, DataType = "long", ParameterType = "query", Verb = "POST")] + public long PositionTicks { get; set; } + } + + [Route("/SyncPlay/{SessionId}/BufferingRequest", "POST", Summary = "Request group wait in SyncPlay group while buffering")] + [Authenticated] + public class SyncPlayBufferingRequest : IReturnVoid + { + [ApiMember(Name = "SessionId", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] + public string SessionId { get; set; } + + /// + /// Gets or sets the date used to pin PositionTicks in time. + /// + /// The date related to PositionTicks. + [ApiMember(Name = "When", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")] + public string When { get; set; } + + [ApiMember(Name = "PositionTicks", IsRequired = true, DataType = "long", ParameterType = "query", Verb = "POST")] + public long PositionTicks { get; set; } + + /// + /// Gets or sets whether this is a buffering or a buffering-done request. + /// + /// true if buffering is complete; false otherwise. + [ApiMember(Name = "BufferingDone", IsRequired = true, DataType = "bool", ParameterType = "query", Verb = "POST")] + public bool BufferingDone { get; set; } + } + + [Route("/SyncPlay/{SessionId}/UpdatePing", "POST", Summary = "Update session ping")] + [Authenticated] + public class SyncPlayUpdatePing : IReturnVoid + { + [ApiMember(Name = "SessionId", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] + public string SessionId { get; set; } + + [ApiMember(Name = "Ping", IsRequired = true, DataType = "double", ParameterType = "query", Verb = "POST")] + public double Ping { get; set; } + } + + /// + /// Class SyncPlayService. + /// + public class SyncPlayService : BaseApiService + { + /// + /// The session context. + /// + private readonly ISessionContext _sessionContext; + + /// + /// The SyncPlay manager. + /// + private readonly ISyncPlayManager _syncPlayManager; + + public SyncPlayService( + ILogger logger, + IServerConfigurationManager serverConfigurationManager, + IHttpResultFactory httpResultFactory, + ISessionContext sessionContext, + ISyncPlayManager syncPlayManager) + : base(logger, serverConfigurationManager, httpResultFactory) + { + _sessionContext = sessionContext; + _syncPlayManager = syncPlayManager; + } + + /// + /// Handles the specified request. + /// + /// The request. + public void Post(SyncPlayNewGroup request) + { + var currentSession = GetSession(_sessionContext); + _syncPlayManager.NewGroup(currentSession, CancellationToken.None); + } + + /// + /// Handles the specified request. + /// + /// The request. + public void Post(SyncPlayJoinGroup request) + { + var currentSession = GetSession(_sessionContext); + var joinRequest = new JoinGroupRequest() + { + GroupId = Guid.Parse(request.GroupId) + }; + + // Both null and empty strings mean that client isn't playing anything + if (!String.IsNullOrEmpty(request.PlayingItemId)) + { + try + { + joinRequest.PlayingItemId = Guid.Parse(request.PlayingItemId); + } + catch (ArgumentNullException) + { + // Should never happen, but just in case + Logger.LogError("JoinGroup: null value for PlayingItemId. Ignoring request."); + return; + } + catch (FormatException) + { + Logger.LogError("JoinGroup: {0} is not a valid format for PlayingItemId. Ignoring request.", request.PlayingItemId); + return; + } + } + _syncPlayManager.JoinGroup(currentSession, request.GroupId, joinRequest, CancellationToken.None); + } + + /// + /// Handles the specified request. + /// + /// The request. + public void Post(SyncPlayLeaveGroup request) + { + var currentSession = GetSession(_sessionContext); + _syncPlayManager.LeaveGroup(currentSession, CancellationToken.None); + } + + /// + /// Handles the specified request. + /// + /// The request. + /// The requested list of groups. + public List Post(SyncPlayListGroups request) + { + var currentSession = GetSession(_sessionContext); + var filterItemId = Guid.Empty; + if (!String.IsNullOrEmpty(request.FilterItemId)) + { + try + { + filterItemId = Guid.Parse(request.FilterItemId); + } + catch (ArgumentNullException) + { + Logger.LogWarning("ListGroups: null value for FilterItemId. Ignoring filter."); + } + catch (FormatException) + { + Logger.LogWarning("ListGroups: {0} is not a valid format for FilterItemId. Ignoring filter.", request.FilterItemId); + } + } + return _syncPlayManager.ListGroups(currentSession, filterItemId); + } + + /// + /// Handles the specified request. + /// + /// The request. + public void Post(SyncPlayPlayRequest request) + { + var currentSession = GetSession(_sessionContext); + var syncPlayRequest = new PlaybackRequest() + { + Type = PlaybackRequestType.Play + }; + _syncPlayManager.HandleRequest(currentSession, syncPlayRequest, CancellationToken.None); + } + + /// + /// Handles the specified request. + /// + /// The request. + public void Post(SyncPlayPauseRequest request) + { + var currentSession = GetSession(_sessionContext); + var syncPlayRequest = new PlaybackRequest() + { + Type = PlaybackRequestType.Pause + }; + _syncPlayManager.HandleRequest(currentSession, syncPlayRequest, CancellationToken.None); + } + + /// + /// Handles the specified request. + /// + /// The request. + public void Post(SyncPlaySeekRequest request) + { + var currentSession = GetSession(_sessionContext); + var syncPlayRequest = new PlaybackRequest() + { + Type = PlaybackRequestType.Seek, + PositionTicks = request.PositionTicks + }; + _syncPlayManager.HandleRequest(currentSession, syncPlayRequest, CancellationToken.None); + } + + /// + /// Handles the specified request. + /// + /// The request. + public void Post(SyncPlayBufferingRequest request) + { + var currentSession = GetSession(_sessionContext); + var syncPlayRequest = new PlaybackRequest() + { + Type = request.BufferingDone ? PlaybackRequestType.BufferingDone : PlaybackRequestType.Buffering, + When = DateTime.Parse(request.When), + PositionTicks = request.PositionTicks + }; + _syncPlayManager.HandleRequest(currentSession, syncPlayRequest, CancellationToken.None); + } + + /// + /// Handles the specified request. + /// + /// The request. + public void Post(SyncPlayUpdatePing request) + { + var currentSession = GetSession(_sessionContext); + var syncPlayRequest = new PlaybackRequest() + { + Type = PlaybackRequestType.UpdatePing, + Ping = Convert.ToInt64(request.Ping) + }; + _syncPlayManager.HandleRequest(currentSession, syncPlayRequest, CancellationToken.None); + } + } +} diff --git a/MediaBrowser.Api/SyncPlay/TimeSyncService.cs b/MediaBrowser.Api/SyncPlay/TimeSyncService.cs new file mode 100644 index 000000000..4a9307e62 --- /dev/null +++ b/MediaBrowser.Api/SyncPlay/TimeSyncService.cs @@ -0,0 +1,52 @@ +using System; +using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Net; +using MediaBrowser.Model.Services; +using MediaBrowser.Model.SyncPlay; +using Microsoft.Extensions.Logging; + +namespace MediaBrowser.Api.SyncPlay +{ + [Route("/GetUtcTime", "GET", Summary = "Get UtcTime")] + public class GetUtcTime : IReturnVoid + { + // Nothing + } + + /// + /// Class TimeSyncService. + /// + public class TimeSyncService : BaseApiService + { + public TimeSyncService( + ILogger logger, + IServerConfigurationManager serverConfigurationManager, + IHttpResultFactory httpResultFactory) + : base(logger, serverConfigurationManager, httpResultFactory) + { + // Do nothing + } + + /// + /// Handles the specified request. + /// + /// The request. + /// The current UTC time response. + public UtcTimeResponse Get(GetUtcTime request) + { + // Important to keep the following line at the beginning + var requestReceptionTime = DateTime.UtcNow.ToUniversalTime().ToString("o"); + + var response = new UtcTimeResponse(); + response.RequestReceptionTime = requestReceptionTime; + + // Important to keep the following two lines at the end + var responseTransmissionTime = DateTime.UtcNow.ToUniversalTime().ToString("o"); + response.ResponseTransmissionTime = responseTransmissionTime; + + // Implementing NTP on such a high level results in this useless + // information being sent. On the other hand it enables future additions. + return response; + } + } +} diff --git a/MediaBrowser.Api/Syncplay/SyncplayService.cs b/MediaBrowser.Api/Syncplay/SyncplayService.cs deleted file mode 100644 index 4b6e16762..000000000 --- a/MediaBrowser.Api/Syncplay/SyncplayService.cs +++ /dev/null @@ -1,312 +0,0 @@ -using System.Threading; -using System; -using System.Collections.Generic; -using MediaBrowser.Controller.Configuration; -using MediaBrowser.Controller.Net; -using MediaBrowser.Controller.Session; -using MediaBrowser.Controller.Syncplay; -using MediaBrowser.Model.Services; -using MediaBrowser.Model.Syncplay; -using Microsoft.Extensions.Logging; - -namespace MediaBrowser.Api.Syncplay -{ - [Route("/Syncplay/{SessionId}/NewGroup", "POST", Summary = "Create a new Syncplay group")] - [Authenticated] - public class SyncplayNewGroup : IReturnVoid - { - [ApiMember(Name = "SessionId", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] - public string SessionId { get; set; } - } - - [Route("/Syncplay/{SessionId}/JoinGroup", "POST", Summary = "Join an existing Syncplay group")] - [Authenticated] - public class SyncplayJoinGroup : IReturnVoid - { - [ApiMember(Name = "SessionId", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] - public string SessionId { get; set; } - - /// - /// Gets or sets the Group id. - /// - /// The Group id to join. - [ApiMember(Name = "GroupId", Description = "Group Id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")] - public string GroupId { get; set; } - - /// - /// Gets or sets the playing item id. - /// - /// The client's currently playing item id. - [ApiMember(Name = "PlayingItemId", Description = "Client's playing item id", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")] - public string PlayingItemId { get; set; } - } - - [Route("/Syncplay/{SessionId}/LeaveGroup", "POST", Summary = "Leave joined Syncplay group")] - [Authenticated] - public class SyncplayLeaveGroup : IReturnVoid - { - [ApiMember(Name = "SessionId", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] - public string SessionId { get; set; } - } - - [Route("/Syncplay/{SessionId}/ListGroups", "POST", Summary = "List Syncplay groups")] - [Authenticated] - public class SyncplayListGroups : IReturnVoid - { - [ApiMember(Name = "SessionId", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] - public string SessionId { get; set; } - - /// - /// Gets or sets the filter item id. - /// - /// The filter item id. - [ApiMember(Name = "FilterItemId", Description = "Filter by item id", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")] - public string FilterItemId { get; set; } - } - - [Route("/Syncplay/{SessionId}/PlayRequest", "POST", Summary = "Request play in Syncplay group")] - [Authenticated] - public class SyncplayPlayRequest : IReturnVoid - { - [ApiMember(Name = "SessionId", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] - public string SessionId { get; set; } - } - - [Route("/Syncplay/{SessionId}/PauseRequest", "POST", Summary = "Request pause in Syncplay group")] - [Authenticated] - public class SyncplayPauseRequest : IReturnVoid - { - [ApiMember(Name = "SessionId", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] - public string SessionId { get; set; } - } - - [Route("/Syncplay/{SessionId}/SeekRequest", "POST", Summary = "Request seek in Syncplay group")] - [Authenticated] - public class SyncplaySeekRequest : IReturnVoid - { - [ApiMember(Name = "SessionId", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] - public string SessionId { get; set; } - - [ApiMember(Name = "PositionTicks", IsRequired = true, DataType = "long", ParameterType = "query", Verb = "POST")] - public long PositionTicks { get; set; } - } - - [Route("/Syncplay/{SessionId}/BufferingRequest", "POST", Summary = "Request group wait in Syncplay group while buffering")] - [Authenticated] - public class SyncplayBufferingRequest : IReturnVoid - { - [ApiMember(Name = "SessionId", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] - public string SessionId { get; set; } - - /// - /// Gets or sets the date used to pin PositionTicks in time. - /// - /// The date related to PositionTicks. - [ApiMember(Name = "When", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")] - public string When { get; set; } - - [ApiMember(Name = "PositionTicks", IsRequired = true, DataType = "long", ParameterType = "query", Verb = "POST")] - public long PositionTicks { get; set; } - - /// - /// Gets or sets whether this is a buffering or a buffering-done request. - /// - /// true if buffering is complete; false otherwise. - [ApiMember(Name = "BufferingDone", IsRequired = true, DataType = "bool", ParameterType = "query", Verb = "POST")] - public bool BufferingDone { get; set; } - } - - [Route("/Syncplay/{SessionId}/UpdatePing", "POST", Summary = "Update session ping")] - [Authenticated] - public class SyncplayUpdatePing : IReturnVoid - { - [ApiMember(Name = "SessionId", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] - public string SessionId { get; set; } - - [ApiMember(Name = "Ping", IsRequired = true, DataType = "double", ParameterType = "query", Verb = "POST")] - public double Ping { get; set; } - } - - /// - /// Class SyncplayService. - /// - public class SyncplayService : BaseApiService - { - /// - /// The session context. - /// - private readonly ISessionContext _sessionContext; - - /// - /// The Syncplay manager. - /// - private readonly ISyncplayManager _syncplayManager; - - public SyncplayService( - ILogger logger, - IServerConfigurationManager serverConfigurationManager, - IHttpResultFactory httpResultFactory, - ISessionContext sessionContext, - ISyncplayManager syncplayManager) - : base(logger, serverConfigurationManager, httpResultFactory) - { - _sessionContext = sessionContext; - _syncplayManager = syncplayManager; - } - - /// - /// Handles the specified request. - /// - /// The request. - public void Post(SyncplayNewGroup request) - { - var currentSession = GetSession(_sessionContext); - _syncplayManager.NewGroup(currentSession, CancellationToken.None); - } - - /// - /// Handles the specified request. - /// - /// The request. - public void Post(SyncplayJoinGroup request) - { - var currentSession = GetSession(_sessionContext); - var joinRequest = new JoinGroupRequest() - { - GroupId = Guid.Parse(request.GroupId) - }; - - // Both null and empty strings mean that client isn't playing anything - if (!String.IsNullOrEmpty(request.PlayingItemId)) - { - try - { - joinRequest.PlayingItemId = Guid.Parse(request.PlayingItemId); - } - catch (ArgumentNullException) - { - // Should never happen, but just in case - Logger.LogError("JoinGroup: null value for PlayingItemId. Ignoring request."); - return; - } - catch (FormatException) - { - Logger.LogError("JoinGroup: {0} is not a valid format for PlayingItemId. Ignoring request.", request.PlayingItemId); - return; - } - } - _syncplayManager.JoinGroup(currentSession, request.GroupId, joinRequest, CancellationToken.None); - } - - /// - /// Handles the specified request. - /// - /// The request. - public void Post(SyncplayLeaveGroup request) - { - var currentSession = GetSession(_sessionContext); - _syncplayManager.LeaveGroup(currentSession, CancellationToken.None); - } - - /// - /// Handles the specified request. - /// - /// The request. - /// The requested list of groups. - public List Post(SyncplayListGroups request) - { - var currentSession = GetSession(_sessionContext); - var filterItemId = Guid.Empty; - if (!String.IsNullOrEmpty(request.FilterItemId)) - { - try - { - filterItemId = Guid.Parse(request.FilterItemId); - } - catch (ArgumentNullException) - { - Logger.LogWarning("ListGroups: null value for FilterItemId. Ignoring filter."); - } - catch (FormatException) - { - Logger.LogWarning("ListGroups: {0} is not a valid format for FilterItemId. Ignoring filter.", request.FilterItemId); - } - } - return _syncplayManager.ListGroups(currentSession, filterItemId); - } - - /// - /// Handles the specified request. - /// - /// The request. - public void Post(SyncplayPlayRequest request) - { - var currentSession = GetSession(_sessionContext); - var syncplayRequest = new PlaybackRequest() - { - Type = PlaybackRequestType.Play - }; - _syncplayManager.HandleRequest(currentSession, syncplayRequest, CancellationToken.None); - } - - /// - /// Handles the specified request. - /// - /// The request. - public void Post(SyncplayPauseRequest request) - { - var currentSession = GetSession(_sessionContext); - var syncplayRequest = new PlaybackRequest() - { - Type = PlaybackRequestType.Pause - }; - _syncplayManager.HandleRequest(currentSession, syncplayRequest, CancellationToken.None); - } - - /// - /// Handles the specified request. - /// - /// The request. - public void Post(SyncplaySeekRequest request) - { - var currentSession = GetSession(_sessionContext); - var syncplayRequest = new PlaybackRequest() - { - Type = PlaybackRequestType.Seek, - PositionTicks = request.PositionTicks - }; - _syncplayManager.HandleRequest(currentSession, syncplayRequest, CancellationToken.None); - } - - /// - /// Handles the specified request. - /// - /// The request. - public void Post(SyncplayBufferingRequest request) - { - var currentSession = GetSession(_sessionContext); - var syncplayRequest = new PlaybackRequest() - { - Type = request.BufferingDone ? PlaybackRequestType.BufferingDone : PlaybackRequestType.Buffering, - When = DateTime.Parse(request.When), - PositionTicks = request.PositionTicks - }; - _syncplayManager.HandleRequest(currentSession, syncplayRequest, CancellationToken.None); - } - - /// - /// Handles the specified request. - /// - /// The request. - public void Post(SyncplayUpdatePing request) - { - var currentSession = GetSession(_sessionContext); - var syncplayRequest = new PlaybackRequest() - { - Type = PlaybackRequestType.UpdatePing, - Ping = Convert.ToInt64(request.Ping) - }; - _syncplayManager.HandleRequest(currentSession, syncplayRequest, CancellationToken.None); - } - } -} diff --git a/MediaBrowser.Api/Syncplay/TimeSyncService.cs b/MediaBrowser.Api/Syncplay/TimeSyncService.cs deleted file mode 100644 index 9a26ffd99..000000000 --- a/MediaBrowser.Api/Syncplay/TimeSyncService.cs +++ /dev/null @@ -1,52 +0,0 @@ -using System; -using MediaBrowser.Controller.Configuration; -using MediaBrowser.Controller.Net; -using MediaBrowser.Model.Services; -using MediaBrowser.Model.Syncplay; -using Microsoft.Extensions.Logging; - -namespace MediaBrowser.Api.Syncplay -{ - [Route("/GetUtcTime", "GET", Summary = "Get UtcTime")] - public class GetUtcTime : IReturnVoid - { - // Nothing - } - - /// - /// Class TimeSyncService. - /// - public class TimeSyncService : BaseApiService - { - public TimeSyncService( - ILogger logger, - IServerConfigurationManager serverConfigurationManager, - IHttpResultFactory httpResultFactory) - : base(logger, serverConfigurationManager, httpResultFactory) - { - // Do nothing - } - - /// - /// Handles the specified request. - /// - /// The request. - /// The current UTC time response. - public UtcTimeResponse Get(GetUtcTime request) - { - // Important to keep the following line at the beginning - var requestReceptionTime = DateTime.UtcNow.ToUniversalTime().ToString("o"); - - var response = new UtcTimeResponse(); - response.RequestReceptionTime = requestReceptionTime; - - // Important to keep the following two lines at the end - var responseTransmissionTime = DateTime.UtcNow.ToUniversalTime().ToString("o"); - response.ResponseTransmissionTime = responseTransmissionTime; - - // Implementing NTP on such a high level results in this useless - // information being sent. On the other hand it enables future additions. - return response; - } - } -} diff --git a/MediaBrowser.Controller/Session/ISessionManager.cs b/MediaBrowser.Controller/Session/ISessionManager.cs index 39c065b89..4c2f834cb 100644 --- a/MediaBrowser.Controller/Session/ISessionManager.cs +++ b/MediaBrowser.Controller/Session/ISessionManager.cs @@ -9,7 +9,7 @@ using MediaBrowser.Controller.Security; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Events; using MediaBrowser.Model.Session; -using MediaBrowser.Model.Syncplay; +using MediaBrowser.Model.SyncPlay; namespace MediaBrowser.Controller.Session { @@ -142,22 +142,22 @@ namespace MediaBrowser.Controller.Session Task SendPlayCommand(string controllingSessionId, string sessionId, PlayRequest command, CancellationToken cancellationToken); /// - /// Sends the SyncplayCommand. + /// Sends the SyncPlayCommand. /// /// The session id. /// The command. /// The cancellation token. /// Task. - Task SendSyncplayCommand(string sessionId, SendCommand command, CancellationToken cancellationToken); + Task SendSyncPlayCommand(string sessionId, SendCommand command, CancellationToken cancellationToken); /// - /// Sends the SyncplayGroupUpdate. + /// Sends the SyncPlayGroupUpdate. /// /// The session id. /// The group update. /// The cancellation token. /// Task. - Task SendSyncplayGroupUpdate(string sessionId, GroupUpdate command, CancellationToken cancellationToken); + Task SendSyncPlayGroupUpdate(string sessionId, GroupUpdate command, CancellationToken cancellationToken); /// /// Sends the browse command. diff --git a/MediaBrowser.Controller/SyncPlay/GroupInfo.cs b/MediaBrowser.Controller/SyncPlay/GroupInfo.cs new file mode 100644 index 000000000..087748de0 --- /dev/null +++ b/MediaBrowser.Controller/SyncPlay/GroupInfo.cs @@ -0,0 +1,150 @@ +using System; +using System.Collections.Generic; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Session; + +namespace MediaBrowser.Controller.SyncPlay +{ + /// + /// Class GroupInfo. + /// + /// + /// Class is not thread-safe, external locking is required when accessing methods. + /// + public class GroupInfo + { + /// + /// Default ping value used for sessions. + /// + public readonly long DefaulPing = 500; + /// + /// Gets or sets the group identifier. + /// + /// The group identifier. + public readonly Guid GroupId = Guid.NewGuid(); + + /// + /// Gets or sets the playing item. + /// + /// The playing item. + public BaseItem PlayingItem { get; set; } + + /// + /// Gets or sets whether playback is paused. + /// + /// Playback is paused. + public bool IsPaused { get; set; } + + /// + /// Gets or sets the position ticks. + /// + /// The position ticks. + public long PositionTicks { get; set; } + + /// + /// Gets or sets the last activity. + /// + /// The last activity. + public DateTime LastActivity { get; set; } + + /// + /// Gets the participants. + /// + /// The participants, or members of the group. + public readonly Dictionary Participants = + new Dictionary(StringComparer.OrdinalIgnoreCase); + + /// + /// Checks if a session is in this group. + /// + /// true if the session is in this group; false otherwise. + public bool ContainsSession(string sessionId) + { + return Participants.ContainsKey(sessionId); + } + + /// + /// Adds the session to the group. + /// + /// The session. + public void AddSession(SessionInfo session) + { + if (ContainsSession(session.Id.ToString())) return; + var member = new GroupMember(); + member.Session = session; + member.Ping = DefaulPing; + member.IsBuffering = false; + Participants[session.Id.ToString()] = member; + } + + /// + /// Removes the session from the group. + /// + /// The session. + + public void RemoveSession(SessionInfo session) + { + if (!ContainsSession(session.Id.ToString())) return; + GroupMember member; + Participants.Remove(session.Id.ToString(), out member); + } + + /// + /// Updates the ping of a session. + /// + /// The session. + /// The ping. + public void UpdatePing(SessionInfo session, long ping) + { + if (!ContainsSession(session.Id.ToString())) return; + Participants[session.Id.ToString()].Ping = ping; + } + + /// + /// Gets the highest ping in the group. + /// + /// The highest ping in the group. + public long GetHighestPing() + { + long max = Int64.MinValue; + foreach (var session in Participants.Values) + { + max = Math.Max(max, session.Ping); + } + return max; + } + + /// + /// Sets the session's buffering state. + /// + /// The session. + /// The state. + public void SetBuffering(SessionInfo session, bool isBuffering) + { + if (!ContainsSession(session.Id.ToString())) return; + Participants[session.Id.ToString()].IsBuffering = isBuffering; + } + + /// + /// Gets the group buffering state. + /// + /// true if there is a session buffering in the group; false otherwise. + public bool IsBuffering() + { + foreach (var session in Participants.Values) + { + if (session.IsBuffering) return true; + } + return false; + } + + /// + /// Checks if the group is empty. + /// + /// true if the group is empty; false otherwise. + public bool IsEmpty() + { + return Participants.Count == 0; + } + } +} diff --git a/MediaBrowser.Controller/SyncPlay/GroupMember.cs b/MediaBrowser.Controller/SyncPlay/GroupMember.cs new file mode 100644 index 000000000..a3975c334 --- /dev/null +++ b/MediaBrowser.Controller/SyncPlay/GroupMember.cs @@ -0,0 +1,28 @@ +using MediaBrowser.Controller.Session; + +namespace MediaBrowser.Controller.SyncPlay +{ + /// + /// Class GroupMember. + /// + public class GroupMember + { + /// + /// Gets or sets whether this member is buffering. + /// + /// true if member is buffering; false otherwise. + public bool IsBuffering { get; set; } + + /// + /// Gets or sets the session. + /// + /// The session. + public SessionInfo Session { get; set; } + + /// + /// Gets or sets the ping. + /// + /// The ping. + public long Ping { get; set; } + } +} diff --git a/MediaBrowser.Controller/SyncPlay/ISyncPlayController.cs b/MediaBrowser.Controller/SyncPlay/ISyncPlayController.cs new file mode 100644 index 000000000..de1fcd259 --- /dev/null +++ b/MediaBrowser.Controller/SyncPlay/ISyncPlayController.cs @@ -0,0 +1,67 @@ +using System; +using System.Threading; +using MediaBrowser.Controller.Session; +using MediaBrowser.Model.SyncPlay; + +namespace MediaBrowser.Controller.SyncPlay +{ + /// + /// Interface ISyncPlayController. + /// + public interface ISyncPlayController + { + /// + /// Gets the group id. + /// + /// The group id. + Guid GetGroupId(); + + /// + /// Gets the playing item id. + /// + /// The playing item id. + Guid GetPlayingItemId(); + + /// + /// Checks if the group is empty. + /// + /// If the group is empty. + bool IsGroupEmpty(); + + /// + /// Initializes the group with the session's info. + /// + /// The session. + /// The cancellation token. + void InitGroup(SessionInfo session, CancellationToken cancellationToken); + + /// + /// Adds the session to the group. + /// + /// The session. + /// The request. + /// The cancellation token. + void SessionJoin(SessionInfo session, JoinGroupRequest request, CancellationToken cancellationToken); + + /// + /// Removes the session from the group. + /// + /// The session. + /// The cancellation token. + void SessionLeave(SessionInfo session, CancellationToken cancellationToken); + + /// + /// Handles the requested action by the session. + /// + /// The session. + /// The requested action. + /// The cancellation token. + void HandleRequest(SessionInfo session, PlaybackRequest request, CancellationToken cancellationToken); + + /// + /// Gets the info about the group for the clients. + /// + /// The group info for the clients. + GroupInfoView GetInfo(); + } +} \ No newline at end of file diff --git a/MediaBrowser.Controller/SyncPlay/ISyncPlayManager.cs b/MediaBrowser.Controller/SyncPlay/ISyncPlayManager.cs new file mode 100644 index 000000000..6c962ec85 --- /dev/null +++ b/MediaBrowser.Controller/SyncPlay/ISyncPlayManager.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using MediaBrowser.Controller.Session; +using MediaBrowser.Model.SyncPlay; + +namespace MediaBrowser.Controller.SyncPlay +{ + /// + /// Interface ISyncPlayManager. + /// + public interface ISyncPlayManager + { + /// + /// Creates a new group. + /// + /// The session that's creating the group. + /// The cancellation token. + void NewGroup(SessionInfo session, CancellationToken cancellationToken); + + /// + /// Adds the session to a group. + /// + /// The session. + /// The group id. + /// The request. + /// The cancellation token. + void JoinGroup(SessionInfo session, string groupId, JoinGroupRequest request, CancellationToken cancellationToken); + + /// + /// Removes the session from a group. + /// + /// The session. + /// The cancellation token. + void LeaveGroup(SessionInfo session, CancellationToken cancellationToken); + + /// + /// Gets list of available groups for a session. + /// + /// The session. + /// The item id to filter by. + /// The list of available groups. + List ListGroups(SessionInfo session, Guid filterItemId); + + /// + /// Handle a request by a session in a group. + /// + /// The session. + /// The request. + /// The cancellation token. + void HandleRequest(SessionInfo session, PlaybackRequest request, CancellationToken cancellationToken); + + /// + /// Maps a session to a group. + /// + /// The session. + /// The group. + /// + void AddSessionToGroup(SessionInfo session, ISyncPlayController group); + + /// + /// Unmaps a session from a group. + /// + /// The session. + /// The group. + /// + void RemoveSessionFromGroup(SessionInfo session, ISyncPlayController group); + } +} diff --git a/MediaBrowser.Controller/Syncplay/GroupInfo.cs b/MediaBrowser.Controller/Syncplay/GroupInfo.cs deleted file mode 100644 index c01fead83..000000000 --- a/MediaBrowser.Controller/Syncplay/GroupInfo.cs +++ /dev/null @@ -1,150 +0,0 @@ -using System; -using System.Collections.Generic; -using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Session; - -namespace MediaBrowser.Controller.Syncplay -{ - /// - /// Class GroupInfo. - /// - /// - /// Class is not thread-safe, external locking is required when accessing methods. - /// - public class GroupInfo - { - /// - /// Default ping value used for sessions. - /// - public readonly long DefaulPing = 500; - /// - /// Gets or sets the group identifier. - /// - /// The group identifier. - public readonly Guid GroupId = Guid.NewGuid(); - - /// - /// Gets or sets the playing item. - /// - /// The playing item. - public BaseItem PlayingItem { get; set; } - - /// - /// Gets or sets whether playback is paused. - /// - /// Playback is paused. - public bool IsPaused { get; set; } - - /// - /// Gets or sets the position ticks. - /// - /// The position ticks. - public long PositionTicks { get; set; } - - /// - /// Gets or sets the last activity. - /// - /// The last activity. - public DateTime LastActivity { get; set; } - - /// - /// Gets the participants. - /// - /// The participants, or members of the group. - public readonly Dictionary Participants = - new Dictionary(StringComparer.OrdinalIgnoreCase); - - /// - /// Checks if a session is in this group. - /// - /// true if the session is in this group; false otherwise. - public bool ContainsSession(string sessionId) - { - return Participants.ContainsKey(sessionId); - } - - /// - /// Adds the session to the group. - /// - /// The session. - public void AddSession(SessionInfo session) - { - if (ContainsSession(session.Id.ToString())) return; - var member = new GroupMember(); - member.Session = session; - member.Ping = DefaulPing; - member.IsBuffering = false; - Participants[session.Id.ToString()] = member; - } - - /// - /// Removes the session from the group. - /// - /// The session. - - public void RemoveSession(SessionInfo session) - { - if (!ContainsSession(session.Id.ToString())) return; - GroupMember member; - Participants.Remove(session.Id.ToString(), out member); - } - - /// - /// Updates the ping of a session. - /// - /// The session. - /// The ping. - public void UpdatePing(SessionInfo session, long ping) - { - if (!ContainsSession(session.Id.ToString())) return; - Participants[session.Id.ToString()].Ping = ping; - } - - /// - /// Gets the highest ping in the group. - /// - /// The highest ping in the group. - public long GetHighestPing() - { - long max = Int64.MinValue; - foreach (var session in Participants.Values) - { - max = Math.Max(max, session.Ping); - } - return max; - } - - /// - /// Sets the session's buffering state. - /// - /// The session. - /// The state. - public void SetBuffering(SessionInfo session, bool isBuffering) - { - if (!ContainsSession(session.Id.ToString())) return; - Participants[session.Id.ToString()].IsBuffering = isBuffering; - } - - /// - /// Gets the group buffering state. - /// - /// true if there is a session buffering in the group; false otherwise. - public bool IsBuffering() - { - foreach (var session in Participants.Values) - { - if (session.IsBuffering) return true; - } - return false; - } - - /// - /// Checks if the group is empty. - /// - /// true if the group is empty; false otherwise. - public bool IsEmpty() - { - return Participants.Count == 0; - } - } -} diff --git a/MediaBrowser.Controller/Syncplay/GroupMember.cs b/MediaBrowser.Controller/Syncplay/GroupMember.cs deleted file mode 100644 index 7630428d7..000000000 --- a/MediaBrowser.Controller/Syncplay/GroupMember.cs +++ /dev/null @@ -1,28 +0,0 @@ -using MediaBrowser.Controller.Session; - -namespace MediaBrowser.Controller.Syncplay -{ - /// - /// Class GroupMember. - /// - public class GroupMember - { - /// - /// Gets or sets whether this member is buffering. - /// - /// true if member is buffering; false otherwise. - public bool IsBuffering { get; set; } - - /// - /// Gets or sets the session. - /// - /// The session. - public SessionInfo Session { get; set; } - - /// - /// Gets or sets the ping. - /// - /// The ping. - public long Ping { get; set; } - } -} diff --git a/MediaBrowser.Controller/Syncplay/ISyncplayController.cs b/MediaBrowser.Controller/Syncplay/ISyncplayController.cs deleted file mode 100644 index 34eae4062..000000000 --- a/MediaBrowser.Controller/Syncplay/ISyncplayController.cs +++ /dev/null @@ -1,67 +0,0 @@ -using System; -using System.Threading; -using MediaBrowser.Controller.Session; -using MediaBrowser.Model.Syncplay; - -namespace MediaBrowser.Controller.Syncplay -{ - /// - /// Interface ISyncplayController. - /// - public interface ISyncplayController - { - /// - /// Gets the group id. - /// - /// The group id. - Guid GetGroupId(); - - /// - /// Gets the playing item id. - /// - /// The playing item id. - Guid GetPlayingItemId(); - - /// - /// Checks if the group is empty. - /// - /// If the group is empty. - bool IsGroupEmpty(); - - /// - /// Initializes the group with the session's info. - /// - /// The session. - /// The cancellation token. - void InitGroup(SessionInfo session, CancellationToken cancellationToken); - - /// - /// Adds the session to the group. - /// - /// The session. - /// The request. - /// The cancellation token. - void SessionJoin(SessionInfo session, JoinGroupRequest request, CancellationToken cancellationToken); - - /// - /// Removes the session from the group. - /// - /// The session. - /// The cancellation token. - void SessionLeave(SessionInfo session, CancellationToken cancellationToken); - - /// - /// Handles the requested action by the session. - /// - /// The session. - /// The requested action. - /// The cancellation token. - void HandleRequest(SessionInfo session, PlaybackRequest request, CancellationToken cancellationToken); - - /// - /// Gets the info about the group for the clients. - /// - /// The group info for the clients. - GroupInfoView GetInfo(); - } -} \ No newline at end of file diff --git a/MediaBrowser.Controller/Syncplay/ISyncplayManager.cs b/MediaBrowser.Controller/Syncplay/ISyncplayManager.cs deleted file mode 100644 index fbc208d27..000000000 --- a/MediaBrowser.Controller/Syncplay/ISyncplayManager.cs +++ /dev/null @@ -1,69 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Threading; -using MediaBrowser.Controller.Session; -using MediaBrowser.Model.Syncplay; - -namespace MediaBrowser.Controller.Syncplay -{ - /// - /// Interface ISyncplayManager. - /// - public interface ISyncplayManager - { - /// - /// Creates a new group. - /// - /// The session that's creating the group. - /// The cancellation token. - void NewGroup(SessionInfo session, CancellationToken cancellationToken); - - /// - /// Adds the session to a group. - /// - /// The session. - /// The group id. - /// The request. - /// The cancellation token. - void JoinGroup(SessionInfo session, string groupId, JoinGroupRequest request, CancellationToken cancellationToken); - - /// - /// Removes the session from a group. - /// - /// The session. - /// The cancellation token. - void LeaveGroup(SessionInfo session, CancellationToken cancellationToken); - - /// - /// Gets list of available groups for a session. - /// - /// The session. - /// The item id to filter by. - /// The list of available groups. - List ListGroups(SessionInfo session, Guid filterItemId); - - /// - /// Handle a request by a session in a group. - /// - /// The session. - /// The request. - /// The cancellation token. - void HandleRequest(SessionInfo session, PlaybackRequest request, CancellationToken cancellationToken); - - /// - /// Maps a session to a group. - /// - /// The session. - /// The group. - /// - void AddSessionToGroup(SessionInfo session, ISyncplayController group); - - /// - /// Unmaps a session from a group. - /// - /// The session. - /// The group. - /// - void RemoveSessionFromGroup(SessionInfo session, ISyncplayController group); - } -} diff --git a/MediaBrowser.Model/Configuration/SyncplayAccess.cs b/MediaBrowser.Model/Configuration/SyncplayAccess.cs index cddf68c42..d891a8167 100644 --- a/MediaBrowser.Model/Configuration/SyncplayAccess.cs +++ b/MediaBrowser.Model/Configuration/SyncplayAccess.cs @@ -1,9 +1,9 @@ namespace MediaBrowser.Model.Configuration { /// - /// Enum SyncplayAccess. + /// Enum SyncPlayAccess. /// - public enum SyncplayAccess + public enum SyncPlayAccess { /// /// User can create groups and join them. @@ -16,7 +16,7 @@ namespace MediaBrowser.Model.Configuration JoinGroups, /// - /// Syncplay is disabled for the user. + /// SyncPlay is disabled for the user. /// None } diff --git a/MediaBrowser.Model/SyncPlay/GroupInfoView.cs b/MediaBrowser.Model/SyncPlay/GroupInfoView.cs new file mode 100644 index 000000000..7b833506b --- /dev/null +++ b/MediaBrowser.Model/SyncPlay/GroupInfoView.cs @@ -0,0 +1,38 @@ +namespace MediaBrowser.Model.SyncPlay +{ + /// + /// Class GroupInfoView. + /// + public class GroupInfoView + { + /// + /// Gets or sets the group identifier. + /// + /// The group identifier. + public string GroupId { get; set; } + + /// + /// Gets or sets the playing item id. + /// + /// The playing item id. + public string PlayingItemId { get; set; } + + /// + /// Gets or sets the playing item name. + /// + /// The playing item name. + public string PlayingItemName { get; set; } + + /// + /// Gets or sets the position ticks. + /// + /// The position ticks. + public long PositionTicks { get; set; } + + /// + /// Gets or sets the participants. + /// + /// The participants. + public string[] Participants { get; set; } + } +} diff --git a/MediaBrowser.Model/SyncPlay/GroupUpdate.cs b/MediaBrowser.Model/SyncPlay/GroupUpdate.cs new file mode 100644 index 000000000..895702f3d --- /dev/null +++ b/MediaBrowser.Model/SyncPlay/GroupUpdate.cs @@ -0,0 +1,26 @@ +namespace MediaBrowser.Model.SyncPlay +{ + /// + /// Class GroupUpdate. + /// + public class GroupUpdate + { + /// + /// Gets or sets the group identifier. + /// + /// The group identifier. + public string GroupId { get; set; } + + /// + /// Gets or sets the update type. + /// + /// The update type. + public GroupUpdateType Type { get; set; } + + /// + /// Gets or sets the data. + /// + /// The data. + public T Data { get; set; } + } +} diff --git a/MediaBrowser.Model/SyncPlay/GroupUpdateType.cs b/MediaBrowser.Model/SyncPlay/GroupUpdateType.cs new file mode 100644 index 000000000..89d245787 --- /dev/null +++ b/MediaBrowser.Model/SyncPlay/GroupUpdateType.cs @@ -0,0 +1,53 @@ +namespace MediaBrowser.Model.SyncPlay +{ + /// + /// Enum GroupUpdateType. + /// + public enum GroupUpdateType + { + /// + /// The user-joined update. Tells members of a group about a new user. + /// + UserJoined, + /// + /// The user-left update. Tells members of a group that a user left. + /// + UserLeft, + /// + /// The group-joined update. Tells a user that the group has been joined. + /// + GroupJoined, + /// + /// The group-left update. Tells a user that the group has been left. + /// + GroupLeft, + /// + /// The group-wait update. Tells members of the group that a user is buffering. + /// + GroupWait, + /// + /// The prepare-session update. Tells a user to load some content. + /// + PrepareSession, + /// + /// The not-in-group error. Tells a user that they don't belong to a group. + /// + NotInGroup, + /// + /// The group-does-not-exist error. Sent when trying to join a non-existing group. + /// + GroupDoesNotExist, + /// + /// The create-group-denied error. Sent when a user tries to create a group without required permissions. + /// + CreateGroupDenied, + /// + /// The join-group-denied error. Sent when a user tries to join a group without required permissions. + /// + JoinGroupDenied, + /// + /// The library-access-denied error. Sent when a user tries to join a group without required access to the library. + /// + LibraryAccessDenied + } +} diff --git a/MediaBrowser.Model/SyncPlay/JoinGroupRequest.cs b/MediaBrowser.Model/SyncPlay/JoinGroupRequest.cs new file mode 100644 index 000000000..d67b6bd55 --- /dev/null +++ b/MediaBrowser.Model/SyncPlay/JoinGroupRequest.cs @@ -0,0 +1,22 @@ +using System; + +namespace MediaBrowser.Model.SyncPlay +{ + /// + /// Class JoinGroupRequest. + /// + public class JoinGroupRequest + { + /// + /// Gets or sets the Group id. + /// + /// The Group id to join. + public Guid GroupId { get; set; } + + /// + /// Gets or sets the playing item id. + /// + /// The client's currently playing item id. + public Guid PlayingItemId { get; set; } + } +} diff --git a/MediaBrowser.Model/SyncPlay/PlaybackRequest.cs b/MediaBrowser.Model/SyncPlay/PlaybackRequest.cs new file mode 100644 index 000000000..9de23194e --- /dev/null +++ b/MediaBrowser.Model/SyncPlay/PlaybackRequest.cs @@ -0,0 +1,34 @@ +using System; + +namespace MediaBrowser.Model.SyncPlay +{ + /// + /// Class PlaybackRequest. + /// + public class PlaybackRequest + { + /// + /// Gets or sets the request type. + /// + /// The request type. + public PlaybackRequestType Type { get; set; } + + /// + /// Gets or sets when the request has been made by the client. + /// + /// The date of the request. + public DateTime? When { get; set; } + + /// + /// Gets or sets the position ticks. + /// + /// The position ticks. + public long? PositionTicks { get; set; } + + /// + /// Gets or sets the ping time. + /// + /// The ping time. + public long? Ping { get; set; } + } +} diff --git a/MediaBrowser.Model/SyncPlay/PlaybackRequestType.cs b/MediaBrowser.Model/SyncPlay/PlaybackRequestType.cs new file mode 100644 index 000000000..f1e175fde --- /dev/null +++ b/MediaBrowser.Model/SyncPlay/PlaybackRequestType.cs @@ -0,0 +1,33 @@ +namespace MediaBrowser.Model.SyncPlay +{ + /// + /// Enum PlaybackRequestType + /// + public enum PlaybackRequestType + { + /// + /// A user is requesting a play command for the group. + /// + Play = 0, + /// + /// A user is requesting a pause command for the group. + /// + Pause = 1, + /// + /// A user is requesting a seek command for the group. + /// + Seek = 2, + /// + /// A user is signaling that playback is buffering. + /// + Buffering = 3, + /// + /// A user is signaling that playback resumed. + /// + BufferingDone = 4, + /// + /// A user is reporting its ping. + /// + UpdatePing = 5 + } +} diff --git a/MediaBrowser.Model/SyncPlay/SendCommand.cs b/MediaBrowser.Model/SyncPlay/SendCommand.cs new file mode 100644 index 000000000..0f06e381f --- /dev/null +++ b/MediaBrowser.Model/SyncPlay/SendCommand.cs @@ -0,0 +1,38 @@ +namespace MediaBrowser.Model.SyncPlay +{ + /// + /// Class SendCommand. + /// + public class SendCommand + { + /// + /// Gets or sets the group identifier. + /// + /// The group identifier. + public string GroupId { get; set; } + + /// + /// Gets or sets the UTC time when to execute the command. + /// + /// The UTC time when to execute the command. + public string When { get; set; } + + /// + /// Gets or sets the position ticks. + /// + /// The position ticks. + public long? PositionTicks { get; set; } + + /// + /// Gets or sets the command. + /// + /// The command. + public SendCommandType Command { get; set; } + + /// + /// Gets or sets the UTC time when this command has been emitted. + /// + /// The UTC time when this command has been emitted. + public string EmittedAt { get; set; } + } +} diff --git a/MediaBrowser.Model/SyncPlay/SendCommandType.cs b/MediaBrowser.Model/SyncPlay/SendCommandType.cs new file mode 100644 index 000000000..113719871 --- /dev/null +++ b/MediaBrowser.Model/SyncPlay/SendCommandType.cs @@ -0,0 +1,21 @@ +namespace MediaBrowser.Model.SyncPlay +{ + /// + /// Enum SendCommandType. + /// + public enum SendCommandType + { + /// + /// The play command. Instructs users to start playback. + /// + Play = 0, + /// + /// The pause command. Instructs users to pause playback. + /// + Pause = 1, + /// + /// The seek command. Instructs users to seek to a specified time. + /// + Seek = 2 + } +} diff --git a/MediaBrowser.Model/SyncPlay/UtcTimeResponse.cs b/MediaBrowser.Model/SyncPlay/UtcTimeResponse.cs new file mode 100644 index 000000000..0a6036154 --- /dev/null +++ b/MediaBrowser.Model/SyncPlay/UtcTimeResponse.cs @@ -0,0 +1,20 @@ +namespace MediaBrowser.Model.SyncPlay +{ + /// + /// Class UtcTimeResponse. + /// + public class UtcTimeResponse + { + /// + /// Gets or sets the UTC time when request has been received. + /// + /// The UTC time when request has been received. + public string RequestReceptionTime { get; set; } + + /// + /// Gets or sets the UTC time when response has been sent. + /// + /// The UTC time when response has been sent. + public string ResponseTransmissionTime { get; set; } + } +} diff --git a/MediaBrowser.Model/Syncplay/GroupInfoView.cs b/MediaBrowser.Model/Syncplay/GroupInfoView.cs deleted file mode 100644 index 50ad70630..000000000 --- a/MediaBrowser.Model/Syncplay/GroupInfoView.cs +++ /dev/null @@ -1,38 +0,0 @@ -namespace MediaBrowser.Model.Syncplay -{ - /// - /// Class GroupInfoView. - /// - public class GroupInfoView - { - /// - /// Gets or sets the group identifier. - /// - /// The group identifier. - public string GroupId { get; set; } - - /// - /// Gets or sets the playing item id. - /// - /// The playing item id. - public string PlayingItemId { get; set; } - - /// - /// Gets or sets the playing item name. - /// - /// The playing item name. - public string PlayingItemName { get; set; } - - /// - /// Gets or sets the position ticks. - /// - /// The position ticks. - public long PositionTicks { get; set; } - - /// - /// Gets or sets the participants. - /// - /// The participants. - public string[] Participants { get; set; } - } -} diff --git a/MediaBrowser.Model/Syncplay/GroupUpdate.cs b/MediaBrowser.Model/Syncplay/GroupUpdate.cs deleted file mode 100644 index cc49e92a9..000000000 --- a/MediaBrowser.Model/Syncplay/GroupUpdate.cs +++ /dev/null @@ -1,26 +0,0 @@ -namespace MediaBrowser.Model.Syncplay -{ - /// - /// Class GroupUpdate. - /// - public class GroupUpdate - { - /// - /// Gets or sets the group identifier. - /// - /// The group identifier. - public string GroupId { get; set; } - - /// - /// Gets or sets the update type. - /// - /// The update type. - public GroupUpdateType Type { get; set; } - - /// - /// Gets or sets the data. - /// - /// The data. - public T Data { get; set; } - } -} diff --git a/MediaBrowser.Model/Syncplay/GroupUpdateType.cs b/MediaBrowser.Model/Syncplay/GroupUpdateType.cs deleted file mode 100644 index 9f40f9577..000000000 --- a/MediaBrowser.Model/Syncplay/GroupUpdateType.cs +++ /dev/null @@ -1,53 +0,0 @@ -namespace MediaBrowser.Model.Syncplay -{ - /// - /// Enum GroupUpdateType. - /// - public enum GroupUpdateType - { - /// - /// The user-joined update. Tells members of a group about a new user. - /// - UserJoined, - /// - /// The user-left update. Tells members of a group that a user left. - /// - UserLeft, - /// - /// The group-joined update. Tells a user that the group has been joined. - /// - GroupJoined, - /// - /// The group-left update. Tells a user that the group has been left. - /// - GroupLeft, - /// - /// The group-wait update. Tells members of the group that a user is buffering. - /// - GroupWait, - /// - /// The prepare-session update. Tells a user to load some content. - /// - PrepareSession, - /// - /// The not-in-group error. Tells a user that they don't belong to a group. - /// - NotInGroup, - /// - /// The group-does-not-exist error. Sent when trying to join a non-existing group. - /// - GroupDoesNotExist, - /// - /// The create-group-denied error. Sent when a user tries to create a group without required permissions. - /// - CreateGroupDenied, - /// - /// The join-group-denied error. Sent when a user tries to join a group without required permissions. - /// - JoinGroupDenied, - /// - /// The library-access-denied error. Sent when a user tries to join a group without required access to the library. - /// - LibraryAccessDenied - } -} diff --git a/MediaBrowser.Model/Syncplay/JoinGroupRequest.cs b/MediaBrowser.Model/Syncplay/JoinGroupRequest.cs deleted file mode 100644 index 8d8a2646a..000000000 --- a/MediaBrowser.Model/Syncplay/JoinGroupRequest.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System; - -namespace MediaBrowser.Model.Syncplay -{ - /// - /// Class JoinGroupRequest. - /// - public class JoinGroupRequest - { - /// - /// Gets or sets the Group id. - /// - /// The Group id to join. - public Guid GroupId { get; set; } - - /// - /// Gets or sets the playing item id. - /// - /// The client's currently playing item id. - public Guid PlayingItemId { get; set; } - } -} diff --git a/MediaBrowser.Model/Syncplay/PlaybackRequest.cs b/MediaBrowser.Model/Syncplay/PlaybackRequest.cs deleted file mode 100644 index ba97641f6..000000000 --- a/MediaBrowser.Model/Syncplay/PlaybackRequest.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System; - -namespace MediaBrowser.Model.Syncplay -{ - /// - /// Class PlaybackRequest. - /// - public class PlaybackRequest - { - /// - /// Gets or sets the request type. - /// - /// The request type. - public PlaybackRequestType Type { get; set; } - - /// - /// Gets or sets when the request has been made by the client. - /// - /// The date of the request. - public DateTime? When { get; set; } - - /// - /// Gets or sets the position ticks. - /// - /// The position ticks. - public long? PositionTicks { get; set; } - - /// - /// Gets or sets the ping time. - /// - /// The ping time. - public long? Ping { get; set; } - } -} diff --git a/MediaBrowser.Model/Syncplay/PlaybackRequestType.cs b/MediaBrowser.Model/Syncplay/PlaybackRequestType.cs deleted file mode 100644 index b3d49d09e..000000000 --- a/MediaBrowser.Model/Syncplay/PlaybackRequestType.cs +++ /dev/null @@ -1,33 +0,0 @@ -namespace MediaBrowser.Model.Syncplay -{ - /// - /// Enum PlaybackRequestType - /// - public enum PlaybackRequestType - { - /// - /// A user is requesting a play command for the group. - /// - Play = 0, - /// - /// A user is requesting a pause command for the group. - /// - Pause = 1, - /// - /// A user is requesting a seek command for the group. - /// - Seek = 2, - /// - /// A user is signaling that playback is buffering. - /// - Buffering = 3, - /// - /// A user is signaling that playback resumed. - /// - BufferingDone = 4, - /// - /// A user is reporting its ping. - /// - UpdatePing = 5 - } -} diff --git a/MediaBrowser.Model/Syncplay/SendCommand.cs b/MediaBrowser.Model/Syncplay/SendCommand.cs deleted file mode 100644 index d9f391403..000000000 --- a/MediaBrowser.Model/Syncplay/SendCommand.cs +++ /dev/null @@ -1,38 +0,0 @@ -namespace MediaBrowser.Model.Syncplay -{ - /// - /// Class SendCommand. - /// - public class SendCommand - { - /// - /// Gets or sets the group identifier. - /// - /// The group identifier. - public string GroupId { get; set; } - - /// - /// Gets or sets the UTC time when to execute the command. - /// - /// The UTC time when to execute the command. - public string When { get; set; } - - /// - /// Gets or sets the position ticks. - /// - /// The position ticks. - public long? PositionTicks { get; set; } - - /// - /// Gets or sets the command. - /// - /// The command. - public SendCommandType Command { get; set; } - - /// - /// Gets or sets the UTC time when this command has been emitted. - /// - /// The UTC time when this command has been emitted. - public string EmittedAt { get; set; } - } -} diff --git a/MediaBrowser.Model/Syncplay/SendCommandType.cs b/MediaBrowser.Model/Syncplay/SendCommandType.cs deleted file mode 100644 index 02e4774d0..000000000 --- a/MediaBrowser.Model/Syncplay/SendCommandType.cs +++ /dev/null @@ -1,21 +0,0 @@ -namespace MediaBrowser.Model.Syncplay -{ - /// - /// Enum SendCommandType. - /// - public enum SendCommandType - { - /// - /// The play command. Instructs users to start playback. - /// - Play = 0, - /// - /// The pause command. Instructs users to pause playback. - /// - Pause = 1, - /// - /// The seek command. Instructs users to seek to a specified time. - /// - Seek = 2 - } -} diff --git a/MediaBrowser.Model/Syncplay/UtcTimeResponse.cs b/MediaBrowser.Model/Syncplay/UtcTimeResponse.cs deleted file mode 100644 index f7887dc33..000000000 --- a/MediaBrowser.Model/Syncplay/UtcTimeResponse.cs +++ /dev/null @@ -1,20 +0,0 @@ -namespace MediaBrowser.Model.Syncplay -{ - /// - /// Class UtcTimeResponse. - /// - public class UtcTimeResponse - { - /// - /// Gets or sets the UTC time when request has been received. - /// - /// The UTC time when request has been received. - public string RequestReceptionTime { get; set; } - - /// - /// Gets or sets the UTC time when response has been sent. - /// - /// The UTC time when response has been sent. - public string ResponseTransmissionTime { get; set; } - } -} diff --git a/MediaBrowser.Model/Users/UserPolicy.cs b/MediaBrowser.Model/Users/UserPolicy.cs index cf576c358..3e027e831 100644 --- a/MediaBrowser.Model/Users/UserPolicy.cs +++ b/MediaBrowser.Model/Users/UserPolicy.cs @@ -81,10 +81,10 @@ namespace MediaBrowser.Model.Users public string PasswordResetProviderId { get; set; } /// - /// Gets or sets a value indicating what Syncplay features the user can access. + /// Gets or sets a value indicating what SyncPlay features the user can access. /// - /// Access level to Syncplay features. - public SyncplayAccess SyncplayAccess { get; set; } + /// Access level to SyncPlay features. + public SyncPlayAccess SyncPlayAccess { get; set; } public UserPolicy() { @@ -131,7 +131,7 @@ namespace MediaBrowser.Model.Users EnableContentDownloading = true; EnablePublicSharing = true; EnableRemoteAccess = true; - SyncplayAccess = SyncplayAccess.CreateAndJoinGroups; + SyncPlayAccess = SyncPlayAccess.CreateAndJoinGroups; } } } -- cgit v1.2.3 From 5c8cbd4087261f13d003d7d4eab082cbf335b4d4 Mon Sep 17 00:00:00 2001 From: gion Date: Sat, 9 May 2020 14:34:07 +0200 Subject: Fix code issues --- .../Session/SessionWebSocketListener.cs | 21 +++++----- .../SyncPlay/SyncPlayController.cs | 4 +- .../SyncPlay/SyncPlayManager.cs | 28 +++++++++---- MediaBrowser.Api/SyncPlay/SyncPlayService.cs | 47 +++++++++++----------- .../Net/IWebSocketConnection.cs | 2 +- MediaBrowser.Controller/SyncPlay/GroupInfo.cs | 32 +++++++++++---- .../SyncPlay/ISyncPlayManager.cs | 2 +- MediaBrowser.Model/SyncPlay/GroupInfoView.cs | 4 +- 8 files changed, 86 insertions(+), 54 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/Session/SessionWebSocketListener.cs b/Emby.Server.Implementations/Session/SessionWebSocketListener.cs index d1ee22ea8..3704445ab 100644 --- a/Emby.Server.Implementations/Session/SessionWebSocketListener.cs +++ b/Emby.Server.Implementations/Session/SessionWebSocketListener.cs @@ -22,17 +22,17 @@ namespace Emby.Server.Implementations.Session /// /// The timeout in seconds after which a WebSocket is considered to be lost. /// - public readonly int WebSocketLostTimeout = 60; + public const int WebSocketLostTimeout = 60; /// /// The keep-alive interval factor; controls how often the watcher will check on the status of the WebSockets. /// - public readonly double IntervalFactor = 0.2; + public const float IntervalFactor = 0.2f; /// /// The ForceKeepAlive factor; controls when a ForceKeepAlive is sent. /// - public readonly double ForceKeepAliveFactor = 0.75; + public const float ForceKeepAliveFactor = 0.75f; /// /// The _session manager @@ -213,7 +213,7 @@ namespace Emby.Server.Implementations.Session { _keepAliveCancellationToken = new CancellationTokenSource(); // Start KeepAlive watcher - var task = RepeatAsyncCallbackEvery( + _ = RepeatAsyncCallbackEvery( KeepAliveSockets, TimeSpan.FromSeconds(WebSocketLostTimeout * IntervalFactor), _keepAliveCancellationToken.Token); @@ -241,6 +241,7 @@ namespace Emby.Server.Implementations.Session { webSocket.Closed -= OnWebSocketClosed; } + _webSockets.Clear(); } } @@ -250,8 +251,8 @@ namespace Emby.Server.Implementations.Session /// private async Task KeepAliveSockets() { - IEnumerable inactive; - IEnumerable lost; + List inactive; + List lost; lock (_webSocketsLock) { @@ -261,8 +262,8 @@ namespace Emby.Server.Implementations.Session { var elapsed = (DateTime.UtcNow - i.LastKeepAliveDate).TotalSeconds; return (elapsed > WebSocketLostTimeout * ForceKeepAliveFactor) && (elapsed < WebSocketLostTimeout); - }); - lost = _webSockets.Where(i => (DateTime.UtcNow - i.LastKeepAliveDate).TotalSeconds >= WebSocketLostTimeout); + }).ToList(); + lost = _webSockets.Where(i => (DateTime.UtcNow - i.LastKeepAliveDate).TotalSeconds >= WebSocketLostTimeout).ToList(); } if (inactive.Any()) @@ -279,7 +280,7 @@ namespace Emby.Server.Implementations.Session catch (WebSocketException exception) { _logger.LogInformation(exception, "Error sending ForceKeepAlive message to WebSocket."); - lost = lost.Append(webSocket); + lost.Add(webSocket); } } @@ -288,7 +289,7 @@ namespace Emby.Server.Implementations.Session if (lost.Any()) { _logger.LogInformation("Lost {0} WebSockets.", lost.Count()); - foreach (var webSocket in lost.ToList()) + foreach (var webSocket in lost) { // TODO: handle session relative to the lost webSocket RemoveWebSocket(webSocket); diff --git a/Emby.Server.Implementations/SyncPlay/SyncPlayController.cs b/Emby.Server.Implementations/SyncPlay/SyncPlayController.cs index 9c9758de1..c7bd242a7 100644 --- a/Emby.Server.Implementations/SyncPlay/SyncPlayController.cs +++ b/Emby.Server.Implementations/SyncPlay/SyncPlayController.cs @@ -144,7 +144,7 @@ namespace Emby.Server.Implementations.SyncPlay session => session.Session ).ToArray(); default: - return new SessionInfo[] { }; + return Array.Empty(); } } @@ -541,7 +541,7 @@ namespace Emby.Server.Implementations.SyncPlay PlayingItemName = _group.PlayingItem.Name, PlayingItemId = _group.PlayingItem.Id.ToString(), PositionTicks = _group.PositionTicks, - Participants = _group.Participants.Values.Select(session => session.Session.UserName).Distinct().ToArray() + Participants = _group.Participants.Values.Select(session => session.Session.UserName).Distinct().ToList().AsReadOnly() }; } } diff --git a/Emby.Server.Implementations/SyncPlay/SyncPlayManager.cs b/Emby.Server.Implementations/SyncPlay/SyncPlayManager.cs index d3197d97b..93cec1304 100644 --- a/Emby.Server.Implementations/SyncPlay/SyncPlayManager.cs +++ b/Emby.Server.Implementations/SyncPlay/SyncPlayManager.cs @@ -47,8 +47,8 @@ namespace Emby.Server.Implementations.SyncPlay /// /// The groups. /// - private readonly Dictionary _groups = - new Dictionary(StringComparer.OrdinalIgnoreCase); + private readonly Dictionary _groups = + new Dictionary(); /// /// Lock used for accesing any group. @@ -113,14 +113,22 @@ namespace Emby.Server.Implementations.SyncPlay private void OnSessionManagerSessionEnded(object sender, SessionEventArgs e) { var session = e.SessionInfo; - if (!IsSessionInGroup(session)) return; + if (!IsSessionInGroup(session)) + { + return; + } + LeaveGroup(session, CancellationToken.None); } private void OnSessionManagerPlaybackStopped(object sender, PlaybackStopEventArgs e) { var session = e.Session; - if (!IsSessionInGroup(session)) return; + if (!IsSessionInGroup(session)) + { + return; + } + LeaveGroup(session, CancellationToken.None); } @@ -193,14 +201,14 @@ namespace Emby.Server.Implementations.SyncPlay } var group = new SyncPlayController(_sessionManager, this); - _groups[group.GetGroupId().ToString()] = group; + _groups[group.GetGroupId()] = group; group.InitGroup(session, cancellationToken); } } /// - public void JoinGroup(SessionInfo session, string groupId, JoinGroupRequest request, CancellationToken cancellationToken) + public void JoinGroup(SessionInfo session, Guid groupId, JoinGroupRequest request, CancellationToken cancellationToken) { var user = _userManager.GetUserById(session.UserId); @@ -248,7 +256,11 @@ namespace Emby.Server.Implementations.SyncPlay if (IsSessionInGroup(session)) { - if (GetSessionGroup(session).Equals(groupId)) return; + if (GetSessionGroup(session).Equals(groupId)) + { + return; + } + LeaveGroup(session, cancellationToken); } @@ -282,7 +294,7 @@ namespace Emby.Server.Implementations.SyncPlay if (group.IsGroupEmpty()) { _logger.LogInformation("LeaveGroup: removing empty group {0}.", group.GetGroupId()); - _groups.Remove(group.GetGroupId().ToString(), out _); + _groups.Remove(group.GetGroupId(), out _); } } } diff --git a/MediaBrowser.Api/SyncPlay/SyncPlayService.cs b/MediaBrowser.Api/SyncPlay/SyncPlayService.cs index bcdc833e4..9137faf9f 100644 --- a/MediaBrowser.Api/SyncPlay/SyncPlayService.cs +++ b/MediaBrowser.Api/SyncPlay/SyncPlayService.cs @@ -171,31 +171,35 @@ namespace MediaBrowser.Api.SyncPlay public void Post(SyncPlayJoinGroup request) { var currentSession = GetSession(_sessionContext); - var joinRequest = new JoinGroupRequest() + + Guid groupId; + Guid playingItemId = Guid.Empty; + + var valid = Guid.TryParse(request.GroupId, out groupId); + if (!valid) { - GroupId = Guid.Parse(request.GroupId) - }; + Logger.LogError("JoinGroup: {0} is not a valid format for GroupId. Ignoring request.", request.GroupId); + return; + } // Both null and empty strings mean that client isn't playing anything if (!String.IsNullOrEmpty(request.PlayingItemId)) { - try - { - joinRequest.PlayingItemId = Guid.Parse(request.PlayingItemId); - } - catch (ArgumentNullException) - { - // Should never happen, but just in case - Logger.LogError("JoinGroup: null value for PlayingItemId. Ignoring request."); - return; - } - catch (FormatException) + valid = Guid.TryParse(request.PlayingItemId, out playingItemId); + if (!valid) { Logger.LogError("JoinGroup: {0} is not a valid format for PlayingItemId. Ignoring request.", request.PlayingItemId); return; } } - _syncPlayManager.JoinGroup(currentSession, request.GroupId, joinRequest, CancellationToken.None); + + var joinRequest = new JoinGroupRequest() + { + GroupId = groupId, + PlayingItemId = playingItemId + }; + + _syncPlayManager.JoinGroup(currentSession, groupId, joinRequest, CancellationToken.None); } /// @@ -217,21 +221,16 @@ namespace MediaBrowser.Api.SyncPlay { var currentSession = GetSession(_sessionContext); var filterItemId = Guid.Empty; + if (!String.IsNullOrEmpty(request.FilterItemId)) { - try - { - filterItemId = Guid.Parse(request.FilterItemId); - } - catch (ArgumentNullException) - { - Logger.LogWarning("ListGroups: null value for FilterItemId. Ignoring filter."); - } - catch (FormatException) + var valid = Guid.TryParse(request.FilterItemId, out filterItemId); + if (!valid) { Logger.LogWarning("ListGroups: {0} is not a valid format for FilterItemId. Ignoring filter.", request.FilterItemId); } } + return _syncPlayManager.ListGroups(currentSession, filterItemId); } diff --git a/MediaBrowser.Controller/Net/IWebSocketConnection.cs b/MediaBrowser.Controller/Net/IWebSocketConnection.cs index fb766ab57..b371a59e9 100644 --- a/MediaBrowser.Controller/Net/IWebSocketConnection.cs +++ b/MediaBrowser.Controller/Net/IWebSocketConnection.cs @@ -30,7 +30,7 @@ namespace MediaBrowser.Controller.Net /// Gets or sets the date of last Keeplive received. /// /// The date of last Keeplive received. - public DateTime LastKeepAliveDate { get; set; } + DateTime LastKeepAliveDate { get; set; } /// /// Gets or sets the URL. diff --git a/MediaBrowser.Controller/SyncPlay/GroupInfo.cs b/MediaBrowser.Controller/SyncPlay/GroupInfo.cs index 087748de0..bda49bd1b 100644 --- a/MediaBrowser.Controller/SyncPlay/GroupInfo.cs +++ b/MediaBrowser.Controller/SyncPlay/GroupInfo.cs @@ -69,7 +69,11 @@ namespace MediaBrowser.Controller.SyncPlay /// The session. public void AddSession(SessionInfo session) { - if (ContainsSession(session.Id.ToString())) return; + if (ContainsSession(session.Id.ToString())) + { + return; + } + var member = new GroupMember(); member.Session = session; member.Ping = DefaulPing; @@ -84,9 +88,12 @@ namespace MediaBrowser.Controller.SyncPlay public void RemoveSession(SessionInfo session) { - if (!ContainsSession(session.Id.ToString())) return; - GroupMember member; - Participants.Remove(session.Id.ToString(), out member); + if (!ContainsSession(session.Id.ToString())) + { + return; + } + + Participants.Remove(session.Id.ToString(), out _); } /// @@ -96,7 +103,11 @@ namespace MediaBrowser.Controller.SyncPlay /// The ping. public void UpdatePing(SessionInfo session, long ping) { - if (!ContainsSession(session.Id.ToString())) return; + if (!ContainsSession(session.Id.ToString())) + { + return; + } + Participants[session.Id.ToString()].Ping = ping; } @@ -121,7 +132,11 @@ namespace MediaBrowser.Controller.SyncPlay /// The state. public void SetBuffering(SessionInfo session, bool isBuffering) { - if (!ContainsSession(session.Id.ToString())) return; + if (!ContainsSession(session.Id.ToString())) + { + return; + } + Participants[session.Id.ToString()].IsBuffering = isBuffering; } @@ -133,7 +148,10 @@ namespace MediaBrowser.Controller.SyncPlay { foreach (var session in Participants.Values) { - if (session.IsBuffering) return true; + if (session.IsBuffering) + { + return true; + } } return false; } diff --git a/MediaBrowser.Controller/SyncPlay/ISyncPlayManager.cs b/MediaBrowser.Controller/SyncPlay/ISyncPlayManager.cs index 6c962ec85..006fb687b 100644 --- a/MediaBrowser.Controller/SyncPlay/ISyncPlayManager.cs +++ b/MediaBrowser.Controller/SyncPlay/ISyncPlayManager.cs @@ -25,7 +25,7 @@ namespace MediaBrowser.Controller.SyncPlay /// The group id. /// The request. /// The cancellation token. - void JoinGroup(SessionInfo session, string groupId, JoinGroupRequest request, CancellationToken cancellationToken); + void JoinGroup(SessionInfo session, Guid groupId, JoinGroupRequest request, CancellationToken cancellationToken); /// /// Removes the session from a group. diff --git a/MediaBrowser.Model/SyncPlay/GroupInfoView.cs b/MediaBrowser.Model/SyncPlay/GroupInfoView.cs index 7b833506b..f28ecf16d 100644 --- a/MediaBrowser.Model/SyncPlay/GroupInfoView.cs +++ b/MediaBrowser.Model/SyncPlay/GroupInfoView.cs @@ -1,3 +1,5 @@ +using System.Collections.Generic; + namespace MediaBrowser.Model.SyncPlay { /// @@ -33,6 +35,6 @@ namespace MediaBrowser.Model.SyncPlay /// Gets or sets the participants. /// /// The participants. - public string[] Participants { get; set; } + public IReadOnlyList Participants { get; set; } } } -- cgit v1.2.3 From 43c22a58229892836df645031fb570f37994e19e Mon Sep 17 00:00:00 2001 From: Mark Monteiro Date: Sun, 10 May 2020 14:36:11 -0400 Subject: Add GetLoopbackHttpApiUrl() helper method to replace forceHttps functionality Also refactor to use return a Uri instead of a string and use UriBuilder under the hood --- Emby.Server.Implementations/ApplicationHost.cs | 30 +++++++++++----------- .../Browser/BrowserLauncher.cs | 2 +- .../LiveTv/EmbyTV/EmbyTV.cs | 2 +- .../TunerHosts/HdHomerun/HdHomerunUdpStream.cs | 2 +- .../LiveTv/TunerHosts/SharedHttpStream.cs | 2 +- MediaBrowser.Controller/IServerApplicationHost.cs | 25 ++++++++++++++---- 6 files changed, 39 insertions(+), 24 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index 8f20a4921..2201c3cfc 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -1229,28 +1229,28 @@ namespace Emby.Server.Implementations str.CopyTo(span.Slice(1)); span[^1] = ']'; - return GetLocalApiUrl(span); + return GetLocalApiUrl(span).ToString(); } - return GetLocalApiUrl(ipAddress.ToString()); + return GetLocalApiUrl(ipAddress.ToString()).ToString(); } /// - public string GetLocalApiUrl(ReadOnlySpan host) + public Uri GetLoopbackHttpApiUrl() { - var url = new StringBuilder(64); - url.Append(ListenWithHttps ? "https://" : "http://") - .Append(host) - .Append(':') - .Append(ListenWithHttps ? HttpsPort : HttpPort); - - string baseUrl = ServerConfigurationManager.Configuration.BaseUrl; - if (baseUrl.Length != 0) - { - url.Append(baseUrl); - } + return GetLocalApiUrl("127.0.0.1", Uri.UriSchemeHttp, HttpPort); + } - return url.ToString(); + /// + public Uri GetLocalApiUrl(ReadOnlySpan host, string scheme = null, int? port = null) + { + return new UriBuilder + { + Scheme = scheme ?? (ListenWithHttps ? Uri.UriSchemeHttps : Uri.UriSchemeHttp), + Host = host.ToString(), + Port = port ?? (ListenWithHttps ? HttpsPort : HttpPort), + Path = ServerConfigurationManager.Configuration.BaseUrl + }.Uri; } public Task> GetLocalIpAddresses(CancellationToken cancellationToken) diff --git a/Emby.Server.Implementations/Browser/BrowserLauncher.cs b/Emby.Server.Implementations/Browser/BrowserLauncher.cs index 96096e142..ccb733b3c 100644 --- a/Emby.Server.Implementations/Browser/BrowserLauncher.cs +++ b/Emby.Server.Implementations/Browser/BrowserLauncher.cs @@ -36,7 +36,7 @@ namespace Emby.Server.Implementations.Browser { try { - string baseUrl = appHost.GetLocalApiUrl("localhost"); + Uri baseUrl = appHost.GetLocalApiUrl("localhost"); appHost.LaunchUrl(baseUrl + url); } catch (Exception ex) diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index 900f12062..3efe1ee25 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -1059,7 +1059,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV { var stream = new MediaSourceInfo { - EncoderPath = _appHost.GetLocalApiUrl("127.0.0.1") + "/LiveTv/LiveRecordings/" + info.Id + "/stream", + EncoderPath = _appHost.GetLoopbackHttpApiUrl() + "/LiveTv/LiveRecordings/" + info.Id + "/stream", EncoderProtocol = MediaProtocol.Http, Path = info.Path, Protocol = MediaProtocol.File, diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs index 03ee5bfb6..82b1f3cf1 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs @@ -121,7 +121,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun //OpenedMediaSource.Path = tempFile; //OpenedMediaSource.ReadAtNativeFramerate = true; - MediaSource.Path = _appHost.GetLocalApiUrl("127.0.0.1") + "/LiveTv/LiveStreamFiles/" + UniqueId + "/stream.ts"; + MediaSource.Path = _appHost.GetLoopbackHttpApiUrl() + "/LiveTv/LiveStreamFiles/" + UniqueId + "/stream.ts"; MediaSource.Protocol = MediaProtocol.Http; //OpenedMediaSource.SupportsDirectPlay = false; //OpenedMediaSource.SupportsDirectStream = true; diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs index d63588bbd..083fcd029 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs @@ -106,7 +106,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts //OpenedMediaSource.Path = tempFile; //OpenedMediaSource.ReadAtNativeFramerate = true; - MediaSource.Path = _appHost.GetLocalApiUrl("127.0.0.1") + "/LiveTv/LiveStreamFiles/" + UniqueId + "/stream.ts"; + MediaSource.Path = _appHost.GetLoopbackHttpApiUrl() + "/LiveTv/LiveStreamFiles/" + UniqueId + "/stream.ts"; MediaSource.Protocol = MediaProtocol.Http; //OpenedMediaSource.Path = TempFilePath; diff --git a/MediaBrowser.Controller/IServerApplicationHost.cs b/MediaBrowser.Controller/IServerApplicationHost.cs index 8537e4180..0028bd689 100644 --- a/MediaBrowser.Controller/IServerApplicationHost.cs +++ b/MediaBrowser.Controller/IServerApplicationHost.cs @@ -65,26 +65,41 @@ namespace MediaBrowser.Controller /// /// 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 . + /// IP address that can be found via . HTTPS will be preferred when available. /// /// A cancellation token that can be used to cancel the task. /// The server URL. Task GetLocalApiUrl(CancellationToken cancellationToken); /// - /// Gets a local (LAN) URL that can be used to access the API. + /// Gets a local (LAN) URL that can be used to access the API using the loop-back IP address (127.0.0.1) + /// over HTTP (not HTTPS). /// - /// The hostname to use in the URL. /// The API URL. - string GetLocalApiUrl(ReadOnlySpan hostname); + public Uri GetLoopbackHttpApiUrl(); /// - /// Gets a local (LAN) URL that can be used to access the API. + /// Gets a local (LAN) URL that can be used to access the API. HTTPS will be preferred when available. /// /// The IP address to use as the hostname in the URL. /// The API URL. string GetLocalApiUrl(IPAddress address); + /// + /// Gets a local (LAN) URL that can be used to access the API. + /// + /// The hostname to use in the URL. + /// + /// The scheme to use for the URL. If null, the scheme will be selected automatically, + /// preferring HTTPS, if available. + /// + /// + /// The port to use for the URL. If null, the port will be selected automatically, + /// preferring the HTTPS port, if available. + /// + /// The API URL. + Uri GetLocalApiUrl(ReadOnlySpan hostname, string scheme = null, int? port = null); + /// /// Open a URL in an external browser window. /// -- cgit v1.2.3 From 3abf870c1e321dbeb484e4e255000a27760d7bc9 Mon Sep 17 00:00:00 2001 From: Mark Monteiro Date: Sun, 10 May 2020 18:07:56 -0400 Subject: Do not include a double slash in URLs when a base URL is not set --- Emby.Server.Implementations/ApplicationHost.cs | 15 ++++++++------- Emby.Server.Implementations/Browser/BrowserLauncher.cs | 10 +++++----- MediaBrowser.Controller/IServerApplicationHost.cs | 4 ++-- 3 files changed, 15 insertions(+), 14 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index 10a7e879e..693b049cd 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -1236,28 +1236,30 @@ namespace Emby.Server.Implementations str.CopyTo(span.Slice(1)); span[^1] = ']'; - return GetLocalApiUrl(span).ToString(); + return GetLocalApiUrl(span); } - return GetLocalApiUrl(ipAddress.ToString()).ToString(); + return GetLocalApiUrl(ipAddress.ToString()); } /// - public Uri GetLoopbackHttpApiUrl() + public string GetLoopbackHttpApiUrl() { return GetLocalApiUrl("127.0.0.1", Uri.UriSchemeHttp, HttpPort); } /// - public Uri GetLocalApiUrl(ReadOnlySpan host, string scheme = null, int? port = null) + public string GetLocalApiUrl(ReadOnlySpan host, string scheme = null, int? port = null) { + // NOTE: If no BaseUrl is set then UriBuilder appends a trailing slash, but if there is no BaseUrl it does + // not. For consistency, always trim the trailing slash. return new UriBuilder { Scheme = scheme ?? (ListenWithHttps ? Uri.UriSchemeHttps : Uri.UriSchemeHttp), Host = host.ToString(), Port = port ?? (ListenWithHttps ? HttpsPort : HttpPort), Path = ServerConfigurationManager.Configuration.BaseUrl - }.Uri; + }.ToString().TrimEnd('/'); } public Task> GetLocalIpAddresses(CancellationToken cancellationToken) @@ -1333,8 +1335,7 @@ namespace Emby.Server.Implementations return true; } - var apiUrl = GetLocalApiUrl(address); - apiUrl += "/system/ping"; + var apiUrl = GetLocalApiUrl(address) + "/system/ping"; if (_validAddressResults.TryGetValue(apiUrl, out var cachedResult)) { diff --git a/Emby.Server.Implementations/Browser/BrowserLauncher.cs b/Emby.Server.Implementations/Browser/BrowserLauncher.cs index ccb733b3c..7f7c6a0be 100644 --- a/Emby.Server.Implementations/Browser/BrowserLauncher.cs +++ b/Emby.Server.Implementations/Browser/BrowserLauncher.cs @@ -31,18 +31,18 @@ namespace Emby.Server.Implementations.Browser /// Opens the specified URL in an external browser window. Any exceptions will be logged, but ignored. /// /// The application host. - /// The URL. - private static void TryOpenUrl(IServerApplicationHost appHost, string url) + /// The URL to open, relative to the server base URL. + private static void TryOpenUrl(IServerApplicationHost appHost, string relativeUrl) { try { - Uri baseUrl = appHost.GetLocalApiUrl("localhost"); - appHost.LaunchUrl(baseUrl + url); + string baseUrl = appHost.GetLocalApiUrl("localhost"); + appHost.LaunchUrl(baseUrl + relativeUrl); } catch (Exception ex) { var logger = appHost.Resolve(); - logger?.LogError(ex, "Failed to open browser window with URL {URL}", url); + logger?.LogError(ex, "Failed to open browser window with URL {URL}", relativeUrl); } } } diff --git a/MediaBrowser.Controller/IServerApplicationHost.cs b/MediaBrowser.Controller/IServerApplicationHost.cs index 0028bd689..4f0ff1ee1 100644 --- a/MediaBrowser.Controller/IServerApplicationHost.cs +++ b/MediaBrowser.Controller/IServerApplicationHost.cs @@ -76,7 +76,7 @@ namespace MediaBrowser.Controller /// over HTTP (not HTTPS). /// /// The API URL. - public Uri GetLoopbackHttpApiUrl(); + string GetLoopbackHttpApiUrl(); /// /// Gets a local (LAN) URL that can be used to access the API. HTTPS will be preferred when available. @@ -98,7 +98,7 @@ namespace MediaBrowser.Controller /// preferring the HTTPS port, if available. /// /// The API URL. - Uri GetLocalApiUrl(ReadOnlySpan hostname, string scheme = null, int? port = null); + string GetLocalApiUrl(ReadOnlySpan hostname, string scheme = null, int? port = null); /// /// Open a URL in an external browser window. -- cgit v1.2.3 From 9ad839c7766bd5d6121a10b2c306d6fef9666c52 Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Tue, 12 May 2020 22:10:35 -0400 Subject: Initial migration code --- Emby.Dlna/ContentDirectory/ContentDirectory.cs | 13 +- Emby.Dlna/ContentDirectory/ControlHandler.cs | 89 +- Emby.Dlna/Didl/DidlBuilder.cs | 11 +- Emby.Dlna/PlayTo/PlayToController.cs | 8 +- Emby.Drawing/ImageProcessor.cs | 9 + Emby.Notifications/Api/NotificationsService.cs | 6 +- Emby.Notifications/NotificationManager.cs | 13 +- .../Activity/ActivityLogEntryPoint.cs | 42 +- Emby.Server.Implementations/ApplicationHost.cs | 15 +- .../Channels/ChannelManager.cs | 7 +- .../Collections/CollectionManager.cs | 4 +- .../Data/SqliteDisplayPreferencesRepository.cs | 225 ---- .../Data/SqliteItemRepository.cs | 4 +- .../Data/SqliteUserDataRepository.cs | 379 ------- .../Data/SqliteUserRepository.cs | 240 ----- .../Devices/DeviceManager.cs | 26 +- Emby.Server.Implementations/Dto/DtoService.cs | 23 +- .../EntryPoints/LibraryChangedNotifier.cs | 2 +- .../EntryPoints/RecordingNotifier.cs | 3 +- .../EntryPoints/RefreshUsersMetadata.cs | 77 -- .../EntryPoints/ServerEventNotifier.cs | 29 +- .../HttpServer/Security/AuthService.cs | 24 +- .../HttpServer/Security/AuthorizationContext.cs | 4 +- .../HttpServer/Security/SessionContext.cs | 4 +- .../Library/DefaultAuthenticationProvider.cs | 177 ---- .../Library/DefaultPasswordResetProvider.cs | 140 --- .../Library/InvalidAuthProvider.cs | 54 - .../Library/LibraryManager.cs | 22 +- .../Library/MediaSourceManager.cs | 52 +- .../Library/MediaStreamSelector.cs | 1 + .../Library/MusicManager.cs | 32 +- .../Library/SearchEngine.cs | 4 +- .../Library/UserDataManager.cs | 10 +- Emby.Server.Implementations/Library/UserManager.cs | 1107 -------------------- .../Library/UserViewManager.cs | 29 +- .../LiveTv/LiveTvManager.cs | 40 +- .../Playlists/ManualPlaylistsFolder.cs | 6 +- .../Playlists/PlaylistManager.cs | 4 +- .../Session/SessionManager.cs | 91 +- .../Sorting/DateLastMediaAddedComparer.cs | 2 +- .../Sorting/DatePlayedComparer.cs | 2 +- .../Sorting/IsFavoriteOrLikeComparer.cs | 2 +- .../Sorting/IsPlayedComparer.cs | 2 +- .../Sorting/IsUnplayedComparer.cs | 2 +- .../Sorting/PlayCountComparer.cs | 2 +- Emby.Server.Implementations/TV/TVSeriesManager.cs | 13 +- Jellyfin.Api/Auth/CustomAuthenticationHandler.cs | 5 +- Jellyfin.Api/Controllers/StartupController.cs | 4 +- Jellyfin.Data/DayOfWeekHelper.cs | 70 ++ Jellyfin.Data/Entities/AccessSchedule.cs | 68 ++ Jellyfin.Data/Entities/ImageInfo.cs | 25 + Jellyfin.Data/Entities/User.cs | 284 +++-- Jellyfin.Data/Enums/DynamicDayOfWeek.cs | 18 + Jellyfin.Data/Enums/PermissionKind.cs | 11 +- Jellyfin.Data/Enums/PreferenceKind.cs | 13 +- Jellyfin.Data/Enums/SubtitlePlaybackMode.cs | 13 + Jellyfin.Data/Enums/UnratedItem.cs | 17 + Jellyfin.Server.Implementations/JellyfinDb.cs | 2 +- .../User/DefaultAuthenticationProvider.cs | 185 ++++ .../User/DefaultPasswordResetProvider.cs | 126 +++ .../User/DeviceAccessEntryPoint.cs | 65 ++ .../User/InvalidAuthProvider.cs | 47 + .../User/UserManager.cs | 749 +++++++++++++ .../Migrations/Routines/MigrateUserDb.cs | 8 + MediaBrowser.Api/BaseApiService.cs | 5 +- MediaBrowser.Api/FilterService.cs | 2 +- MediaBrowser.Api/Images/ImageService.cs | 147 ++- MediaBrowser.Api/Library/LibraryService.cs | 8 +- MediaBrowser.Api/LiveTv/LiveTvService.cs | 3 +- MediaBrowser.Api/Movies/MoviesService.cs | 28 +- MediaBrowser.Api/Music/InstantMixService.cs | 2 +- MediaBrowser.Api/Playback/BaseStreamingService.cs | 3 +- MediaBrowser.Api/Playback/MediaInfoService.cs | 36 +- MediaBrowser.Api/Sessions/SessionService.cs | 5 +- MediaBrowser.Api/SuggestionsService.cs | 2 +- MediaBrowser.Api/TvShowsService.cs | 8 +- .../UserLibrary/BaseItemsByNameService.cs | 4 +- MediaBrowser.Api/UserLibrary/ItemsService.cs | 20 +- MediaBrowser.Api/UserLibrary/PlaystateService.cs | 2 +- MediaBrowser.Api/UserLibrary/UserLibraryService.cs | 2 +- MediaBrowser.Api/UserService.cs | 36 +- .../Authentication/IAuthenticationProvider.cs | 2 +- .../Authentication/IPasswordResetProvider.cs | 2 +- MediaBrowser.Controller/Channels/Channel.cs | 13 +- .../Collections/ICollectionManager.cs | 2 +- MediaBrowser.Controller/Devices/IDeviceManager.cs | 2 +- MediaBrowser.Controller/Drawing/IImageProcessor.cs | 3 + .../Drawing/ImageProcessorExtensions.cs | 1 + MediaBrowser.Controller/Dto/IDtoService.cs | 8 +- MediaBrowser.Controller/Entities/Audio/Audio.cs | 1 + .../Entities/Audio/MusicAlbum.cs | 8 +- .../Entities/Audio/MusicArtist.cs | 8 +- MediaBrowser.Controller/Entities/AudioBook.cs | 1 + MediaBrowser.Controller/Entities/BaseItem.cs | 69 +- MediaBrowser.Controller/Entities/Book.cs | 1 + .../Entities/DayOfWeekHelper.cs | 71 -- MediaBrowser.Controller/Entities/Folder.cs | 55 +- .../Entities/InternalItemsQuery.cs | 18 +- MediaBrowser.Controller/Entities/Movies/BoxSet.cs | 19 +- MediaBrowser.Controller/Entities/Movies/Movie.cs | 1 + MediaBrowser.Controller/Entities/MusicVideo.cs | 1 + MediaBrowser.Controller/Entities/TV/Episode.cs | 1 + MediaBrowser.Controller/Entities/TV/Season.cs | 17 +- MediaBrowser.Controller/Entities/TV/Series.cs | 43 +- MediaBrowser.Controller/Entities/Trailer.cs | 1 + MediaBrowser.Controller/Entities/User.cs | 262 ----- MediaBrowser.Controller/Entities/UserRootFolder.cs | 4 +- MediaBrowser.Controller/Entities/UserView.cs | 8 +- .../Entities/UserViewBuilder.cs | 86 +- MediaBrowser.Controller/Library/IIntroProvider.cs | 2 +- MediaBrowser.Controller/Library/ILibraryManager.cs | 12 +- .../Library/IMediaSourceManager.cs | 6 +- MediaBrowser.Controller/Library/IMusicManager.cs | 6 +- .../Library/IUserDataManager.cs | 8 +- MediaBrowser.Controller/Library/IUserManager.cs | 125 +-- .../Library/PlaybackProgressEventArgs.cs | 4 +- MediaBrowser.Controller/LiveTv/ILiveTvManager.cs | 12 +- MediaBrowser.Controller/LiveTv/LiveTvChannel.cs | 1 + MediaBrowser.Controller/LiveTv/LiveTvProgram.cs | 1 + .../MediaEncoding/EncodingHelper.cs | 7 +- .../MediaEncoding/EncodingJobInfo.cs | 17 +- MediaBrowser.Controller/Net/AuthorizationInfo.cs | 10 +- MediaBrowser.Controller/Net/IAuthService.cs | 2 +- MediaBrowser.Controller/Net/ISessionContext.cs | 2 +- .../Notifications/INotificationService.cs | 2 +- .../Notifications/UserNotification.cs | 2 +- .../Persistence/IUserRepository.cs | 27 - MediaBrowser.Controller/Playlists/Playlist.cs | 26 +- .../Providers/IProviderManager.cs | 3 + MediaBrowser.Controller/Session/ISessionManager.cs | 2 +- .../Sorting/IUserBaseItemComparer.cs | 2 +- MediaBrowser.Model/Configuration/AccessSchedule.cs | 2 + .../Configuration/DynamicDayOfWeek.cs | 18 - .../Configuration/SubtitlePlaybackMode.cs | 13 - MediaBrowser.Model/Configuration/UnratedItem.cs | 17 - .../Configuration/UserConfiguration.cs | 1 + .../Notifications/NotificationOptions.cs | 5 +- MediaBrowser.Model/Users/UserPolicy.cs | 7 +- MediaBrowser.Providers/Manager/ImageSaver.cs | 27 +- MediaBrowser.Providers/Manager/ProviderManager.cs | 14 +- .../Users/UserMetadataService.cs | 30 - .../Auth/CustomAuthenticationHandlerTests.cs | 13 +- 142 files changed, 2531 insertions(+), 3677 deletions(-) delete mode 100644 Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs delete mode 100644 Emby.Server.Implementations/Data/SqliteUserDataRepository.cs delete mode 100644 Emby.Server.Implementations/Data/SqliteUserRepository.cs delete mode 100644 Emby.Server.Implementations/EntryPoints/RefreshUsersMetadata.cs delete mode 100644 Emby.Server.Implementations/Library/DefaultAuthenticationProvider.cs delete mode 100644 Emby.Server.Implementations/Library/DefaultPasswordResetProvider.cs delete mode 100644 Emby.Server.Implementations/Library/InvalidAuthProvider.cs delete mode 100644 Emby.Server.Implementations/Library/UserManager.cs create mode 100644 Jellyfin.Data/DayOfWeekHelper.cs create mode 100644 Jellyfin.Data/Entities/AccessSchedule.cs create mode 100644 Jellyfin.Data/Entities/ImageInfo.cs create mode 100644 Jellyfin.Data/Enums/DynamicDayOfWeek.cs create mode 100644 Jellyfin.Data/Enums/SubtitlePlaybackMode.cs create mode 100644 Jellyfin.Data/Enums/UnratedItem.cs create mode 100644 Jellyfin.Server.Implementations/User/DefaultAuthenticationProvider.cs create mode 100644 Jellyfin.Server.Implementations/User/DefaultPasswordResetProvider.cs create mode 100644 Jellyfin.Server.Implementations/User/DeviceAccessEntryPoint.cs create mode 100644 Jellyfin.Server.Implementations/User/InvalidAuthProvider.cs create mode 100644 Jellyfin.Server.Implementations/User/UserManager.cs create mode 100644 Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs delete mode 100644 MediaBrowser.Controller/Entities/DayOfWeekHelper.cs delete mode 100644 MediaBrowser.Controller/Entities/User.cs delete mode 100644 MediaBrowser.Controller/Persistence/IUserRepository.cs delete mode 100644 MediaBrowser.Model/Configuration/DynamicDayOfWeek.cs delete mode 100644 MediaBrowser.Model/Configuration/SubtitlePlaybackMode.cs delete mode 100644 MediaBrowser.Model/Configuration/UnratedItem.cs delete mode 100644 MediaBrowser.Providers/Users/UserMetadataService.cs (limited to 'MediaBrowser.Controller') diff --git a/Emby.Dlna/ContentDirectory/ContentDirectory.cs b/Emby.Dlna/ContentDirectory/ContentDirectory.cs index 64cd308a2..ea577a905 100644 --- a/Emby.Dlna/ContentDirectory/ContentDirectory.cs +++ b/Emby.Dlna/ContentDirectory/ContentDirectory.cs @@ -1,8 +1,10 @@ #pragma warning disable CS1591 using System; +using System.Linq; using System.Threading.Tasks; using Emby.Dlna.Service; +using Jellyfin.Data.Enums; using MediaBrowser.Common.Net; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Dlna; @@ -104,7 +106,7 @@ namespace Emby.Dlna.ContentDirectory .ProcessControlRequestAsync(request); } - private User GetUser(DeviceProfile profile) + private Jellyfin.Data.Entities.User GetUser(DeviceProfile profile) { if (!string.IsNullOrEmpty(profile.UserId)) { @@ -130,18 +132,13 @@ namespace Emby.Dlna.ContentDirectory foreach (var user in _userManager.Users) { - if (user.Policy.IsAdministrator) + if (user.HasPermission(PermissionKind.IsAdministrator)) { return user; } } - foreach (var user in _userManager.Users) - { - return user; - } - - return null; + return _userManager.Users.FirstOrDefault(); } } } diff --git a/Emby.Dlna/ContentDirectory/ControlHandler.cs b/Emby.Dlna/ContentDirectory/ControlHandler.cs index 28888f031..32bda2fe1 100644 --- a/Emby.Dlna/ContentDirectory/ControlHandler.cs +++ b/Emby.Dlna/ContentDirectory/ControlHandler.cs @@ -36,7 +36,7 @@ namespace Emby.Dlna.ContentDirectory private readonly ILibraryManager _libraryManager; private readonly IUserDataManager _userDataManager; private readonly IServerConfigurationManager _config; - private readonly User _user; + private readonly Jellyfin.Data.Entities.User _user; private readonly IUserViewManager _userViewManager; private readonly ITVSeriesManager _tvSeriesManager; @@ -59,7 +59,7 @@ namespace Emby.Dlna.ContentDirectory string accessToken, IImageProcessor imageProcessor, IUserDataManager userDataManager, - User user, + Jellyfin.Data.Entities.User user, int systemUpdateId, IServerConfigurationManager config, ILocalizationManager localization, @@ -432,7 +432,7 @@ namespace Emby.Dlna.ContentDirectory xmlWriter.WriteElementString("UpdateID", _systemUpdateId.ToString(CultureInfo.InvariantCulture)); } - private QueryResult GetChildrenSorted(BaseItem item, User user, SearchCriteria search, SortCriteria sort, int? startIndex, int? limit) + private QueryResult GetChildrenSorted(BaseItem item, Jellyfin.Data.Entities.User user, SearchCriteria search, SortCriteria sort, int? startIndex, int? limit) { var folder = (Folder)item; @@ -489,7 +489,7 @@ namespace Emby.Dlna.ContentDirectory return new DtoOptions(true); } - private QueryResult GetUserItems(BaseItem item, StubType? stubType, User user, SortCriteria sort, int? startIndex, int? limit) + private QueryResult GetUserItems(BaseItem item, StubType? stubType, Jellyfin.Data.Entities.User user, SortCriteria sort, int? startIndex, int? limit) { if (item is MusicGenre) { @@ -558,7 +558,7 @@ namespace Emby.Dlna.ContentDirectory return ToResult(queryResult); } - private QueryResult GetLiveTvChannels(User user, SortCriteria sort, int? startIndex, int? limit) + private QueryResult GetLiveTvChannels(Jellyfin.Data.Entities.User user, SortCriteria sort, int? startIndex, int? limit) { var query = new InternalItemsQuery(user) { @@ -574,7 +574,7 @@ namespace Emby.Dlna.ContentDirectory return ToResult(result); } - private QueryResult GetMusicFolders(BaseItem item, User user, StubType? stubType, SortCriteria sort, int? startIndex, int? limit) + private QueryResult GetMusicFolders(BaseItem item, Jellyfin.Data.Entities.User user, StubType? stubType, SortCriteria sort, int? startIndex, int? limit) { var query = new InternalItemsQuery(user) { @@ -692,7 +692,7 @@ namespace Emby.Dlna.ContentDirectory }; } - private QueryResult GetMovieFolders(BaseItem item, User user, StubType? stubType, SortCriteria sort, int? startIndex, int? limit) + private QueryResult GetMovieFolders(BaseItem item, Jellyfin.Data.Entities.User user, StubType? stubType, SortCriteria sort, int? startIndex, int? limit) { var query = new InternalItemsQuery(user) { @@ -731,7 +731,7 @@ namespace Emby.Dlna.ContentDirectory return GetGenres(item, user, query); } - var array = new ServerItem[] + var array = new[] { new ServerItem(item) { @@ -766,7 +766,7 @@ namespace Emby.Dlna.ContentDirectory }; } - private QueryResult GetFolders(User user, int? startIndex, int? limit) + private QueryResult GetFolders(Jellyfin.Data.Entities.User user, int? startIndex, int? limit) { var folders = _libraryManager.GetUserRootFolder().GetChildren(user, true) .OrderBy(i => i.SortName) @@ -783,7 +783,7 @@ namespace Emby.Dlna.ContentDirectory }, startIndex, limit); } - private QueryResult GetTvFolders(BaseItem item, User user, StubType? stubType, SortCriteria sort, int? startIndex, int? limit) + private QueryResult GetTvFolders(BaseItem item, Jellyfin.Data.Entities.User user, StubType? stubType, SortCriteria sort, int? startIndex, int? limit) { var query = new InternalItemsQuery(user) { @@ -871,7 +871,7 @@ namespace Emby.Dlna.ContentDirectory }; } - private QueryResult GetMovieContinueWatching(BaseItem parent, User user, InternalItemsQuery query) + private QueryResult GetMovieContinueWatching(BaseItem parent, Jellyfin.Data.Entities.User user, InternalItemsQuery query) { query.Recursive = true; query.Parent = parent; @@ -891,7 +891,7 @@ namespace Emby.Dlna.ContentDirectory return ToResult(result); } - private QueryResult GetSeries(BaseItem parent, User user, InternalItemsQuery query) + private QueryResult GetSeries(BaseItem parent, Jellyfin.Data.Entities.User user, InternalItemsQuery query) { query.Recursive = true; query.Parent = parent; @@ -904,7 +904,7 @@ namespace Emby.Dlna.ContentDirectory return ToResult(result); } - private QueryResult GetMovieMovies(BaseItem parent, User user, InternalItemsQuery query) + private QueryResult GetMovieMovies(BaseItem parent, Jellyfin.Data.Entities.User user, InternalItemsQuery query) { query.Recursive = true; query.Parent = parent; @@ -917,7 +917,7 @@ namespace Emby.Dlna.ContentDirectory return ToResult(result); } - private QueryResult GetMovieCollections(User user, InternalItemsQuery query) + private QueryResult GetMovieCollections(Jellyfin.Data.Entities.User user, InternalItemsQuery query) { query.Recursive = true; //query.Parent = parent; @@ -930,7 +930,7 @@ namespace Emby.Dlna.ContentDirectory return ToResult(result); } - private QueryResult GetMusicAlbums(BaseItem parent, User user, InternalItemsQuery query) + private QueryResult GetMusicAlbums(BaseItem parent, Jellyfin.Data.Entities.User user, InternalItemsQuery query) { query.Recursive = true; query.Parent = parent; @@ -943,7 +943,7 @@ namespace Emby.Dlna.ContentDirectory return ToResult(result); } - private QueryResult GetMusicSongs(BaseItem parent, User user, InternalItemsQuery query) + private QueryResult GetMusicSongs(BaseItem parent, Jellyfin.Data.Entities.User user, InternalItemsQuery query) { query.Recursive = true; query.Parent = parent; @@ -956,7 +956,7 @@ namespace Emby.Dlna.ContentDirectory return ToResult(result); } - private QueryResult GetFavoriteSongs(BaseItem parent, User user, InternalItemsQuery query) + private QueryResult GetFavoriteSongs(BaseItem parent, Jellyfin.Data.Entities.User user, InternalItemsQuery query) { query.Recursive = true; query.Parent = parent; @@ -969,7 +969,7 @@ namespace Emby.Dlna.ContentDirectory return ToResult(result); } - private QueryResult GetFavoriteSeries(BaseItem parent, User user, InternalItemsQuery query) + private QueryResult GetFavoriteSeries(BaseItem parent, Jellyfin.Data.Entities.User user, InternalItemsQuery query) { query.Recursive = true; query.Parent = parent; @@ -982,7 +982,7 @@ namespace Emby.Dlna.ContentDirectory return ToResult(result); } - private QueryResult GetFavoriteEpisodes(BaseItem parent, User user, InternalItemsQuery query) + private QueryResult GetFavoriteEpisodes(BaseItem parent, Jellyfin.Data.Entities.User user, InternalItemsQuery query) { query.Recursive = true; query.Parent = parent; @@ -995,7 +995,7 @@ namespace Emby.Dlna.ContentDirectory return ToResult(result); } - private QueryResult GetMovieFavorites(BaseItem parent, User user, InternalItemsQuery query) + private QueryResult GetMovieFavorites(BaseItem parent, Jellyfin.Data.Entities.User user, InternalItemsQuery query) { query.Recursive = true; query.Parent = parent; @@ -1008,7 +1008,7 @@ namespace Emby.Dlna.ContentDirectory return ToResult(result); } - private QueryResult GetFavoriteAlbums(BaseItem parent, User user, InternalItemsQuery query) + private QueryResult GetFavoriteAlbums(BaseItem parent, Jellyfin.Data.Entities.User user, InternalItemsQuery query) { query.Recursive = true; query.Parent = parent; @@ -1021,7 +1021,7 @@ namespace Emby.Dlna.ContentDirectory return ToResult(result); } - private QueryResult GetGenres(BaseItem parent, User user, InternalItemsQuery query) + private QueryResult GetGenres(BaseItem parent, Jellyfin.Data.Entities.User user, InternalItemsQuery query) { var genresResult = _libraryManager.GetGenres(new InternalItemsQuery(user) { @@ -1039,7 +1039,7 @@ namespace Emby.Dlna.ContentDirectory return ToResult(result); } - private QueryResult GetMusicGenres(BaseItem parent, User user, InternalItemsQuery query) + private QueryResult GetMusicGenres(BaseItem parent, Jellyfin.Data.Entities.User user, InternalItemsQuery query) { var genresResult = _libraryManager.GetMusicGenres(new InternalItemsQuery(user) { @@ -1057,7 +1057,7 @@ namespace Emby.Dlna.ContentDirectory return ToResult(result); } - private QueryResult GetMusicAlbumArtists(BaseItem parent, User user, InternalItemsQuery query) + private QueryResult GetMusicAlbumArtists(BaseItem parent, Jellyfin.Data.Entities.User user, InternalItemsQuery query) { var artists = _libraryManager.GetAlbumArtists(new InternalItemsQuery(user) { @@ -1075,7 +1075,7 @@ namespace Emby.Dlna.ContentDirectory return ToResult(result); } - private QueryResult GetMusicArtists(BaseItem parent, User user, InternalItemsQuery query) + private QueryResult GetMusicArtists(BaseItem parent, Jellyfin.Data.Entities.User user, InternalItemsQuery query) { var artists = _libraryManager.GetArtists(new InternalItemsQuery(user) { @@ -1093,7 +1093,7 @@ namespace Emby.Dlna.ContentDirectory return ToResult(result); } - private QueryResult GetFavoriteArtists(BaseItem parent, User user, InternalItemsQuery query) + private QueryResult GetFavoriteArtists(BaseItem parent, Jellyfin.Data.Entities.User user, InternalItemsQuery query) { var artists = _libraryManager.GetArtists(new InternalItemsQuery(user) { @@ -1112,10 +1112,10 @@ namespace Emby.Dlna.ContentDirectory return ToResult(result); } - private QueryResult GetMusicPlaylists(User user, InternalItemsQuery query) + private QueryResult GetMusicPlaylists(Jellyfin.Data.Entities.User user, InternalItemsQuery query) { query.Parent = null; - query.IncludeItemTypes = new[] { typeof(Playlist).Name }; + query.IncludeItemTypes = new[] { nameof(Playlist) }; query.SetUser(user); query.Recursive = true; @@ -1124,7 +1124,7 @@ namespace Emby.Dlna.ContentDirectory return ToResult(result); } - private QueryResult GetMusicLatest(BaseItem parent, User user, InternalItemsQuery query) + private QueryResult GetMusicLatest(BaseItem parent, Jellyfin.Data.Entities.User user, InternalItemsQuery query) { query.OrderBy = Array.Empty<(string, SortOrder)>(); @@ -1132,10 +1132,9 @@ namespace Emby.Dlna.ContentDirectory { UserId = user.Id, Limit = 50, - IncludeItemTypes = new[] { typeof(Audio).Name }, - ParentId = parent == null ? Guid.Empty : parent.Id, + IncludeItemTypes = new[] { nameof(Audio) }, + ParentId = parent?.Id ?? Guid.Empty, GroupItems = true - }, query.DtoOptions).Select(i => i.Item1 ?? i.Item2.FirstOrDefault()).Where(i => i != null).ToArray(); return ToResult(items); @@ -1150,13 +1149,12 @@ namespace Emby.Dlna.ContentDirectory Limit = query.Limit, StartIndex = query.StartIndex, UserId = query.User.Id - }, new[] { parent }, query.DtoOptions); return ToResult(result); } - private QueryResult GetTvLatest(BaseItem parent, User user, InternalItemsQuery query) + private QueryResult GetTvLatest(BaseItem parent, Jellyfin.Data.Entities.User user, InternalItemsQuery query) { query.OrderBy = Array.Empty<(string, SortOrder)>(); @@ -1167,30 +1165,29 @@ namespace Emby.Dlna.ContentDirectory IncludeItemTypes = new[] { typeof(Episode).Name }, ParentId = parent == null ? Guid.Empty : parent.Id, GroupItems = false - }, query.DtoOptions).Select(i => i.Item1 ?? i.Item2.FirstOrDefault()).Where(i => i != null).ToArray(); return ToResult(items); } - private QueryResult GetMovieLatest(BaseItem parent, User user, InternalItemsQuery query) + private QueryResult GetMovieLatest(BaseItem parent, Jellyfin.Data.Entities.User user, InternalItemsQuery query) { query.OrderBy = Array.Empty<(string, SortOrder)>(); - var items = _userViewManager.GetLatestItems(new LatestItemsQuery + var items = _userViewManager.GetLatestItems( + new LatestItemsQuery { UserId = user.Id, Limit = 50, - IncludeItemTypes = new[] { typeof(Movie).Name }, - ParentId = parent == null ? Guid.Empty : parent.Id, + IncludeItemTypes = new[] { nameof(Movie) }, + ParentId = parent?.Id ?? Guid.Empty, GroupItems = true - }, query.DtoOptions).Select(i => i.Item1 ?? i.Item2.FirstOrDefault()).Where(i => i != null).ToArray(); return ToResult(items); } - private QueryResult GetMusicArtistItems(BaseItem item, Guid parentId, User user, SortCriteria sort, int? startIndex, int? limit) + private QueryResult GetMusicArtistItems(BaseItem item, Guid parentId, Jellyfin.Data.Entities.User user, SortCriteria sort, int? startIndex, int? limit) { var query = new InternalItemsQuery(user) { @@ -1210,14 +1207,18 @@ namespace Emby.Dlna.ContentDirectory return ToResult(result); } - private QueryResult GetGenreItems(BaseItem item, Guid parentId, User user, SortCriteria sort, int? startIndex, int? limit) + private QueryResult GetGenreItems(BaseItem item, Guid parentId, Jellyfin.Data.Entities.User user, SortCriteria sort, int? startIndex, int? limit) { var query = new InternalItemsQuery(user) { Recursive = true, ParentId = parentId, GenreIds = new[] { item.Id }, - IncludeItemTypes = new[] { typeof(Movie).Name, typeof(Series).Name }, + IncludeItemTypes = new[] + { + nameof(Movie), + nameof(Series) + }, Limit = limit, StartIndex = startIndex, DtoOptions = GetDtoOptions() @@ -1230,7 +1231,7 @@ namespace Emby.Dlna.ContentDirectory return ToResult(result); } - private QueryResult GetMusicGenreItems(BaseItem item, Guid parentId, User user, SortCriteria sort, int? startIndex, int? limit) + private QueryResult GetMusicGenreItems(BaseItem item, Guid parentId, Jellyfin.Data.Entities.User user, SortCriteria sort, int? startIndex, int? limit) { var query = new InternalItemsQuery(user) { diff --git a/Emby.Dlna/Didl/DidlBuilder.cs b/Emby.Dlna/Didl/DidlBuilder.cs index f7d840c62..24932ced9 100644 --- a/Emby.Dlna/Didl/DidlBuilder.cs +++ b/Emby.Dlna/Didl/DidlBuilder.cs @@ -6,7 +6,6 @@ using System.IO; using System.Linq; using System.Text; using System.Xml; -using Emby.Dlna.Configuration; using Emby.Dlna.ContentDirectory; using MediaBrowser.Controller.Channels; using MediaBrowser.Controller.Drawing; @@ -39,7 +38,7 @@ namespace Emby.Dlna.Didl private readonly IImageProcessor _imageProcessor; private readonly string _serverAddress; private readonly string _accessToken; - private readonly User _user; + private readonly Jellyfin.Data.Entities.User _user; private readonly IUserDataManager _userDataManager; private readonly ILocalizationManager _localization; private readonly IMediaSourceManager _mediaSourceManager; @@ -49,7 +48,7 @@ namespace Emby.Dlna.Didl public DidlBuilder( DeviceProfile profile, - User user, + Jellyfin.Data.Entities.User user, IImageProcessor imageProcessor, string serverAddress, string accessToken, @@ -78,7 +77,7 @@ namespace Emby.Dlna.Didl return url + "&dlnaheaders=true"; } - public string GetItemDidl(BaseItem item, User user, BaseItem context, string deviceId, Filter filter, StreamInfo streamInfo) + public string GetItemDidl(BaseItem item, Jellyfin.Data.Entities.User user, BaseItem context, string deviceId, Filter filter, StreamInfo streamInfo) { var settings = new XmlWriterSettings { @@ -132,7 +131,7 @@ namespace Emby.Dlna.Didl public void WriteItemElement( XmlWriter writer, BaseItem item, - User user, + Jellyfin.Data.Entities.User user, BaseItem context, StubType? contextStubType, string deviceId, @@ -663,7 +662,7 @@ namespace Emby.Dlna.Didl writer.WriteFullEndElement(); } - private void AddSamsungBookmarkInfo(BaseItem item, User user, XmlWriter writer, StreamInfo streamInfo) + private void AddSamsungBookmarkInfo(BaseItem item, Jellyfin.Data.Entities.User user, XmlWriter writer, StreamInfo streamInfo) { if (!item.SupportsPositionTicksResume || item is Folder) { diff --git a/Emby.Dlna/PlayTo/PlayToController.cs b/Emby.Dlna/PlayTo/PlayToController.cs index 43e983054..ff37407a2 100644 --- a/Emby.Dlna/PlayTo/PlayToController.cs +++ b/Emby.Dlna/PlayTo/PlayToController.cs @@ -441,7 +441,13 @@ namespace Emby.Dlna.PlayTo } } - private PlaylistItem CreatePlaylistItem(BaseItem item, User user, long startPostionTicks, string mediaSourceId, int? audioStreamIndex, int? subtitleStreamIndex) + private PlaylistItem CreatePlaylistItem( + BaseItem item, + Jellyfin.Data.Entities.User user, + long startPostionTicks, + string mediaSourceId, + int? audioStreamIndex, + int? subtitleStreamIndex) { var deviceInfo = _device.Properties; diff --git a/Emby.Drawing/ImageProcessor.cs b/Emby.Drawing/ImageProcessor.cs index 0b3bbe29e..b9172d2a8 100644 --- a/Emby.Drawing/ImageProcessor.cs +++ b/Emby.Drawing/ImageProcessor.cs @@ -4,6 +4,7 @@ using System.Globalization; using System.IO; using System.Linq; using System.Threading.Tasks; +using Jellyfin.Data.Entities; using MediaBrowser.Common.Extensions; using MediaBrowser.Controller; using MediaBrowser.Controller.Drawing; @@ -14,6 +15,7 @@ using MediaBrowser.Model.Entities; using MediaBrowser.Model.IO; using MediaBrowser.Model.Net; using Microsoft.Extensions.Logging; +using Photo = MediaBrowser.Controller.Entities.Photo; namespace Emby.Drawing { @@ -328,6 +330,13 @@ namespace Emby.Drawing }); } + /// + public string GetImageCacheTag(User user) + { + return (user.ProfileImage.Path + user.ProfileImage.LastModified.Ticks).GetMD5() + .ToString("N", CultureInfo.InvariantCulture); + } + private async Task<(string path, DateTime dateModified)> GetSupportedImage(string originalImagePath, DateTime dateModified) { var inputFormat = Path.GetExtension(originalImagePath) diff --git a/Emby.Notifications/Api/NotificationsService.cs b/Emby.Notifications/Api/NotificationsService.cs index 788750796..221db5423 100644 --- a/Emby.Notifications/Api/NotificationsService.cs +++ b/Emby.Notifications/Api/NotificationsService.cs @@ -8,6 +8,7 @@ using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Threading; using System.Threading.Tasks; +using Jellyfin.Data.Enums; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Net; using MediaBrowser.Controller.Notifications; @@ -164,7 +165,10 @@ namespace Emby.Notifications.Api Level = request.Level, Name = request.Name, Url = request.Url, - UserIds = _userManager.Users.Where(i => i.Policy.IsAdministrator).Select(i => i.Id).ToArray() + UserIds = _userManager.Users + .Where(p => p.Permissions.Select(x => x.Kind).Contains(PermissionKind.IsAdministrator)) + .Select(p => p.Id) + .ToArray() }; return _notificationManager.SendNotification(notification, CancellationToken.None); diff --git a/Emby.Notifications/NotificationManager.cs b/Emby.Notifications/NotificationManager.cs index 639a5e1aa..9a9bc4415 100644 --- a/Emby.Notifications/NotificationManager.cs +++ b/Emby.Notifications/NotificationManager.cs @@ -4,6 +4,7 @@ using System.Globalization; using System.Linq; using System.Threading; using System.Threading.Tasks; +using Jellyfin.Data.Enums; using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.Configuration; @@ -81,7 +82,7 @@ namespace Emby.Notifications private Task SendNotification( NotificationRequest request, INotificationService service, - IEnumerable users, + IEnumerable users, string title, string description, CancellationToken cancellationToken) @@ -101,7 +102,7 @@ namespace Emby.Notifications switch (request.SendToUserMode.Value) { case SendToUserType.Admins: - return _userManager.Users.Where(i => i.Policy.IsAdministrator) + return _userManager.Users.Where(i => i.HasPermission(PermissionKind.IsAdministrator)) .Select(i => i.Id); case SendToUserType.All: return _userManager.UsersIds; @@ -117,7 +118,7 @@ namespace Emby.Notifications var config = GetConfiguration(); return _userManager.Users - .Where(i => config.IsEnabledToSendToUser(request.NotificationType, i.Id.ToString("N", CultureInfo.InvariantCulture), i.Policy)) + .Where(i => config.IsEnabledToSendToUser(request.NotificationType, i.Id.ToString("N", CultureInfo.InvariantCulture), i)) .Select(i => i.Id); } @@ -129,7 +130,7 @@ namespace Emby.Notifications INotificationService service, string title, string description, - User user, + Jellyfin.Data.Entities.User user, CancellationToken cancellationToken) { var notification = new UserNotification @@ -142,7 +143,7 @@ namespace Emby.Notifications User = user }; - _logger.LogDebug("Sending notification via {0} to user {1}", service.Name, user.Name); + _logger.LogDebug("Sending notification via {0} to user {1}", service.Name, user.Username); try { @@ -154,7 +155,7 @@ namespace Emby.Notifications } } - private bool IsEnabledForUser(INotificationService service, User user) + private bool IsEnabledForUser(INotificationService service, Jellyfin.Data.Entities.User user) { try { diff --git a/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs b/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs index 54894fd65..3d3859078 100644 --- a/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs +++ b/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs @@ -93,11 +93,10 @@ namespace Emby.Server.Implementations.Activity _subManager.SubtitleDownloadFailure += OnSubtitleDownloadFailure; - _userManager.UserCreated += OnUserCreated; - _userManager.UserPasswordChanged += OnUserPasswordChanged; - _userManager.UserDeleted += OnUserDeleted; - _userManager.UserPolicyUpdated += OnUserPolicyUpdated; - _userManager.UserLockedOut += OnUserLockedOut; + _userManager.OnUserCreated += OnUserCreated; + _userManager.OnUserPasswordChanged += OnUserPasswordChanged; + _userManager.OnUserDeleted += OnUserDeleted; + _userManager.OnUserLockedOut += OnUserLockedOut; _deviceManager.CameraImageUploaded += OnCameraImageUploaded; @@ -118,13 +117,13 @@ namespace Emby.Server.Implementations.Activity .ConfigureAwait(false); } - private async void OnUserLockedOut(object sender, GenericEventArgs e) + private async void OnUserLockedOut(object sender, GenericEventArgs e) { await CreateLogEntry(new ActivityLog( string.Format( CultureInfo.InvariantCulture, _localization.GetLocalizedString("UserLockedOutWithName"), - e.Argument.Name), + e.Argument.Username), NotificationType.UserLockedOut.ToString(), e.Argument.Id, DateTime.UtcNow, @@ -177,7 +176,7 @@ namespace Emby.Server.Implementations.Activity string.Format( CultureInfo.InvariantCulture, _localization.GetLocalizedString("UserStoppedPlayingItemWithValues"), - user.Name, + user.Username, GetItemName(item), e.DeviceName), GetPlaybackStoppedNotificationType(item.MediaType), @@ -214,7 +213,7 @@ namespace Emby.Server.Implementations.Activity string.Format( CultureInfo.InvariantCulture, _localization.GetLocalizedString("UserStartedPlayingItemWithValues"), - user.Name, + user.Username, GetItemName(item), e.DeviceName), GetPlaybackNotificationType(item.MediaType), @@ -338,13 +337,13 @@ namespace Emby.Server.Implementations.Activity }).ConfigureAwait(false); } - private async void OnUserPolicyUpdated(object sender, GenericEventArgs e) + private async void OnUserPolicyUpdated(object sender, GenericEventArgs e) { await CreateLogEntry(new ActivityLog( string.Format( CultureInfo.InvariantCulture, _localization.GetLocalizedString("UserPolicyUpdatedWithName"), - e.Argument.Name), + e.Argument.Username), "UserPolicyUpdated", e.Argument.Id, DateTime.UtcNow, @@ -352,13 +351,13 @@ namespace Emby.Server.Implementations.Activity .ConfigureAwait(false); } - private async void OnUserDeleted(object sender, GenericEventArgs e) + private async void OnUserDeleted(object sender, GenericEventArgs e) { await CreateLogEntry(new ActivityLog( string.Format( CultureInfo.InvariantCulture, _localization.GetLocalizedString("UserDeletedWithName"), - e.Argument.Name), + e.Argument.Username), "UserDeleted", Guid.Empty, DateTime.UtcNow, @@ -366,26 +365,26 @@ namespace Emby.Server.Implementations.Activity .ConfigureAwait(false); } - private async void OnUserPasswordChanged(object sender, GenericEventArgs e) + private async void OnUserPasswordChanged(object sender, GenericEventArgs e) { await CreateLogEntry(new ActivityLog( string.Format( CultureInfo.InvariantCulture, _localization.GetLocalizedString("UserPasswordChangedWithName"), - e.Argument.Name), + e.Argument.Username), "UserPasswordChanged", e.Argument.Id, DateTime.UtcNow, LogLevel.Trace)).ConfigureAwait(false); } - private async void OnUserCreated(object sender, GenericEventArgs e) + private async void OnUserCreated(object sender, GenericEventArgs e) { await CreateLogEntry(new ActivityLog( string.Format( CultureInfo.InvariantCulture, _localization.GetLocalizedString("UserCreatedWithName"), - e.Argument.Name), + e.Argument.Username), "UserCreated", e.Argument.Id, DateTime.UtcNow, @@ -562,11 +561,10 @@ namespace Emby.Server.Implementations.Activity _subManager.SubtitleDownloadFailure -= OnSubtitleDownloadFailure; - _userManager.UserCreated -= OnUserCreated; - _userManager.UserPasswordChanged -= OnUserPasswordChanged; - _userManager.UserDeleted -= OnUserDeleted; - _userManager.UserPolicyUpdated -= OnUserPolicyUpdated; - _userManager.UserLockedOut -= OnUserLockedOut; + _userManager.OnUserCreated -= OnUserCreated; + _userManager.OnUserPasswordChanged -= OnUserPasswordChanged; + _userManager.OnUserDeleted -= OnUserDeleted; + _userManager.OnUserLockedOut -= OnUserLockedOut; _deviceManager.CameraImageUploaded -= OnCameraImageUploaded; } diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index ddd9c7953..52b48d081 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -48,6 +48,7 @@ using Emby.Server.Implementations.TV; using Emby.Server.Implementations.Updates; using Jellyfin.Server.Implementations; using Jellyfin.Server.Implementations.Activity; +using Jellyfin.Server.Implementations.User; using MediaBrowser.Api; using MediaBrowser.Common; using MediaBrowser.Common.Configuration; @@ -595,17 +596,12 @@ namespace Emby.Server.Implementations serviceCollection.AddSingleton(); - serviceCollection.AddSingleton(); serviceCollection.AddSingleton(); - serviceCollection.AddSingleton(); - serviceCollection.AddSingleton(); serviceCollection.AddSingleton(); - serviceCollection.AddSingleton(); - // TODO: Refactor to eliminate the circular dependency here so that Lazy isn't required serviceCollection.AddTransient(provider => new Lazy(provider.GetRequiredService)); serviceCollection.AddSingleton(); @@ -700,17 +696,11 @@ namespace Emby.Server.Implementations _httpServer = Resolve(); _httpClient = Resolve(); - ((SqliteDisplayPreferencesRepository)Resolve()).Initialize(); ((AuthenticationRepository)Resolve()).Initialize(); - ((SqliteUserRepository)Resolve()).Initialize(); SetStaticProperties(); - var userManager = (UserManager)Resolve(); - userManager.Initialize(); - - var userDataRepo = (SqliteUserDataRepository)Resolve(); - ((SqliteItemRepository)Resolve()).Initialize(userDataRepo, userManager); + ((SqliteItemRepository)Resolve()).Initialize(); FindParts(); } @@ -793,7 +783,6 @@ namespace Emby.Server.Implementations BaseItem.ProviderManager = Resolve(); BaseItem.LocalizationManager = Resolve(); BaseItem.ItemRepository = Resolve(); - User.UserManager = Resolve(); BaseItem.FileSystem = _fileSystemManager; BaseItem.UserDataManager = Resolve(); BaseItem.ChannelManager = Resolve(); diff --git a/Emby.Server.Implementations/Channels/ChannelManager.cs b/Emby.Server.Implementations/Channels/ChannelManager.cs index 138832fb8..cb320dcb1 100644 --- a/Emby.Server.Implementations/Channels/ChannelManager.cs +++ b/Emby.Server.Implementations/Channels/ChannelManager.cs @@ -46,7 +46,7 @@ namespace Emby.Server.Implementations.Channels new ConcurrentDictionary>>(); private readonly SemaphoreSlim _resourcePool = new SemaphoreSlim(1, 1); - + /// /// Initializes a new instance of the class. /// @@ -791,8 +791,9 @@ namespace Emby.Server.Implementations.Channels return result; } - private async Task GetChannelItems(IChannel channel, - User user, + private async Task GetChannelItems( + IChannel channel, + Jellyfin.Data.Entities.User user, string externalFolderId, ChannelItemSortField? sortField, bool sortDescending, diff --git a/Emby.Server.Implementations/Collections/CollectionManager.cs b/Emby.Server.Implementations/Collections/CollectionManager.cs index 7c518d483..61963b633 100644 --- a/Emby.Server.Implementations/Collections/CollectionManager.cs +++ b/Emby.Server.Implementations/Collections/CollectionManager.cs @@ -121,7 +121,7 @@ namespace Emby.Server.Implementations.Collections return EnsureLibraryFolder(GetCollectionsFolderPath(), createIfNeeded); } - private IEnumerable GetCollections(User user) + private IEnumerable GetCollections(Jellyfin.Data.Entities.User user) { var folder = GetCollectionsFolder(false).Result; @@ -325,7 +325,7 @@ namespace Emby.Server.Implementations.Collections } /// - public IEnumerable CollapseItemsWithinBoxSets(IEnumerable items, User user) + public IEnumerable CollapseItemsWithinBoxSets(IEnumerable items, Jellyfin.Data.Entities.User user) { var results = new Dictionary(); diff --git a/Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs b/Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs deleted file mode 100644 index d474f1c6b..000000000 --- a/Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs +++ /dev/null @@ -1,225 +0,0 @@ -#pragma warning disable CS1591 - -using System; -using System.Collections.Generic; -using System.Globalization; -using System.IO; -using System.Text.Json; -using System.Threading; -using MediaBrowser.Common.Configuration; -using MediaBrowser.Common.Extensions; -using MediaBrowser.Common.Json; -using MediaBrowser.Controller.Persistence; -using MediaBrowser.Model.Entities; -using MediaBrowser.Model.IO; -using Microsoft.Extensions.Logging; -using SQLitePCL.pretty; - -namespace Emby.Server.Implementations.Data -{ - /// - /// Class SQLiteDisplayPreferencesRepository. - /// - public class SqliteDisplayPreferencesRepository : BaseSqliteRepository, IDisplayPreferencesRepository - { - private readonly IFileSystem _fileSystem; - - private readonly JsonSerializerOptions _jsonOptions; - - public SqliteDisplayPreferencesRepository(ILogger logger, IApplicationPaths appPaths, IFileSystem fileSystem) - : base(logger) - { - _fileSystem = fileSystem; - - _jsonOptions = JsonDefaults.GetOptions(); - - DbFilePath = Path.Combine(appPaths.DataPath, "displaypreferences.db"); - } - - /// - /// Gets the name of the repository. - /// - /// The name. - public string Name => "SQLite"; - - public void Initialize() - { - try - { - InitializeInternal(); - } - catch (Exception ex) - { - Logger.LogError(ex, "Error loading database file. Will reset and retry."); - - _fileSystem.DeleteFile(DbFilePath); - - InitializeInternal(); - } - } - - /// - /// Opens the connection to the database - /// - /// Task. - private void InitializeInternal() - { - string[] queries = - { - "create table if not exists userdisplaypreferences (id GUID NOT NULL, userId GUID NOT NULL, client text NOT NULL, data BLOB NOT NULL)", - "create unique index if not exists userdisplaypreferencesindex on userdisplaypreferences (id, userId, client)" - }; - - using (var connection = GetConnection()) - { - connection.RunQueries(queries); - } - } - - /// - /// Save the display preferences associated with an item in the repo - /// - /// The display preferences. - /// The user id. - /// The client. - /// The cancellation token. - /// item - public void SaveDisplayPreferences(DisplayPreferences displayPreferences, Guid userId, string client, CancellationToken cancellationToken) - { - if (displayPreferences == null) - { - throw new ArgumentNullException(nameof(displayPreferences)); - } - - if (string.IsNullOrEmpty(displayPreferences.Id)) - { - throw new ArgumentException("Display preferences has an invalid Id", nameof(displayPreferences)); - } - - cancellationToken.ThrowIfCancellationRequested(); - - using (var connection = GetConnection()) - { - connection.RunInTransaction( - db => SaveDisplayPreferences(displayPreferences, userId, client, db), - TransactionMode); - } - } - - private void SaveDisplayPreferences(DisplayPreferences displayPreferences, Guid userId, string client, IDatabaseConnection connection) - { - var serialized = JsonSerializer.SerializeToUtf8Bytes(displayPreferences, _jsonOptions); - - using (var statement = connection.PrepareStatement("replace into userdisplaypreferences (id, userid, client, data) values (@id, @userId, @client, @data)")) - { - statement.TryBind("@id", new Guid(displayPreferences.Id).ToByteArray()); - statement.TryBind("@userId", userId.ToByteArray()); - statement.TryBind("@client", client); - statement.TryBind("@data", serialized); - - statement.MoveNext(); - } - } - - /// - /// Save all display preferences associated with a user in the repo - /// - /// The display preferences. - /// The user id. - /// The cancellation token. - /// item - public void SaveAllDisplayPreferences(IEnumerable displayPreferences, Guid userId, CancellationToken cancellationToken) - { - if (displayPreferences == null) - { - throw new ArgumentNullException(nameof(displayPreferences)); - } - - cancellationToken.ThrowIfCancellationRequested(); - - using (var connection = GetConnection()) - { - connection.RunInTransaction( - db => - { - foreach (var displayPreference in displayPreferences) - { - SaveDisplayPreferences(displayPreference, userId, displayPreference.Client, db); - } - }, - TransactionMode); - } - } - - /// - /// Gets the display preferences. - /// - /// The display preferences id. - /// The user id. - /// The client. - /// Task{DisplayPreferences}. - /// item - public DisplayPreferences GetDisplayPreferences(string displayPreferencesId, Guid userId, string client) - { - if (string.IsNullOrEmpty(displayPreferencesId)) - { - throw new ArgumentNullException(nameof(displayPreferencesId)); - } - - var guidId = displayPreferencesId.GetMD5(); - - using (var connection = GetConnection(true)) - { - using (var statement = connection.PrepareStatement("select data from userdisplaypreferences where id = @id and userId=@userId and client=@client")) - { - statement.TryBind("@id", guidId.ToByteArray()); - statement.TryBind("@userId", userId.ToByteArray()); - statement.TryBind("@client", client); - - foreach (var row in statement.ExecuteQuery()) - { - return Get(row); - } - } - } - - return new DisplayPreferences - { - Id = guidId.ToString("N", CultureInfo.InvariantCulture) - }; - } - - /// - /// Gets all display preferences for the given user. - /// - /// The user id. - /// Task{DisplayPreferences}. - /// item - public IEnumerable GetAllDisplayPreferences(Guid userId) - { - var list = new List(); - - using (var connection = GetConnection(true)) - using (var statement = connection.PrepareStatement("select data from userdisplaypreferences where userId=@userId")) - { - statement.TryBind("@userId", userId.ToByteArray()); - - foreach (var row in statement.ExecuteQuery()) - { - list.Add(Get(row)); - } - } - - return list; - } - - private DisplayPreferences Get(IReadOnlyList row) - => JsonSerializer.Deserialize(row[0].ToBlob(), _jsonOptions); - - public void SaveDisplayPreferences(DisplayPreferences displayPreferences, string userId, string client, CancellationToken cancellationToken) - => SaveDisplayPreferences(displayPreferences, new Guid(userId), client, cancellationToken); - - public DisplayPreferences GetDisplayPreferences(string displayPreferencesId, string userId, string client) - => GetDisplayPreferences(displayPreferencesId, new Guid(userId), client); - } -} diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index ca5cd6fdd..74b8ffc18 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -102,7 +102,7 @@ namespace Emby.Server.Implementations.Data /// /// Opens the connection to the database /// - public void Initialize(SqliteUserDataRepository userDataRepo, IUserManager userManager) + public void Initialize() { const string CreateMediaStreamsTableCommand = "create table if not exists mediastreams (ItemId GUID, StreamIndex INT, StreamType TEXT, Codec TEXT, Language TEXT, ChannelLayout TEXT, Profile TEXT, AspectRatio TEXT, Path TEXT, IsInterlaced BIT, BitRate INT NULL, Channels INT NULL, SampleRate INT NULL, IsDefault BIT, IsForced BIT, IsExternal BIT, Height INT NULL, Width INT NULL, AverageFrameRate FLOAT NULL, RealFrameRate FLOAT NULL, Level FLOAT NULL, PixelFormat TEXT, BitDepth INT NULL, IsAnamorphic BIT NULL, RefFrames INT NULL, CodecTag TEXT NULL, Comment TEXT NULL, NalLengthSize TEXT NULL, IsAvc BIT NULL, Title TEXT NULL, TimeBase TEXT NULL, CodecTimeBase TEXT NULL, ColorPrimaries TEXT NULL, ColorSpace TEXT NULL, ColorTransfer TEXT NULL, PRIMARY KEY (ItemId, StreamIndex))"; @@ -324,8 +324,6 @@ namespace Emby.Server.Implementations.Data connection.RunQueries(postQueries); } - - userDataRepo.Initialize(userManager, WriteLock, WriteConnection); } private static readonly string[] _retriveItemColumns = diff --git a/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs b/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs deleted file mode 100644 index 22955850a..000000000 --- a/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs +++ /dev/null @@ -1,379 +0,0 @@ -#pragma warning disable CS1591 - -using System; -using System.Collections.Generic; -using System.IO; -using System.Threading; -using MediaBrowser.Common.Configuration; -using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Library; -using MediaBrowser.Controller.Persistence; -using Microsoft.Extensions.Logging; -using SQLitePCL.pretty; - -namespace Emby.Server.Implementations.Data -{ - public class SqliteUserDataRepository : BaseSqliteRepository, IUserDataRepository - { - public SqliteUserDataRepository( - ILogger logger, - IApplicationPaths appPaths) - : base(logger) - { - DbFilePath = Path.Combine(appPaths.DataPath, "library.db"); - } - - /// - public string Name => "SQLite"; - - /// - /// Opens the connection to the database. - /// - public void Initialize(IUserManager userManager, SemaphoreSlim dbLock, SQLiteDatabaseConnection dbConnection) - { - WriteLock.Dispose(); - WriteLock = dbLock; - WriteConnection?.Dispose(); - WriteConnection = dbConnection; - - using (var connection = GetConnection()) - { - var userDatasTableExists = TableExists(connection, "UserDatas"); - var userDataTableExists = TableExists(connection, "userdata"); - - var users = userDatasTableExists ? null : userManager.Users; - - connection.RunInTransaction(db => - { - db.ExecuteAll(string.Join(";", new[] { - - "create table if not exists UserDatas (key nvarchar not null, userId INT not null, rating float null, played bit not null, playCount int not null, isFavorite bit not null, playbackPositionTicks bigint not null, lastPlayedDate datetime null, AudioStreamIndex INT, SubtitleStreamIndex INT)", - - "drop index if exists idx_userdata", - "drop index if exists idx_userdata1", - "drop index if exists idx_userdata2", - "drop index if exists userdataindex1", - "drop index if exists userdataindex", - "drop index if exists userdataindex3", - "drop index if exists userdataindex4", - "create unique index if not exists UserDatasIndex1 on UserDatas (key, userId)", - "create index if not exists UserDatasIndex2 on UserDatas (key, userId, played)", - "create index if not exists UserDatasIndex3 on UserDatas (key, userId, playbackPositionTicks)", - "create index if not exists UserDatasIndex4 on UserDatas (key, userId, isFavorite)" - })); - - if (userDataTableExists) - { - var existingColumnNames = GetColumnNames(db, "userdata"); - - AddColumn(db, "userdata", "InternalUserId", "int", existingColumnNames); - AddColumn(db, "userdata", "AudioStreamIndex", "int", existingColumnNames); - AddColumn(db, "userdata", "SubtitleStreamIndex", "int", existingColumnNames); - - if (!userDatasTableExists) - { - ImportUserIds(db, users); - - db.ExecuteAll("INSERT INTO UserDatas (key, userId, rating, played, playCount, isFavorite, playbackPositionTicks, lastPlayedDate, AudioStreamIndex, SubtitleStreamIndex) SELECT key, InternalUserId, rating, played, playCount, isFavorite, playbackPositionTicks, lastPlayedDate, AudioStreamIndex, SubtitleStreamIndex from userdata where InternalUserId not null"); - } - } - }, TransactionMode); - } - } - - private void ImportUserIds(IDatabaseConnection db, IEnumerable users) - { - var userIdsWithUserData = GetAllUserIdsWithUserData(db); - - using (var statement = db.PrepareStatement("update userdata set InternalUserId=@InternalUserId where UserId=@UserId")) - { - foreach (var user in users) - { - if (!userIdsWithUserData.Contains(user.Id)) - { - continue; - } - - statement.TryBind("@UserId", user.Id.ToByteArray()); - statement.TryBind("@InternalUserId", user.InternalId); - - statement.MoveNext(); - statement.Reset(); - } - } - } - - private List GetAllUserIdsWithUserData(IDatabaseConnection db) - { - var list = new List(); - - using (var statement = PrepareStatement(db, "select DISTINCT UserId from UserData where UserId not null")) - { - foreach (var row in statement.ExecuteQuery()) - { - try - { - list.Add(row[0].ReadGuidFromBlob()); - } - catch (Exception ex) - { - Logger.LogError(ex, "Error while getting user"); - } - } - } - - return list; - } - - /// - /// Saves the user data. - /// - public void SaveUserData(long internalUserId, string key, UserItemData userData, CancellationToken cancellationToken) - { - if (userData == null) - { - throw new ArgumentNullException(nameof(userData)); - } - if (internalUserId <= 0) - { - throw new ArgumentNullException(nameof(internalUserId)); - } - if (string.IsNullOrEmpty(key)) - { - throw new ArgumentNullException(nameof(key)); - } - - PersistUserData(internalUserId, key, userData, cancellationToken); - } - - public void SaveAllUserData(long internalUserId, UserItemData[] userData, CancellationToken cancellationToken) - { - if (userData == null) - { - throw new ArgumentNullException(nameof(userData)); - } - if (internalUserId <= 0) - { - throw new ArgumentNullException(nameof(internalUserId)); - } - - PersistAllUserData(internalUserId, userData, cancellationToken); - } - - /// - /// Persists the user data. - /// - /// The user id. - /// The key. - /// The user data. - /// The cancellation token. - /// Task. - public void PersistUserData(long internalUserId, string key, UserItemData userData, CancellationToken cancellationToken) - { - cancellationToken.ThrowIfCancellationRequested(); - - using (var connection = GetConnection()) - { - connection.RunInTransaction(db => - { - SaveUserData(db, internalUserId, key, userData); - }, TransactionMode); - } - } - - private static void SaveUserData(IDatabaseConnection db, long internalUserId, string key, UserItemData userData) - { - using (var statement = db.PrepareStatement("replace into UserDatas (key, userId, rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate,AudioStreamIndex,SubtitleStreamIndex) values (@key, @userId, @rating,@played,@playCount,@isFavorite,@playbackPositionTicks,@lastPlayedDate,@AudioStreamIndex,@SubtitleStreamIndex)")) - { - statement.TryBind("@userId", internalUserId); - statement.TryBind("@key", key); - - if (userData.Rating.HasValue) - { - statement.TryBind("@rating", userData.Rating.Value); - } - else - { - statement.TryBindNull("@rating"); - } - - statement.TryBind("@played", userData.Played); - statement.TryBind("@playCount", userData.PlayCount); - statement.TryBind("@isFavorite", userData.IsFavorite); - statement.TryBind("@playbackPositionTicks", userData.PlaybackPositionTicks); - - if (userData.LastPlayedDate.HasValue) - { - statement.TryBind("@lastPlayedDate", userData.LastPlayedDate.Value.ToDateTimeParamValue()); - } - else - { - statement.TryBindNull("@lastPlayedDate"); - } - - if (userData.AudioStreamIndex.HasValue) - { - statement.TryBind("@AudioStreamIndex", userData.AudioStreamIndex.Value); - } - else - { - statement.TryBindNull("@AudioStreamIndex"); - } - - if (userData.SubtitleStreamIndex.HasValue) - { - statement.TryBind("@SubtitleStreamIndex", userData.SubtitleStreamIndex.Value); - } - else - { - statement.TryBindNull("@SubtitleStreamIndex"); - } - - statement.MoveNext(); - } - } - - /// - /// Persist all user data for the specified user - /// - private void PersistAllUserData(long internalUserId, UserItemData[] userDataList, CancellationToken cancellationToken) - { - cancellationToken.ThrowIfCancellationRequested(); - - using (var connection = GetConnection()) - { - connection.RunInTransaction(db => - { - foreach (var userItemData in userDataList) - { - SaveUserData(db, internalUserId, userItemData.Key, userItemData); - } - }, TransactionMode); - } - } - - /// - /// Gets the user data. - /// - /// The user id. - /// The key. - /// Task{UserItemData}. - /// - /// userId - /// or - /// key - /// - public UserItemData GetUserData(long internalUserId, string key) - { - if (internalUserId <= 0) - { - throw new ArgumentNullException(nameof(internalUserId)); - } - - if (string.IsNullOrEmpty(key)) - { - throw new ArgumentNullException(nameof(key)); - } - - using (var connection = GetConnection(true)) - { - using (var statement = connection.PrepareStatement("select key,userid,rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate,AudioStreamIndex,SubtitleStreamIndex from UserDatas where key =@Key and userId=@UserId")) - { - statement.TryBind("@UserId", internalUserId); - statement.TryBind("@Key", key); - - foreach (var row in statement.ExecuteQuery()) - { - return ReadRow(row); - } - } - - return null; - } - } - - public UserItemData GetUserData(long internalUserId, List keys) - { - if (keys == null) - { - throw new ArgumentNullException(nameof(keys)); - } - - if (keys.Count == 0) - { - return null; - } - - return GetUserData(internalUserId, keys[0]); - } - - /// - /// Return all user-data associated with the given user - /// - /// - /// - public List GetAllUserData(long internalUserId) - { - if (internalUserId <= 0) - { - throw new ArgumentNullException(nameof(internalUserId)); - } - - var list = new List(); - - using (var connection = GetConnection()) - { - using (var statement = connection.PrepareStatement("select key,userid,rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate,AudioStreamIndex,SubtitleStreamIndex from UserDatas where userId=@UserId")) - { - statement.TryBind("@UserId", internalUserId); - - foreach (var row in statement.ExecuteQuery()) - { - list.Add(ReadRow(row)); - } - } - } - - return list; - } - - /// - /// Read a row from the specified reader into the provided userData object - /// - /// - private UserItemData ReadRow(IReadOnlyList reader) - { - var userData = new UserItemData(); - - userData.Key = reader[0].ToString(); - //userData.UserId = reader[1].ReadGuidFromBlob(); - - if (reader[2].SQLiteType != SQLiteType.Null) - { - userData.Rating = reader[2].ToDouble(); - } - - userData.Played = reader[3].ToBool(); - userData.PlayCount = reader[4].ToInt(); - userData.IsFavorite = reader[5].ToBool(); - userData.PlaybackPositionTicks = reader[6].ToInt64(); - - if (reader[7].SQLiteType != SQLiteType.Null) - { - userData.LastPlayedDate = reader[7].TryReadDateTime(); - } - - if (reader[8].SQLiteType != SQLiteType.Null) - { - userData.AudioStreamIndex = reader[8].ToInt(); - } - - if (reader[9].SQLiteType != SQLiteType.Null) - { - userData.SubtitleStreamIndex = reader[9].ToInt(); - } - - return userData; - } - } -} diff --git a/Emby.Server.Implementations/Data/SqliteUserRepository.cs b/Emby.Server.Implementations/Data/SqliteUserRepository.cs deleted file mode 100644 index 0c3f26974..000000000 --- a/Emby.Server.Implementations/Data/SqliteUserRepository.cs +++ /dev/null @@ -1,240 +0,0 @@ -#pragma warning disable CS1591 - -using System; -using System.Collections.Generic; -using System.IO; -using System.Text.Json; -using MediaBrowser.Common.Json; -using MediaBrowser.Controller; -using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Persistence; -using Microsoft.Extensions.Logging; -using SQLitePCL.pretty; - -namespace Emby.Server.Implementations.Data -{ - /// - /// Class SQLiteUserRepository - /// - public class SqliteUserRepository : BaseSqliteRepository, IUserRepository - { - private readonly JsonSerializerOptions _jsonOptions; - - public SqliteUserRepository( - ILogger logger, - IServerApplicationPaths appPaths) - : base(logger) - { - _jsonOptions = JsonDefaults.GetOptions(); - - DbFilePath = Path.Combine(appPaths.DataPath, "users.db"); - } - - /// - /// Gets the name of the repository - /// - /// The name. - public string Name => "SQLite"; - - /// - /// Opens the connection to the database. - /// - public void Initialize() - { - using (var connection = GetConnection()) - { - var localUsersTableExists = TableExists(connection, "LocalUsersv2"); - - connection.RunQueries(new[] { - "create table if not exists LocalUsersv2 (Id INTEGER PRIMARY KEY, guid GUID NOT NULL, data BLOB NOT NULL)", - "drop index if exists idx_users" - }); - - if (!localUsersTableExists && TableExists(connection, "Users")) - { - TryMigrateToLocalUsersTable(connection); - } - - RemoveEmptyPasswordHashes(connection); - } - } - - private void TryMigrateToLocalUsersTable(ManagedConnection connection) - { - try - { - connection.RunQueries(new[] - { - "INSERT INTO LocalUsersv2 (guid, data) SELECT guid,data from users" - }); - } - catch (Exception ex) - { - Logger.LogError(ex, "Error migrating users database"); - } - } - - private void RemoveEmptyPasswordHashes(ManagedConnection connection) - { - foreach (var user in RetrieveAllUsers(connection)) - { - // If the user password is the sha1 hash of the empty string, remove it - if (!string.Equals(user.Password, "DA39A3EE5E6B4B0D3255BFEF95601890AFD80709", StringComparison.Ordinal) - && !string.Equals(user.Password, "$SHA1$DA39A3EE5E6B4B0D3255BFEF95601890AFD80709", StringComparison.Ordinal)) - { - continue; - } - - user.Password = null; - var serialized = JsonSerializer.SerializeToUtf8Bytes(user, _jsonOptions); - - connection.RunInTransaction(db => - { - using (var statement = db.PrepareStatement("update LocalUsersv2 set data=@data where Id=@InternalId")) - { - statement.TryBind("@InternalId", user.InternalId); - statement.TryBind("@data", serialized); - statement.MoveNext(); - } - }, TransactionMode); - } - } - - /// - /// Save a user in the repo - /// - public void CreateUser(User user) - { - if (user == null) - { - throw new ArgumentNullException(nameof(user)); - } - - var serialized = JsonSerializer.SerializeToUtf8Bytes(user, _jsonOptions); - - using (var connection = GetConnection()) - { - connection.RunInTransaction(db => - { - using (var statement = db.PrepareStatement("insert into LocalUsersv2 (guid, data) values (@guid, @data)")) - { - statement.TryBind("@guid", user.Id.ToByteArray()); - statement.TryBind("@data", serialized); - - statement.MoveNext(); - } - - var createdUser = GetUser(user.Id, connection); - - if (createdUser == null) - { - throw new ApplicationException("created user should never be null"); - } - - user.InternalId = createdUser.InternalId; - - }, TransactionMode); - } - } - - public void UpdateUser(User user) - { - if (user == null) - { - throw new ArgumentNullException(nameof(user)); - } - - var serialized = JsonSerializer.SerializeToUtf8Bytes(user, _jsonOptions); - - using (var connection = GetConnection()) - { - connection.RunInTransaction(db => - { - using (var statement = db.PrepareStatement("update LocalUsersv2 set data=@data where Id=@InternalId")) - { - statement.TryBind("@InternalId", user.InternalId); - statement.TryBind("@data", serialized); - statement.MoveNext(); - } - - }, TransactionMode); - } - } - - private User GetUser(Guid guid, ManagedConnection connection) - { - using (var statement = connection.PrepareStatement("select id,guid,data from LocalUsersv2 where guid=@guid")) - { - statement.TryBind("@guid", guid); - - foreach (var row in statement.ExecuteQuery()) - { - return GetUser(row); - } - } - - return null; - } - - private User GetUser(IReadOnlyList row) - { - var id = row[0].ToInt64(); - var guid = row[1].ReadGuidFromBlob(); - - var user = JsonSerializer.Deserialize(row[2].ToBlob(), _jsonOptions); - user.InternalId = id; - user.Id = guid; - return user; - } - - /// - /// Retrieve all users from the database - /// - /// IEnumerable{User}. - public List RetrieveAllUsers() - { - using (var connection = GetConnection(true)) - { - return new List(RetrieveAllUsers(connection)); - } - } - - /// - /// Retrieve all users from the database - /// - /// IEnumerable{User}. - private IEnumerable RetrieveAllUsers(ManagedConnection connection) - { - foreach (var row in connection.Query("select id,guid,data from LocalUsersv2")) - { - yield return GetUser(row); - } - } - - /// - /// Deletes the user. - /// - /// The user. - /// Task. - /// user - public void DeleteUser(User user) - { - if (user == null) - { - throw new ArgumentNullException(nameof(user)); - } - - using (var connection = GetConnection()) - { - connection.RunInTransaction(db => - { - using (var statement = db.PrepareStatement("delete from LocalUsersv2 where Id=@id")) - { - statement.TryBind("@id", user.InternalId); - statement.MoveNext(); - } - }, TransactionMode); - } - } - } -} diff --git a/Emby.Server.Implementations/Devices/DeviceManager.cs b/Emby.Server.Implementations/Devices/DeviceManager.cs index 579cb895e..d6bce93f8 100644 --- a/Emby.Server.Implementations/Devices/DeviceManager.cs +++ b/Emby.Server.Implementations/Devices/DeviceManager.cs @@ -6,6 +6,7 @@ using System.Globalization; using System.IO; using System.Linq; using System.Threading.Tasks; +using Jellyfin.Data.Enums; using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.Configuration; @@ -360,7 +361,7 @@ namespace Emby.Server.Implementations.Devices private string DefaultCameraUploadsPath => Path.Combine(_config.CommonApplicationPaths.DataPath, "camerauploads"); - public bool CanAccessDevice(User user, string deviceId) + public bool CanAccessDevice(Jellyfin.Data.Entities.User user, string deviceId) { if (user == null) { @@ -371,7 +372,13 @@ namespace Emby.Server.Implementations.Devices throw new ArgumentNullException(nameof(deviceId)); } - if (!CanAccessDevice(user.Policy, deviceId)) + if (user.HasPermission(PermissionKind.EnableAllDevices) + || user.HasPermission(PermissionKind.IsAdministrator)) + { + return true; + } + + if (!user.GetPreference(PreferenceKind.EnabledDevices).Contains(deviceId, StringComparer.OrdinalIgnoreCase)) { var capabilities = GetCapabilities(deviceId); @@ -383,21 +390,6 @@ namespace Emby.Server.Implementations.Devices return true; } - - private static bool CanAccessDevice(UserPolicy policy, string id) - { - if (policy.EnableAllDevices) - { - return true; - } - - if (policy.IsAdministrator) - { - return true; - } - - return policy.EnabledDevices.Contains(id, StringComparer.OrdinalIgnoreCase); - } } public class DeviceManagerEntryPoint : IServerEntryPoint diff --git a/Emby.Server.Implementations/Dto/DtoService.cs b/Emby.Server.Implementations/Dto/DtoService.cs index c4b65d265..da40bca4c 100644 --- a/Emby.Server.Implementations/Dto/DtoService.cs +++ b/Emby.Server.Implementations/Dto/DtoService.cs @@ -6,6 +6,7 @@ using System.Globalization; using System.IO; using System.Linq; using System.Threading.Tasks; +using Jellyfin.Data.Enums; using MediaBrowser.Common; using MediaBrowser.Controller.Channels; using MediaBrowser.Controller.Drawing; @@ -74,7 +75,7 @@ namespace Emby.Server.Implementations.Dto /// The owner. /// Task{DtoBaseItem}. /// item - public BaseItemDto GetBaseItemDto(BaseItem item, ItemFields[] fields, User user = null, BaseItem owner = null) + public BaseItemDto GetBaseItemDto(BaseItem item, ItemFields[] fields, Jellyfin.Data.Entities.User user = null, BaseItem owner = null) { var options = new DtoOptions { @@ -85,7 +86,7 @@ namespace Emby.Server.Implementations.Dto } /// - public IReadOnlyList GetBaseItemDtos(IReadOnlyList items, DtoOptions options, User user = null, BaseItem owner = null) + public IReadOnlyList GetBaseItemDtos(IReadOnlyList items, DtoOptions options, Jellyfin.Data.Entities.User user = null, BaseItem owner = null) { var returnItems = new BaseItemDto[items.Count]; var programTuples = new List<(BaseItem, BaseItemDto)>(); @@ -138,7 +139,7 @@ namespace Emby.Server.Implementations.Dto return returnItems; } - public BaseItemDto GetBaseItemDto(BaseItem item, DtoOptions options, User user = null, BaseItem owner = null) + public BaseItemDto GetBaseItemDto(BaseItem item, DtoOptions options, Jellyfin.Data.Entities.User user = null, BaseItem owner = null) { var dto = GetBaseItemDtoInternal(item, options, user, owner); if (item is LiveTvChannel tvChannel) @@ -172,7 +173,7 @@ namespace Emby.Server.Implementations.Dto return dto; } - private static IList GetTaggedItems(IItemByName byName, User user, DtoOptions options) + private static IList GetTaggedItems(IItemByName byName, Jellyfin.Data.Entities.User user, DtoOptions options) { return byName.GetTaggedItems( new InternalItemsQuery(user) @@ -182,7 +183,7 @@ namespace Emby.Server.Implementations.Dto }); } - private BaseItemDto GetBaseItemDtoInternal(BaseItem item, DtoOptions options, User user = null, BaseItem owner = null) + private BaseItemDto GetBaseItemDtoInternal(BaseItem item, DtoOptions options, Jellyfin.Data.Entities.User user = null, BaseItem owner = null) { var dto = new BaseItemDto { @@ -315,7 +316,7 @@ namespace Emby.Server.Implementations.Dto } } - public BaseItemDto GetItemByNameDto(BaseItem item, DtoOptions options, List taggedItems, User user = null) + public BaseItemDto GetItemByNameDto(BaseItem item, DtoOptions options, List taggedItems, Jellyfin.Data.Entities.User user = null) { var dto = GetBaseItemDtoInternal(item, options, user); @@ -327,7 +328,7 @@ namespace Emby.Server.Implementations.Dto return dto; } - private static void SetItemByNameInfo(BaseItem item, BaseItemDto dto, IList taggedItems, User user = null) + private static void SetItemByNameInfo(BaseItem item, BaseItemDto dto, IList taggedItems, Jellyfin.Data.Entities.User user = null) { if (item is MusicArtist) { @@ -363,7 +364,7 @@ namespace Emby.Server.Implementations.Dto /// /// Attaches the user specific info. /// - private void AttachUserSpecificInfo(BaseItemDto dto, BaseItem item, User user, DtoOptions options) + private void AttachUserSpecificInfo(BaseItemDto dto, BaseItem item, Jellyfin.Data.Entities.User user, DtoOptions options) { if (item.IsFolder) { @@ -384,7 +385,7 @@ namespace Emby.Server.Implementations.Dto if (options.ContainsField(ItemFields.ChildCount)) { - dto.ChildCount = dto.ChildCount ?? GetChildCount(folder, user); + dto.ChildCount ??= GetChildCount(folder, user); } } @@ -414,7 +415,7 @@ namespace Emby.Server.Implementations.Dto if (options.ContainsField(ItemFields.BasicSyncInfo)) { - var userCanSync = user != null && user.Policy.EnableContentDownloading; + var userCanSync = user != null && user.HasPermission(PermissionKind.EnableContentDownloading); if (userCanSync && item.SupportsExternalTransfer) { dto.SupportsSync = true; @@ -422,7 +423,7 @@ namespace Emby.Server.Implementations.Dto } } - private static int GetChildCount(Folder folder, User user) + private static int GetChildCount(Folder folder, Jellyfin.Data.Entities.User user) { // Right now this is too slow to calculate for top level folders on a per-user basis // Just return something so that apps that are expecting a value won't think the folders are empty diff --git a/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs b/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs index 8e3236407..7ece52cad 100644 --- a/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs +++ b/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs @@ -446,7 +446,7 @@ namespace Emby.Server.Implementations.EntryPoints /// The user. /// if set to true [include if not found]. /// IEnumerable{``0}. - private IEnumerable TranslatePhysicalItemToUserLibrary(T item, User user, bool includeIfNotFound = false) + private IEnumerable TranslatePhysicalItemToUserLibrary(T item, Jellyfin.Data.Entities.User user, bool includeIfNotFound = false) where T : BaseItem { // If the physical root changed, return the user root diff --git a/Emby.Server.Implementations/EntryPoints/RecordingNotifier.cs b/Emby.Server.Implementations/EntryPoints/RecordingNotifier.cs index 41c0c5115..75dde5598 100644 --- a/Emby.Server.Implementations/EntryPoints/RecordingNotifier.cs +++ b/Emby.Server.Implementations/EntryPoints/RecordingNotifier.cs @@ -4,6 +4,7 @@ using System; using System.Linq; using System.Threading; using System.Threading.Tasks; +using Jellyfin.Data.Enums; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.LiveTv; using MediaBrowser.Controller.Plugins; @@ -64,7 +65,7 @@ namespace Emby.Server.Implementations.EntryPoints private async void SendMessage(string name, TimerEventInfo info) { - var users = _userManager.Users.Where(i => i.Policy.EnableLiveTvAccess).Select(i => i.Id).ToList(); + var users = _userManager.Users.Where(i => i.HasPermission(PermissionKind.EnableLiveTvAccess)).Select(i => i.Id).ToList(); try { diff --git a/Emby.Server.Implementations/EntryPoints/RefreshUsersMetadata.cs b/Emby.Server.Implementations/EntryPoints/RefreshUsersMetadata.cs deleted file mode 100644 index 54f4b67e6..000000000 --- a/Emby.Server.Implementations/EntryPoints/RefreshUsersMetadata.cs +++ /dev/null @@ -1,77 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; -using MediaBrowser.Controller.Library; -using MediaBrowser.Controller.Providers; -using MediaBrowser.Model.IO; -using MediaBrowser.Model.Tasks; - -namespace Emby.Server.Implementations.EntryPoints -{ - /// - /// Class RefreshUsersMetadata. - /// - public class RefreshUsersMetadata : IScheduledTask, IConfigurableScheduledTask - { - /// - /// The user manager. - /// - private readonly IUserManager _userManager; - private readonly IFileSystem _fileSystem; - - /// - /// Initializes a new instance of the class. - /// - public RefreshUsersMetadata(IUserManager userManager, IFileSystem fileSystem) - { - _userManager = userManager; - _fileSystem = fileSystem; - } - - /// - public string Name => "Refresh Users"; - - /// - public string Key => "RefreshUsers"; - - /// - public string Description => "Refresh user infos"; - - /// - public string Category => "Library"; - - /// - public bool IsHidden => true; - - /// - public bool IsEnabled => true; - - /// - public bool IsLogged => true; - - /// - public async Task Execute(CancellationToken cancellationToken, IProgress progress) - { - foreach (var user in _userManager.Users) - { - cancellationToken.ThrowIfCancellationRequested(); - - await user.RefreshMetadata(new MetadataRefreshOptions(new DirectoryService(_fileSystem)), cancellationToken).ConfigureAwait(false); - } - } - - /// - public IEnumerable GetDefaultTriggers() - { - return new[] - { - new TaskTriggerInfo - { - IntervalTicks = TimeSpan.FromDays(1).Ticks, - Type = TaskTriggerInfo.TriggerInterval - } - }; - } - } -} diff --git a/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs b/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs index e1dbb663b..436d723f0 100644 --- a/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs +++ b/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs @@ -3,10 +3,10 @@ using System.Collections.Generic; using System.Globalization; using System.Threading; using System.Threading.Tasks; +using Jellyfin.Data.Entities; using MediaBrowser.Common.Plugins; using MediaBrowser.Common.Updates; using MediaBrowser.Controller; -using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Plugins; using MediaBrowser.Controller.Session; @@ -67,10 +67,8 @@ namespace Emby.Server.Implementations.EntryPoints /// public Task RunAsync() { - _userManager.UserDeleted += OnUserDeleted; - _userManager.UserUpdated += OnUserUpdated; - _userManager.UserPolicyUpdated += OnUserPolicyUpdated; - _userManager.UserConfigurationUpdated += OnUserConfigurationUpdated; + _userManager.OnUserDeleted += OnUserDeleted; + _userManager.OnUserUpdated += OnUserUpdated; _appHost.HasPendingRestartChanged += OnHasPendingRestartChanged; @@ -152,20 +150,6 @@ namespace Emby.Server.Implementations.EntryPoints SendMessageToUserSession(e.Argument, "UserDeleted", e.Argument.Id.ToString("N", CultureInfo.InvariantCulture)); } - private void OnUserPolicyUpdated(object sender, GenericEventArgs e) - { - var dto = _userManager.GetUserDto(e.Argument); - - SendMessageToUserSession(e.Argument, "UserPolicyUpdated", dto); - } - - private void OnUserConfigurationUpdated(object sender, GenericEventArgs e) - { - var dto = _userManager.GetUserDto(e.Argument); - - SendMessageToUserSession(e.Argument, "UserConfigurationUpdated", dto); - } - private async void SendMessageToAdminSessions(string name, T data) { try @@ -209,10 +193,9 @@ namespace Emby.Server.Implementations.EntryPoints { if (dispose) { - _userManager.UserDeleted -= OnUserDeleted; - _userManager.UserUpdated -= OnUserUpdated; - _userManager.UserPolicyUpdated -= OnUserPolicyUpdated; - _userManager.UserConfigurationUpdated -= OnUserConfigurationUpdated; + _userManager.OnUserDeleted -= OnUserDeleted; + _userManager.OnUserUpdated -= OnUserUpdated; + _installationManager.PluginUninstalled -= OnPluginUninstalled; _installationManager.PackageInstalling -= OnPackageInstalling; diff --git a/Emby.Server.Implementations/HttpServer/Security/AuthService.cs b/Emby.Server.Implementations/HttpServer/Security/AuthService.cs index 256b24924..ad7b76d4f 100644 --- a/Emby.Server.Implementations/HttpServer/Security/AuthService.cs +++ b/Emby.Server.Implementations/HttpServer/Security/AuthService.cs @@ -4,6 +4,7 @@ using System; using System.Linq; using System.Security.Authentication; using Emby.Server.Implementations.SocketSharp; +using Jellyfin.Data.Enums; using MediaBrowser.Common.Net; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; @@ -43,14 +44,14 @@ namespace Emby.Server.Implementations.HttpServer.Security ValidateUser(request, authAttribtues); } - public User Authenticate(HttpRequest request, IAuthenticationAttributes authAttributes) + public Jellyfin.Data.Entities.User Authenticate(HttpRequest request, IAuthenticationAttributes authAttributes) { var req = new WebSocketSharpRequest(request, null, request.Path, _logger); var user = ValidateUser(req, authAttributes); return user; } - private User ValidateUser(IRequest request, IAuthenticationAttributes authAttribtues) + private Jellyfin.Data.Entities.User ValidateUser(IRequest request, IAuthenticationAttributes authAttribtues) { // This code is executed before the service var auth = _authorizationContext.GetAuthorizationInfo(request); @@ -90,7 +91,8 @@ namespace Emby.Server.Implementations.HttpServer.Security !string.IsNullOrEmpty(auth.Client) && !string.IsNullOrEmpty(auth.Device)) { - _sessionManager.LogSessionActivity(auth.Client, + _sessionManager.LogSessionActivity( + auth.Client, auth.Version, auth.DeviceId, auth.Device, @@ -102,22 +104,22 @@ namespace Emby.Server.Implementations.HttpServer.Security } private void ValidateUserAccess( - User user, + Jellyfin.Data.Entities.User user, IRequest request, IAuthenticationAttributes authAttribtues, AuthorizationInfo auth) { - if (user.Policy.IsDisabled) + if (user.HasPermission(PermissionKind.IsDisabled)) { throw new SecurityException("User account has been disabled."); } - if (!user.Policy.EnableRemoteAccess && !_networkManager.IsInLocalNetwork(request.RemoteIp)) + if (!user.HasPermission(PermissionKind.EnableRemoteAccess) && !_networkManager.IsInLocalNetwork(request.RemoteIp)) { throw new SecurityException("User account has been disabled."); } - if (!user.Policy.IsAdministrator + if (!user.HasPermission(PermissionKind.IsAdministrator) && !authAttribtues.EscapeParentalControl && !user.IsParentalScheduleAllowed()) { @@ -176,11 +178,11 @@ namespace Emby.Server.Implementations.HttpServer.Security return false; } - private static void ValidateRoles(string[] roles, User user) + private static void ValidateRoles(string[] roles, Jellyfin.Data.Entities.User user) { if (roles.Contains("admin", StringComparer.OrdinalIgnoreCase)) { - if (user == null || !user.Policy.IsAdministrator) + if (user == null || !user.HasPermission(PermissionKind.IsAdministrator)) { throw new SecurityException("User does not have admin access."); } @@ -188,7 +190,7 @@ namespace Emby.Server.Implementations.HttpServer.Security if (roles.Contains("delete", StringComparer.OrdinalIgnoreCase)) { - if (user == null || !user.Policy.EnableContentDeletion) + if (user == null || !user.HasPermission(PermissionKind.EnableContentDeletion)) { throw new SecurityException("User does not have delete access."); } @@ -196,7 +198,7 @@ namespace Emby.Server.Implementations.HttpServer.Security if (roles.Contains("download", StringComparer.OrdinalIgnoreCase)) { - if (user == null || !user.Policy.EnableContentDownloading) + if (user == null || !user.HasPermission(PermissionKind.EnableContentDownloading)) { throw new SecurityException("User does not have download access."); } diff --git a/Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs b/Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs index 129faeaab..9558cb4c6 100644 --- a/Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs +++ b/Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs @@ -149,9 +149,9 @@ namespace Emby.Server.Implementations.HttpServer.Security { info.User = _userManager.GetUserById(tokenInfo.UserId); - if (info.User != null && !string.Equals(info.User.Name, tokenInfo.UserName, StringComparison.OrdinalIgnoreCase)) + if (info.User != null && !string.Equals(info.User.Username, tokenInfo.UserName, StringComparison.OrdinalIgnoreCase)) { - tokenInfo.UserName = info.User.Name; + tokenInfo.UserName = info.User.Username; updateToken = true; } } diff --git a/Emby.Server.Implementations/HttpServer/Security/SessionContext.cs b/Emby.Server.Implementations/HttpServer/Security/SessionContext.cs index 166952c64..3f8a64f99 100644 --- a/Emby.Server.Implementations/HttpServer/Security/SessionContext.cs +++ b/Emby.Server.Implementations/HttpServer/Security/SessionContext.cs @@ -42,14 +42,14 @@ namespace Emby.Server.Implementations.HttpServer.Security return GetSession((IRequest)requestContext); } - public User GetUser(IRequest requestContext) + public Jellyfin.Data.Entities.User GetUser(IRequest requestContext) { var session = GetSession(requestContext); return session == null || session.UserId.Equals(Guid.Empty) ? null : _userManager.GetUserById(session.UserId); } - public User GetUser(object requestContext) + public Jellyfin.Data.Entities.User GetUser(object requestContext) { return GetUser((IRequest)requestContext); } diff --git a/Emby.Server.Implementations/Library/DefaultAuthenticationProvider.cs b/Emby.Server.Implementations/Library/DefaultAuthenticationProvider.cs deleted file mode 100644 index 52c8facc3..000000000 --- a/Emby.Server.Implementations/Library/DefaultAuthenticationProvider.cs +++ /dev/null @@ -1,177 +0,0 @@ -using System; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using MediaBrowser.Common; -using MediaBrowser.Common.Cryptography; -using MediaBrowser.Controller.Authentication; -using MediaBrowser.Controller.Entities; -using MediaBrowser.Model.Cryptography; - -namespace Emby.Server.Implementations.Library -{ - /// - /// The default authentication provider. - /// - public class DefaultAuthenticationProvider : IAuthenticationProvider, IRequiresResolvedUser - { - private readonly ICryptoProvider _cryptographyProvider; - - /// - /// Initializes a new instance of the class. - /// - /// The cryptography provider. - public DefaultAuthenticationProvider(ICryptoProvider cryptographyProvider) - { - _cryptographyProvider = cryptographyProvider; - } - - /// - public string Name => "Default"; - - /// - public bool IsEnabled => true; - - /// - // This is dumb and an artifact of the backwards way auth providers were designed. - // This version of authenticate was never meant to be called, but needs to be here for interface compat - // Only the providers that don't provide local user support use this - public Task Authenticate(string username, string password) - { - throw new NotImplementedException(); - } - - /// - // This is the version that we need to use for local users. Because reasons. - public Task Authenticate(string username, string password, User resolvedUser) - { - if (resolvedUser == null) - { - throw new AuthenticationException($"Specified user does not exist."); - } - - bool success = false; - - // As long as jellyfin supports passwordless users, we need this little block here to accommodate - if (!HasPassword(resolvedUser) && string.IsNullOrEmpty(password)) - { - return Task.FromResult(new ProviderAuthenticationResult - { - Username = username - }); - } - - byte[] passwordbytes = Encoding.UTF8.GetBytes(password); - - PasswordHash readyHash = PasswordHash.Parse(resolvedUser.Password); - if (_cryptographyProvider.GetSupportedHashMethods().Contains(readyHash.Id) - || _cryptographyProvider.DefaultHashMethod == readyHash.Id) - { - byte[] calculatedHash = _cryptographyProvider.ComputeHash( - readyHash.Id, - passwordbytes, - readyHash.Salt.ToArray()); - - if (readyHash.Hash.SequenceEqual(calculatedHash)) - { - success = true; - } - } - else - { - throw new AuthenticationException($"Requested crypto method not available in provider: {readyHash.Id}"); - } - - if (!success) - { - throw new AuthenticationException("Invalid username or password"); - } - - return Task.FromResult(new ProviderAuthenticationResult - { - Username = username - }); - } - - /// - public bool HasPassword(User user) - => !string.IsNullOrEmpty(user.Password); - - /// - public Task ChangePassword(User user, string newPassword) - { - if (string.IsNullOrEmpty(newPassword)) - { - user.Password = null; - return Task.CompletedTask; - } - - PasswordHash newPasswordHash = _cryptographyProvider.CreatePasswordHash(newPassword); - user.Password = newPasswordHash.ToString(); - - return Task.CompletedTask; - } - - /// - public void ChangeEasyPassword(User user, string newPassword, string newPasswordHash) - { - if (newPassword != null) - { - newPasswordHash = _cryptographyProvider.CreatePasswordHash(newPassword).ToString(); - } - - if (string.IsNullOrWhiteSpace(newPasswordHash)) - { - throw new ArgumentNullException(nameof(newPasswordHash)); - } - - user.EasyPassword = newPasswordHash; - } - - /// - public string GetEasyPasswordHash(User user) - { - return string.IsNullOrEmpty(user.EasyPassword) - ? null - : Hex.Encode(PasswordHash.Parse(user.EasyPassword).Hash); - } - - /// - /// Gets the hashed string. - /// - public string GetHashedString(User user, string str) - { - if (string.IsNullOrEmpty(user.Password)) - { - return _cryptographyProvider.CreatePasswordHash(str).ToString(); - } - - // TODO: make use of iterations parameter? - PasswordHash passwordHash = PasswordHash.Parse(user.Password); - var salt = passwordHash.Salt.ToArray(); - return new PasswordHash( - passwordHash.Id, - _cryptographyProvider.ComputeHash( - passwordHash.Id, - Encoding.UTF8.GetBytes(str), - salt), - salt, - passwordHash.Parameters.ToDictionary(x => x.Key, y => y.Value)).ToString(); - } - - public ReadOnlySpan GetHashed(User user, string str) - { - if (string.IsNullOrEmpty(user.Password)) - { - return _cryptographyProvider.CreatePasswordHash(str).Hash; - } - - // TODO: make use of iterations parameter? - PasswordHash passwordHash = PasswordHash.Parse(user.Password); - return _cryptographyProvider.ComputeHash( - passwordHash.Id, - Encoding.UTF8.GetBytes(str), - passwordHash.Salt.ToArray()); - } - } -} diff --git a/Emby.Server.Implementations/Library/DefaultPasswordResetProvider.cs b/Emby.Server.Implementations/Library/DefaultPasswordResetProvider.cs deleted file mode 100644 index 6c6fbd86f..000000000 --- a/Emby.Server.Implementations/Library/DefaultPasswordResetProvider.cs +++ /dev/null @@ -1,140 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Security.Cryptography; -using System.Threading.Tasks; -using MediaBrowser.Common.Extensions; -using MediaBrowser.Controller.Authentication; -using MediaBrowser.Controller.Configuration; -using MediaBrowser.Controller.Library; -using MediaBrowser.Model.Serialization; -using MediaBrowser.Model.Users; - -namespace Emby.Server.Implementations.Library -{ - /// - /// The default password reset provider. - /// - public class DefaultPasswordResetProvider : IPasswordResetProvider - { - private const string BaseResetFileName = "passwordreset"; - - private readonly IJsonSerializer _jsonSerializer; - private readonly IUserManager _userManager; - - private readonly string _passwordResetFileBase; - private readonly string _passwordResetFileBaseDir; - - /// - /// Initializes a new instance of the class. - /// - /// The configuration manager. - /// The JSON serializer. - /// The user manager. - public DefaultPasswordResetProvider( - IServerConfigurationManager configurationManager, - IJsonSerializer jsonSerializer, - IUserManager userManager) - { - _passwordResetFileBaseDir = configurationManager.ApplicationPaths.ProgramDataPath; - _passwordResetFileBase = Path.Combine(_passwordResetFileBaseDir, BaseResetFileName); - _jsonSerializer = jsonSerializer; - _userManager = userManager; - } - - /// - public string Name => "Default Password Reset Provider"; - - /// - public bool IsEnabled => true; - - /// - public async Task RedeemPasswordResetPin(string pin) - { - SerializablePasswordReset spr; - List usersreset = new List(); - foreach (var resetfile in Directory.EnumerateFiles(_passwordResetFileBaseDir, $"{BaseResetFileName}*")) - { - using (var str = File.OpenRead(resetfile)) - { - spr = await _jsonSerializer.DeserializeFromStreamAsync(str).ConfigureAwait(false); - } - - if (spr.ExpirationDate < DateTime.Now) - { - File.Delete(resetfile); - } - else if (string.Equals( - spr.Pin.Replace("-", string.Empty, StringComparison.Ordinal), - pin.Replace("-", string.Empty, StringComparison.Ordinal), - StringComparison.InvariantCultureIgnoreCase)) - { - var resetUser = _userManager.GetUserByName(spr.UserName); - if (resetUser == null) - { - throw new ResourceNotFoundException($"User with a username of {spr.UserName} not found"); - } - - await _userManager.ChangePassword(resetUser, pin).ConfigureAwait(false); - usersreset.Add(resetUser.Name); - File.Delete(resetfile); - } - } - - if (usersreset.Count < 1) - { - throw new ResourceNotFoundException($"No Users found with a password reset request matching pin {pin}"); - } - else - { - return new PinRedeemResult - { - Success = true, - UsersReset = usersreset.ToArray() - }; - } - } - - /// - public async Task StartForgotPasswordProcess(MediaBrowser.Controller.Entities.User user, bool isInNetwork) - { - string pin = string.Empty; - using (var cryptoRandom = RandomNumberGenerator.Create()) - { - byte[] bytes = new byte[4]; - cryptoRandom.GetBytes(bytes); - pin = BitConverter.ToString(bytes); - } - - DateTime expireTime = DateTime.Now.AddMinutes(30); - string filePath = _passwordResetFileBase + user.InternalId + ".json"; - SerializablePasswordReset spr = new SerializablePasswordReset - { - ExpirationDate = expireTime, - Pin = pin, - PinFile = filePath, - UserName = user.Name - }; - - using (FileStream fileStream = File.OpenWrite(filePath)) - { - _jsonSerializer.SerializeToStream(spr, fileStream); - await fileStream.FlushAsync().ConfigureAwait(false); - } - - return new ForgotPasswordResult - { - Action = ForgotPasswordAction.PinCode, - PinExpirationDate = expireTime, - PinFile = filePath - }; - } - - private class SerializablePasswordReset : PasswordPinCreationResult - { - public string Pin { get; set; } - - public string UserName { get; set; } - } - } -} diff --git a/Emby.Server.Implementations/Library/InvalidAuthProvider.cs b/Emby.Server.Implementations/Library/InvalidAuthProvider.cs deleted file mode 100644 index dc61aacd7..000000000 --- a/Emby.Server.Implementations/Library/InvalidAuthProvider.cs +++ /dev/null @@ -1,54 +0,0 @@ -using System.Threading.Tasks; -using MediaBrowser.Controller.Authentication; -using MediaBrowser.Controller.Entities; - -namespace Emby.Server.Implementations.Library -{ - /// - /// An invalid authentication provider. - /// - public class InvalidAuthProvider : IAuthenticationProvider - { - /// - public string Name => "InvalidOrMissingAuthenticationProvider"; - - /// - public bool IsEnabled => true; - - /// - public Task Authenticate(string username, string password) - { - throw new AuthenticationException("User Account cannot login with this provider. The Normal provider for this user cannot be found"); - } - - /// - public bool HasPassword(User user) - { - return true; - } - - /// - public Task ChangePassword(User user, string newPassword) - { - return Task.CompletedTask; - } - - /// - public void ChangeEasyPassword(User user, string newPassword, string newPasswordHash) - { - // Nothing here - } - - /// - public string GetPasswordHash(User user) - { - return string.Empty; - } - - /// - public string GetEasyPasswordHash(User user) - { - return string.Empty; - } - } -} diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index 0b86b2db7..e7cd7512c 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -17,6 +17,7 @@ using Emby.Server.Implementations.Library.Resolvers; using Emby.Server.Implementations.Library.Validators; using Emby.Server.Implementations.Playlists; using Emby.Server.Implementations.ScheduledTasks; +using Jellyfin.Data.Enums; using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Progress; using MediaBrowser.Controller; @@ -1470,7 +1471,7 @@ namespace Emby.Server.Implementations.Library query.Parent = null; } - private void AddUserToQuery(InternalItemsQuery query, User user, bool allowExternalContent = true) + private void AddUserToQuery(InternalItemsQuery query, Jellyfin.Data.Entities.User user, bool allowExternalContent = true) { if (query.AncestorIds.Length == 0 && query.ParentId.Equals(Guid.Empty) && @@ -1491,7 +1492,7 @@ namespace Emby.Server.Implementations.Library } } - private IEnumerable GetTopParentIdsForQuery(BaseItem item, User user) + private IEnumerable GetTopParentIdsForQuery(BaseItem item, Jellyfin.Data.Entities.User user) { if (item is UserView view) { @@ -1524,7 +1525,8 @@ namespace Emby.Server.Implementations.Library } // Handle grouping - if (user != null && !string.IsNullOrEmpty(view.ViewType) && UserView.IsEligibleForGrouping(view.ViewType) && user.Configuration.GroupedFolders.Length > 0) + if (user != null && !string.IsNullOrEmpty(view.ViewType) && UserView.IsEligibleForGrouping(view.ViewType) + && user.GetPreference(PreferenceKind.GroupedFolders).Length > 0) { return GetUserRootFolder() .GetChildren(user, true) @@ -1557,7 +1559,7 @@ namespace Emby.Server.Implementations.Library /// The item. /// The user. /// IEnumerable{System.String}. - public async Task> GetIntros(BaseItem item, User user) + public async Task> GetIntros(BaseItem item, Jellyfin.Data.Entities.User user) { var tasks = IntroProviders .OrderBy(i => i.GetType().Name.Contains("Default", StringComparison.OrdinalIgnoreCase) ? 1 : 0) @@ -1579,7 +1581,7 @@ namespace Emby.Server.Implementations.Library /// The item. /// The user. /// Task<IEnumerable<IntroInfo>>. - private async Task> GetIntros(IIntroProvider provider, BaseItem item, User user) + private async Task> GetIntros(IIntroProvider provider, BaseItem item, Jellyfin.Data.Entities.User user) { try { @@ -1680,7 +1682,7 @@ namespace Emby.Server.Implementations.Library /// The sort by. /// The sort order. /// IEnumerable{BaseItem}. - public IEnumerable Sort(IEnumerable items, User user, IEnumerable sortBy, SortOrder sortOrder) + public IEnumerable Sort(IEnumerable items, Jellyfin.Data.Entities.User user, IEnumerable sortBy, SortOrder sortOrder) { var isFirst = true; @@ -1703,7 +1705,7 @@ namespace Emby.Server.Implementations.Library return orderedItems ?? items; } - public IEnumerable Sort(IEnumerable items, User user, IEnumerable> orderByList) + public IEnumerable Sort(IEnumerable items, Jellyfin.Data.Entities.User user, IEnumerable> orderByList) { var isFirst = true; @@ -1740,7 +1742,7 @@ namespace Emby.Server.Implementations.Library /// The name. /// The user. /// IBaseItemComparer. - private IBaseItemComparer GetComparer(string name, User user) + private IBaseItemComparer GetComparer(string name, Jellyfin.Data.Entities.User user) { var comparer = Comparers.FirstOrDefault(c => string.Equals(name, c.Name, StringComparison.OrdinalIgnoreCase)); @@ -2072,7 +2074,7 @@ namespace Emby.Server.Implementations.Library private readonly TimeSpan _viewRefreshInterval = TimeSpan.FromHours(24); public UserView GetNamedView( - User user, + Jellyfin.Data.Entities.User user, string name, string viewType, string sortName) @@ -2125,7 +2127,7 @@ namespace Emby.Server.Implementations.Library } public UserView GetNamedView( - User user, + Jellyfin.Data.Entities.User user, string name, Guid parentId, string viewType, diff --git a/Emby.Server.Implementations/Library/MediaSourceManager.cs b/Emby.Server.Implementations/Library/MediaSourceManager.cs index 01fe98f3a..25af69058 100644 --- a/Emby.Server.Implementations/Library/MediaSourceManager.cs +++ b/Emby.Server.Implementations/Library/MediaSourceManager.cs @@ -7,6 +7,7 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; +using Jellyfin.Data.Enums; using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.Entities; @@ -14,7 +15,6 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Controller.Persistence; using MediaBrowser.Controller.Providers; -using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; @@ -145,7 +145,7 @@ namespace Emby.Server.Implementations.Library }); } - public async Task> GetPlaybackMediaSources(BaseItem item, User user, bool allowMediaProbe, bool enablePathSubstitution, CancellationToken cancellationToken) + public async Task> GetPlaybackMediaSources(BaseItem item, Jellyfin.Data.Entities.User user, bool allowMediaProbe, bool enablePathSubstitution, CancellationToken cancellationToken) { var mediaSources = GetStaticMediaSources(item, enablePathSubstitution, user); @@ -190,10 +190,7 @@ namespace Emby.Server.Implementations.Library { if (string.Equals(item.MediaType, MediaType.Audio, StringComparison.OrdinalIgnoreCase)) { - if (!user.Policy.EnableAudioPlaybackTranscoding) - { - source.SupportsTranscoding = false; - } + source.SupportsTranscoding = user.HasPermission(PermissionKind.EnableAudioPlaybackTranscoding); } } } @@ -312,7 +309,7 @@ namespace Emby.Server.Implementations.Library return sources.FirstOrDefault(i => string.Equals(i.Id, mediaSourceId, StringComparison.OrdinalIgnoreCase)); } - public List GetStaticMediaSources(BaseItem item, bool enablePathSubstitution, User user = null) + public List GetStaticMediaSources(BaseItem item, bool enablePathSubstitution, Jellyfin.Data.Entities.User user = null) { if (item == null) { @@ -350,9 +347,11 @@ namespace Emby.Server.Implementations.Library return new string[] { language }; } - private void SetDefaultSubtitleStreamIndex(MediaSourceInfo source, UserItemData userData, User user, bool allowRememberingSelection) + private void SetDefaultSubtitleStreamIndex(MediaSourceInfo source, UserItemData userData, Jellyfin.Data.Entities.User user, bool allowRememberingSelection) { - if (userData.SubtitleStreamIndex.HasValue && user.Configuration.RememberSubtitleSelections && user.Configuration.SubtitleMode != SubtitlePlaybackMode.None && allowRememberingSelection) + if (userData.SubtitleStreamIndex.HasValue + && user.RememberSubtitleSelections + && user.SubtitleMode != SubtitlePlaybackMode.None && allowRememberingSelection) { var index = userData.SubtitleStreamIndex.Value; // Make sure the saved index is still valid @@ -363,26 +362,27 @@ namespace Emby.Server.Implementations.Library } } - var preferredSubs = string.IsNullOrEmpty(user.Configuration.SubtitleLanguagePreference) - ? Array.Empty() : NormalizeLanguage(user.Configuration.SubtitleLanguagePreference); + + var preferredSubs = string.IsNullOrEmpty(user.SubtitleLanguagePreference) + ? Array.Empty() : NormalizeLanguage(user.SubtitleLanguagePreference); var defaultAudioIndex = source.DefaultAudioStreamIndex; var audioLangage = defaultAudioIndex == null ? null : source.MediaStreams.Where(i => i.Type == MediaStreamType.Audio && i.Index == defaultAudioIndex).Select(i => i.Language).FirstOrDefault(); - source.DefaultSubtitleStreamIndex = MediaStreamSelector.GetDefaultSubtitleStreamIndex(source.MediaStreams, + source.DefaultSubtitleStreamIndex = MediaStreamSelector.GetDefaultSubtitleStreamIndex( + source.MediaStreams, preferredSubs, - user.Configuration.SubtitleMode, + user.SubtitleMode, audioLangage); - MediaStreamSelector.SetSubtitleStreamScores(source.MediaStreams, preferredSubs, - user.Configuration.SubtitleMode, audioLangage); + MediaStreamSelector.SetSubtitleStreamScores(source.MediaStreams, preferredSubs, user.SubtitleMode, audioLangage); } - private void SetDefaultAudioStreamIndex(MediaSourceInfo source, UserItemData userData, User user, bool allowRememberingSelection) + private void SetDefaultAudioStreamIndex(MediaSourceInfo source, UserItemData userData, Jellyfin.Data.Entities.User user, bool allowRememberingSelection) { - if (userData.AudioStreamIndex.HasValue && user.Configuration.RememberAudioSelections && allowRememberingSelection) + if (userData.AudioStreamIndex.HasValue && user.RememberAudioSelections && allowRememberingSelection) { var index = userData.AudioStreamIndex.Value; // Make sure the saved index is still valid @@ -393,14 +393,14 @@ namespace Emby.Server.Implementations.Library } } - var preferredAudio = string.IsNullOrEmpty(user.Configuration.AudioLanguagePreference) + var preferredAudio = string.IsNullOrEmpty(user.AudioLanguagePreference) ? Array.Empty() - : NormalizeLanguage(user.Configuration.AudioLanguagePreference); + : NormalizeLanguage(user.AudioLanguagePreference); - source.DefaultAudioStreamIndex = MediaStreamSelector.GetDefaultAudioStreamIndex(source.MediaStreams, preferredAudio, user.Configuration.PlayDefaultAudioTrack); + source.DefaultAudioStreamIndex = MediaStreamSelector.GetDefaultAudioStreamIndex(source.MediaStreams, preferredAudio, user.PlayDefaultAudioTrack); } - public void SetDefaultAudioAndSubtitleStreamIndexes(BaseItem item, MediaSourceInfo source, User user) + public void SetDefaultAudioAndSubtitleStreamIndexes(BaseItem item, MediaSourceInfo source, Jellyfin.Data.Entities.User user) { // Item would only be null if the app didn't supply ItemId as part of the live stream open request var mediaType = item == null ? MediaType.Video : item.MediaType; @@ -560,17 +560,14 @@ namespace Emby.Server.Implementations.Library { videoStream.BitRate = 30000000; } - else if (width >= 1900) { videoStream.BitRate = 20000000; } - else if (width >= 1200) { videoStream.BitRate = 8000000; } - else if (width >= 700) { videoStream.BitRate = 2000000; @@ -674,13 +671,14 @@ namespace Emby.Server.Implementations.Library mediaSource.AnalyzeDurationMs = 3000; } - mediaInfo = await _mediaEncoder.GetMediaInfo(new MediaInfoRequest + mediaInfo = await _mediaEncoder.GetMediaInfo( + new MediaInfoRequest { MediaSource = mediaSource, MediaType = isAudio ? DlnaProfileType.Audio : DlnaProfileType.Video, ExtractChapters = false - - }, cancellationToken).ConfigureAwait(false); + }, + cancellationToken).ConfigureAwait(false); if (cacheFilePath != null) { diff --git a/Emby.Server.Implementations/Library/MediaStreamSelector.cs b/Emby.Server.Implementations/Library/MediaStreamSelector.cs index e27145a1d..a177138b7 100644 --- a/Emby.Server.Implementations/Library/MediaStreamSelector.cs +++ b/Emby.Server.Implementations/Library/MediaStreamSelector.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using System.Linq; +using Jellyfin.Data.Enums; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Entities; diff --git a/Emby.Server.Implementations/Library/MusicManager.cs b/Emby.Server.Implementations/Library/MusicManager.cs index 1ec578371..ad8c70f5e 100644 --- a/Emby.Server.Implementations/Library/MusicManager.cs +++ b/Emby.Server.Implementations/Library/MusicManager.cs @@ -22,7 +22,7 @@ namespace Emby.Server.Implementations.Library _libraryManager = libraryManager; } - public List GetInstantMixFromSong(Audio item, User user, DtoOptions dtoOptions) + public List GetInstantMixFromSong(Audio item, Jellyfin.Data.Entities.User user, DtoOptions dtoOptions) { var list = new List /// The user object. /// The item. - private void OnPlaybackStart(User user, BaseItem item) + private void OnPlaybackStart(Jellyfin.Data.Entities.User user, BaseItem item) { var data = _userDataManager.GetUserData(user, item); @@ -754,7 +764,7 @@ namespace Emby.Server.Implementations.Session StartIdleCheckTimer(); } - private void OnPlaybackProgress(User user, BaseItem item, PlaybackProgressInfo info) + private void OnPlaybackProgress(Jellyfin.Data.Entities.User user, BaseItem item, PlaybackProgressInfo info) { var data = _userDataManager.GetUserData(user, item); @@ -780,11 +790,11 @@ namespace Emby.Server.Implementations.Session } } - private static bool UpdatePlaybackSettings(User user, PlaybackProgressInfo info, UserItemData data) + private static bool UpdatePlaybackSettings(Jellyfin.Data.Entities.User user, PlaybackProgressInfo info, UserItemData data) { var changed = false; - if (user.Configuration.RememberAudioSelections) + if (user.RememberAudioSelections) { if (data.AudioStreamIndex != info.AudioStreamIndex) { @@ -801,7 +811,7 @@ namespace Emby.Server.Implementations.Session } } - if (user.Configuration.RememberSubtitleSelections) + if (user.RememberSubtitleSelections) { if (data.SubtitleStreamIndex != info.SubtitleStreamIndex) { @@ -940,7 +950,7 @@ namespace Emby.Server.Implementations.Session _logger); } - private bool OnPlaybackStopped(User user, BaseItem item, long? positionTicks, bool playbackFailed) + private bool OnPlaybackStopped(Jellyfin.Data.Entities.User user, BaseItem item, long? positionTicks, bool playbackFailed) { bool playedToCompletion = false; @@ -1112,13 +1122,13 @@ namespace Emby.Server.Implementations.Session if (items.Any(i => i.GetPlayAccess(user) != PlayAccess.Full)) { throw new ArgumentException( - string.Format(CultureInfo.InvariantCulture, "{0} is not allowed to play media.", user.Name)); + string.Format(CultureInfo.InvariantCulture, "{0} is not allowed to play media.", user.Username)); } } if (user != null && command.ItemIds.Length == 1 - && user.Configuration.EnableNextEpisodeAutoPlay + && user.EnableNextEpisodeAutoPlay && _libraryManager.GetItemById(command.ItemIds[0]) is Episode episode) { var series = episode.Series; @@ -1154,7 +1164,7 @@ namespace Emby.Server.Implementations.Session await SendMessageToSession(session, "Play", command, cancellationToken).ConfigureAwait(false); } - private IEnumerable TranslateItemForPlayback(Guid id, User user) + private IEnumerable TranslateItemForPlayback(Guid id, Jellyfin.Data.Entities.User user) { var item = _libraryManager.GetItemById(id); @@ -1173,7 +1183,7 @@ namespace Emby.Server.Implementations.Session DtoOptions = new DtoOptions(false) { EnableImages = false, - Fields = new ItemFields[] + Fields = new[] { ItemFields.SortName } @@ -1207,7 +1217,7 @@ namespace Emby.Server.Implementations.Session return new[] { item }; } - private IEnumerable TranslateItemForInstantMix(Guid id, User user) + private IEnumerable TranslateItemForInstantMix(Guid id, Jellyfin.Data.Entities.User user) { var item = _libraryManager.GetItemById(id); @@ -1335,7 +1345,7 @@ namespace Emby.Server.Implementations.Session list.Add(new SessionUserInfo { UserId = userId, - UserName = user.Name + UserName = user.Username }); session.AdditionalUsers = list.ToArray(); @@ -1390,7 +1400,7 @@ namespace Emby.Server.Implementations.Session { CheckDisposed(); - User user = null; + Jellyfin.Data.Entities.User user = null; if (request.UserId != Guid.Empty) { user = _userManager.GetUserById(request.UserId); @@ -1446,7 +1456,7 @@ namespace Emby.Server.Implementations.Session return returnResult; } - private string GetAuthorizationToken(User user, string deviceId, string app, string appVersion, string deviceName) + private string GetAuthorizationToken(Jellyfin.Data.Entities.User user, string deviceId, string app, string appVersion, string deviceName) { var existing = _authRepo.Get( new AuthenticationInfoQuery @@ -1495,7 +1505,7 @@ namespace Emby.Server.Implementations.Session DeviceName = deviceName, UserId = user.Id, AccessToken = Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture), - UserName = user.Name + UserName = user.Username }; _logger.LogInformation("Creating new access token for user {0}", user.Id); @@ -1692,15 +1702,15 @@ namespace Emby.Server.Implementations.Session return info; } - private string GetImageCacheTag(BaseItem item, ImageType type) + private string GetImageCacheTag(Jellyfin.Data.Entities.User user) { try { - return _imageProcessor.GetImageCacheTag(item, type); + return _imageProcessor.GetImageCacheTag(user); } - catch (Exception ex) + catch (Exception e) { - _logger.LogError(ex, "Error getting image information for {Type}", type); + _logger.LogError(e, "Error getting image information for profile image"); return null; } } @@ -1809,7 +1819,10 @@ namespace Emby.Server.Implementations.Session { CheckDisposed(); - var adminUserIds = _userManager.Users.Where(i => i.Policy.IsAdministrator).Select(i => i.Id).ToList(); + var adminUserIds = _userManager.Users + .Where(i => i.HasPermission(PermissionKind.IsAdministrator)) + .Select(i => i.Id) + .ToList(); return SendMessageToUserSessions(adminUserIds, name, data, cancellationToken); } diff --git a/Emby.Server.Implementations/Sorting/DateLastMediaAddedComparer.cs b/Emby.Server.Implementations/Sorting/DateLastMediaAddedComparer.cs index 623675157..3cc294371 100644 --- a/Emby.Server.Implementations/Sorting/DateLastMediaAddedComparer.cs +++ b/Emby.Server.Implementations/Sorting/DateLastMediaAddedComparer.cs @@ -12,7 +12,7 @@ namespace Emby.Server.Implementations.Sorting /// Gets or sets the user. /// /// The user. - public User User { get; set; } + public Jellyfin.Data.Entities.User User { get; set; } /// /// Gets or sets the user manager. diff --git a/Emby.Server.Implementations/Sorting/DatePlayedComparer.cs b/Emby.Server.Implementations/Sorting/DatePlayedComparer.cs index 73f59f8cd..57a1a00d9 100644 --- a/Emby.Server.Implementations/Sorting/DatePlayedComparer.cs +++ b/Emby.Server.Implementations/Sorting/DatePlayedComparer.cs @@ -15,7 +15,7 @@ namespace Emby.Server.Implementations.Sorting /// Gets or sets the user. /// /// The user. - public User User { get; set; } + public Jellyfin.Data.Entities.User User { get; set; } /// /// Gets or sets the user manager. diff --git a/Emby.Server.Implementations/Sorting/IsFavoriteOrLikeComparer.cs b/Emby.Server.Implementations/Sorting/IsFavoriteOrLikeComparer.cs index 66de05a6a..c9feca7e3 100644 --- a/Emby.Server.Implementations/Sorting/IsFavoriteOrLikeComparer.cs +++ b/Emby.Server.Implementations/Sorting/IsFavoriteOrLikeComparer.cs @@ -11,7 +11,7 @@ namespace Emby.Server.Implementations.Sorting /// Gets or sets the user. /// /// The user. - public User User { get; set; } + public Jellyfin.Data.Entities.User User { get; set; } /// /// Compares the specified x. diff --git a/Emby.Server.Implementations/Sorting/IsPlayedComparer.cs b/Emby.Server.Implementations/Sorting/IsPlayedComparer.cs index da3f3dd25..6f383e65f 100644 --- a/Emby.Server.Implementations/Sorting/IsPlayedComparer.cs +++ b/Emby.Server.Implementations/Sorting/IsPlayedComparer.cs @@ -11,7 +11,7 @@ namespace Emby.Server.Implementations.Sorting /// Gets or sets the user. /// /// The user. - public User User { get; set; } + public Jellyfin.Data.Entities.User User { get; set; } /// /// Compares the specified x. diff --git a/Emby.Server.Implementations/Sorting/IsUnplayedComparer.cs b/Emby.Server.Implementations/Sorting/IsUnplayedComparer.cs index d99d0eff2..4845fdc0d 100644 --- a/Emby.Server.Implementations/Sorting/IsUnplayedComparer.cs +++ b/Emby.Server.Implementations/Sorting/IsUnplayedComparer.cs @@ -11,7 +11,7 @@ namespace Emby.Server.Implementations.Sorting /// Gets or sets the user. /// /// The user. - public User User { get; set; } + public Jellyfin.Data.Entities.User User { get; set; } /// /// Compares the specified x. diff --git a/Emby.Server.Implementations/Sorting/PlayCountComparer.cs b/Emby.Server.Implementations/Sorting/PlayCountComparer.cs index eb74ce1bd..99846db61 100644 --- a/Emby.Server.Implementations/Sorting/PlayCountComparer.cs +++ b/Emby.Server.Implementations/Sorting/PlayCountComparer.cs @@ -14,7 +14,7 @@ namespace Emby.Server.Implementations.Sorting /// Gets or sets the user. /// /// The user. - public User User { get; set; } + public Jellyfin.Data.Entities.User User { get; set; } /// /// Compares the specified x. diff --git a/Emby.Server.Implementations/TV/TVSeriesManager.cs b/Emby.Server.Implementations/TV/TVSeriesManager.cs index 4c2f24e6f..905a1ea99 100644 --- a/Emby.Server.Implementations/TV/TVSeriesManager.cs +++ b/Emby.Server.Implementations/TV/TVSeriesManager.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Globalization; using System.Linq; +using Jellyfin.Data.Enums; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; @@ -74,7 +75,8 @@ namespace Emby.Server.Implementations.TV { parents = _libraryManager.GetUserRootFolder().GetChildren(user, true) .Where(i => i is Folder) - .Where(i => !user.Configuration.LatestItemsExcludes.Contains(i.Id.ToString("N", CultureInfo.InvariantCulture))) + .Where(i => !user.GetPreference(PreferenceKind.LatestItemExcludes) + .Contains(i.Id.ToString("N", CultureInfo.InvariantCulture))) .ToArray(); } @@ -137,7 +139,7 @@ namespace Emby.Server.Implementations.TV return GetResult(episodes, request); } - public IEnumerable GetNextUpEpisodes(NextUpQuery request, User user, IEnumerable seriesKeys, DtoOptions dtoOptions) + public IEnumerable GetNextUpEpisodes(NextUpQuery request, Jellyfin.Data.Entities.User user, IEnumerable seriesKeys, DtoOptions dtoOptions) { // Avoid implicitly captured closure var currentUser = user; @@ -186,13 +188,13 @@ namespace Emby.Server.Implementations.TV /// Gets the next up. /// /// Task{Episode}. - private Tuple> GetNextUp(string seriesKey, User user, DtoOptions dtoOptions) + private Tuple> GetNextUp(string seriesKey, Jellyfin.Data.Entities.User user, DtoOptions dtoOptions) { var lastWatchedEpisode = _libraryManager.GetItemList(new InternalItemsQuery(user) { AncestorWithPresentationUniqueKey = null, SeriesPresentationUniqueKey = seriesKey, - IncludeItemTypes = new[] { typeof(Episode).Name }, + IncludeItemTypes = new[] { nameof(Episode) }, OrderBy = new[] { new ValueTuple(ItemSortBy.SortName, SortOrder.Descending) }, IsPlayed = true, Limit = 1, @@ -205,7 +207,6 @@ namespace Emby.Server.Implementations.TV }, EnableImages = false } - }).FirstOrDefault(); Func getEpisode = () => @@ -220,7 +221,7 @@ namespace Emby.Server.Implementations.TV IsPlayed = false, IsVirtualItem = false, ParentIndexNumberNotEquals = 0, - MinSortName = lastWatchedEpisode == null ? null : lastWatchedEpisode.SortName, + MinSortName = lastWatchedEpisode?.SortName, DtoOptions = dtoOptions }).Cast().FirstOrDefault(); diff --git a/Jellyfin.Api/Auth/CustomAuthenticationHandler.cs b/Jellyfin.Api/Auth/CustomAuthenticationHandler.cs index 26f7d9d2d..4929e8897 100644 --- a/Jellyfin.Api/Auth/CustomAuthenticationHandler.cs +++ b/Jellyfin.Api/Auth/CustomAuthenticationHandler.cs @@ -2,6 +2,7 @@ using System.Security.Claims; using System.Text.Encodings.Web; using System.Threading.Tasks; using Jellyfin.Api.Constants; +using Jellyfin.Data.Enums; using MediaBrowser.Controller.Net; using Microsoft.AspNetCore.Authentication; using Microsoft.Extensions.Logging; @@ -48,10 +49,10 @@ namespace Jellyfin.Api.Auth var claims = new[] { - new Claim(ClaimTypes.Name, user.Name), + new Claim(ClaimTypes.Name, user.Username), new Claim( ClaimTypes.Role, - value: user.Policy.IsAdministrator ? UserRoles.Administrator : UserRoles.User) + value: user.HasPermission(PermissionKind.IsAdministrator) ? UserRoles.Administrator : UserRoles.User) }; var identity = new ClaimsIdentity(claims, Scheme.Name); var principal = new ClaimsPrincipal(identity); diff --git a/Jellyfin.Api/Controllers/StartupController.cs b/Jellyfin.Api/Controllers/StartupController.cs index afc9b8f3d..f965d83f3 100644 --- a/Jellyfin.Api/Controllers/StartupController.cs +++ b/Jellyfin.Api/Controllers/StartupController.cs @@ -98,7 +98,7 @@ namespace Jellyfin.Api.Controllers var user = _userManager.Users.First(); return new StartupUserDto { - Name = user.Name, + Name = user.Username, Password = user.Password }; } @@ -113,7 +113,7 @@ namespace Jellyfin.Api.Controllers { var user = _userManager.Users.First(); - user.Name = startupUserDto.Name; + user.Username = startupUserDto.Name; _userManager.UpdateUser(user); diff --git a/Jellyfin.Data/DayOfWeekHelper.cs b/Jellyfin.Data/DayOfWeekHelper.cs new file mode 100644 index 000000000..33410b732 --- /dev/null +++ b/Jellyfin.Data/DayOfWeekHelper.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections.Generic; +using Jellyfin.Data.Enums; + +namespace Jellyfin.Data +{ + public static class DayOfWeekHelper + { + public static List GetDaysOfWeek(DynamicDayOfWeek day) + { + return GetDaysOfWeek(new List { day }); + } + + public static List GetDaysOfWeek(List days) + { + var list = new List(); + + if (days.Contains(DynamicDayOfWeek.Sunday) || + days.Contains(DynamicDayOfWeek.Weekend) || + days.Contains(DynamicDayOfWeek.Everyday)) + { + list.Add(DayOfWeek.Sunday); + } + + if (days.Contains(DynamicDayOfWeek.Saturday) || + days.Contains(DynamicDayOfWeek.Weekend) || + days.Contains(DynamicDayOfWeek.Everyday)) + { + list.Add(DayOfWeek.Saturday); + } + + if (days.Contains(DynamicDayOfWeek.Monday) || + days.Contains(DynamicDayOfWeek.Weekday) || + days.Contains(DynamicDayOfWeek.Everyday)) + { + list.Add(DayOfWeek.Monday); + } + + if (days.Contains(DynamicDayOfWeek.Tuesday) || + days.Contains(DynamicDayOfWeek.Weekday) || + days.Contains(DynamicDayOfWeek.Everyday)) + { + list.Add(DayOfWeek.Tuesday); + } + + if (days.Contains(DynamicDayOfWeek.Wednesday) || + days.Contains(DynamicDayOfWeek.Weekday) || + days.Contains(DynamicDayOfWeek.Everyday)) + { + list.Add(DayOfWeek.Wednesday); + } + + if (days.Contains(DynamicDayOfWeek.Thursday) || + days.Contains(DynamicDayOfWeek.Weekday) || + days.Contains(DynamicDayOfWeek.Everyday)) + { + list.Add(DayOfWeek.Thursday); + } + + if (days.Contains(DynamicDayOfWeek.Friday) || + days.Contains(DynamicDayOfWeek.Weekday) || + days.Contains(DynamicDayOfWeek.Everyday)) + { + list.Add(DayOfWeek.Friday); + } + + return list; + } + } +} diff --git a/Jellyfin.Data/Entities/AccessSchedule.cs b/Jellyfin.Data/Entities/AccessSchedule.cs new file mode 100644 index 000000000..7966cdb50 --- /dev/null +++ b/Jellyfin.Data/Entities/AccessSchedule.cs @@ -0,0 +1,68 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using Jellyfin.Data.Enums; + +namespace Jellyfin.Data.Entities +{ + public class AccessSchedule + { + /// + /// Initializes a new instance of the class. + /// Default constructor. Protected due to required properties, but present because EF needs it. + /// + protected AccessSchedule() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The day of the week. + /// The start hour. + /// The end hour. + public AccessSchedule(DynamicDayOfWeek dayOfWeek, double startHour, double endHour) + { + DayOfWeek = dayOfWeek; + StartHour = startHour; + EndHour = endHour; + } + + /// + /// Factory method + /// + /// The day of the week. + /// The start hour. + /// The end hour. + /// The newly created instance. + public static AccessSchedule CreateInstance(DynamicDayOfWeek dayOfWeek, double startHour, double endHour) + { + return new AccessSchedule(dayOfWeek, startHour, endHour); + } + + [Key] + [Required] + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int Id { get; protected set; } + + /// + /// Gets or sets the day of week. + /// + /// The day of week. + [Required] + public DynamicDayOfWeek DayOfWeek { get; set; } + + /// + /// Gets or sets the start hour. + /// + /// The start hour. + [Required] + public double StartHour { get; set; } + + /// + /// Gets or sets the end hour. + /// + /// The end hour. + [Required] + public double EndHour { get; set; } + } +} diff --git a/Jellyfin.Data/Entities/ImageInfo.cs b/Jellyfin.Data/Entities/ImageInfo.cs new file mode 100644 index 000000000..336c13b36 --- /dev/null +++ b/Jellyfin.Data/Entities/ImageInfo.cs @@ -0,0 +1,25 @@ +using System; +using System.ComponentModel.DataAnnotations; + +namespace Jellyfin.Data.Entities +{ + public class ImageInfo + { + public ImageInfo(string path) + { + Path = path; + LastModified = DateTime.UtcNow; + } + + [Key] + [Required] + + public int Id { get; protected set; } + + [Required] + public string Path { get; set; } + + [Required] + public DateTime LastModified { get; set; } + } +} diff --git a/Jellyfin.Data/Entities/User.cs b/Jellyfin.Data/Entities/User.cs index 715969dbf..1aaa8a180 100644 --- a/Jellyfin.Data/Entities/User.cs +++ b/Jellyfin.Data/Entities/User.cs @@ -1,18 +1,20 @@ using System; using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.ComponentModel; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; +using System.Globalization; using System.Linq; -using System.Runtime.CompilerServices; +using Jellyfin.Data.Enums; namespace Jellyfin.Data.Entities { [Table("User")] - public partial class User + public class User { - partial void Init(); + /// + /// The values being delimited here are Guids, so commas work as they do not appear in Guids. + /// + private const char Delimiter = ','; /// /// Default constructor. Protected due to required properties, but present because EF needs it. @@ -23,69 +25,86 @@ namespace Jellyfin.Data.Entities Permissions = new HashSet(); ProviderMappings = new HashSet(); Preferences = new HashSet(); - - Init(); + AccessSchedules = new HashSet(); } /// - /// Replaces default constructor, since it's protected. Caller assumes responsibility for setting all required values before saving. + /// Public constructor with required data /// - public static User CreateUserUnsafe() + /// + /// + /// + /// + /// + /// + public User( + string username, + bool mustUpdatePassword, + string authenticationProviderId, + int invalidLoginAttemptCount, + SubtitlePlaybackMode subtitleMode, + bool playDefaultAudioTrack) { - return new User(); + if (string.IsNullOrEmpty(username)) + { + throw new ArgumentNullException(nameof(username)); + } + + if (string.IsNullOrEmpty(authenticationProviderId)) + { + throw new ArgumentNullException(nameof(authenticationProviderId)); + } + + Username = username; + MustUpdatePassword = mustUpdatePassword; + AuthenticationProviderId = authenticationProviderId; + InvalidLoginAttemptCount = invalidLoginAttemptCount; + SubtitleMode = subtitleMode; + PlayDefaultAudioTrack = playDefaultAudioTrack; + + Groups = new HashSet(); + Permissions = new HashSet(); + ProviderMappings = new HashSet(); + Preferences = new HashSet(); + AccessSchedules = new HashSet(); + + // Set default values + Id = Guid.NewGuid(); + DisplayMissingEpisodes = false; + DisplayCollectionsView = false; + HidePlayedInLatest = true; + RememberAudioSelections = true; + RememberSubtitleSelections = true; + EnableNextEpisodeAutoPlay = true; + EnableAutoLogin = false; } /// - /// Public constructor with required data + /// Replaces default constructor, since it's protected. Caller assumes responsibility for setting all required values before saving. /// - /// - /// - /// - /// - /// - /// - /// - public User(string username, bool mustupdatepassword, string audiolanguagepreference, string authenticationproviderid, int invalidloginattemptcount, string subtitlemode, bool playdefaultaudiotrack) + public static User CreateUserUnsafe() { - if (string.IsNullOrEmpty(username)) throw new ArgumentNullException(nameof(username)); - this.Username = username; - - this.MustUpdatePassword = mustupdatepassword; - - if (string.IsNullOrEmpty(audiolanguagepreference)) throw new ArgumentNullException(nameof(audiolanguagepreference)); - this.AudioLanguagePreference = audiolanguagepreference; - - if (string.IsNullOrEmpty(authenticationproviderid)) throw new ArgumentNullException(nameof(authenticationproviderid)); - this.AuthenticationProviderId = authenticationproviderid; - - this.InvalidLoginAttemptCount = invalidloginattemptcount; - - if (string.IsNullOrEmpty(subtitlemode)) throw new ArgumentNullException(nameof(subtitlemode)); - this.SubtitleMode = subtitlemode; - - this.PlayDefaultAudioTrack = playdefaultaudiotrack; - - this.Groups = new HashSet(); - this.Permissions = new HashSet(); - this.ProviderMappings = new HashSet(); - this.Preferences = new HashSet(); - - Init(); + return new User(); } /// /// Static create function (for use in LINQ queries, etc.) /// /// - /// - /// - /// - /// - /// - /// - public static User Create(string username, bool mustupdatepassword, string audiolanguagepreference, string authenticationproviderid, int invalidloginattemptcount, string subtitlemode, bool playdefaultaudiotrack) + /// + /// + /// + /// + /// + public static User Create( + string username, + bool mustUpdatePassword, + string authenticationProviderId, + int invalidLoginAttemptCount, + SubtitlePlaybackMode subtitleMode, + bool playDefaultAudioTrack) { - return new User(username, mustupdatepassword, audiolanguagepreference, authenticationproviderid, invalidloginattemptcount, subtitlemode, playdefaultaudiotrack); + return new User(username, mustUpdatePassword, authenticationProviderId, invalidLoginAttemptCount, subtitleMode, playDefaultAudioTrack); } /************************************************************************* @@ -97,8 +116,7 @@ namespace Jellyfin.Data.Entities /// [Key] [Required] - [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public int Id { get; protected set; } + public Guid Id { get; protected set; } /// /// Required, Max length = 255 @@ -115,6 +133,13 @@ namespace Jellyfin.Data.Entities [StringLength(65535)] public string Password { get; set; } + /// + /// Max length = 65535. + /// + [MaxLength(65535)] + [StringLength(65535)] + public string EasyPassword { get; set; } + /// /// Required /// @@ -122,9 +147,8 @@ namespace Jellyfin.Data.Entities public bool MustUpdatePassword { get; set; } /// - /// Required, Max length = 255 + /// Max length = 255. /// - [Required] [MaxLength(255)] [StringLength(255)] public string AudioLanguagePreference { get; set; } @@ -137,12 +161,10 @@ namespace Jellyfin.Data.Entities [StringLength(255)] public string AuthenticationProviderId { get; set; } - /// - /// Max length = 65535 - /// - [MaxLength(65535)] - [StringLength(65535)] - public string GroupedFolders { get; set; } + [Required] + [MaxLength(255)] + [StringLength(255)] + public string PasswordResetProviderId { get; set; } /// /// Required @@ -150,36 +172,17 @@ namespace Jellyfin.Data.Entities [Required] public int InvalidLoginAttemptCount { get; set; } - /// - /// Max length = 65535 - /// - [MaxLength(65535)] - [StringLength(65535)] - public string LatestItemExcludes { get; set; } + public DateTime LastActivityDate { get; set; } - public int? LoginAttemptsBeforeLockout { get; set; } + public DateTime LastLoginDate { get; set; } - /// - /// Max length = 65535 - /// - [MaxLength(65535)] - [StringLength(65535)] - public string MyMediaExcludes { get; set; } - - /// - /// Max length = 65535 - /// - [MaxLength(65535)] - [StringLength(65535)] - public string OrderedViews { get; set; } + public int? LoginAttemptsBeforeLockout { get; set; } /// - /// Required, Max length = 255 + /// Required. /// [Required] - [MaxLength(255)] - [StringLength(255)] - public string SubtitleMode { get; set; } + public SubtitlePlaybackMode SubtitleMode { get; set; } /// /// Required @@ -192,21 +195,47 @@ namespace Jellyfin.Data.Entities /// [MaxLength(255)] [StringLength(255)] - public string SubtitleLanguagePrefernce { get; set; } + public string SubtitleLanguagePreference { get; set; } + + [Required] + public bool DisplayMissingEpisodes { get; set; } + + [Required] + public bool DisplayCollectionsView { get; set; } + + [Required] + public bool EnableLocalPassword { get; set; } + + [Required] + public bool HidePlayedInLatest { get; set; } + + [Required] + public bool RememberAudioSelections { get; set; } - public bool? DisplayMissingEpisodes { get; set; } + [Required] + public bool RememberSubtitleSelections { get; set; } - public bool? DisplayCollectionsView { get; set; } + [Required] + public bool EnableNextEpisodeAutoPlay { get; set; } + + [Required] + public bool EnableAutoLogin { get; set; } - public bool? HidePlayedInLatest { get; set; } + [Required] + public bool EnableUserPreferenceAccess { get; set; } - public bool? RememberAudioSelections { get; set; } + public int? MaxParentalAgeRating { get; set; } - public bool? RememberSubtitleSelections { get; set; } + public int? RemoteClientBitrateLimit { get; set; } - public bool? EnableNextEpisodeAutoPlay { get; set; } + /// + /// This is a temporary stopgap for until the library db is migrated. + /// This corresponds to the value of the index of this user in the library db. + /// + [Required] + public long InternalId { get; set; } - public bool? EnableUserPreferenceAccess { get; set; } + public ImageInfo ProfileImage { get; set; } /// /// Required, ConcurrenyToken @@ -224,17 +253,76 @@ namespace Jellyfin.Data.Entities * Navigation properties *************************************************************************/ [ForeignKey("Group_Groups_Id")] - public virtual ICollection Groups { get; protected set; } + public ICollection Groups { get; protected set; } [ForeignKey("Permission_Permissions_Id")] - public virtual ICollection Permissions { get; protected set; } + public ICollection Permissions { get; protected set; } [ForeignKey("ProviderMapping_ProviderMappings_Id")] - public virtual ICollection ProviderMappings { get; protected set; } + public ICollection ProviderMappings { get; protected set; } [ForeignKey("Preference_Preferences_Id")] - public virtual ICollection Preferences { get; protected set; } + public ICollection Preferences { get; protected set; } + public ICollection AccessSchedules { get; protected set; } + + public bool HasPermission(PermissionKind permission) + { + return Permissions.Select(p => p.Kind).Contains(permission); + } + + public void SetPermission(PermissionKind kind, bool value) + { + var permissionObj = Permissions.First(p => p.Kind == kind); + permissionObj.Value = value; + } + + public string[] GetPreference(PreferenceKind preference) + { + return Preferences + .Where(p => p.Kind == preference) + .Select(p => p.Value) + .First() + .Split(Delimiter); + } + + public void SetPreference(PreferenceKind preference, string[] values) + { + var pref = Preferences.First(p => p.Kind == preference); + + pref.Value = string.Join(Delimiter.ToString(CultureInfo.InvariantCulture), values); + } + + public bool IsParentalScheduleAllowed() + { + var schedules = this.AccessSchedules; + + return schedules.Count == 0 || schedules.Any(i => IsParentalScheduleAllowed(i, DateTime.Now)); + } + + public bool IsFolderGrouped(Guid id) + { + return GetPreference(PreferenceKind.GroupedFolders).Any(i => new Guid(i) == id); + } + + private bool IsParentalScheduleAllowed(AccessSchedule schedule, DateTime date) + { + if (date.Kind != DateTimeKind.Utc) + { + throw new ArgumentException("Utc date expected"); + } + + var localTime = date.ToLocalTime(); + + return DayOfWeekHelper.GetDaysOfWeek(schedule.DayOfWeek).Contains(localTime.DayOfWeek) && + IsWithinTime(schedule, localTime); + } + + private bool IsWithinTime(AccessSchedule schedule, DateTime localTime) + { + var hour = localTime.TimeOfDay.TotalHours; + + return hour >= schedule.StartHour && hour <= schedule.EndHour; + } } } - diff --git a/Jellyfin.Data/Enums/DynamicDayOfWeek.cs b/Jellyfin.Data/Enums/DynamicDayOfWeek.cs new file mode 100644 index 000000000..a33cd9d1c --- /dev/null +++ b/Jellyfin.Data/Enums/DynamicDayOfWeek.cs @@ -0,0 +1,18 @@ +#pragma warning disable CS1591 + +namespace Jellyfin.Data.Enums +{ + public enum DynamicDayOfWeek + { + Sunday = 0, + Monday = 1, + Tuesday = 2, + Wednesday = 3, + Thursday = 4, + Friday = 5, + Saturday = 6, + Everyday = 7, + Weekday = 8, + Weekend = 9 + } +} diff --git a/Jellyfin.Data/Enums/PermissionKind.cs b/Jellyfin.Data/Enums/PermissionKind.cs index 4447fdb77..df18261e6 100644 --- a/Jellyfin.Data/Enums/PermissionKind.cs +++ b/Jellyfin.Data/Enums/PermissionKind.cs @@ -1,14 +1,11 @@ -using System; - namespace Jellyfin.Data.Enums { - public enum PermissionKind : Int32 + public enum PermissionKind { IsAdministrator, IsHidden, IsDisabled, - BlockUnrateditems, - EnbleSharedDeviceControl, + EnableSharedDeviceControl, EnableRemoteAccess, EnableLiveTvManagement, EnableLiveTvAccess, @@ -23,6 +20,8 @@ namespace Jellyfin.Data.Enums EnableAllChannels, EnableAllFolders, EnablePublicSharing, - AccessSchedules + EnableRemoteControlOfOtherUsers, + EnablePlaybackRemuxing, + ForceRemoteSourceTranscoding } } diff --git a/Jellyfin.Data/Enums/PreferenceKind.cs b/Jellyfin.Data/Enums/PreferenceKind.cs index e66a51cae..34e20ead6 100644 --- a/Jellyfin.Data/Enums/PreferenceKind.cs +++ b/Jellyfin.Data/Enums/PreferenceKind.cs @@ -2,14 +2,19 @@ using System; namespace Jellyfin.Data.Enums { - public enum PreferenceKind : Int32 + public enum PreferenceKind { - MaxParentalRating, BlockedTags, - RemoteClientBitrateLimit, + BlockedChannels, + BlockedMediaFolders, EnabledDevices, EnabledChannels, EnabledFolders, - EnableContentDeletionFromFolders + EnableContentDeletionFromFolders, + LatestItemExcludes, + MyMediaExcludes, + GroupedFolders, + BlockUnratedItems, + OrderedViews } } diff --git a/Jellyfin.Data/Enums/SubtitlePlaybackMode.cs b/Jellyfin.Data/Enums/SubtitlePlaybackMode.cs new file mode 100644 index 000000000..c8fc21159 --- /dev/null +++ b/Jellyfin.Data/Enums/SubtitlePlaybackMode.cs @@ -0,0 +1,13 @@ +#pragma warning disable CS1591 + +namespace Jellyfin.Data.Enums +{ + public enum SubtitlePlaybackMode + { + Default = 0, + Always = 1, + OnlyForced = 2, + None = 3, + Smart = 4 + } +} diff --git a/Jellyfin.Data/Enums/UnratedItem.cs b/Jellyfin.Data/Enums/UnratedItem.cs new file mode 100644 index 000000000..5259e7739 --- /dev/null +++ b/Jellyfin.Data/Enums/UnratedItem.cs @@ -0,0 +1,17 @@ +#pragma warning disable CS1591 + +namespace Jellyfin.Data.Enums +{ + public enum UnratedItem + { + Movie, + Trailer, + Series, + Music, + Book, + LiveTvChannel, + LiveTvProgram, + ChannelContent, + Other + } +} diff --git a/Jellyfin.Server.Implementations/JellyfinDb.cs b/Jellyfin.Server.Implementations/JellyfinDb.cs index 8b6b7cacc..7e1314690 100644 --- a/Jellyfin.Server.Implementations/JellyfinDb.cs +++ b/Jellyfin.Server.Implementations/JellyfinDb.cs @@ -20,7 +20,7 @@ namespace Jellyfin.Server.Implementations public virtual DbSet Permissions { get; set; } public virtual DbSet Preferences { get; set; } public virtual DbSet ProviderMappings { get; set; } - public virtual DbSet Users { get; set; } + public virtual DbSet Users { get; set; } /*public virtual DbSet Artwork { get; set; } public virtual DbSet Books { get; set; } public virtual DbSet BookMetadata { get; set; } diff --git a/Jellyfin.Server.Implementations/User/DefaultAuthenticationProvider.cs b/Jellyfin.Server.Implementations/User/DefaultAuthenticationProvider.cs new file mode 100644 index 000000000..024500bf8 --- /dev/null +++ b/Jellyfin.Server.Implementations/User/DefaultAuthenticationProvider.cs @@ -0,0 +1,185 @@ +using System; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using MediaBrowser.Common; +using MediaBrowser.Common.Cryptography; +using MediaBrowser.Controller.Authentication; +using MediaBrowser.Model.Cryptography; + +namespace Jellyfin.Server.Implementations.User +{ + /// + /// The default authentication provider. + /// + public class DefaultAuthenticationProvider : IAuthenticationProvider, IRequiresResolvedUser + { + private readonly ICryptoProvider _cryptographyProvider; + + /// + /// Initializes a new instance of the class. + /// + /// The cryptography provider. + public DefaultAuthenticationProvider(ICryptoProvider cryptographyProvider) + { + _cryptographyProvider = cryptographyProvider; + } + + /// + public string Name => "Default"; + + /// + public bool IsEnabled => true; + + /// + // This is dumb and an artifact of the backwards way auth providers were designed. + // This version of authenticate was never meant to be called, but needs to be here for interface compat + // Only the providers that don't provide local user support use this + public Task Authenticate(string username, string password) + { + throw new NotImplementedException(); + } + + /// + // This is the version that we need to use for local users. Because reasons. + public Task Authenticate(string username, string password, Data.Entities.User resolvedUser) + { + if (resolvedUser == null) + { + throw new AuthenticationException("Specified user does not exist."); + } + + bool success = false; + + // As long as jellyfin supports passwordless users, we need this little block here to accommodate + if (!HasPassword(resolvedUser)) + { + return Task.FromResult(new ProviderAuthenticationResult + { + Username = username + }); + } + + byte[] passwordBytes = Encoding.UTF8.GetBytes(password); + + PasswordHash readyHash = PasswordHash.Parse(resolvedUser.Password); + if (_cryptographyProvider.GetSupportedHashMethods().Contains(readyHash.Id) + || _cryptographyProvider.DefaultHashMethod == readyHash.Id) + { + byte[] calculatedHash = _cryptographyProvider.ComputeHash( + readyHash.Id, + passwordBytes, + readyHash.Salt.ToArray()); + + if (readyHash.Hash.SequenceEqual(calculatedHash)) + { + success = true; + } + } + else + { + throw new AuthenticationException($"Requested crypto method not available in provider: {readyHash.Id}"); + } + + if (!success) + { + throw new AuthenticationException("Invalid username or password"); + } + + return Task.FromResult(new ProviderAuthenticationResult + { + Username = username + }); + } + + /// + public bool HasPassword(Data.Entities.User user) + => !string.IsNullOrEmpty(user.Password); + + /// + public Task ChangePassword(Data.Entities.User user, string newPassword) + { + if (string.IsNullOrEmpty(newPassword)) + { + user.Password = null; + return Task.CompletedTask; + } + + PasswordHash newPasswordHash = _cryptographyProvider.CreatePasswordHash(newPassword); + user.Password = newPasswordHash.ToString(); + + return Task.CompletedTask; + } + + /// + public void ChangeEasyPassword(Data.Entities.User user, string newPassword, string newPasswordHash) + { + if (newPassword != null) + { + newPasswordHash = _cryptographyProvider.CreatePasswordHash(newPassword).ToString(); + } + + if (string.IsNullOrWhiteSpace(newPasswordHash)) + { + throw new ArgumentNullException(nameof(newPasswordHash)); + } + + user.EasyPassword = newPasswordHash; + } + + /// + public string GetEasyPasswordHash(Data.Entities.User user) + { + return string.IsNullOrEmpty(user.EasyPassword) + ? null + : Hex.Encode(PasswordHash.Parse(user.EasyPassword).Hash); + } + + /// + /// Hashes the provided string. + /// + /// The user. + /// The string to hash. + /// The hashed string. + public string GetHashedString(Data.Entities.User user, string str) + { + if (string.IsNullOrEmpty(user.Password)) + { + return _cryptographyProvider.CreatePasswordHash(str).ToString(); + } + + // TODO: make use of iterations parameter? + PasswordHash passwordHash = PasswordHash.Parse(user.Password); + var salt = passwordHash.Salt.ToArray(); + return new PasswordHash( + passwordHash.Id, + _cryptographyProvider.ComputeHash( + passwordHash.Id, + Encoding.UTF8.GetBytes(str), + salt), + salt, + passwordHash.Parameters.ToDictionary(x => x.Key, y => y.Value)).ToString(); + } + + /// + /// Hashes the provided string. + /// + /// The user. + /// The string to hash. + /// The hashed string. + public ReadOnlySpan GetHashed(Data.Entities.User user, string str) + { + if (string.IsNullOrEmpty(user.Password)) + { + return _cryptographyProvider.CreatePasswordHash(str).Hash; + } + + // TODO: make use of iterations parameter? + PasswordHash passwordHash = PasswordHash.Parse(user.Password); + return _cryptographyProvider.ComputeHash( + passwordHash.Id, + Encoding.UTF8.GetBytes(str), + passwordHash.Salt.ToArray()); + } + } +} diff --git a/Jellyfin.Server.Implementations/User/DefaultPasswordResetProvider.cs b/Jellyfin.Server.Implementations/User/DefaultPasswordResetProvider.cs new file mode 100644 index 000000000..80ab3ce00 --- /dev/null +++ b/Jellyfin.Server.Implementations/User/DefaultPasswordResetProvider.cs @@ -0,0 +1,126 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Security.Cryptography; +using System.Threading.Tasks; +using MediaBrowser.Common.Extensions; +using MediaBrowser.Controller.Authentication; +using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Library; +using MediaBrowser.Model.Serialization; +using MediaBrowser.Model.Users; + +namespace Jellyfin.Server.Implementations.User +{ + /// + /// The default password reset provider. + /// + public class DefaultPasswordResetProvider : IPasswordResetProvider + { + private const string BaseResetFileName = "passwordreset"; + + private readonly IJsonSerializer _jsonSerializer; + private readonly IUserManager _userManager; + + private readonly string _passwordResetFileBase; + private readonly string _passwordResetFileBaseDir; + + /// + /// Initializes a new instance of the class. + /// + /// The configuration manager. + /// The JSON serializer. + /// The user manager. + public DefaultPasswordResetProvider( + IServerConfigurationManager configurationManager, + IJsonSerializer jsonSerializer, + IUserManager userManager) + { + _passwordResetFileBaseDir = configurationManager.ApplicationPaths.ProgramDataPath; + _passwordResetFileBase = Path.Combine(_passwordResetFileBaseDir, BaseResetFileName); + _jsonSerializer = jsonSerializer; + _userManager = userManager; + } + + /// + public string Name => "Default Password Reset Provider"; + + /// + public bool IsEnabled => true; + + /// + public async Task RedeemPasswordResetPin(string pin) + { + SerializablePasswordReset spr; + List usersReset = new List(); + foreach (var resetFile in Directory.EnumerateFiles(_passwordResetFileBaseDir, $"{BaseResetFileName}*")) + { + await using (var str = File.OpenRead(resetFile)) + { + spr = await _jsonSerializer.DeserializeFromStreamAsync(str).ConfigureAwait(false); + } + + if (spr.ExpirationDate < DateTime.Now) + { + File.Delete(resetFile); + } + else if (string.Equals( + spr.Pin.Replace("-", string.Empty, StringComparison.Ordinal), + pin.Replace("-", string.Empty, StringComparison.Ordinal), + StringComparison.InvariantCultureIgnoreCase)) + { + var resetUser = _userManager.GetUserByName(spr.UserName); + if (resetUser == null) + { + throw new ResourceNotFoundException($"User with a username of {spr.UserName} not found"); + } + + await _userManager.ChangePassword(resetUser, pin).ConfigureAwait(false); + usersReset.Add(resetUser.Username); + File.Delete(resetFile); + } + } + + if (usersReset.Count < 1) + { + throw new ResourceNotFoundException($"No Users found with a password reset request matching pin {pin}"); + } + + return new PinRedeemResult + { + Success = true, + UsersReset = usersReset.ToArray() + }; + } + + /// + public async Task StartForgotPasswordProcess(Jellyfin.Data.Entities.User user, bool isInNetwork) + { + string pin; + using (var cryptoRandom = RandomNumberGenerator.Create()) + { + byte[] bytes = new byte[4]; + cryptoRandom.GetBytes(bytes); + pin = BitConverter.ToString(bytes); + } + + DateTime expireTime = DateTime.Now.AddMinutes(30); + + user.EasyPassword = pin; + await _userManager.UpdateUserAsync(user).ConfigureAwait(false); + + return new ForgotPasswordResult + { + Action = ForgotPasswordAction.PinCode, + PinExpirationDate = expireTime, + }; + } + + private class SerializablePasswordReset : PasswordPinCreationResult + { + public string Pin { get; set; } + + public string UserName { get; set; } + } + } +} diff --git a/Jellyfin.Server.Implementations/User/DeviceAccessEntryPoint.cs b/Jellyfin.Server.Implementations/User/DeviceAccessEntryPoint.cs new file mode 100644 index 000000000..d33034ab2 --- /dev/null +++ b/Jellyfin.Server.Implementations/User/DeviceAccessEntryPoint.cs @@ -0,0 +1,65 @@ +#pragma warning disable CS1591 + +using System.Threading.Tasks; +using Jellyfin.Data.Enums; +using MediaBrowser.Controller.Devices; +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Plugins; +using MediaBrowser.Controller.Security; +using MediaBrowser.Controller.Session; +using MediaBrowser.Model.Events; + +namespace Jellyfin.Server.Implementations.User +{ + public sealed class DeviceAccessEntryPoint : IServerEntryPoint + { + private readonly IUserManager _userManager; + private readonly IAuthenticationRepository _authRepo; + private readonly IDeviceManager _deviceManager; + private readonly ISessionManager _sessionManager; + + public DeviceAccessEntryPoint(IUserManager userManager, IAuthenticationRepository authRepo, IDeviceManager deviceManager, ISessionManager sessionManager) + { + _userManager = userManager; + _authRepo = authRepo; + _deviceManager = deviceManager; + _sessionManager = sessionManager; + } + + public Task RunAsync() + { + _userManager.OnUserUpdated += OnUserUpdated; + + return Task.CompletedTask; + } + + private void OnUserUpdated(object sender, GenericEventArgs e) + { + var user = e.Argument; + if (!user.HasPermission(PermissionKind.EnableAllDevices)) + { + UpdateDeviceAccess(user); + } + } + + public void Dispose() + { + } + + private void UpdateDeviceAccess(Data.Entities.User user) + { + var existing = _authRepo.Get(new AuthenticationInfoQuery + { + UserId = user.Id + }).Items; + + foreach (var authInfo in existing) + { + if (!string.IsNullOrEmpty(authInfo.DeviceId) && !_deviceManager.CanAccessDevice(user, authInfo.DeviceId)) + { + _sessionManager.Logout(authInfo); + } + } + } + } +} diff --git a/Jellyfin.Server.Implementations/User/InvalidAuthProvider.cs b/Jellyfin.Server.Implementations/User/InvalidAuthProvider.cs new file mode 100644 index 000000000..a11ca128a --- /dev/null +++ b/Jellyfin.Server.Implementations/User/InvalidAuthProvider.cs @@ -0,0 +1,47 @@ +using System.Threading.Tasks; +using MediaBrowser.Controller.Authentication; + +namespace Jellyfin.Server.Implementations.User +{ + /// + /// An invalid authentication provider. + /// + public class InvalidAuthProvider : IAuthenticationProvider + { + /// + public string Name => "InvalidOrMissingAuthenticationProvider"; + + /// + public bool IsEnabled => true; + + /// + public Task Authenticate(string username, string password) + { + throw new AuthenticationException("User Account cannot login with this provider. The Normal provider for this user cannot be found"); + } + + /// + public bool HasPassword(Data.Entities.User user) + { + return true; + } + + /// + public Task ChangePassword(Data.Entities.User user, string newPassword) + { + return Task.CompletedTask; + } + + /// + public void ChangeEasyPassword(Data.Entities.User user, string newPassword, string newPasswordHash) + { + // Nothing here + } + + /// + public string GetEasyPasswordHash(Data.Entities.User user) + { + return string.Empty; + } + } +} diff --git a/Jellyfin.Server.Implementations/User/UserManager.cs b/Jellyfin.Server.Implementations/User/UserManager.cs new file mode 100644 index 000000000..1ed11cfcb --- /dev/null +++ b/Jellyfin.Server.Implementations/User/UserManager.cs @@ -0,0 +1,749 @@ +#pragma warning disable CS0067 +#pragma warning disable CS1591 + +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Jellyfin.Data.Enums; +using MediaBrowser.Common.Cryptography; +using MediaBrowser.Common.Net; +using MediaBrowser.Controller.Authentication; +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Net; +using MediaBrowser.Model.Configuration; +using MediaBrowser.Model.Cryptography; +using MediaBrowser.Model.Dto; +using MediaBrowser.Model.Events; +using MediaBrowser.Model.Users; +using Microsoft.Extensions.Logging; + +namespace Jellyfin.Server.Implementations.User +{ + public class UserManager : IUserManager + { + private readonly JellyfinDbProvider _dbProvider; + private readonly ICryptoProvider _cryptoProvider; + private readonly INetworkManager _networkManager; + private readonly ILogger _logger; + + private IAuthenticationProvider[] _authenticationProviders; + private DefaultAuthenticationProvider _defaultAuthenticationProvider; + private InvalidAuthProvider _invalidAuthProvider; + private IPasswordResetProvider[] _passwordResetProviders; + private DefaultPasswordResetProvider _defaultPasswordResetProvider; + + public UserManager( + JellyfinDbProvider dbProvider, + ICryptoProvider cryptoProvider, + INetworkManager networkManager, + ILogger logger) + { + _dbProvider = dbProvider; + _cryptoProvider = cryptoProvider; + _networkManager = networkManager; + _logger = logger; + } + + public event EventHandler> OnUserPasswordChanged; + + /// + public event EventHandler> OnUserUpdated; + + /// + public event EventHandler> OnUserCreated; + + /// + public event EventHandler> OnUserDeleted; + + public event EventHandler> OnUserLockedOut; + + public IEnumerable Users + { + get + { + using var dbContext = _dbProvider.CreateContext(); + return dbContext.Users; + } + } + + public IEnumerable UsersIds + { + get + { + using var dbContext = _dbProvider.CreateContext(); + return dbContext.Users.Select(u => u.Id); + } + } + + public Data.Entities.User GetUserById(Guid id) + { + if (id == Guid.Empty) + { + throw new ArgumentException("Guid can't be empty", nameof(id)); + } + + using var dbContext = _dbProvider.CreateContext(); + + return dbContext.Users.Find(id); + } + + public Data.Entities.User GetUserByName(string name) + { + if (string.IsNullOrWhiteSpace(name)) + { + throw new ArgumentException("Invalid username", nameof(name)); + } + + using var dbContext = _dbProvider.CreateContext(); + + return dbContext.Users.FirstOrDefault(u => + string.Equals(u.Username, name, StringComparison.OrdinalIgnoreCase)); + } + + public async Task RenameUser(Data.Entities.User user, string newName) + { + if (user == null) + { + throw new ArgumentNullException(nameof(user)); + } + + if (string.IsNullOrWhiteSpace(newName)) + { + throw new ArgumentException("Invalid username", nameof(newName)); + } + + if (user.Username.Equals(newName, StringComparison.Ordinal)) + { + throw new ArgumentException("The new and old names must be different."); + } + + if (Users.Any( + u => u.Id != user.Id && u.Username.Equals(newName, StringComparison.OrdinalIgnoreCase))) + { + throw new ArgumentException(string.Format( + CultureInfo.InvariantCulture, + "A user with the name '{0}' already exists.", + newName)); + } + + user.Username = newName; + await UpdateUserAsync(user).ConfigureAwait(false); + + OnUserUpdated?.Invoke(this, new GenericEventArgs(user)); + } + + public void UpdateUser(Data.Entities.User user) + { + using var dbContext = _dbProvider.CreateContext(); + dbContext.Users.Update(user); + dbContext.SaveChanges(); + } + + public async Task UpdateUserAsync(Data.Entities.User user) + { + await using var dbContext = _dbProvider.CreateContext(); + dbContext.Users.Update(user); + + await dbContext.SaveChangesAsync().ConfigureAwait(false); + } + + public Data.Entities.User CreateUser(string name) + { + using var dbContext = _dbProvider.CreateContext(); + + var newUser = CreateUserObject(name); + dbContext.Users.Add(newUser); + dbContext.SaveChanges(); + + return newUser; + } + + public void DeleteUser(Data.Entities.User user) + { + if (user == null) + { + throw new ArgumentNullException(nameof(user)); + } + + using var dbContext = _dbProvider.CreateContext(); + + if (!dbContext.Users.Contains(user)) + { + throw new ArgumentException(string.Format( + CultureInfo.InvariantCulture, + "The user cannot be deleted because there is no user with the Name {0} and Id {1}.", + user.Username, + user.Id)); + } + + if (dbContext.Users.Count() == 1) + { + throw new InvalidOperationException(string.Format( + CultureInfo.InvariantCulture, + "The user '{0}' cannot be deleted because there must be at least one user in the system.", + user.Username)); + } + + if (user.HasPermission(PermissionKind.IsAdministrator) + && Users.Count(i => i.HasPermission(PermissionKind.IsAdministrator)) == 1) + { + throw new ArgumentException( + string.Format( + CultureInfo.InvariantCulture, + "The user '{0}' cannot be deleted because there must be at least one admin user in the system.", + user.Username), + nameof(user)); + } + + dbContext.Users.Remove(user); + dbContext.SaveChanges(); + } + + public Task ResetPassword(Data.Entities.User user) + { + return ChangePassword(user, string.Empty); + } + + public void ResetEasyPassword(Data.Entities.User user) + { + ChangeEasyPassword(user, string.Empty, null); + } + + public async Task ChangePassword(Data.Entities.User user, string newPassword) + { + if (user == null) + { + throw new ArgumentNullException(nameof(user)); + } + + await GetAuthenticationProvider(user).ChangePassword(user, newPassword).ConfigureAwait(false); + await UpdateUserAsync(user).ConfigureAwait(false); + + OnUserPasswordChanged?.Invoke(this, new GenericEventArgs(user)); + } + + public void ChangeEasyPassword(Data.Entities.User user, string newPassword, string newPasswordSha1) + { + if (user == null) + { + throw new ArgumentNullException(nameof(user)); + } + + GetAuthenticationProvider(user).ChangeEasyPassword(user, newPassword, newPasswordSha1); + + UpdateUser(user); + + OnUserPasswordChanged?.Invoke(this, new GenericEventArgs(user)); + } + + public UserDto GetUserDto(Data.Entities.User user, string remoteEndPoint = null) + { + return new UserDto + { + Id = user.Id, + HasPassword = user.Password == null, + EnableAutoLogin = user.EnableAutoLogin, + LastLoginDate = user.LastLoginDate, + LastActivityDate = user.LastActivityDate, + Configuration = new UserConfiguration + { + SubtitleMode = user.SubtitleMode, + HidePlayedInLatest = user.HidePlayedInLatest, + EnableLocalPassword = user.EnableLocalPassword, + PlayDefaultAudioTrack = user.PlayDefaultAudioTrack, + DisplayCollectionsView = user.DisplayCollectionsView, + DisplayMissingEpisodes = user.DisplayMissingEpisodes, + AudioLanguagePreference = user.AudioLanguagePreference, + RememberAudioSelections = user.RememberAudioSelections, + EnableNextEpisodeAutoPlay = user.EnableNextEpisodeAutoPlay, + RememberSubtitleSelections = user.RememberSubtitleSelections, + SubtitleLanguagePreference = user.SubtitleLanguagePreference, + OrderedViews = user.GetPreference(PreferenceKind.OrderedViews), + GroupedFolders = user.GetPreference(PreferenceKind.GroupedFolders), + MyMediaExcludes = user.GetPreference(PreferenceKind.MyMediaExcludes), + LatestItemsExcludes = user.GetPreference(PreferenceKind.LatestItemExcludes) + }, + Policy = new UserPolicy + { + MaxParentalRating = user.MaxParentalAgeRating, + EnableUserPreferenceAccess = user.EnableUserPreferenceAccess, + RemoteClientBitrateLimit = user.RemoteClientBitrateLimit.GetValueOrDefault(), + AuthenticatioIsnProviderId = user.AuthenticationProviderId, + PasswordResetProviderId = user.PasswordResetProviderId, + InvalidLoginAttemptCount = user.InvalidLoginAttemptCount, + LoginAttemptsBeforeLockout = user.LoginAttemptsBeforeLockout.GetValueOrDefault(), + IsAdministrator = user.HasPermission(PermissionKind.IsAdministrator), + IsHidden = user.HasPermission(PermissionKind.IsHidden), + IsDisabled = user.HasPermission(PermissionKind.IsDisabled), + EnableSharedDeviceControl = user.HasPermission(PermissionKind.EnableSharedDeviceControl), + EnableRemoteAccess = user.HasPermission(PermissionKind.EnableRemoteAccess), + EnableLiveTvManagement = user.HasPermission(PermissionKind.EnableLiveTvManagement), + EnableLiveTvAccess = user.HasPermission(PermissionKind.EnableLiveTvAccess), + EnableMediaPlayback = user.HasPermission(PermissionKind.EnableMediaPlayback), + EnableAudioPlaybackTranscoding = user.HasPermission(PermissionKind.EnableAudioPlaybackTranscoding), + EnableVideoPlaybackTranscoding = user.HasPermission(PermissionKind.EnableVideoPlaybackTranscoding), + EnableContentDeletion = user.HasPermission(PermissionKind.EnableContentDeletion), + EnableContentDownloading = user.HasPermission(PermissionKind.EnableContentDownloading), + EnableSyncTranscoding = user.HasPermission(PermissionKind.EnableSyncTranscoding), + EnableMediaConversion = user.HasPermission(PermissionKind.EnableMediaConversion), + EnableAllChannels = user.HasPermission(PermissionKind.EnableAllChannels), + EnableAllDevices = user.HasPermission(PermissionKind.EnableAllDevices), + EnableAllFolders = user.HasPermission(PermissionKind.EnableAllFolders), + EnableRemoteControlOfOtherUsers = user.HasPermission(PermissionKind.EnableRemoteControlOfOtherUsers), + EnablePlaybackRemuxing = user.HasPermission(PermissionKind.EnablePlaybackRemuxing), + ForceRemoteSourceTranscoding = user.HasPermission(PermissionKind.ForceRemoteSourceTranscoding), + EnablePublicSharing = user.HasPermission(PermissionKind.EnablePublicSharing), + AccessSchedules = user.AccessSchedules.ToArray(), + BlockedTags = user.GetPreference(PreferenceKind.BlockedTags), + EnabledChannels = user.GetPreference(PreferenceKind.EnabledChannels), + EnabledDevices = user.GetPreference(PreferenceKind.EnabledDevices), + EnabledFolders = user.GetPreference(PreferenceKind.EnabledFolders), + EnableContentDeletionFromFolders = user.GetPreference(PreferenceKind.EnableContentDeletionFromFolders) + } + }; + } + + public async Task AuthenticateUser( + string username, + string password, + string passwordSha1, + string remoteEndPoint, + bool isUserSession) + { + if (string.IsNullOrWhiteSpace(username)) + { + _logger.LogInformation("Authentication request without username has been denied (IP: {IP}).", remoteEndPoint); + throw new ArgumentNullException(nameof(username)); + } + + var user = Users.FirstOrDefault(i => string.Equals(username, i.Username, StringComparison.OrdinalIgnoreCase)); + bool success; + IAuthenticationProvider authenticationProvider; + + if (user != null) + { + var authResult = await AuthenticateLocalUser(username, password, user, remoteEndPoint) + .ConfigureAwait(false); + authenticationProvider = authResult.authenticationProvider; + success = authResult.success; + } + else + { + var authResult = await AuthenticateLocalUser(username, password, null, remoteEndPoint) + .ConfigureAwait(false); + authenticationProvider = authResult.authenticationProvider; + string updatedUsername = authResult.username; + success = authResult.success; + + if (success + && authenticationProvider != null + && !(authenticationProvider is DefaultAuthenticationProvider)) + { + // Trust the username returned by the authentication provider + username = updatedUsername; + + // Search the database for the user again + // the authentication provider might have created it + user = Users + .FirstOrDefault(i => string.Equals(username, i.Username, StringComparison.OrdinalIgnoreCase)); + + if (authenticationProvider is IHasNewUserPolicy hasNewUserPolicy) + { + UpdatePolicy(user.Id, hasNewUserPolicy.GetNewUserPolicy()); + + await UpdateUserAsync(user).ConfigureAwait(false); + } + } + } + + if (success && user != null && authenticationProvider != null) + { + var providerId = authenticationProvider.GetType().FullName; + + if (!string.Equals(providerId, user.AuthenticationProviderId, StringComparison.OrdinalIgnoreCase)) + { + user.AuthenticationProviderId = providerId; + await UpdateUserAsync(user).ConfigureAwait(false); + } + } + + if (user == null) + { + _logger.LogInformation( + "Authentication request for {UserName} has been denied (IP: {IP}).", + username, + remoteEndPoint); + throw new AuthenticationException("Invalid username or password entered."); + } + + if (user.HasPermission(PermissionKind.IsDisabled)) + { + _logger.LogInformation( + "Authentication request for {UserName} has been denied because this account is currently disabled (IP: {IP}).", + username, + remoteEndPoint); + throw new SecurityException( + $"The {user.Username} account is currently disabled. Please consult with your administrator."); + } + + if (!user.HasPermission(PermissionKind.EnableRemoteAccess) && + !_networkManager.IsInLocalNetwork(remoteEndPoint)) + { + _logger.LogInformation( + "Authentication request for {UserName} forbidden: remote access disabled and user not in local network (IP: {IP}).", + username, + remoteEndPoint); + throw new SecurityException("Forbidden."); + } + + if (!user.IsParentalScheduleAllowed()) + { + _logger.LogInformation( + "Authentication request for {UserName} is not allowed at this time due parental restrictions (IP: {IP}).", + username, + remoteEndPoint); + throw new SecurityException("User is not allowed access at this time."); + } + + // Update LastActivityDate and LastLoginDate, then save + if (success) + { + if (isUserSession) + { + user.LastActivityDate = user.LastLoginDate = DateTime.UtcNow; + UpdateUser(user); + } + + ResetInvalidLoginAttemptCount(user); + _logger.LogInformation("Authentication request for {UserName} has succeeded.", user.Username); + } + else + { + IncrementInvalidLoginAttemptCount(user); + _logger.LogInformation( + "Authentication request for {UserName} has been denied (IP: {IP}).", + user.Username, + remoteEndPoint); + } + + return success ? user : null; + } + + public async Task StartForgotPasswordProcess(string enteredUsername, bool isInNetwork) + { + var user = string.IsNullOrWhiteSpace(enteredUsername) ? null : GetUserByName(enteredUsername); + + var action = ForgotPasswordAction.InNetworkRequired; + + if (user != null && isInNetwork) + { + var passwordResetProvider = GetPasswordResetProvider(user); + return await passwordResetProvider.StartForgotPasswordProcess(user, isInNetwork).ConfigureAwait(false); + } + + return new ForgotPasswordResult + { + Action = action, + PinFile = string.Empty + }; + } + + public async Task RedeemPasswordResetPin(string pin) + { + foreach (var provider in _passwordResetProviders) + { + var result = await provider.RedeemPasswordResetPin(pin).ConfigureAwait(false); + + if (result.Success) + { + return result; + } + } + + return new PinRedeemResult + { + Success = false, + UsersReset = Array.Empty() + }; + } + + public void AddParts(IEnumerable authenticationProviders, IEnumerable passwordResetProviders) + { + _authenticationProviders = authenticationProviders.ToArray(); + + _defaultAuthenticationProvider = _authenticationProviders.OfType().First(); + + _invalidAuthProvider = _authenticationProviders.OfType().First(); + + _passwordResetProviders = passwordResetProviders.ToArray(); + + _defaultPasswordResetProvider = passwordResetProviders.OfType().First(); + } + + public NameIdPair[] GetAuthenticationProviders() + { + return _authenticationProviders + .Where(provider => provider.IsEnabled) + .OrderBy(i => i is DefaultAuthenticationProvider ? 0 : 1) + .ThenBy(i => i.Name) + .Select(i => new NameIdPair + { + Name = i.Name, + Id = i.GetType().FullName + }) + .ToArray(); + } + + public NameIdPair[] GetPasswordResetProviders() + { + return _passwordResetProviders + .Where(provider => provider.IsEnabled) + .OrderBy(i => i is DefaultPasswordResetProvider ? 0 : 1) + .ThenBy(i => i.Name) + .Select(i => new NameIdPair + { + Name = i.Name, + Id = i.GetType().FullName + }) + .ToArray(); + } + + public void UpdateConfiguration(Guid userId, UserConfiguration config) + { + var user = GetUserById(userId); + user.SubtitleMode = config.SubtitleMode; + user.HidePlayedInLatest = config.HidePlayedInLatest; + user.EnableLocalPassword = config.EnableLocalPassword; + user.PlayDefaultAudioTrack = config.PlayDefaultAudioTrack; + user.DisplayCollectionsView = config.DisplayCollectionsView; + user.DisplayMissingEpisodes = config.DisplayMissingEpisodes; + user.AudioLanguagePreference = config.AudioLanguagePreference; + user.RememberAudioSelections = config.RememberAudioSelections; + user.EnableNextEpisodeAutoPlay = config.EnableNextEpisodeAutoPlay; + user.RememberSubtitleSelections = config.RememberSubtitleSelections; + user.SubtitleLanguagePreference = config.SubtitleLanguagePreference; + + user.SetPreference(PreferenceKind.OrderedViews, config.OrderedViews); + user.SetPreference(PreferenceKind.GroupedFolders, config.GroupedFolders); + user.SetPreference(PreferenceKind.MyMediaExcludes, config.MyMediaExcludes); + user.SetPreference(PreferenceKind.LatestItemExcludes, config.LatestItemsExcludes); + + UpdateUser(user); + } + + public void UpdatePolicy(Guid userId, UserPolicy policy) + { + var user = GetUserById(userId); + + user.MaxParentalAgeRating = policy.MaxParentalRating; + user.EnableUserPreferenceAccess = policy.EnableUserPreferenceAccess; + user.RemoteClientBitrateLimit = policy.RemoteClientBitrateLimit; + user.AuthenticationProviderId = policy.AuthenticatioIsnProviderId; + user.PasswordResetProviderId = policy.PasswordResetProviderId; + user.InvalidLoginAttemptCount = policy.InvalidLoginAttemptCount; + user.LoginAttemptsBeforeLockout = policy.LoginAttemptsBeforeLockout == -1 + ? null + : new int?(policy.LoginAttemptsBeforeLockout); + user.SetPermission(PermissionKind.IsAdministrator, policy.IsAdministrator); + user.SetPermission(PermissionKind.IsHidden, policy.IsHidden); + user.SetPermission(PermissionKind.IsDisabled, policy.IsDisabled); + user.SetPermission(PermissionKind.EnableSharedDeviceControl, policy.EnableSharedDeviceControl); + user.SetPermission(PermissionKind.EnableRemoteAccess, policy.EnableRemoteAccess); + user.SetPermission(PermissionKind.EnableLiveTvManagement, policy.EnableLiveTvManagement); + user.SetPermission(PermissionKind.EnableLiveTvAccess, policy.EnableLiveTvAccess); + user.SetPermission(PermissionKind.EnableMediaPlayback, policy.EnableMediaPlayback); + user.SetPermission(PermissionKind.EnableAudioPlaybackTranscoding, policy.EnableAudioPlaybackTranscoding); + user.SetPermission(PermissionKind.EnableVideoPlaybackTranscoding, policy.EnableVideoPlaybackTranscoding); + user.SetPermission(PermissionKind.EnableContentDeletion, policy.EnableContentDeletion); + user.SetPermission(PermissionKind.EnableContentDownloading, policy.EnableContentDownloading); + user.SetPermission(PermissionKind.EnableSyncTranscoding, policy.EnableSyncTranscoding); + user.SetPermission(PermissionKind.EnableMediaConversion, policy.EnableMediaConversion); + user.SetPermission(PermissionKind.EnableAllChannels, policy.EnableAllChannels); + user.SetPermission(PermissionKind.EnableAllDevices, policy.EnableAllDevices); + user.SetPermission(PermissionKind.EnableAllFolders, policy.EnableAllFolders); + user.SetPermission(PermissionKind.EnableRemoteControlOfOtherUsers, policy.EnableRemoteControlOfOtherUsers); + user.SetPermission(PermissionKind.EnablePlaybackRemuxing, policy.EnablePlaybackRemuxing); + user.SetPermission(PermissionKind.ForceRemoteSourceTranscoding, policy.ForceRemoteSourceTranscoding); + user.SetPermission(PermissionKind.EnablePublicSharing, policy.EnablePublicSharing); + + user.AccessSchedules.Clear(); + foreach (var policyAccessSchedule in policy.AccessSchedules) + { + user.AccessSchedules.Add(policyAccessSchedule); + } + + user.SetPreference(PreferenceKind.BlockedTags, policy.BlockedTags); + user.SetPreference(PreferenceKind.EnabledChannels, policy.EnabledChannels); + user.SetPreference(PreferenceKind.EnabledDevices, policy.EnabledDevices); + user.SetPreference(PreferenceKind.EnabledFolders, policy.EnabledFolders); + user.SetPreference(PreferenceKind.EnableContentDeletionFromFolders, policy.EnableContentDeletionFromFolders); + } + + private Data.Entities.User CreateUserObject(string name) + { + return new Data.Entities.User( + username: name, + mustUpdatePassword: false, + authenticationProviderId: _defaultAuthenticationProvider.GetType().FullName, + invalidLoginAttemptCount: -1, + subtitleMode: SubtitlePlaybackMode.Default, + playDefaultAudioTrack: true); + } + + private IAuthenticationProvider GetAuthenticationProvider(Data.Entities.User user) + { + return GetAuthenticationProviders(user)[0]; + } + + private IPasswordResetProvider GetPasswordResetProvider(Data.Entities.User user) + { + return GetPasswordResetProviders(user)[0]; + } + + private IList GetAuthenticationProviders(Data.Entities.User user) + { + var authenticationProviderId = user?.AuthenticationProviderId; + + var providers = _authenticationProviders.Where(i => i.IsEnabled).ToList(); + + if (!string.IsNullOrEmpty(authenticationProviderId)) + { + providers = providers.Where(i => string.Equals(authenticationProviderId, i.GetType().FullName, StringComparison.OrdinalIgnoreCase)).ToList(); + } + + if (providers.Count == 0) + { + // Assign the user to the InvalidAuthProvider since no configured auth provider was valid/found + _logger.LogWarning( + "User {UserName} was found with invalid/missing Authentication Provider {AuthenticationProviderId}. Assigning user to InvalidAuthProvider until this is corrected", + user?.Username, + user?.AuthenticationProviderId); + providers = new List + { + _invalidAuthProvider + }; + } + + return providers; + } + + private IList GetPasswordResetProviders(Data.Entities.User user) + { + var passwordResetProviderId = user?.PasswordResetProviderId; + var providers = _passwordResetProviders.Where(i => i.IsEnabled).ToArray(); + + if (!string.IsNullOrEmpty(passwordResetProviderId)) + { + providers = providers.Where(i => + string.Equals(passwordResetProviderId, i.GetType().FullName, StringComparison.OrdinalIgnoreCase)) + .ToArray(); + } + + if (providers.Length == 0) + { + providers = new IPasswordResetProvider[] + { + _defaultPasswordResetProvider + }; + } + + return providers; + } + + private async Task<(IAuthenticationProvider authenticationProvider, string username, bool success)> + AuthenticateLocalUser( + string username, + string password, + Jellyfin.Data.Entities.User user, + string remoteEndPoint) + { + bool success = false; + IAuthenticationProvider authenticationProvider = null; + + foreach (var provider in GetAuthenticationProviders(user)) + { + var providerAuthResult = + await AuthenticateWithProvider(provider, username, password, user).ConfigureAwait(false); + var updatedUsername = providerAuthResult.username; + success = providerAuthResult.success; + + if (success) + { + authenticationProvider = provider; + username = updatedUsername; + break; + } + } + + if (!success + && _networkManager.IsInLocalNetwork(remoteEndPoint) + && user?.EnableLocalPassword == true + && !string.IsNullOrEmpty(user.EasyPassword)) + { + // Check easy password + var passwordHash = PasswordHash.Parse(user.EasyPassword); + var hash = _cryptoProvider.ComputeHash( + passwordHash.Id, + Encoding.UTF8.GetBytes(password), + passwordHash.Salt.ToArray()); + success = passwordHash.Hash.SequenceEqual(hash); + } + + return (authenticationProvider, username, success); + } + + private async Task<(string username, bool success)> AuthenticateWithProvider( + IAuthenticationProvider provider, + string username, + string password, + Data.Entities.User resolvedUser) + { + try + { + var authenticationResult = provider is IRequiresResolvedUser requiresResolvedUser + ? await requiresResolvedUser.Authenticate(username, password, resolvedUser).ConfigureAwait(false) + : await provider.Authenticate(username, password).ConfigureAwait(false); + + if (authenticationResult.Username != username) + { + _logger.LogDebug("Authentication provider provided updated username {1}", authenticationResult.Username); + username = authenticationResult.Username; + } + + return (username, true); + } + catch (AuthenticationException ex) + { + _logger.LogError(ex, "Error authenticating with provider {Provider}", provider.Name); + + return (username, false); + } + } + + private void IncrementInvalidLoginAttemptCount(Data.Entities.User user) + { + int invalidLogins = user.InvalidLoginAttemptCount; + int? maxInvalidLogins = user.LoginAttemptsBeforeLockout; + if (maxInvalidLogins.HasValue + && invalidLogins >= maxInvalidLogins) + { + user.SetPermission(PermissionKind.IsDisabled, true); + OnUserLockedOut?.Invoke(this, new GenericEventArgs(user)); + _logger.LogWarning( + "Disabling user {UserName} due to {Attempts} unsuccessful login attempts.", + user.Username, + invalidLogins); + } + + UpdateUser(user); + } + + private void ResetInvalidLoginAttemptCount(Data.Entities.User user) + { + user.InvalidLoginAttemptCount = 0; + } + } +} diff --git a/Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs b/Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs new file mode 100644 index 000000000..23d2299cd --- /dev/null +++ b/Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs @@ -0,0 +1,8 @@ +#pragma warning disable CS1591 + +namespace Jellyfin.Server.Migrations.Routines +{ + public class MigrateUserDb + { + } +} diff --git a/MediaBrowser.Api/BaseApiService.cs b/MediaBrowser.Api/BaseApiService.cs index 1a1d86362..a5b504dfa 100644 --- a/MediaBrowser.Api/BaseApiService.cs +++ b/MediaBrowser.Api/BaseApiService.cs @@ -1,6 +1,7 @@ using System; using System.IO; using System.Linq; +using Jellyfin.Data.Enums; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; @@ -94,8 +95,8 @@ namespace MediaBrowser.Api var authenticatedUser = auth.User; // If they're going to update the record of another user, they must be an administrator - if ((!userId.Equals(auth.UserId) && !authenticatedUser.Policy.IsAdministrator) - || (restrictUserPreferences && !authenticatedUser.Policy.EnableUserPreferenceAccess)) + if ((!userId.Equals(auth.UserId) && !authenticatedUser.HasPermission(PermissionKind.IsAdministrator)) + || (restrictUserPreferences && !authenticatedUser.EnableUserPreferenceAccess)) { throw new SecurityException("Unauthorized access."); } diff --git a/MediaBrowser.Api/FilterService.cs b/MediaBrowser.Api/FilterService.cs index 5eb72cdb1..ac61cd491 100644 --- a/MediaBrowser.Api/FilterService.cs +++ b/MediaBrowser.Api/FilterService.cs @@ -220,7 +220,7 @@ namespace MediaBrowser.Api return result; } - private InternalItemsQuery GetItemsQuery(GetQueryFiltersLegacy request, User user) + private InternalItemsQuery GetItemsQuery(GetQueryFiltersLegacy request, Jellyfin.Data.Entities.User user) { var query = new InternalItemsQuery { diff --git a/MediaBrowser.Api/Images/ImageService.cs b/MediaBrowser.Api/Images/ImageService.cs index 2e9b3e6cb..f9976122c 100644 --- a/MediaBrowser.Api/Images/ImageService.cs +++ b/MediaBrowser.Api/Images/ImageService.cs @@ -20,6 +20,7 @@ using MediaBrowser.Model.IO; using MediaBrowser.Model.Services; using Microsoft.Extensions.Logging; using Microsoft.Net.Http.Headers; +using User = Jellyfin.Data.Entities.User; namespace MediaBrowser.Api.Images { @@ -399,14 +400,14 @@ namespace MediaBrowser.Api.Images { var item = _userManager.GetUserById(request.Id); - return GetImage(request, Guid.Empty, item, false); + return GetImage(request, item, false); } public object Head(GetUserImage request) { var item = _userManager.GetUserById(request.Id); - return GetImage(request, Guid.Empty, item, true); + return GetImage(request, item, true); } public object Get(GetItemByNameImage request) @@ -439,9 +440,9 @@ namespace MediaBrowser.Api.Images request.Type = Enum.Parse(GetPathValue(3).ToString(), true); - var item = _userManager.GetUserById(id); + var user = _userManager.GetUserById(id); - return PostImage(item, request.RequestStream, request.Type, Request.ContentType); + return PostImage(user, request.RequestStream, Request.ContentType); } /// @@ -468,9 +469,9 @@ namespace MediaBrowser.Api.Images var userId = request.Id; AssertCanUpdateUser(_authContext, _userManager, userId, true); - var item = _userManager.GetUserById(userId); + var user = _userManager.GetUserById(userId); - item.DeleteImage(request.Type, request.Index ?? 0); + user.ProfileImage = null; } /// @@ -555,18 +556,17 @@ namespace MediaBrowser.Api.Images var imageInfo = GetImageInfo(request, item); if (imageInfo == null) { - var displayText = item == null ? itemId.ToString() : item.Name; - throw new ResourceNotFoundException(string.Format("{0} does not have an image of type {1}", displayText, request.Type)); + throw new ResourceNotFoundException(string.Format("{0} does not have an image of type {1}", item.Name, request.Type)); } - bool cropwhitespace; + bool cropWhitespace; if (request.CropWhitespace.HasValue) { - cropwhitespace = request.CropWhitespace.Value; + cropWhitespace = request.CropWhitespace.Value; } else { - cropwhitespace = request.Type == ImageType.Logo || request.Type == ImageType.Art; + cropWhitespace = request.Type == ImageType.Logo || request.Type == ImageType.Art; } var outputFormats = GetOutputFormats(request); @@ -589,13 +589,94 @@ namespace MediaBrowser.Api.Images itemId, request, imageInfo, - cropwhitespace, + cropWhitespace, outputFormats, cacheDuration, responseHeaders, isHeadRequest); } + public Task GetImage(ImageRequest request, User user, bool isHeadRequest) + { + var imageInfo = GetImageInfo(request, user); + + TimeSpan? cacheDuration = null; + + if (!string.IsNullOrEmpty(request.Tag)) + { + cacheDuration = TimeSpan.FromDays(365); + } + + var responseHeaders = new Dictionary + { + {"transferMode.dlna.org", "Interactive"}, + {"realTimeInfo.dlna.org", "DLNA.ORG_TLAG=*"} + }; + + var outputFormats = GetOutputFormats(request); + + return GetImageResult( + user, + user.Id, + request, + imageInfo, + false, + outputFormats, + cacheDuration, + responseHeaders, + isHeadRequest); + } + + private async Task GetImageResult( + User user, + Guid itemId, + ImageRequest request, + ItemImageInfo info, + bool cropWhitespace, + IReadOnlyCollection supportedFormats, + TimeSpan? cacheDuration, + IDictionary headers, + bool isHeadRequest) + { + var options = new ImageProcessingOptions + { + CropWhiteSpace = true, + Height = request.Height, + ImageIndex = request.Index ?? 0, + Image = info, + Item = null, // Hack alert + ItemId = itemId, + MaxHeight = request.MaxHeight, + MaxWidth = request.MaxWidth, + Quality = request.Quality ?? 100, + Width = request.Width, + AddPlayedIndicator = request.AddPlayedIndicator, + PercentPlayed = 0, + UnplayedCount = request.UnplayedCount, + Blur = request.Blur, + BackgroundColor = request.BackgroundColor, + ForegroundLayer = request.ForegroundLayer, + SupportedOutputFormats = supportedFormats + }; + + var imageResult = await _imageProcessor.ProcessImage(options).ConfigureAwait(false); + + headers[HeaderNames.Vary] = HeaderNames.Accept; + + return await ResultFactory.GetStaticFileResult(Request, new StaticFileResultOptions + { + CacheDuration = cacheDuration, + ResponseHeaders = headers, + ContentType = imageResult.Item2, + DateLastModified = imageResult.Item3, + IsHeadRequest = isHeadRequest, + Path = imageResult.Item1, + + FileShare = FileShare.Read + + }).ConfigureAwait(false); + } + private async Task GetImageResult( BaseItem item, Guid itemId, @@ -740,6 +821,28 @@ namespace MediaBrowser.Api.Images return item.GetImageInfo(request.Type, index); } + private ItemImageInfo GetImageInfo(ImageRequest request, User user) + { + var info = new ItemImageInfo + { + Path = user.ProfileImage.Path, + Type = ImageType.Primary, + DateModified = user.ProfileImage.LastModified, + }; + + if (request.Width.HasValue) + { + info.Width = request.Width.Value; + } + + if (request.Height.HasValue) + { + info.Height = request.Height.Value; + } + + return info; + } + /// /// Posts the image. /// @@ -767,5 +870,25 @@ namespace MediaBrowser.Api.Images entity.UpdateToRepository(ItemUpdateType.ImageUpdate, CancellationToken.None); } + + public async Task PostImage(User user, Stream inputStream, string mimeType) + { + using var reader = new StreamReader(inputStream); + var text = await reader.ReadToEndAsync().ConfigureAwait(false); + + var bytes = Convert.FromBase64String(text); + var memoryStream = new MemoryStream(bytes) + { + Position = 0 + }; + + // Handle image/png; charset=utf-8 + mimeType = mimeType.Split(';').FirstOrDefault(); + + await _providerManager + .SaveImage(user, memoryStream, mimeType, Path.Combine(ServerConfigurationManager.ApplicationPaths.UserConfigurationDirectoryPath, _imageProcessor.GetImageCacheTag(user))) + .ConfigureAwait(false); + await _userManager.UpdateUserAsync(user); + } } } diff --git a/MediaBrowser.Api/Library/LibraryService.cs b/MediaBrowser.Api/Library/LibraryService.cs index 997b1c45a..783fc6073 100644 --- a/MediaBrowser.Api/Library/LibraryService.cs +++ b/MediaBrowser.Api/Library/LibraryService.cs @@ -755,12 +755,12 @@ namespace MediaBrowser.Api.Library }); } - private void LogDownload(BaseItem item, User user, AuthorizationInfo auth) + private void LogDownload(BaseItem item, Jellyfin.Data.Entities.User user, AuthorizationInfo auth) { try { _activityManager.Create(new Jellyfin.Data.Entities.ActivityLog( - string.Format(_localization.GetLocalizedString("UserDownloadingItemWithValues"), user.Name, item.Name), + string.Format(_localization.GetLocalizedString("UserDownloadingItemWithValues"), user.Username, item.Name), "UserDownloadingContent", auth.UserId, DateTime.UtcNow, @@ -840,7 +840,7 @@ namespace MediaBrowser.Api.Library return baseItemDtos; } - private BaseItem TranslateParentItem(BaseItem item, User user) + private BaseItem TranslateParentItem(BaseItem item, Jellyfin.Data.Entities.User user) { return item.GetParent() is AggregateFolder ? _libraryManager.GetUserRootFolder().GetChildren(user, true) @@ -882,7 +882,7 @@ namespace MediaBrowser.Api.Library return ToOptimizedResult(counts); } - private int GetCount(Type type, User user, GetItemCounts request) + private int GetCount(Type type, Jellyfin.Data.Entities.User user, GetItemCounts request) { var query = new InternalItemsQuery(user) { diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs index 5fe4c0cca..279fd6ee9 100644 --- a/MediaBrowser.Api/LiveTv/LiveTvService.cs +++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs @@ -7,6 +7,7 @@ using System.Security.Cryptography; using System.Text; using System.Threading; using System.Threading.Tasks; +using Jellyfin.Data.Enums; using MediaBrowser.Api.UserLibrary; using MediaBrowser.Common; using MediaBrowser.Common.Configuration; @@ -859,7 +860,7 @@ namespace MediaBrowser.Api.LiveTv throw new SecurityException("Anonymous live tv management is not allowed."); } - if (!user.Policy.EnableLiveTvManagement) + if (!user.HasPermission(PermissionKind.EnableLiveTvManagement)) { throw new SecurityException("The current user does not have permission to manage live tv."); } diff --git a/MediaBrowser.Api/Movies/MoviesService.cs b/MediaBrowser.Api/Movies/MoviesService.cs index 46da8b909..b97a0dca1 100644 --- a/MediaBrowser.Api/Movies/MoviesService.cs +++ b/MediaBrowser.Api/Movies/MoviesService.cs @@ -148,7 +148,12 @@ namespace MediaBrowser.Api.Movies return result; } - private IEnumerable GetRecommendationCategories(User user, string parentId, int categoryLimit, int itemLimit, DtoOptions dtoOptions) + private IEnumerable GetRecommendationCategories( + Jellyfin.Data.Entities.User user, + string parentId, + int categoryLimit, + int itemLimit, + DtoOptions dtoOptions) { var categories = new List(); @@ -251,7 +256,12 @@ namespace MediaBrowser.Api.Movies return categories.OrderBy(i => i.RecommendationType); } - private IEnumerable GetWithDirector(User user, IEnumerable names, int itemLimit, DtoOptions dtoOptions, RecommendationType type) + private IEnumerable GetWithDirector( + Jellyfin.Data.Entities.User user, + IEnumerable names, + int itemLimit, + DtoOptions dtoOptions, + RecommendationType type) { var itemTypes = new List { typeof(Movie).Name }; if (ServerConfigurationManager.Configuration.EnableExternalContentInSuggestions) @@ -293,7 +303,12 @@ namespace MediaBrowser.Api.Movies } } - private IEnumerable GetWithActor(User user, IEnumerable names, int itemLimit, DtoOptions dtoOptions, RecommendationType type) + private IEnumerable GetWithActor( + Jellyfin.Data.Entities.User user, + IEnumerable names, + int itemLimit, + DtoOptions dtoOptions, + RecommendationType type) { var itemTypes = new List { typeof(Movie).Name }; if (ServerConfigurationManager.Configuration.EnableExternalContentInSuggestions) @@ -334,7 +349,12 @@ namespace MediaBrowser.Api.Movies } } - private IEnumerable GetSimilarTo(User user, List baselineItems, int itemLimit, DtoOptions dtoOptions, RecommendationType type) + private IEnumerable GetSimilarTo( + Jellyfin.Data.Entities.User user, + List baselineItems, + int itemLimit, + DtoOptions dtoOptions, + RecommendationType type) { var itemTypes = new List { typeof(Movie).Name }; if (ServerConfigurationManager.Configuration.EnableExternalContentInSuggestions) diff --git a/MediaBrowser.Api/Music/InstantMixService.cs b/MediaBrowser.Api/Music/InstantMixService.cs index cacec8d64..e00b06e38 100644 --- a/MediaBrowser.Api/Music/InstantMixService.cs +++ b/MediaBrowser.Api/Music/InstantMixService.cs @@ -171,7 +171,7 @@ namespace MediaBrowser.Api.Music return GetResult(items, user, request, dtoOptions); } - private object GetResult(List items, User user, BaseGetSimilarItems request, DtoOptions dtoOptions) + private object GetResult(List items, Jellyfin.Data.Entities.User user, BaseGetSimilarItems request, DtoOptions dtoOptions) { var list = items; diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index 928ca1612..65f6ccd4d 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -7,6 +7,7 @@ using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; +using Jellyfin.Data.Enums; using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.Configuration; @@ -196,7 +197,7 @@ namespace MediaBrowser.Api.Playback if (state.VideoRequest != null && !string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase)) { var auth = AuthorizationContext.GetAuthorizationInfo(Request); - if (auth.User != null && !auth.User.Policy.EnableVideoPlaybackTranscoding) + if (auth.User != null && !auth.User.HasPermission(PermissionKind.EnableVideoPlaybackTranscoding)) { ApiEntryPoint.Instance.OnTranscodeFailedToStart(outputPath, TranscodingJobType, state); diff --git a/MediaBrowser.Api/Playback/MediaInfoService.cs b/MediaBrowser.Api/Playback/MediaInfoService.cs index db24eaca6..0ef39c2d7 100644 --- a/MediaBrowser.Api/Playback/MediaInfoService.cs +++ b/MediaBrowser.Api/Playback/MediaInfoService.cs @@ -9,6 +9,7 @@ using System.Linq; using System.Text.Json; using System.Threading; using System.Threading.Tasks; +using Jellyfin.Data.Enums; using MediaBrowser.Common.Net; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Devices; @@ -400,21 +401,24 @@ namespace MediaBrowser.Api.Playback if (item is Audio) { - Logger.LogInformation("User policy for {0}. EnableAudioPlaybackTranscoding: {1}", user.Name, user.Policy.EnableAudioPlaybackTranscoding); + Logger.LogInformation( + "User policy for {0}. EnableAudioPlaybackTranscoding: {1}", + user.Username, + user.HasPermission(PermissionKind.EnableAudioPlaybackTranscoding)); } else { Logger.LogInformation("User policy for {0}. EnablePlaybackRemuxing: {1} EnableVideoPlaybackTranscoding: {2} EnableAudioPlaybackTranscoding: {3}", - user.Name, - user.Policy.EnablePlaybackRemuxing, - user.Policy.EnableVideoPlaybackTranscoding, - user.Policy.EnableAudioPlaybackTranscoding); + user.Username, + user.HasPermission(PermissionKind.EnablePlaybackRemuxing), + user.HasPermission(PermissionKind.EnableVideoPlaybackTranscoding), + user.HasPermission(PermissionKind.EnableAudioPlaybackTranscoding)); } // Beginning of Playback Determination: Attempt DirectPlay first if (mediaSource.SupportsDirectPlay) { - if (mediaSource.IsRemote && user.Policy.ForceRemoteSourceTranscoding) + if (mediaSource.IsRemote && user.HasPermission(PermissionKind.ForceRemoteSourceTranscoding)) { mediaSource.SupportsDirectPlay = false; } @@ -428,14 +432,16 @@ namespace MediaBrowser.Api.Playback if (item is Audio) { - if (!user.Policy.EnableAudioPlaybackTranscoding) + if (!user.HasPermission(PermissionKind.EnableAudioPlaybackTranscoding)) { options.ForceDirectPlay = true; } } else if (item is Video) { - if (!user.Policy.EnableAudioPlaybackTranscoding && !user.Policy.EnableVideoPlaybackTranscoding && !user.Policy.EnablePlaybackRemuxing) + if (!user.HasPermission(PermissionKind.EnableAudioPlaybackTranscoding) + && !user.HasPermission(PermissionKind.EnableVideoPlaybackTranscoding) + && !user.HasPermission(PermissionKind.EnablePlaybackRemuxing)) { options.ForceDirectPlay = true; } @@ -463,7 +469,7 @@ namespace MediaBrowser.Api.Playback if (mediaSource.SupportsDirectStream) { - if (mediaSource.IsRemote && user.Policy.ForceRemoteSourceTranscoding) + if (mediaSource.IsRemote && user.HasPermission(PermissionKind.ForceRemoteSourceTranscoding)) { mediaSource.SupportsDirectStream = false; } @@ -473,14 +479,16 @@ namespace MediaBrowser.Api.Playback if (item is Audio) { - if (!user.Policy.EnableAudioPlaybackTranscoding) + if (!user.HasPermission(PermissionKind.EnableAudioPlaybackTranscoding)) { options.ForceDirectStream = true; } } else if (item is Video) { - if (!user.Policy.EnableAudioPlaybackTranscoding && !user.Policy.EnableVideoPlaybackTranscoding && !user.Policy.EnablePlaybackRemuxing) + if (!user.HasPermission(PermissionKind.EnableAudioPlaybackTranscoding) + && !user.HasPermission(PermissionKind.EnableVideoPlaybackTranscoding) + && !user.HasPermission(PermissionKind.EnablePlaybackRemuxing)) { options.ForceDirectStream = true; } @@ -512,7 +520,7 @@ namespace MediaBrowser.Api.Playback ? streamBuilder.BuildAudioItem(options) : streamBuilder.BuildVideoItem(options); - if (mediaSource.IsRemote && user.Policy.ForceRemoteSourceTranscoding) + if (mediaSource.IsRemote && user.HasPermission(PermissionKind.ForceRemoteSourceTranscoding)) { if (streamInfo != null) { @@ -576,10 +584,10 @@ namespace MediaBrowser.Api.Playback } } - private long? GetMaxBitrate(long? clientMaxBitrate, User user) + private long? GetMaxBitrate(long? clientMaxBitrate, Jellyfin.Data.Entities.User user) { var maxBitrate = clientMaxBitrate; - var remoteClientMaxBitrate = user?.Policy.RemoteClientBitrateLimit ?? 0; + var remoteClientMaxBitrate = user?.RemoteClientBitrateLimit ?? 0; if (remoteClientMaxBitrate <= 0) { diff --git a/MediaBrowser.Api/Sessions/SessionService.cs b/MediaBrowser.Api/Sessions/SessionService.cs index 020bb5042..d986eea65 100644 --- a/MediaBrowser.Api/Sessions/SessionService.cs +++ b/MediaBrowser.Api/Sessions/SessionService.cs @@ -2,6 +2,7 @@ using System; using System.Linq; using System.Threading; using System.Threading.Tasks; +using Jellyfin.Data.Enums; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Devices; using MediaBrowser.Controller.Library; @@ -326,12 +327,12 @@ namespace MediaBrowser.Api.Sessions var user = _userManager.GetUserById(request.ControllableByUserId); - if (!user.Policy.EnableRemoteControlOfOtherUsers) + if (!user.HasPermission(PermissionKind.EnableRemoteControlOfOtherUsers)) { result = result.Where(i => i.UserId.Equals(Guid.Empty) || i.ContainsUser(request.ControllableByUserId)); } - if (!user.Policy.EnableSharedDeviceControl) + if (!user.HasPermission(PermissionKind.EnableSharedDeviceControl)) { result = result.Where(i => !i.UserId.Equals(Guid.Empty)); } diff --git a/MediaBrowser.Api/SuggestionsService.cs b/MediaBrowser.Api/SuggestionsService.cs index 91f85db6f..51fa1eb71 100644 --- a/MediaBrowser.Api/SuggestionsService.cs +++ b/MediaBrowser.Api/SuggestionsService.cs @@ -78,7 +78,7 @@ namespace MediaBrowser.Api }; } - private QueryResult GetItems(GetSuggestedItems request, User user, DtoOptions dtoOptions) + private QueryResult GetItems(GetSuggestedItems request, Jellyfin.Data.Entities.User user, DtoOptions dtoOptions) { return _libraryManager.GetItemsResult(new InternalItemsQuery(user) { diff --git a/MediaBrowser.Api/TvShowsService.cs b/MediaBrowser.Api/TvShowsService.cs index cd8e8dfbe..0c23d8b29 100644 --- a/MediaBrowser.Api/TvShowsService.cs +++ b/MediaBrowser.Api/TvShowsService.cs @@ -378,7 +378,7 @@ namespace MediaBrowser.Api { var user = _userManager.GetUserById(request.UserId); - var series = GetSeries(request.Id, user); + var series = GetSeries(request.Id); if (series == null) { @@ -404,7 +404,7 @@ namespace MediaBrowser.Api }; } - private Series GetSeries(string seriesId, User user) + private Series GetSeries(string seriesId) { if (!string.IsNullOrWhiteSpace(seriesId)) { @@ -433,7 +433,7 @@ namespace MediaBrowser.Api } else if (request.Season.HasValue) { - var series = GetSeries(request.Id, user); + var series = GetSeries(request.Id); if (series == null) { @@ -446,7 +446,7 @@ namespace MediaBrowser.Api } else { - var series = GetSeries(request.Id, user); + var series = GetSeries(request.Id); if (series == null) { diff --git a/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs b/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs index c4a52d5f5..75a33350e 100644 --- a/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs +++ b/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs @@ -94,7 +94,7 @@ namespace MediaBrowser.Api.UserLibrary { var dtoOptions = GetDtoOptions(AuthorizationContext, request); - User user = null; + Jellyfin.Data.Entities.User user = null; BaseItem parentItem; if (!request.UserId.Equals(Guid.Empty)) @@ -246,7 +246,7 @@ namespace MediaBrowser.Api.UserLibrary { var dtoOptions = GetDtoOptions(AuthorizationContext, request); - User user = null; + Jellyfin.Data.Entities.User user = null; BaseItem parentItem; if (!request.UserId.Equals(Guid.Empty)) diff --git a/MediaBrowser.Api/UserLibrary/ItemsService.cs b/MediaBrowser.Api/UserLibrary/ItemsService.cs index c4d44042b..cbceb3625 100644 --- a/MediaBrowser.Api/UserLibrary/ItemsService.cs +++ b/MediaBrowser.Api/UserLibrary/ItemsService.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Globalization; using System.Linq; +using Jellyfin.Data.Enums; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; @@ -86,7 +87,7 @@ namespace MediaBrowser.Api.UserLibrary var ancestorIds = Array.Empty(); - var excludeFolderIds = user.Configuration.LatestItemsExcludes; + var excludeFolderIds = user.GetPreference(PreferenceKind.LatestItemExcludes); if (parentIdGuid.Equals(Guid.Empty) && excludeFolderIds.Length > 0) { ancestorIds = _libraryManager.GetUserRootFolder().GetChildren(user, true) @@ -179,7 +180,7 @@ namespace MediaBrowser.Api.UserLibrary /// /// Gets the items to serialize. /// - private QueryResult GetQueryResult(GetItems request, DtoOptions dtoOptions, User user) + private QueryResult GetQueryResult(GetItems request, DtoOptions dtoOptions, Jellyfin.Data.Entities.User user) { if (string.Equals(request.IncludeItemTypes, "Playlist", StringComparison.OrdinalIgnoreCase) || string.Equals(request.IncludeItemTypes, "BoxSet", StringComparison.OrdinalIgnoreCase)) @@ -211,14 +212,14 @@ namespace MediaBrowser.Api.UserLibrary request.IncludeItemTypes = "Playlist"; } - bool isInEnabledFolder = user.Policy.EnabledFolders.Any(i => new Guid(i) == item.Id) + bool isInEnabledFolder = user.GetPreference(PreferenceKind.EnabledFolders).Any(i => new Guid(i) == item.Id) // Assume all folders inside an EnabledChannel are enabled - || user.Policy.EnabledChannels.Any(i => new Guid(i) == item.Id); + || user.GetPreference(PreferenceKind.EnabledChannels).Any(i => new Guid(i) == item.Id); var collectionFolders = _libraryManager.GetCollectionFolders(item); foreach (var collectionFolder in collectionFolders) { - if (user.Policy.EnabledFolders.Contains( + if (user.GetPreference(PreferenceKind.EnabledFolders).Contains( collectionFolder.Id.ToString("N", CultureInfo.InvariantCulture), StringComparer.OrdinalIgnoreCase)) { @@ -226,9 +227,12 @@ namespace MediaBrowser.Api.UserLibrary } } - if (!(item is UserRootFolder) && !user.Policy.EnableAllFolders && !isInEnabledFolder && !user.Policy.EnableAllChannels) + if (!(item is UserRootFolder) + && !isInEnabledFolder + && !user.HasPermission(PermissionKind.EnableAllFolders) + && !user.HasPermission(PermissionKind.EnableAllChannels)) { - Logger.LogWarning("{UserName} is not permitted to access Library {ItemName}.", user.Name, item.Name); + Logger.LogWarning("{UserName} is not permitted to access Library {ItemName}.", user.Username, item.Name); return new QueryResult { Items = Array.Empty(), @@ -251,7 +255,7 @@ namespace MediaBrowser.Api.UserLibrary }; } - private InternalItemsQuery GetItemsQuery(GetItems request, DtoOptions dtoOptions, User user) + private InternalItemsQuery GetItemsQuery(GetItems request, DtoOptions dtoOptions, Jellyfin.Data.Entities.User user) { var query = new InternalItemsQuery(user) { diff --git a/MediaBrowser.Api/UserLibrary/PlaystateService.cs b/MediaBrowser.Api/UserLibrary/PlaystateService.cs index d0faca163..fb8bda190 100644 --- a/MediaBrowser.Api/UserLibrary/PlaystateService.cs +++ b/MediaBrowser.Api/UserLibrary/PlaystateService.cs @@ -437,7 +437,7 @@ namespace MediaBrowser.Api.UserLibrary /// if set to true [was played]. /// The date played. /// Task. - private UserItemDataDto UpdatePlayedStatus(User user, string itemId, bool wasPlayed, DateTime? datePlayed) + private UserItemDataDto UpdatePlayedStatus(Jellyfin.Data.Entities.User user, string itemId, bool wasPlayed, DateTime? datePlayed) { var item = _libraryManager.GetItemById(itemId); diff --git a/MediaBrowser.Api/UserLibrary/UserLibraryService.cs b/MediaBrowser.Api/UserLibrary/UserLibraryService.cs index 7fa750adb..f75852885 100644 --- a/MediaBrowser.Api/UserLibrary/UserLibraryService.cs +++ b/MediaBrowser.Api/UserLibrary/UserLibraryService.cs @@ -312,7 +312,7 @@ namespace MediaBrowser.Api.UserLibrary if (!request.IsPlayed.HasValue) { - if (user.Configuration.HidePlayedInLatest) + if (user.HidePlayedInLatest) { request.IsPlayed = false; } diff --git a/MediaBrowser.Api/UserService.cs b/MediaBrowser.Api/UserService.cs index 78fc6c694..7bf4f88f4 100644 --- a/MediaBrowser.Api/UserService.cs +++ b/MediaBrowser.Api/UserService.cs @@ -1,6 +1,7 @@ using System; using System.Linq; using System.Threading.Tasks; +using Jellyfin.Data.Enums; using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Net; using MediaBrowser.Controller.Authentication; @@ -300,12 +301,12 @@ namespace MediaBrowser.Api if (request.IsDisabled.HasValue) { - users = users.Where(i => i.Policy.IsDisabled == request.IsDisabled.Value); + users = users.Where(i => i.HasPermission(PermissionKind.IsDisabled) == request.IsDisabled.Value); } if (request.IsHidden.HasValue) { - users = users.Where(i => i.Policy.IsHidden == request.IsHidden.Value); + users = users.Where(i => i.HasPermission(PermissionKind.IsHidden) == request.IsHidden.Value); } if (filterByDevice) @@ -322,12 +323,12 @@ namespace MediaBrowser.Api { if (!_networkManager.IsInLocalNetwork(Request.RemoteIp)) { - users = users.Where(i => i.Policy.EnableRemoteAccess); + users = users.Where(i => i.HasPermission(PermissionKind.EnableRemoteAccess)); } } var result = users - .OrderBy(u => u.Name) + .OrderBy(u => u.Username) .Select(i => _userManager.GetUserDto(i, Request.RemoteIp)) .ToArray(); @@ -397,7 +398,7 @@ namespace MediaBrowser.Api // Password should always be null return Post(new AuthenticateUserByName { - Username = user.Name, + Username = user.Username, Password = null, Pw = request.Pw }); @@ -456,7 +457,12 @@ namespace MediaBrowser.Api } else { - var success = await _userManager.AuthenticateUser(user.Name, request.CurrentPw, request.CurrentPassword, Request.RemoteIp, false).ConfigureAwait(false); + var success = await _userManager.AuthenticateUser( + user.Username, + request.CurrentPw, + request.CurrentPassword, + Request.RemoteIp, + false).ConfigureAwait(false); if (success == null) { @@ -506,10 +512,10 @@ namespace MediaBrowser.Api var user = _userManager.GetUserById(id); - if (string.Equals(user.Name, dtoUser.Name, StringComparison.Ordinal)) + if (string.Equals(user.Username, dtoUser.Name, StringComparison.Ordinal)) { - _userManager.UpdateUser(user); - _userManager.UpdateConfiguration(user, dtoUser.Configuration); + await _userManager.UpdateUserAsync(user); + _userManager.UpdateConfiguration(user.Id, dtoUser.Configuration); } else { @@ -568,24 +574,24 @@ namespace MediaBrowser.Api var user = _userManager.GetUserById(request.Id); // If removing admin access - if (!request.IsAdministrator && user.Policy.IsAdministrator) + if (!request.IsAdministrator && user.HasPermission(PermissionKind.IsAdministrator)) { - if (_userManager.Users.Count(i => i.Policy.IsAdministrator) == 1) + if (_userManager.Users.Count(i => i.HasPermission(PermissionKind.IsAdministrator)) == 1) { throw new ArgumentException("There must be at least one user in the system with administrative access."); } } // If disabling - if (request.IsDisabled && user.Policy.IsAdministrator) + if (request.IsDisabled && user.HasPermission(PermissionKind.IsAdministrator)) { throw new ArgumentException("Administrators cannot be disabled."); } // If disabling - if (request.IsDisabled && !user.Policy.IsDisabled) + if (request.IsDisabled && !user.HasPermission(PermissionKind.IsDisabled)) { - if (_userManager.Users.Count(i => !i.Policy.IsDisabled) == 1) + if (_userManager.Users.Count(i => !i.HasPermission(PermissionKind.IsDisabled)) == 1) { throw new ArgumentException("There must be at least one enabled user in the system."); } @@ -594,7 +600,7 @@ namespace MediaBrowser.Api _sessionMananger.RevokeUserTokens(user.Id, currentToken); } - _userManager.UpdateUserPolicy(request.Id, request); + _userManager.UpdatePolicy(request.Id, request); } } } diff --git a/MediaBrowser.Controller/Authentication/IAuthenticationProvider.cs b/MediaBrowser.Controller/Authentication/IAuthenticationProvider.cs index f5571065f..c0324a384 100644 --- a/MediaBrowser.Controller/Authentication/IAuthenticationProvider.cs +++ b/MediaBrowser.Controller/Authentication/IAuthenticationProvider.cs @@ -1,5 +1,5 @@ using System.Threading.Tasks; -using MediaBrowser.Controller.Entities; +using Jellyfin.Data.Entities; using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.Authentication diff --git a/MediaBrowser.Controller/Authentication/IPasswordResetProvider.cs b/MediaBrowser.Controller/Authentication/IPasswordResetProvider.cs index 2639960e7..d9b814f69 100644 --- a/MediaBrowser.Controller/Authentication/IPasswordResetProvider.cs +++ b/MediaBrowser.Controller/Authentication/IPasswordResetProvider.cs @@ -1,6 +1,6 @@ using System; using System.Threading.Tasks; -using MediaBrowser.Controller.Entities; +using Jellyfin.Data.Entities; using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.Authentication diff --git a/MediaBrowser.Controller/Channels/Channel.cs b/MediaBrowser.Controller/Channels/Channel.cs index cdf2ca69e..d6a1fc84e 100644 --- a/MediaBrowser.Controller/Channels/Channel.cs +++ b/MediaBrowser.Controller/Channels/Channel.cs @@ -3,6 +3,7 @@ using System.Globalization; using System.Linq; using System.Text.Json.Serialization; using System.Threading; +using Jellyfin.Data.Enums; using MediaBrowser.Common.Progress; using MediaBrowser.Controller.Entities; using MediaBrowser.Model.Querying; @@ -11,18 +12,20 @@ namespace MediaBrowser.Controller.Channels { public class Channel : Folder { - public override bool IsVisible(User user) + public override bool IsVisible(Jellyfin.Data.Entities.User user) { - if (user.Policy.BlockedChannels != null) + if (user.GetPreference(PreferenceKind.BlockedChannels) != null) { - if (user.Policy.BlockedChannels.Contains(Id.ToString("N", CultureInfo.InvariantCulture), StringComparer.OrdinalIgnoreCase)) + if (user.GetPreference(PreferenceKind.BlockedChannels).Contains(Id.ToString("N", CultureInfo.InvariantCulture), StringComparer.OrdinalIgnoreCase)) { return false; } } else { - if (!user.Policy.EnableAllChannels && !user.Policy.EnabledChannels.Contains(Id.ToString("N", CultureInfo.InvariantCulture), StringComparer.OrdinalIgnoreCase)) + if (!user.HasPermission(PermissionKind.EnableAllChannels) + && !user.GetPreference(PreferenceKind.EnabledChannels) + .Contains(Id.ToString("N", CultureInfo.InvariantCulture), StringComparer.OrdinalIgnoreCase)) { return false; } @@ -74,7 +77,7 @@ namespace MediaBrowser.Controller.Channels return false; } - internal static bool IsChannelVisible(BaseItem channelItem, User user) + internal static bool IsChannelVisible(BaseItem channelItem, Jellyfin.Data.Entities.User user) { var channel = ChannelManager.GetChannel(channelItem.ChannelId.ToString("")); diff --git a/MediaBrowser.Controller/Collections/ICollectionManager.cs b/MediaBrowser.Controller/Collections/ICollectionManager.cs index cfe8493d3..f51c73bd7 100644 --- a/MediaBrowser.Controller/Collections/ICollectionManager.cs +++ b/MediaBrowser.Controller/Collections/ICollectionManager.cs @@ -51,6 +51,6 @@ namespace MediaBrowser.Controller.Collections /// The items. /// The user. /// IEnumerable{BaseItem}. - IEnumerable CollapseItemsWithinBoxSets(IEnumerable items, User user); + IEnumerable CollapseItemsWithinBoxSets(IEnumerable items, Jellyfin.Data.Entities.User user); } } diff --git a/MediaBrowser.Controller/Devices/IDeviceManager.cs b/MediaBrowser.Controller/Devices/IDeviceManager.cs index 77d567631..117af110a 100644 --- a/MediaBrowser.Controller/Devices/IDeviceManager.cs +++ b/MediaBrowser.Controller/Devices/IDeviceManager.cs @@ -1,7 +1,7 @@ using System; using System.IO; using System.Threading.Tasks; -using MediaBrowser.Controller.Entities; +using Jellyfin.Data.Entities; using MediaBrowser.Model.Devices; using MediaBrowser.Model.Events; using MediaBrowser.Model.Querying; diff --git a/MediaBrowser.Controller/Drawing/IImageProcessor.cs b/MediaBrowser.Controller/Drawing/IImageProcessor.cs index 36c746624..bdb12402a 100644 --- a/MediaBrowser.Controller/Drawing/IImageProcessor.cs +++ b/MediaBrowser.Controller/Drawing/IImageProcessor.cs @@ -47,8 +47,11 @@ namespace MediaBrowser.Controller.Drawing /// The image. /// Guid. string GetImageCacheTag(BaseItem item, ItemImageInfo image); + string GetImageCacheTag(BaseItem item, ChapterInfo info); + string GetImageCacheTag(Jellyfin.Data.Entities.User user); + /// /// Processes the image. /// diff --git a/MediaBrowser.Controller/Drawing/ImageProcessorExtensions.cs b/MediaBrowser.Controller/Drawing/ImageProcessorExtensions.cs index df9050de5..9f505be93 100644 --- a/MediaBrowser.Controller/Drawing/ImageProcessorExtensions.cs +++ b/MediaBrowser.Controller/Drawing/ImageProcessorExtensions.cs @@ -1,5 +1,6 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Model.Entities; +using User = Jellyfin.Data.Entities.User; namespace MediaBrowser.Controller.Drawing { diff --git a/MediaBrowser.Controller/Dto/IDtoService.cs b/MediaBrowser.Controller/Dto/IDtoService.cs index ba693a065..5ac4f05c0 100644 --- a/MediaBrowser.Controller/Dto/IDtoService.cs +++ b/MediaBrowser.Controller/Dto/IDtoService.cs @@ -38,7 +38,7 @@ namespace MediaBrowser.Controller.Dto /// The fields. /// The user. /// The owner. - BaseItemDto GetBaseItemDto(BaseItem item, ItemFields[] fields, User user = null, BaseItem owner = null); + BaseItemDto GetBaseItemDto(BaseItem item, ItemFields[] fields, Jellyfin.Data.Entities.User user = null, BaseItem owner = null); /// /// Gets the base item dto. @@ -48,7 +48,7 @@ namespace MediaBrowser.Controller.Dto /// The user. /// The owner. /// BaseItemDto. - BaseItemDto GetBaseItemDto(BaseItem item, DtoOptions options, User user = null, BaseItem owner = null); + BaseItemDto GetBaseItemDto(BaseItem item, DtoOptions options, Jellyfin.Data.Entities.User user = null, BaseItem owner = null); /// /// Gets the base item dtos. @@ -57,11 +57,11 @@ namespace MediaBrowser.Controller.Dto /// The options. /// The user. /// The owner. - IReadOnlyList GetBaseItemDtos(IReadOnlyList items, DtoOptions options, User user = null, BaseItem owner = null); + IReadOnlyList GetBaseItemDtos(IReadOnlyList items, DtoOptions options, Jellyfin.Data.Entities.User user = null, BaseItem owner = null); /// /// Gets the item by name dto. /// - BaseItemDto GetItemByNameDto(BaseItem item, DtoOptions options, List taggedItems, User user = null); + BaseItemDto GetItemByNameDto(BaseItem item, DtoOptions options, List taggedItems, Jellyfin.Data.Entities.User user = null); } } diff --git a/MediaBrowser.Controller/Entities/Audio/Audio.cs b/MediaBrowser.Controller/Entities/Audio/Audio.cs index a700d0be4..9065cb27f 100644 --- a/MediaBrowser.Controller/Entities/Audio/Audio.cs +++ b/MediaBrowser.Controller/Entities/Audio/Audio.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Linq; using System.Text.Json.Serialization; +using Jellyfin.Data.Enums; using MediaBrowser.Controller.Persistence; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Configuration; diff --git a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs index c216176e7..fbadeafad 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs @@ -1,9 +1,11 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Text.Json.Serialization; using System.Threading; using System.Threading.Tasks; +using Jellyfin.Data.Enums; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Providers; @@ -77,7 +79,7 @@ namespace MediaBrowser.Controller.Entities.Audio [JsonIgnore] public IEnumerable /// The user. /// PlayAccess. - public PlayAccess GetPlayAccess(User user) + public PlayAccess GetPlayAccess(Jellyfin.Data.Entities.User user) { - if (!user.Policy.EnableMediaPlayback) + if (!user.HasPermission(PermissionKind.EnableMediaPlayback)) { return PlayAccess.None; } @@ -1760,7 +1761,7 @@ namespace MediaBrowser.Controller.Entities /// The user. /// true if [is parental allowed] [the specified user]; otherwise, false. /// user - public bool IsParentalAllowed(User user) + public bool IsParentalAllowed(Jellyfin.Data.Entities.User user) { if (user == null) { @@ -1772,7 +1773,7 @@ namespace MediaBrowser.Controller.Entities return false; } - var maxAllowedRating = user.Policy.MaxParentalRating; + var maxAllowedRating = user.MaxParentalAgeRating; if (maxAllowedRating == null) { @@ -1788,7 +1789,7 @@ namespace MediaBrowser.Controller.Entities if (string.IsNullOrEmpty(rating)) { - return !GetBlockUnratedValue(user.Policy); + return !GetBlockUnratedValue(user); } var value = LocalizationManager.GetRatingLevel(rating); @@ -1796,7 +1797,7 @@ namespace MediaBrowser.Controller.Entities // Could not determine the integer value if (!value.HasValue) { - var isAllowed = !GetBlockUnratedValue(user.Policy); + var isAllowed = !GetBlockUnratedValue(user); if (!isAllowed) { @@ -1856,10 +1857,9 @@ namespace MediaBrowser.Controller.Entities return list.Distinct(StringComparer.OrdinalIgnoreCase).ToList(); } - private bool IsVisibleViaTags(User user) + private bool IsVisibleViaTags(Jellyfin.Data.Entities.User user) { - var policy = user.Policy; - if (policy.BlockedTags.Any(i => Tags.Contains(i, StringComparer.OrdinalIgnoreCase))) + if (user.GetPreference(PreferenceKind.BlockedTags).Any(i => Tags.Contains(i, StringComparer.OrdinalIgnoreCase))) { return false; } @@ -1885,22 +1885,18 @@ namespace MediaBrowser.Controller.Entities /// /// Gets the block unrated value. /// - /// The configuration. + /// The configuration. /// true if XXXX, false otherwise. - protected virtual bool GetBlockUnratedValue(UserPolicy config) + protected virtual bool GetBlockUnratedValue(Jellyfin.Data.Entities.User user) { // Don't block plain folders that are unrated. Let the media underneath get blocked // Special folders like series and albums will override this method. - if (IsFolder) - { - return false; - } - if (this is IItemByName) + if (IsFolder || this is IItemByName) { return false; } - return config.BlockUnratedItems.Contains(GetBlockUnratedType()); + return user.GetPreference(PreferenceKind.BlockUnratedItems).Contains(GetBlockUnratedType().ToString()); } /// @@ -1910,7 +1906,7 @@ namespace MediaBrowser.Controller.Entities /// The user. /// true if the specified user is visible; otherwise, false. /// user - public virtual bool IsVisible(User user) + public virtual bool IsVisible(Jellyfin.Data.Entities.User user) { if (user == null) { @@ -1920,7 +1916,7 @@ namespace MediaBrowser.Controller.Entities return IsParentalAllowed(user); } - public virtual bool IsVisibleStandalone(User user) + public virtual bool IsVisibleStandalone(Jellyfin.Data.Entities.User user) { if (SourceType == SourceType.Channel) { @@ -1933,7 +1929,7 @@ namespace MediaBrowser.Controller.Entities [JsonIgnore] public virtual bool SupportsInheritedParentImages => false; - protected bool IsVisibleStandaloneInternal(User user, bool checkFolders) + protected bool IsVisibleStandaloneInternal(Jellyfin.Data.Entities.User user, bool checkFolders) { if (!IsVisible(user)) { @@ -2130,7 +2126,8 @@ namespace MediaBrowser.Controller.Entities /// if set to true [reset position]. /// Task. /// - public virtual void MarkPlayed(User user, + public virtual void MarkPlayed( + Jellyfin.Data.Entities.User user, DateTime? datePlayed, bool resetPosition) { @@ -2167,7 +2164,7 @@ namespace MediaBrowser.Controller.Entities /// The user. /// Task. /// - public virtual void MarkUnplayed(User user) + public virtual void MarkUnplayed(Jellyfin.Data.Entities.User user) { if (user == null) { @@ -2543,21 +2540,21 @@ namespace MediaBrowser.Controller.Entities UpdateToRepository(ItemUpdateType.ImageUpdate, CancellationToken.None); } - public virtual bool IsPlayed(User user) + public virtual bool IsPlayed(Jellyfin.Data.Entities.User user) { var userdata = UserDataManager.GetUserData(user, this); return userdata != null && userdata.Played; } - public bool IsFavoriteOrLiked(User user) + public bool IsFavoriteOrLiked(Jellyfin.Data.Entities.User user) { var userdata = UserDataManager.GetUserData(user, this); return userdata != null && (userdata.IsFavorite || (userdata.Likes ?? false)); } - public virtual bool IsUnplayed(User user) + public virtual bool IsUnplayed(Jellyfin.Data.Entities.User user) { if (user == null) { @@ -2623,7 +2620,7 @@ namespace MediaBrowser.Controller.Entities return path; } - public virtual void FillUserDataDtoValues(UserItemDataDto dto, UserItemData userData, BaseItemDto itemDto, User user, DtoOptions fields) + public virtual void FillUserDataDtoValues(UserItemDataDto dto, UserItemData userData, BaseItemDto itemDto, Jellyfin.Data.Entities.User user, DtoOptions fields) { if (RunTimeTicks.HasValue) { @@ -2736,14 +2733,14 @@ namespace MediaBrowser.Controller.Entities return RefreshMetadataForOwnedItem(video, copyTitleMetadata, newOptions, cancellationToken); } - public string GetEtag(User user) + public string GetEtag(Jellyfin.Data.Entities.User user) { var list = GetEtagValues(user); return string.Join("|", list).GetMD5().ToString("N", CultureInfo.InvariantCulture); } - protected virtual List GetEtagValues(User user) + protected virtual List GetEtagValues(Jellyfin.Data.Entities.User user) { return new List { diff --git a/MediaBrowser.Controller/Entities/Book.cs b/MediaBrowser.Controller/Entities/Book.cs index dcad2554b..c4a2929dc 100644 --- a/MediaBrowser.Controller/Entities/Book.cs +++ b/MediaBrowser.Controller/Entities/Book.cs @@ -1,6 +1,7 @@ using System; using System.Linq; using System.Text.Json.Serialization; +using Jellyfin.Data.Enums; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Configuration; diff --git a/MediaBrowser.Controller/Entities/DayOfWeekHelper.cs b/MediaBrowser.Controller/Entities/DayOfWeekHelper.cs deleted file mode 100644 index 8a79e0783..000000000 --- a/MediaBrowser.Controller/Entities/DayOfWeekHelper.cs +++ /dev/null @@ -1,71 +0,0 @@ -using System; -using System.Collections.Generic; -using MediaBrowser.Model.Configuration; - -namespace MediaBrowser.Controller.Entities -{ - public static class DayOfWeekHelper - { - public static List GetDaysOfWeek(DynamicDayOfWeek day) - { - return GetDaysOfWeek(new List { day }); - } - - public static List GetDaysOfWeek(List days) - { - var list = new List(); - - if (days.Contains(DynamicDayOfWeek.Sunday) || - days.Contains(DynamicDayOfWeek.Weekend) || - days.Contains(DynamicDayOfWeek.Everyday)) - { - list.Add(DayOfWeek.Sunday); - } - - if (days.Contains(DynamicDayOfWeek.Saturday) || - days.Contains(DynamicDayOfWeek.Weekend) || - days.Contains(DynamicDayOfWeek.Everyday)) - { - list.Add(DayOfWeek.Saturday); - } - - if (days.Contains(DynamicDayOfWeek.Monday) || - days.Contains(DynamicDayOfWeek.Weekday) || - days.Contains(DynamicDayOfWeek.Everyday)) - { - list.Add(DayOfWeek.Monday); - } - - if (days.Contains(DynamicDayOfWeek.Tuesday) || - days.Contains(DynamicDayOfWeek.Weekday) || - days.Contains(DynamicDayOfWeek.Everyday)) - { - list.Add(DayOfWeek.Tuesday - ); - } - - if (days.Contains(DynamicDayOfWeek.Wednesday) || - days.Contains(DynamicDayOfWeek.Weekday) || - days.Contains(DynamicDayOfWeek.Everyday)) - { - list.Add(DayOfWeek.Wednesday); - } - - if (days.Contains(DynamicDayOfWeek.Thursday) || - days.Contains(DynamicDayOfWeek.Weekday) || - days.Contains(DynamicDayOfWeek.Everyday)) - { - list.Add(DayOfWeek.Thursday); - } - - if (days.Contains(DynamicDayOfWeek.Friday) || - days.Contains(DynamicDayOfWeek.Weekday) || - days.Contains(DynamicDayOfWeek.Everyday)) - { - list.Add(DayOfWeek.Friday); - } - - return list; - } - } -} diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index a468e0c35..03644b0c6 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -8,6 +8,7 @@ using System.Linq; using System.Text.Json.Serialization; using System.Threading; using System.Threading.Tasks; +using Jellyfin.Data.Enums; using MediaBrowser.Common.Progress; using MediaBrowser.Controller.Channels; using MediaBrowser.Controller.Collections; @@ -173,23 +174,25 @@ namespace MediaBrowser.Controller.Entities [JsonIgnore] public IEnumerable RecursiveChildren => GetRecursiveChildren(); - public override bool IsVisible(User user) + public override bool IsVisible(Jellyfin.Data.Entities.User user) { if (this is ICollectionFolder && !(this is BasePluginFolder)) { - if (user.Policy.BlockedMediaFolders != null) + if (user.GetPreference(PreferenceKind.BlockedMediaFolders) != null) { - if (user.Policy.BlockedMediaFolders.Contains(Id.ToString("N", CultureInfo.InvariantCulture), StringComparer.OrdinalIgnoreCase) || + if (user.GetPreference(PreferenceKind.BlockedMediaFolders).Contains(Id.ToString("N", CultureInfo.InvariantCulture), StringComparer.OrdinalIgnoreCase) || // Backwards compatibility - user.Policy.BlockedMediaFolders.Contains(Name, StringComparer.OrdinalIgnoreCase)) + user.GetPreference(PreferenceKind.BlockedMediaFolders).Contains(Name, StringComparer.OrdinalIgnoreCase)) { return false; } } else { - if (!user.Policy.EnableAllFolders && !user.Policy.EnabledFolders.Contains(Id.ToString("N", CultureInfo.InvariantCulture), StringComparer.OrdinalIgnoreCase)) + if (!user.HasPermission(PermissionKind.EnableAllFolders) + && !user.GetPreference(PreferenceKind.EnabledFolders) + .Contains(Id.ToString("N", CultureInfo.InvariantCulture), StringComparer.OrdinalIgnoreCase)) { return false; } @@ -583,7 +586,7 @@ namespace MediaBrowser.Controller.Entities }); } - public virtual int GetChildCount(User user) + public virtual int GetChildCount(Jellyfin.Data.Entities.User user) { if (LinkedChildren.Length > 0) { @@ -608,7 +611,7 @@ namespace MediaBrowser.Controller.Entities return result.TotalRecordCount; } - public virtual int GetRecursiveChildCount(User user) + public virtual int GetRecursiveChildCount(Jellyfin.Data.Entities.User user) { return GetItems(new InternalItemsQuery(user) { @@ -877,7 +880,7 @@ namespace MediaBrowser.Controller.Entities try { query.Parent = this; - query.ChannelIds = new Guid[] { ChannelId }; + query.ChannelIds = new[] { ChannelId }; // Don't blow up here because it could cause parent screens with other content to fail return ChannelManager.GetChannelItemsInternal(query, new SimpleProgress(), CancellationToken.None).Result; @@ -947,11 +950,13 @@ namespace MediaBrowser.Controller.Entities return UserViewBuilder.SortAndPage(items, null, query, LibraryManager, enableSorting); } - private static IEnumerable CollapseBoxSetItemsIfNeeded(IEnumerable items, + private static IEnumerable CollapseBoxSetItemsIfNeeded( + IEnumerable items, InternalItemsQuery query, BaseItem queryParent, - User user, - IServerConfigurationManager configurationManager, ICollectionManager collectionManager) + Jellyfin.Data.Entities.User user, + IServerConfigurationManager configurationManager, + ICollectionManager collectionManager) { if (items == null) { @@ -968,7 +973,7 @@ namespace MediaBrowser.Controller.Entities private static bool CollapseBoxSetItems(InternalItemsQuery query, BaseItem queryParent, - User user, + Jellyfin.Data.Entities.User user, IServerConfigurationManager configurationManager) { // Could end up stuck in a loop like this @@ -1191,7 +1196,7 @@ namespace MediaBrowser.Controller.Entities return true; } - public List GetChildren(User user, bool includeLinkedChildren) + public List GetChildren(Jellyfin.Data.Entities.User user, bool includeLinkedChildren) { if (user == null) { @@ -1201,7 +1206,7 @@ namespace MediaBrowser.Controller.Entities return GetChildren(user, includeLinkedChildren, null); } - public virtual List GetChildren(User user, bool includeLinkedChildren, InternalItemsQuery query) + public virtual List GetChildren(Jellyfin.Data.Entities.User user, bool includeLinkedChildren, InternalItemsQuery query) { if (user == null) { @@ -1221,7 +1226,7 @@ namespace MediaBrowser.Controller.Entities return result.Values.ToList(); } - protected virtual IEnumerable GetEligibleChildrenForRecursiveChildren(User user) + protected virtual IEnumerable GetEligibleChildrenForRecursiveChildren(Jellyfin.Data.Entities.User user) { return Children; } @@ -1230,7 +1235,7 @@ namespace MediaBrowser.Controller.Entities /// Adds the children to list. /// /// true if XXXX, false otherwise - private void AddChildren(User user, bool includeLinkedChildren, Dictionary result, bool recursive, InternalItemsQuery query) + private void AddChildren(Jellyfin.Data.Entities.User user, bool includeLinkedChildren, Dictionary result, bool recursive, InternalItemsQuery query) { foreach (var child in GetEligibleChildrenForRecursiveChildren(user)) { @@ -1279,12 +1284,12 @@ namespace MediaBrowser.Controller.Entities /// if set to true [include linked children]. /// IEnumerable{BaseItem}. /// - public IEnumerable GetRecursiveChildren(User user, bool includeLinkedChildren = true) + public IEnumerable GetRecursiveChildren(Jellyfin.Data.Entities.User user, bool includeLinkedChildren = true) { return GetRecursiveChildren(user, null); } - public virtual IEnumerable GetRecursiveChildren(User user, InternalItemsQuery query) + public virtual IEnumerable GetRecursiveChildren(Jellyfin.Data.Entities.User user, InternalItemsQuery query) { if (user == null) { @@ -1403,7 +1408,7 @@ namespace MediaBrowser.Controller.Entities return false; } - public List GetLinkedChildren(User user) + public List GetLinkedChildren(Jellyfin.Data.Entities.User user) { if (!FilterLinkedChildrenPerUser || user == null) { @@ -1565,7 +1570,7 @@ namespace MediaBrowser.Controller.Entities /// The date played. /// if set to true [reset position]. /// Task. - public override void MarkPlayed(User user, + public override void MarkPlayed(Jellyfin.Data.Entities.User user, DateTime? datePlayed, bool resetPosition) { @@ -1577,7 +1582,7 @@ namespace MediaBrowser.Controller.Entities EnableTotalRecordCount = false }; - if (!user.Configuration.DisplayMissingEpisodes) + if (!user.DisplayMissingEpisodes) { query.IsVirtualItem = false; } @@ -1606,7 +1611,7 @@ namespace MediaBrowser.Controller.Entities /// /// The user. /// Task. - public override void MarkUnplayed(User user) + public override void MarkUnplayed(Jellyfin.Data.Entities.User user) { var itemsResult = GetItemList(new InternalItemsQuery { @@ -1624,7 +1629,7 @@ namespace MediaBrowser.Controller.Entities } } - public override bool IsPlayed(User user) + public override bool IsPlayed(Jellyfin.Data.Entities.User user) { var itemsResult = GetItemList(new InternalItemsQuery(user) { @@ -1639,7 +1644,7 @@ namespace MediaBrowser.Controller.Entities .All(i => i.IsPlayed(user)); } - public override bool IsUnplayed(User user) + public override bool IsUnplayed(Jellyfin.Data.Entities.User user) { return !IsPlayed(user); } @@ -1684,7 +1689,7 @@ namespace MediaBrowser.Controller.Entities } } - public override void FillUserDataDtoValues(UserItemDataDto dto, UserItemData userData, BaseItemDto itemDto, User user, DtoOptions fields) + public override void FillUserDataDtoValues(UserItemDataDto dto, UserItemData userData, BaseItemDto itemDto, Jellyfin.Data.Entities.User user, DtoOptions fields) { if (!SupportsUserDataFromChildren) { diff --git a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs index bd96059e3..6a2cafcba 100644 --- a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs +++ b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using Jellyfin.Data.Enums; using MediaBrowser.Controller.Dto; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Entities; @@ -15,7 +16,7 @@ namespace MediaBrowser.Controller.Entities public int? Limit { get; set; } - public User User { get; set; } + public Jellyfin.Data.Entities.User User { get; set; } public BaseItem SimilarTo { get; set; } @@ -213,25 +214,26 @@ namespace MediaBrowser.Controller.Entities Years = Array.Empty(); } - public InternalItemsQuery(User user) + public InternalItemsQuery(Jellyfin.Data.Entities.User user) : this() { SetUser(user); } - public void SetUser(User user) + public void SetUser(Jellyfin.Data.Entities.User user) { if (user != null) { - var policy = user.Policy; - MaxParentalRating = policy.MaxParentalRating; + MaxParentalRating = user.MaxParentalAgeRating; - if (policy.MaxParentalRating.HasValue) + if (MaxParentalRating.HasValue) { - BlockUnratedItems = policy.BlockUnratedItems.Where(i => i != UnratedItem.Other).ToArray(); + BlockUnratedItems = user.GetPreference(PreferenceKind.BlockUnratedItems) + .Where(i => i != UnratedItem.Other.ToString()) + .Select(e => Enum.Parse(e, true)).ToArray(); } - ExcludeInheritedTags = policy.BlockedTags; + ExcludeInheritedTags = user.GetPreference(PreferenceKind.BlockedTags); User = user; } diff --git a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs index feaf8c45a..1c1bde3e4 100644 --- a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs +++ b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs @@ -2,11 +2,10 @@ using System; using System.Collections.Generic; using System.Linq; using System.Text.Json.Serialization; +using Jellyfin.Data.Enums; using MediaBrowser.Controller.Providers; -using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Querying; -using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.Entities.Movies { @@ -45,9 +44,9 @@ namespace MediaBrowser.Controller.Entities.Movies /// The display order. public string DisplayOrder { get; set; } - protected override bool GetBlockUnratedValue(UserPolicy config) + protected override bool GetBlockUnratedValue(Jellyfin.Data.Entities.User user) { - return config.BlockUnratedItems.Contains(UnratedItem.Movie); + return user.GetPreference(PreferenceKind.BlockUnratedItems).Contains(UnratedItem.Movie.ToString()); } public override double GetDefaultPrimaryImageAspectRatio() @@ -101,7 +100,7 @@ namespace MediaBrowser.Controller.Entities.Movies [JsonIgnore] public override bool IsPreSorted => true; - public override bool IsAuthorizedToDelete(User user, List allCollectionFolders) + public override bool IsAuthorizedToDelete(Jellyfin.Data.Entities.User user, List allCollectionFolders) { return true; } @@ -111,7 +110,7 @@ namespace MediaBrowser.Controller.Entities.Movies return true; } - public override List GetChildren(User user, bool includeLinkedChildren, InternalItemsQuery query) + public override List GetChildren(Jellyfin.Data.Entities.User user, bool includeLinkedChildren, InternalItemsQuery query) { var children = base.GetChildren(user, includeLinkedChildren, query); @@ -131,7 +130,7 @@ namespace MediaBrowser.Controller.Entities.Movies return LibraryManager.Sort(children, user, new[] { ItemSortBy.ProductionYear, ItemSortBy.PremiereDate, ItemSortBy.SortName }, SortOrder.Ascending).ToList(); } - public override IEnumerable GetRecursiveChildren(User user, InternalItemsQuery query) + public override IEnumerable GetRecursiveChildren(Jellyfin.Data.Entities.User user, InternalItemsQuery query) { var children = base.GetRecursiveChildren(user, query); @@ -149,7 +148,7 @@ namespace MediaBrowser.Controller.Entities.Movies return GetItemLookupInfo(); } - public override bool IsVisible(User user) + public override bool IsVisible(Jellyfin.Data.Entities.User user) { if (IsLegacyBoxSet) { @@ -177,7 +176,7 @@ namespace MediaBrowser.Controller.Entities.Movies return false; } - public override bool IsVisibleStandalone(User user) + public override bool IsVisibleStandalone(Jellyfin.Data.Entities.User user) { if (IsLegacyBoxSet) { @@ -189,7 +188,7 @@ namespace MediaBrowser.Controller.Entities.Movies public Guid[] LibraryFolderIds { get; set; } - private Guid[] GetLibraryFolderIds(User user) + private Guid[] GetLibraryFolderIds(Jellyfin.Data.Entities.User user) { return LibraryManager.GetUserRootFolder().GetChildren(user, true) .Select(i => i.Id) diff --git a/MediaBrowser.Controller/Entities/Movies/Movie.cs b/MediaBrowser.Controller/Entities/Movies/Movie.cs index 11dc472b6..38359afcc 100644 --- a/MediaBrowser.Controller/Entities/Movies/Movie.cs +++ b/MediaBrowser.Controller/Entities/Movies/Movie.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Text.Json.Serialization; using System.Threading; using System.Threading.Tasks; +using Jellyfin.Data.Enums; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Entities; diff --git a/MediaBrowser.Controller/Entities/MusicVideo.cs b/MediaBrowser.Controller/Entities/MusicVideo.cs index 603242063..1b9d4614e 100644 --- a/MediaBrowser.Controller/Entities/MusicVideo.cs +++ b/MediaBrowser.Controller/Entities/MusicVideo.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Text.Json.Serialization; +using Jellyfin.Data.Enums; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Configuration; diff --git a/MediaBrowser.Controller/Entities/TV/Episode.cs b/MediaBrowser.Controller/Entities/TV/Episode.cs index 49229fa4b..0a89da46d 100644 --- a/MediaBrowser.Controller/Entities/TV/Episode.cs +++ b/MediaBrowser.Controller/Entities/TV/Episode.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Text.Json.Serialization; +using Jellyfin.Data.Enums; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Entities; diff --git a/MediaBrowser.Controller/Entities/TV/Season.cs b/MediaBrowser.Controller/Entities/TV/Season.cs index 9c8a469e2..0d1fec62f 100644 --- a/MediaBrowser.Controller/Entities/TV/Season.cs +++ b/MediaBrowser.Controller/Entities/TV/Season.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Linq; using System.Text.Json.Serialization; +using Jellyfin.Data.Enums; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Configuration; @@ -60,7 +61,7 @@ namespace MediaBrowser.Controller.Entities.TV return list; } - public override int GetChildCount(User user) + public override int GetChildCount(Jellyfin.Data.Entities.User user) { var result = GetChildren(user, true).Count; @@ -143,17 +144,17 @@ namespace MediaBrowser.Controller.Entities.TV /// /// Gets the episodes. /// - public List GetEpisodes(User user, DtoOptions options) + public List GetEpisodes(Jellyfin.Data.Entities.User user, DtoOptions options) { return GetEpisodes(Series, user, options); } - public List GetEpisodes(Series series, User user, DtoOptions options) + public List GetEpisodes(Series series, Jellyfin.Data.Entities.User user, DtoOptions options) { return GetEpisodes(series, user, null, options); } - public List GetEpisodes(Series series, User user, IEnumerable allSeriesEpisodes, DtoOptions options) + public List GetEpisodes(Series series, Jellyfin.Data.Entities.User user, IEnumerable allSeriesEpisodes, DtoOptions options) { return series.GetSeasonEpisodes(this, user, allSeriesEpisodes, options); } @@ -163,12 +164,12 @@ namespace MediaBrowser.Controller.Entities.TV return Series.GetSeasonEpisodes(this, null, null, new DtoOptions(true)); } - public override List GetChildren(User user, bool includeLinkedChildren, InternalItemsQuery query) + public override List GetChildren(Jellyfin.Data.Entities.User user, bool includeLinkedChildren, InternalItemsQuery query) { return GetEpisodes(user, new DtoOptions(true)); } - protected override bool GetBlockUnratedValue(UserPolicy config) + protected override bool GetBlockUnratedValue(Jellyfin.Data.Entities.User config) { // Don't block. Let either the entire series rating or episode rating determine it return false; @@ -203,7 +204,7 @@ namespace MediaBrowser.Controller.Entities.TV public Guid FindSeriesId() { var series = FindParent(); - return series == null ? Guid.Empty : series.Id; + return series?.Id ?? Guid.Empty; } /// @@ -234,7 +235,7 @@ namespace MediaBrowser.Controller.Entities.TV if (!IndexNumber.HasValue && !string.IsNullOrEmpty(Path)) { - IndexNumber = IndexNumber ?? LibraryManager.GetSeasonNumberFromPath(Path); + IndexNumber ??= LibraryManager.GetSeasonNumberFromPath(Path); // If a change was made record it if (IndexNumber.HasValue) diff --git a/MediaBrowser.Controller/Entities/TV/Series.cs b/MediaBrowser.Controller/Entities/TV/Series.cs index 2475b2b7e..4aed5fbdc 100644 --- a/MediaBrowser.Controller/Entities/TV/Series.cs +++ b/MediaBrowser.Controller/Entities/TV/Series.cs @@ -5,13 +5,12 @@ using System.Linq; using System.Text.Json.Serialization; using System.Threading; using System.Threading.Tasks; +using Jellyfin.Data.Enums; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Providers; -using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Providers; using MediaBrowser.Model.Querying; -using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.Entities.TV { @@ -111,7 +110,7 @@ namespace MediaBrowser.Controller.Entities.TV return series.GetPresentationUniqueKey(); } - public override int GetChildCount(User user) + public override int GetChildCount(Jellyfin.Data.Entities.User user) { var seriesKey = GetUniqueSeriesKey(this); @@ -119,7 +118,7 @@ namespace MediaBrowser.Controller.Entities.TV { AncestorWithPresentationUniqueKey = null, SeriesPresentationUniqueKey = seriesKey, - IncludeItemTypes = new[] { typeof(Season).Name }, + IncludeItemTypes = new[] { nameof(Season) }, IsVirtualItem = false, Limit = 0, DtoOptions = new DtoOptions(false) @@ -131,7 +130,7 @@ namespace MediaBrowser.Controller.Entities.TV return result; } - public override int GetRecursiveChildCount(User user) + public override int GetRecursiveChildCount(Jellyfin.Data.Entities.User user) { var seriesKey = GetUniqueSeriesKey(this); @@ -179,12 +178,12 @@ namespace MediaBrowser.Controller.Entities.TV return list; } - public override List GetChildren(User user, bool includeLinkedChildren, InternalItemsQuery query) + public override List GetChildren(Jellyfin.Data.Entities.User user, bool includeLinkedChildren, InternalItemsQuery query) { return GetSeasons(user, new DtoOptions(true)); } - public List GetSeasons(User user, DtoOptions options) + public List GetSeasons(Jellyfin.Data.Entities.User user, DtoOptions options) { var query = new InternalItemsQuery(user) { @@ -196,7 +195,7 @@ namespace MediaBrowser.Controller.Entities.TV return LibraryManager.GetItemList(query); } - private void SetSeasonQueryOptions(InternalItemsQuery query, User user) + private void SetSeasonQueryOptions(InternalItemsQuery query, Jellyfin.Data.Entities.User user) { var seriesKey = GetUniqueSeriesKey(this); @@ -205,14 +204,9 @@ namespace MediaBrowser.Controller.Entities.TV query.IncludeItemTypes = new[] { typeof(Season).Name }; query.OrderBy = new[] { ItemSortBy.SortName }.Select(i => new ValueTuple(i, SortOrder.Ascending)).ToArray(); - if (user != null) + if (user != null && !user.DisplayMissingEpisodes) { - var config = user.Configuration; - - if (!config.DisplayMissingEpisodes) - { - query.IsMissing = false; - } + query.IsMissing = false; } } @@ -245,7 +239,7 @@ namespace MediaBrowser.Controller.Entities.TV return LibraryManager.GetItemsResult(query); } - public IEnumerable GetEpisodes(User user, DtoOptions options) + public IEnumerable GetEpisodes(Jellyfin.Data.Entities.User user, DtoOptions options) { var seriesKey = GetUniqueSeriesKey(this); @@ -257,8 +251,8 @@ namespace MediaBrowser.Controller.Entities.TV OrderBy = new[] { ItemSortBy.SortName }.Select(i => new ValueTuple(i, SortOrder.Ascending)).ToArray(), DtoOptions = options }; - var config = user.Configuration; - if (!config.DisplayMissingEpisodes) + + if (!user.DisplayMissingEpisodes) { query.IsMissing = false; } @@ -311,7 +305,7 @@ namespace MediaBrowser.Controller.Entities.TV // Refresh episodes and other children foreach (var item in items) { - if ((item is Season)) + if (item is Season) { continue; } @@ -351,7 +345,7 @@ namespace MediaBrowser.Controller.Entities.TV await ProviderManager.RefreshSingleItem(this, refreshOptions, cancellationToken).ConfigureAwait(false); } - public List GetSeasonEpisodes(Season parentSeason, User user, DtoOptions options) + public List GetSeasonEpisodes(Season parentSeason, Jellyfin.Data.Entities.User user, DtoOptions options) { var queryFromSeries = ConfigurationManager.Configuration.DisplaySpecialsWithinSeasons; @@ -370,8 +364,7 @@ namespace MediaBrowser.Controller.Entities.TV }; if (user != null) { - var config = user.Configuration; - if (!config.DisplayMissingEpisodes) + if (!user.DisplayMissingEpisodes) { query.IsMissing = false; } @@ -382,7 +375,7 @@ namespace MediaBrowser.Controller.Entities.TV return GetSeasonEpisodes(parentSeason, user, allItems, options); } - public List GetSeasonEpisodes(Season parentSeason, User user, IEnumerable allSeriesEpisodes, DtoOptions options) + public List GetSeasonEpisodes(Season parentSeason, Jellyfin.Data.Entities.User user, IEnumerable allSeriesEpisodes, DtoOptions options) { if (allSeriesEpisodes == null) { @@ -452,9 +445,9 @@ namespace MediaBrowser.Controller.Entities.TV } - protected override bool GetBlockUnratedValue(UserPolicy config) + protected override bool GetBlockUnratedValue(Jellyfin.Data.Entities.User user) { - return config.BlockUnratedItems.Contains(UnratedItem.Series); + return user.GetPreference(PreferenceKind.BlockUnratedItems).Contains(UnratedItem.Series.ToString()); } public override UnratedItem GetBlockUnratedType() diff --git a/MediaBrowser.Controller/Entities/Trailer.cs b/MediaBrowser.Controller/Entities/Trailer.cs index 0b8be90cd..c646e8ae6 100644 --- a/MediaBrowser.Controller/Entities/Trailer.cs +++ b/MediaBrowser.Controller/Entities/Trailer.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Text.Json.Serialization; +using Jellyfin.Data.Enums; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Entities; diff --git a/MediaBrowser.Controller/Entities/User.cs b/MediaBrowser.Controller/Entities/User.cs deleted file mode 100644 index 53601a610..000000000 --- a/MediaBrowser.Controller/Entities/User.cs +++ /dev/null @@ -1,262 +0,0 @@ -using System; -using System.Globalization; -using System.IO; -using System.Text.Json.Serialization; -using System.Threading; -using System.Threading.Tasks; -using MediaBrowser.Controller.Library; -using MediaBrowser.Controller.Providers; -using MediaBrowser.Model.Configuration; -using MediaBrowser.Model.Users; - -namespace MediaBrowser.Controller.Entities -{ - /// - /// Class User - /// - public class User : BaseItem - { - public static IUserManager UserManager { get; set; } - - /// - /// Gets or sets the password. - /// - /// The password. - public string Password { get; set; } - public string EasyPassword { get; set; } - - // Strictly to remove JsonIgnore - public override ItemImageInfo[] ImageInfos - { - get => base.ImageInfos; - set => base.ImageInfos = value; - } - - /// - /// Gets or sets the path. - /// - /// The path. - [JsonIgnore] - public override string Path - { - get => ConfigurationDirectoryPath; - set => base.Path = value; - } - - private string _name; - /// - /// Gets or sets the name. - /// - /// The name. - public override string Name - { - get => _name; - set - { - _name = value; - - // lazy load this again - SortName = null; - } - } - - /// - /// Returns the folder containing the item. - /// If the item is a folder, it returns the folder itself - /// - /// The containing folder path. - [JsonIgnore] - public override string ContainingFolderPath => Path; - - /// - /// Gets the root folder. - /// - /// The root folder. - [JsonIgnore] - public Folder RootFolder => LibraryManager.GetUserRootFolder(); - - /// - /// Gets or sets the last login date. - /// - /// The last login date. - public DateTime? LastLoginDate { get; set; } - /// - /// Gets or sets the last activity date. - /// - /// The last activity date. - public DateTime? LastActivityDate { get; set; } - - private volatile UserConfiguration _config; - private readonly object _configSyncLock = new object(); - [JsonIgnore] - public UserConfiguration Configuration - { - get - { - if (_config == null) - { - lock (_configSyncLock) - { - if (_config == null) - { - _config = UserManager.GetUserConfiguration(this); - } - } - } - - return _config; - } - set => _config = value; - } - - private volatile UserPolicy _policy; - private readonly object _policySyncLock = new object(); - [JsonIgnore] - public UserPolicy Policy - { - get - { - if (_policy == null) - { - lock (_policySyncLock) - { - if (_policy == null) - { - _policy = UserManager.GetUserPolicy(this); - } - } - } - - return _policy; - } - set => _policy = value; - } - - /// - /// Renames the user. - /// - /// The new name. - /// Task. - /// - public Task Rename(string newName) - { - if (string.IsNullOrWhiteSpace(newName)) - { - throw new ArgumentException("Username can't be empty", nameof(newName)); - } - - Name = newName; - - return RefreshMetadata( - new MetadataRefreshOptions(new DirectoryService(FileSystem)) - { - ReplaceAllMetadata = true, - ImageRefreshMode = MetadataRefreshMode.FullRefresh, - MetadataRefreshMode = MetadataRefreshMode.FullRefresh, - ForceSave = true - - }, - CancellationToken.None); - } - - public override void UpdateToRepository(ItemUpdateType updateReason, CancellationToken cancellationToken) - { - UserManager.UpdateUser(this); - } - - /// - /// Gets the path to the user's configuration directory - /// - /// The configuration directory path. - [JsonIgnore] - public string ConfigurationDirectoryPath => GetConfigurationDirectoryPath(Name); - - public override double GetDefaultPrimaryImageAspectRatio() - { - return 1; - } - - /// - /// Gets the configuration directory path. - /// - /// The username. - /// System.String. - private string GetConfigurationDirectoryPath(string username) - { - var parentPath = ConfigurationManager.ApplicationPaths.UserConfigurationDirectoryPath; - - // TODO: Remove idPath and just use usernamePath for future releases - var usernamePath = System.IO.Path.Combine(parentPath, username); - var idPath = System.IO.Path.Combine(parentPath, Id.ToString("N", CultureInfo.InvariantCulture)); - if (!Directory.Exists(usernamePath) && Directory.Exists(idPath)) - { - Directory.Move(idPath, usernamePath); - } - - return usernamePath; - } - - public bool IsParentalScheduleAllowed() - { - return IsParentalScheduleAllowed(DateTime.UtcNow); - } - - public bool IsParentalScheduleAllowed(DateTime date) - { - var schedules = Policy.AccessSchedules; - - if (schedules.Length == 0) - { - return true; - } - - foreach (var i in schedules) - { - if (IsParentalScheduleAllowed(i, date)) - { - return true; - } - } - return false; - } - - private bool IsParentalScheduleAllowed(AccessSchedule schedule, DateTime date) - { - if (date.Kind != DateTimeKind.Utc) - { - throw new ArgumentException("Utc date expected"); - } - - var localTime = date.ToLocalTime(); - - return DayOfWeekHelper.GetDaysOfWeek(schedule.DayOfWeek).Contains(localTime.DayOfWeek) && - IsWithinTime(schedule, localTime); - } - - private bool IsWithinTime(AccessSchedule schedule, DateTime localTime) - { - var hour = localTime.TimeOfDay.TotalHours; - - return hour >= schedule.StartHour && hour <= schedule.EndHour; - } - - public bool IsFolderGrouped(Guid id) - { - foreach (var i in Configuration.GroupedFolders) - { - if (new Guid(i) == id) - { - return true; - } - } - return false; - } - - [JsonIgnore] - public override bool SupportsPeople => false; - - public long InternalId { get; set; } - - - } -} diff --git a/MediaBrowser.Controller/Entities/UserRootFolder.cs b/MediaBrowser.Controller/Entities/UserRootFolder.cs index 8a68f830c..9d211540d 100644 --- a/MediaBrowser.Controller/Entities/UserRootFolder.cs +++ b/MediaBrowser.Controller/Entities/UserRootFolder.cs @@ -63,7 +63,7 @@ namespace MediaBrowser.Controller.Entities return UserViewBuilder.SortAndPage(result, null, query, LibraryManager, true); } - public override int GetChildCount(User user) + public override int GetChildCount(Jellyfin.Data.Entities.User user) { return GetChildren(user, true).Count; } @@ -74,7 +74,7 @@ namespace MediaBrowser.Controller.Entities [JsonIgnore] public override bool IsPreSorted => true; - protected override IEnumerable GetEligibleChildrenForRecursiveChildren(User user) + protected override IEnumerable GetEligibleChildrenForRecursiveChildren(Jellyfin.Data.Entities.User user) { var list = base.GetEligibleChildrenForRecursiveChildren(user).ToList(); list.AddRange(LibraryManager.RootFolder.VirtualChildren); diff --git a/MediaBrowser.Controller/Entities/UserView.cs b/MediaBrowser.Controller/Entities/UserView.cs index 4ce9ec6f8..b44e7c191 100644 --- a/MediaBrowser.Controller/Entities/UserView.cs +++ b/MediaBrowser.Controller/Entities/UserView.cs @@ -48,7 +48,7 @@ namespace MediaBrowser.Controller.Entities [JsonIgnore] public override bool SupportsPlayedStatus => false; - public override int GetChildCount(User user) + public override int GetChildCount(Jellyfin.Data.Entities.User user) { return GetChildren(user, true).Count; } @@ -70,7 +70,7 @@ namespace MediaBrowser.Controller.Entities .GetUserItems(parent, this, CollectionType, query); } - public override List GetChildren(User user, bool includeLinkedChildren, InternalItemsQuery query) + public override List GetChildren(Jellyfin.Data.Entities.User user, bool includeLinkedChildren, InternalItemsQuery query) { if (query == null) { @@ -93,7 +93,7 @@ namespace MediaBrowser.Controller.Entities return true; } - public override IEnumerable GetRecursiveChildren(User user, InternalItemsQuery query) + public override IEnumerable GetRecursiveChildren(Jellyfin.Data.Entities.User user, InternalItemsQuery query) { query.SetUser(user); query.Recursive = true; @@ -103,7 +103,7 @@ namespace MediaBrowser.Controller.Entities return GetItemList(query); } - protected override IEnumerable GetEligibleChildrenForRecursiveChildren(User user) + protected override IEnumerable GetEligibleChildrenForRecursiveChildren(Jellyfin.Data.Entities.User user) { return GetChildren(user, false); } diff --git a/MediaBrowser.Controller/Entities/UserViewBuilder.cs b/MediaBrowser.Controller/Entities/UserViewBuilder.cs index 435a1e8da..0ad8e6b71 100644 --- a/MediaBrowser.Controller/Entities/UserViewBuilder.cs +++ b/MediaBrowser.Controller/Entities/UserViewBuilder.cs @@ -125,7 +125,7 @@ namespace MediaBrowser.Controller.Entities return 50; } - private QueryResult GetMovieFolders(Folder parent, User user, InternalItemsQuery query) + private QueryResult GetMovieFolders(Folder parent, Jellyfin.Data.Entities.User user, InternalItemsQuery query) { if (query.Recursive) { @@ -140,19 +140,20 @@ namespace MediaBrowser.Controller.Entities return parent.QueryRecursive(query); } - var list = new List(); - - list.Add(GetUserView(SpecialFolder.MovieResume, "HeaderContinueWatching", "0", parent)); - list.Add(GetUserView(SpecialFolder.MovieLatest, "Latest", "1", parent)); - list.Add(GetUserView(SpecialFolder.MovieMovies, "Movies", "2", parent)); - list.Add(GetUserView(SpecialFolder.MovieCollections, "Collections", "3", parent)); - list.Add(GetUserView(SpecialFolder.MovieFavorites, "Favorites", "4", parent)); - list.Add(GetUserView(SpecialFolder.MovieGenres, "Genres", "5", parent)); + var list = new List + { + GetUserView(SpecialFolder.MovieResume, "HeaderContinueWatching", "0", parent), + GetUserView(SpecialFolder.MovieLatest, "Latest", "1", parent), + GetUserView(SpecialFolder.MovieMovies, "Movies", "2", parent), + GetUserView(SpecialFolder.MovieCollections, "Collections", "3", parent), + GetUserView(SpecialFolder.MovieFavorites, "Favorites", "4", parent), + GetUserView(SpecialFolder.MovieGenres, "Genres", "5", parent) + }; return GetResult(list, parent, query); } - private QueryResult GetFavoriteMovies(Folder parent, User user, InternalItemsQuery query) + private QueryResult GetFavoriteMovies(Folder parent, Jellyfin.Data.Entities.User user, InternalItemsQuery query) { query.Recursive = true; query.Parent = parent; @@ -163,7 +164,7 @@ namespace MediaBrowser.Controller.Entities return _libraryManager.GetItemsResult(query); } - private QueryResult GetFavoriteSeries(Folder parent, User user, InternalItemsQuery query) + private QueryResult GetFavoriteSeries(Folder parent, Jellyfin.Data.Entities.User user, InternalItemsQuery query) { query.Recursive = true; query.Parent = parent; @@ -174,7 +175,7 @@ namespace MediaBrowser.Controller.Entities return _libraryManager.GetItemsResult(query); } - private QueryResult GetFavoriteEpisodes(Folder parent, User user, InternalItemsQuery query) + private QueryResult GetFavoriteEpisodes(Folder parent, Jellyfin.Data.Entities.User user, InternalItemsQuery query) { query.Recursive = true; query.Parent = parent; @@ -185,7 +186,7 @@ namespace MediaBrowser.Controller.Entities return _libraryManager.GetItemsResult(query); } - private QueryResult GetMovieMovies(Folder parent, User user, InternalItemsQuery query) + private QueryResult GetMovieMovies(Folder parent, Jellyfin.Data.Entities.User user, InternalItemsQuery query) { query.Recursive = true; query.Parent = parent; @@ -196,7 +197,7 @@ namespace MediaBrowser.Controller.Entities return _libraryManager.GetItemsResult(query); } - private QueryResult GetMovieCollections(Folder parent, User user, InternalItemsQuery query) + private QueryResult GetMovieCollections(Folder parent, Jellyfin.Data.Entities.User user, InternalItemsQuery query) { query.Parent = null; query.IncludeItemTypes = new[] { typeof(BoxSet).Name }; @@ -206,7 +207,7 @@ namespace MediaBrowser.Controller.Entities return _libraryManager.GetItemsResult(query); } - private QueryResult GetMovieLatest(Folder parent, User user, InternalItemsQuery query) + private QueryResult GetMovieLatest(Folder parent, Jellyfin.Data.Entities.User user, InternalItemsQuery query) { query.OrderBy = new[] { ItemSortBy.DateCreated, ItemSortBy.SortName }.Select(i => new ValueTuple(i, SortOrder.Descending)).ToArray(); @@ -219,7 +220,7 @@ namespace MediaBrowser.Controller.Entities return ConvertToResult(_libraryManager.GetItemList(query)); } - private QueryResult GetMovieResume(Folder parent, User user, InternalItemsQuery query) + private QueryResult GetMovieResume(Folder parent, Jellyfin.Data.Entities.User user, InternalItemsQuery query) { query.OrderBy = new[] { ItemSortBy.DatePlayed, ItemSortBy.SortName }.Select(i => new ValueTuple(i, SortOrder.Descending)).ToArray(); query.IsResumable = true; @@ -242,7 +243,7 @@ namespace MediaBrowser.Controller.Entities }; } - private QueryResult GetMovieGenres(Folder parent, User user, InternalItemsQuery query) + private QueryResult GetMovieGenres(Folder parent, Jellyfin.Data.Entities.User user, InternalItemsQuery query) { var genres = parent.QueryRecursive(new InternalItemsQuery(user) { @@ -272,7 +273,7 @@ namespace MediaBrowser.Controller.Entities return GetResult(genres, parent, query); } - private QueryResult GetMovieGenreItems(Folder queryParent, Folder displayParent, User user, InternalItemsQuery query) + private QueryResult GetMovieGenreItems(Folder queryParent, Folder displayParent, Jellyfin.Data.Entities.User user, InternalItemsQuery query) { query.Recursive = true; query.Parent = queryParent; @@ -284,7 +285,7 @@ namespace MediaBrowser.Controller.Entities return _libraryManager.GetItemsResult(query); } - private QueryResult GetTvView(Folder parent, User user, InternalItemsQuery query) + private QueryResult GetTvView(Folder parent, Jellyfin.Data.Entities.User user, InternalItemsQuery query) { if (query.Recursive) { @@ -293,26 +294,32 @@ namespace MediaBrowser.Controller.Entities if (query.IncludeItemTypes.Length == 0) { - query.IncludeItemTypes = new[] { typeof(Series).Name, typeof(Season).Name, typeof(Episode).Name }; + query.IncludeItemTypes = new[] + { + nameof(Series), + nameof(Season), + nameof(Episode) + }; } return parent.QueryRecursive(query); } - var list = new List(); - - list.Add(GetUserView(SpecialFolder.TvResume, "HeaderContinueWatching", "0", parent)); - list.Add(GetUserView(SpecialFolder.TvNextUp, "HeaderNextUp", "1", parent)); - list.Add(GetUserView(SpecialFolder.TvLatest, "Latest", "2", parent)); - list.Add(GetUserView(SpecialFolder.TvShowSeries, "Shows", "3", parent)); - list.Add(GetUserView(SpecialFolder.TvFavoriteSeries, "HeaderFavoriteShows", "4", parent)); - list.Add(GetUserView(SpecialFolder.TvFavoriteEpisodes, "HeaderFavoriteEpisodes", "5", parent)); - list.Add(GetUserView(SpecialFolder.TvGenres, "Genres", "6", parent)); + var list = new List + { + GetUserView(SpecialFolder.TvResume, "HeaderContinueWatching", "0", parent), + GetUserView(SpecialFolder.TvNextUp, "HeaderNextUp", "1", parent), + GetUserView(SpecialFolder.TvLatest, "Latest", "2", parent), + GetUserView(SpecialFolder.TvShowSeries, "Shows", "3", parent), + GetUserView(SpecialFolder.TvFavoriteSeries, "HeaderFavoriteShows", "4", parent), + GetUserView(SpecialFolder.TvFavoriteEpisodes, "HeaderFavoriteEpisodes", "5", parent), + GetUserView(SpecialFolder.TvGenres, "Genres", "6", parent) + }; return GetResult(list, parent, query); } - private QueryResult GetTvLatest(Folder parent, User user, InternalItemsQuery query) + private QueryResult GetTvLatest(Folder parent, Jellyfin.Data.Entities.User user, InternalItemsQuery query) { query.OrderBy = new[] { ItemSortBy.DateCreated, ItemSortBy.SortName }.Select(i => new ValueTuple(i, SortOrder.Descending)).ToArray(); @@ -341,7 +348,7 @@ namespace MediaBrowser.Controller.Entities return result; } - private QueryResult GetTvResume(Folder parent, User user, InternalItemsQuery query) + private QueryResult GetTvResume(Folder parent, Jellyfin.Data.Entities.User user, InternalItemsQuery query) { query.OrderBy = new[] { ItemSortBy.DatePlayed, ItemSortBy.SortName }.Select(i => new ValueTuple(i, SortOrder.Descending)).ToArray(); query.IsResumable = true; @@ -354,7 +361,7 @@ namespace MediaBrowser.Controller.Entities return ConvertToResult(_libraryManager.GetItemList(query)); } - private QueryResult GetTvSeries(Folder parent, User user, InternalItemsQuery query) + private QueryResult GetTvSeries(Folder parent, Jellyfin.Data.Entities.User user, InternalItemsQuery query) { query.Recursive = true; query.Parent = parent; @@ -365,7 +372,7 @@ namespace MediaBrowser.Controller.Entities return _libraryManager.GetItemsResult(query); } - private QueryResult GetTvGenres(Folder parent, User user, InternalItemsQuery query) + private QueryResult GetTvGenres(Folder parent, Jellyfin.Data.Entities.User user, InternalItemsQuery query) { var genres = parent.QueryRecursive(new InternalItemsQuery(user) { @@ -395,7 +402,7 @@ namespace MediaBrowser.Controller.Entities return GetResult(genres, parent, query); } - private QueryResult GetTvGenreItems(Folder queryParent, Folder displayParent, User user, InternalItemsQuery query) + private QueryResult GetTvGenreItems(Folder queryParent, Folder displayParent, Jellyfin.Data.Entities.User user, InternalItemsQuery query) { query.Recursive = true; query.Parent = queryParent; @@ -417,7 +424,8 @@ namespace MediaBrowser.Controller.Entities }; } - private QueryResult GetResult(IEnumerable items, + private QueryResult GetResult( + IEnumerable items, BaseItem queryParent, InternalItemsQuery query) where T : BaseItem @@ -484,7 +492,7 @@ namespace MediaBrowser.Controller.Entities }; } - public static bool Filter(BaseItem item, User user, InternalItemsQuery query, IUserDataManager userDataManager, ILibraryManager libraryManager) + public static bool Filter(BaseItem item, Jellyfin.Data.Entities.User user, InternalItemsQuery query, IUserDataManager userDataManager, ILibraryManager libraryManager) { if (query.MediaTypes.Length > 0 && !query.MediaTypes.Contains(item.MediaType ?? string.Empty, StringComparer.OrdinalIgnoreCase)) { @@ -942,7 +950,7 @@ namespace MediaBrowser.Controller.Entities return true; } - private IEnumerable GetMediaFolders(User user) + private IEnumerable GetMediaFolders(Jellyfin.Data.Entities.User user) { if (user == null) { @@ -957,7 +965,7 @@ namespace MediaBrowser.Controller.Entities .Where(i => user.IsFolderGrouped(i.Id) && UserView.IsEligibleForGrouping(i)); } - private BaseItem[] GetMediaFolders(User user, IEnumerable viewTypes) + private BaseItem[] GetMediaFolders(Jellyfin.Data.Entities.User user, IEnumerable viewTypes) { if (user == null) { @@ -978,7 +986,7 @@ namespace MediaBrowser.Controller.Entities }).ToArray(); } - private BaseItem[] GetMediaFolders(Folder parent, User user, IEnumerable viewTypes) + private BaseItem[] GetMediaFolders(Folder parent, Jellyfin.Data.Entities.User user, IEnumerable viewTypes) { if (parent == null || parent is UserView) { diff --git a/MediaBrowser.Controller/Library/IIntroProvider.cs b/MediaBrowser.Controller/Library/IIntroProvider.cs index d9d1ca8c7..aa7001611 100644 --- a/MediaBrowser.Controller/Library/IIntroProvider.cs +++ b/MediaBrowser.Controller/Library/IIntroProvider.cs @@ -15,7 +15,7 @@ namespace MediaBrowser.Controller.Library /// The item. /// The user. /// IEnumerable{System.String}. - Task> GetIntros(BaseItem item, User user); + Task> GetIntros(BaseItem item, Jellyfin.Data.Entities.User user); /// /// Gets all intro files. diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs index 2e1c97f67..ada570bfd 100644 --- a/MediaBrowser.Controller/Library/ILibraryManager.cs +++ b/MediaBrowser.Controller/Library/ILibraryManager.cs @@ -141,7 +141,7 @@ namespace MediaBrowser.Controller.Library /// The item. /// The user. /// IEnumerable{System.String}. - Task> GetIntros(BaseItem item, User user); + Task> GetIntros(BaseItem item, Jellyfin.Data.Entities.User user); /// /// Gets all intro files. @@ -172,8 +172,8 @@ namespace MediaBrowser.Controller.Library /// The sort by. /// The sort order. /// IEnumerable{BaseItem}. - IEnumerable Sort(IEnumerable items, User user, IEnumerable sortBy, SortOrder sortOrder); - IEnumerable Sort(IEnumerable items, User user, IEnumerable> orderBy); + IEnumerable Sort(IEnumerable items, Jellyfin.Data.Entities.User user, IEnumerable sortBy, SortOrder sortOrder); + IEnumerable Sort(IEnumerable items, Jellyfin.Data.Entities.User user, IEnumerable> orderBy); /// /// Gets the user root folder. @@ -284,7 +284,8 @@ namespace MediaBrowser.Controller.Library /// The parent identifier. /// Type of the view. /// Name of the sort. - UserView GetNamedView(User user, + UserView GetNamedView( + Jellyfin.Data.Entities.User user, string name, Guid parentId, string viewType, @@ -297,7 +298,8 @@ namespace MediaBrowser.Controller.Library /// The name. /// Type of the view. /// Name of the sort. - UserView GetNamedView(User user, + UserView GetNamedView( + Jellyfin.Data.Entities.User user, string name, string viewType, string sortName); diff --git a/MediaBrowser.Controller/Library/IMediaSourceManager.cs b/MediaBrowser.Controller/Library/IMediaSourceManager.cs index 0ceabd0e6..57368778a 100644 --- a/MediaBrowser.Controller/Library/IMediaSourceManager.cs +++ b/MediaBrowser.Controller/Library/IMediaSourceManager.cs @@ -55,12 +55,12 @@ namespace MediaBrowser.Controller.Library /// /// Gets the playack media sources. /// - Task> GetPlaybackMediaSources(BaseItem item, User user, bool allowMediaProbe, bool enablePathSubstitution, CancellationToken cancellationToken); + Task> GetPlaybackMediaSources(BaseItem item, Jellyfin.Data.Entities.User user, bool allowMediaProbe, bool enablePathSubstitution, CancellationToken cancellationToken); /// /// Gets the static media sources. /// - List GetStaticMediaSources(BaseItem item, bool enablePathSubstitution, User user = null); + List GetStaticMediaSources(BaseItem item, bool enablePathSubstitution, Jellyfin.Data.Entities.User user = null); /// /// Gets the static media source. @@ -100,7 +100,7 @@ namespace MediaBrowser.Controller.Library MediaProtocol GetPathProtocol(string path); - void SetDefaultAudioAndSubtitleStreamIndexes(BaseItem item, MediaSourceInfo source, User user); + void SetDefaultAudioAndSubtitleStreamIndexes(BaseItem item, MediaSourceInfo source, Jellyfin.Data.Entities.User user); Task AddMediaInfoWithProbe(MediaSourceInfo mediaSource, bool isAudio, string cacheKey, bool addProbeDelay, bool isLiveStream, CancellationToken cancellationToken); diff --git a/MediaBrowser.Controller/Library/IMusicManager.cs b/MediaBrowser.Controller/Library/IMusicManager.cs index 554dd0895..0618837bc 100644 --- a/MediaBrowser.Controller/Library/IMusicManager.cs +++ b/MediaBrowser.Controller/Library/IMusicManager.cs @@ -10,16 +10,16 @@ namespace MediaBrowser.Controller.Library /// /// Gets the instant mix from song. /// - List GetInstantMixFromItem(BaseItem item, User user, DtoOptions dtoOptions); + List GetInstantMixFromItem(BaseItem item, Jellyfin.Data.Entities.User user, DtoOptions dtoOptions); /// /// Gets the instant mix from artist. /// - List GetInstantMixFromArtist(MusicArtist artist, User user, DtoOptions dtoOptions); + List GetInstantMixFromArtist(MusicArtist artist, Jellyfin.Data.Entities.User user, DtoOptions dtoOptions); /// /// Gets the instant mix from genre. /// - List GetInstantMixFromGenres(IEnumerable genres, User user, DtoOptions dtoOptions); + List GetInstantMixFromGenres(IEnumerable genres, Jellyfin.Data.Entities.User user, DtoOptions dtoOptions); } } diff --git a/MediaBrowser.Controller/Library/IUserDataManager.cs b/MediaBrowser.Controller/Library/IUserDataManager.cs index eb735d31a..15da560ef 100644 --- a/MediaBrowser.Controller/Library/IUserDataManager.cs +++ b/MediaBrowser.Controller/Library/IUserDataManager.cs @@ -27,18 +27,18 @@ namespace MediaBrowser.Controller.Library /// The reason. /// The cancellation token. void SaveUserData(Guid userId, BaseItem item, UserItemData userData, UserDataSaveReason reason, CancellationToken cancellationToken); - void SaveUserData(User userId, BaseItem item, UserItemData userData, UserDataSaveReason reason, CancellationToken cancellationToken); + void SaveUserData(Jellyfin.Data.Entities.User user, BaseItem item, UserItemData userData, UserDataSaveReason reason, CancellationToken cancellationToken); - UserItemData GetUserData(User user, BaseItem item); + UserItemData GetUserData(Jellyfin.Data.Entities.User user, BaseItem item); UserItemData GetUserData(Guid userId, BaseItem item); /// /// Gets the user data dto. /// - UserItemDataDto GetUserDataDto(BaseItem item, User user); + UserItemDataDto GetUserDataDto(BaseItem item, Jellyfin.Data.Entities.User user); - UserItemDataDto GetUserDataDto(BaseItem item, BaseItemDto itemDto, User user, DtoOptions dto_options); + UserItemDataDto GetUserDataDto(BaseItem item, BaseItemDto itemDto, Jellyfin.Data.Entities.User user, DtoOptions dto_options); /// /// Get all user data for the given user diff --git a/MediaBrowser.Controller/Library/IUserManager.cs b/MediaBrowser.Controller/Library/IUserManager.cs index be7b4ce59..1e385dcb9 100644 --- a/MediaBrowser.Controller/Library/IUserManager.cs +++ b/MediaBrowser.Controller/Library/IUserManager.cs @@ -1,9 +1,8 @@ using System; using System.Collections.Generic; -using System.Threading; using System.Threading.Tasks; +using Jellyfin.Data.Entities; using MediaBrowser.Controller.Authentication; -using MediaBrowser.Controller.Entities; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Events; @@ -17,36 +16,41 @@ namespace MediaBrowser.Controller.Library public interface IUserManager { /// - /// Gets the users. + /// Occurs when a user is updated. /// - /// The users. - IEnumerable Users { get; } + event EventHandler> OnUserUpdated; /// - /// Gets the user ids. + /// Occurs when a user is created. /// - /// The users ids. - IEnumerable UsersIds { get; } + event EventHandler> OnUserCreated; /// - /// Occurs when [user updated]. + /// Occurs when a user is deleted. /// - event EventHandler> UserUpdated; + event EventHandler> OnUserDeleted; /// - /// Occurs when [user deleted]. + /// Occurs when a user's password is changed. /// - event EventHandler> UserDeleted; - - event EventHandler> UserCreated; + event EventHandler> OnUserPasswordChanged; - event EventHandler> UserPolicyUpdated; - - event EventHandler> UserConfigurationUpdated; + /// + /// Occurs when a user is locked out. + /// + event EventHandler> OnUserLockedOut; - event EventHandler> UserPasswordChanged; + /// + /// Gets the users. + /// + /// The users. + IEnumerable Users { get; } - event EventHandler> UserLockedOut; + /// + /// Gets the user ids. + /// + /// The users ids. + IEnumerable UsersIds { get; } /// /// Gets a user by Id. @@ -63,13 +67,6 @@ namespace MediaBrowser.Controller.Library /// User. User GetUserByName(string name); - /// - /// Refreshes metadata for each user - /// - /// The cancellation token. - /// Task. - Task RefreshUsersMetadata(CancellationToken cancellationToken); - /// /// Renames the user. /// @@ -89,19 +86,27 @@ namespace MediaBrowser.Controller.Library void UpdateUser(User user); /// - /// Creates the user. + /// Updates the user. /// - /// The name. - /// User. + /// The user. + /// If user is null. + /// If the provided user doesn't exist. + /// A task representing the update of the user. + Task UpdateUserAsync(User user); + + /// + /// Creates a user with the specified name. + /// + /// The name of the new user. + /// The created user. /// name /// User CreateUser(string name); /// - /// Deletes the user. + /// Deletes the specified user. /// - /// The user. - /// Task. + /// The user to be deleted. void DeleteUser(User user); /// @@ -111,13 +116,6 @@ namespace MediaBrowser.Controller.Library /// Task. Task ResetPassword(User user); - /// - /// Gets the offline user dto. - /// - /// The user. - /// UserDto. - UserDto GetOfflineUserDto(User user); - /// /// Resets the easy password. /// @@ -163,47 +161,28 @@ namespace MediaBrowser.Controller.Library /// true if XXXX, false otherwise. Task RedeemPasswordResetPin(string pin); - /// - /// Gets the user policy. - /// - /// The user. - /// UserPolicy. - UserPolicy GetUserPolicy(User user); - - /// - /// Gets the user configuration. - /// - /// The user. - /// UserConfiguration. - UserConfiguration GetUserConfiguration(User user); + void AddParts(IEnumerable authenticationProviders, IEnumerable passwordResetProviders); - /// - /// Updates the configuration. - /// - /// The user identifier. - /// The new configuration. - /// Task. - void UpdateConfiguration(Guid userId, UserConfiguration newConfiguration); + NameIdPair[] GetAuthenticationProviders(); - void UpdateConfiguration(User user, UserConfiguration newConfiguration); + NameIdPair[] GetPasswordResetProviders(); /// - /// Updates the user policy. + /// This method updates the user's configuration. + /// This is only included as a stopgap until the new API, using this internally is not recommended. + /// Instead, modify the user object directlu, then call . /// - /// The user identifier. - /// The user policy. - void UpdateUserPolicy(Guid userId, UserPolicy userPolicy); + /// The user's Id. + /// The request containing the new user configuration. + void UpdateConfiguration(Guid userId, UserConfiguration config); /// - /// Makes the valid username. + /// This method updates the user's policy. + /// This is only included as a stopgap until the new API, using this internally is not recommended. + /// Instead, modify the user object directlu, then call . /// - /// The username. - /// System.String. - string MakeValidUsername(string username); - - void AddParts(IEnumerable authenticationProviders, IEnumerable passwordResetProviders); - - NameIdPair[] GetAuthenticationProviders(); - NameIdPair[] GetPasswordResetProviders(); + /// The user's Id. + /// The request containing the new user policy. + void UpdatePolicy(Guid userId, UserPolicy policy); } } diff --git a/MediaBrowser.Controller/Library/PlaybackProgressEventArgs.cs b/MediaBrowser.Controller/Library/PlaybackProgressEventArgs.cs index b0302d04c..83c0e3297 100644 --- a/MediaBrowser.Controller/Library/PlaybackProgressEventArgs.cs +++ b/MediaBrowser.Controller/Library/PlaybackProgressEventArgs.cs @@ -11,7 +11,7 @@ namespace MediaBrowser.Controller.Library /// public class PlaybackProgressEventArgs : EventArgs { - public List Users { get; set; } + public List Users { get; set; } public long? PlaybackPositionTicks { get; set; } public BaseItem Item { get; set; } public BaseItemDto MediaInfo { get; set; } @@ -28,7 +28,7 @@ namespace MediaBrowser.Controller.Library public PlaybackProgressEventArgs() { - Users = new List(); + Users = new List(); } } } diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs index e02c387e4..99fd18bf9 100644 --- a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs +++ b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs @@ -115,7 +115,7 @@ namespace MediaBrowser.Controller.LiveTv /// The cancellation token. /// The user. /// Task{ProgramInfoDto}. - Task GetProgram(string id, CancellationToken cancellationToken, User user = null); + Task GetProgram(string id, CancellationToken cancellationToken, Jellyfin.Data.Entities.User user = null); /// /// Gets the programs. @@ -202,7 +202,7 @@ namespace MediaBrowser.Controller.LiveTv /// Gets the enabled users. /// /// IEnumerable{User}. - IEnumerable GetEnabledUsers(); + IEnumerable GetEnabledUsers(); /// /// Gets the internal channels. @@ -221,7 +221,7 @@ namespace MediaBrowser.Controller.LiveTv /// The fields. /// The user. /// Task. - Task AddInfoToProgramDto(IReadOnlyCollection<(BaseItem, BaseItemDto)> programs, ItemFields[] fields, User user = null); + Task AddInfoToProgramDto(IReadOnlyCollection<(BaseItem, BaseItemDto)> programs, ItemFields[] fields, Jellyfin.Data.Entities.User user = null); /// /// Saves the tuner host. @@ -258,7 +258,7 @@ namespace MediaBrowser.Controller.LiveTv /// The items. /// The options. /// The user. - void AddChannelInfo(IReadOnlyCollection<(BaseItemDto, LiveTvChannel)> items, DtoOptions options, User user); + void AddChannelInfo(IReadOnlyCollection<(BaseItemDto, LiveTvChannel)> items, DtoOptions options, Jellyfin.Data.Entities.User user); Task> GetChannelsForListingsProvider(string id, CancellationToken cancellationToken); Task> GetChannelsFromListingsProviderData(string id, CancellationToken cancellationToken); @@ -277,9 +277,9 @@ namespace MediaBrowser.Controller.LiveTv ActiveRecordingInfo GetActiveRecordingInfo(string path); - void AddInfoToRecordingDto(BaseItem item, BaseItemDto dto, ActiveRecordingInfo activeRecordingInfo, User user = null); + void AddInfoToRecordingDto(BaseItem item, BaseItemDto dto, ActiveRecordingInfo activeRecordingInfo, Jellyfin.Data.Entities.User user = null); - List GetRecordingFolders(User user); + List GetRecordingFolders(Jellyfin.Data.Entities.User user); } public class ActiveRecordingInfo diff --git a/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs b/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs index 60391bb83..f3ff8bd04 100644 --- a/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs +++ b/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Text.Json.Serialization; +using Jellyfin.Data.Enums; using MediaBrowser.Controller.Entities; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Dto; diff --git a/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs b/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs index 13df85aed..e6dc4bdda 100644 --- a/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs +++ b/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Text.Json.Serialization; +using Jellyfin.Data.Enums; using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Providers; diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 61a330675..2559bc248 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -5,6 +5,7 @@ using System.IO; using System.Linq; using System.Text; using System.Threading; +using Jellyfin.Data.Enums; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Extensions; using MediaBrowser.Model.Configuration; @@ -1991,7 +1992,7 @@ namespace MediaBrowser.Controller.MediaEncoding filters.Add("hwupload"); } - // When the input may or may not be hardware QSV decodable + // When the input may or may not be hardware QSV decodable else if (string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase)) { if (!hasTextSubs) @@ -2147,7 +2148,7 @@ namespace MediaBrowser.Controller.MediaEncoding var user = state.User; // If the user doesn't have access to transcoding, then force stream copy, regardless of whether it will be compatible or not - if (user != null && !user.Policy.EnableVideoPlaybackTranscoding) + if (user != null && !user.HasPermission(PermissionKind.EnableVideoPlaybackTranscoding)) { state.OutputVideoCodec = "copy"; } @@ -2163,7 +2164,7 @@ namespace MediaBrowser.Controller.MediaEncoding var user = state.User; // If the user doesn't have access to transcoding, then force stream copy, regardless of whether it will be compatible or not - if (user != null && !user.Policy.EnableAudioPlaybackTranscoding) + if (user != null && !user.HasPermission(PermissionKind.EnableAudioPlaybackTranscoding)) { state.OutputAudioCodec = "copy"; } diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs b/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs index 1127a08de..dc4361fc3 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs @@ -18,23 +18,38 @@ namespace MediaBrowser.Controller.MediaEncoding public class EncodingJobInfo { public MediaStream VideoStream { get; set; } + public VideoType VideoType { get; set; } + public Dictionary RemoteHttpHeaders { get; set; } + public string OutputVideoCodec { get; set; } + public MediaProtocol InputProtocol { get; set; } + public string MediaPath { get; set; } + public bool IsInputVideo { get; set; } + public IIsoMount IsoMount { get; set; } + public string[] PlayableStreamFileNames { get; set; } + public string OutputAudioCodec { get; set; } + public int? OutputVideoBitrate { get; set; } + public MediaStream SubtitleStream { get; set; } + public SubtitleDeliveryMethod SubtitleDeliveryMethod { get; set; } + public string[] SupportedSubtitleCodecs { get; set; } public int InternalSubtitleStreamOffset { get; set; } + public MediaSourceInfo MediaSource { get; set; } - public User User { get; set; } + + public Jellyfin.Data.Entities.User User { get; set; } public long? RunTimeTicks { get; set; } diff --git a/MediaBrowser.Controller/Net/AuthorizationInfo.cs b/MediaBrowser.Controller/Net/AuthorizationInfo.cs index 3e004763d..4361e253b 100644 --- a/MediaBrowser.Controller/Net/AuthorizationInfo.cs +++ b/MediaBrowser.Controller/Net/AuthorizationInfo.cs @@ -1,36 +1,40 @@ using System; -using MediaBrowser.Controller.Entities; +using Jellyfin.Data.Entities; namespace MediaBrowser.Controller.Net { public class AuthorizationInfo { /// - /// Gets or sets the user identifier. + /// Gets the user identifier. /// /// The user identifier. - public Guid UserId => User == null ? Guid.Empty : User.Id; + public Guid UserId => User?.Id ?? Guid.Empty; /// /// Gets or sets the device identifier. /// /// The device identifier. public string DeviceId { get; set; } + /// /// Gets or sets the device. /// /// The device. public string Device { get; set; } + /// /// Gets or sets the client. /// /// The client. public string Client { get; set; } + /// /// Gets or sets the version. /// /// The version. public string Version { get; set; } + /// /// Gets or sets the token. /// diff --git a/MediaBrowser.Controller/Net/IAuthService.cs b/MediaBrowser.Controller/Net/IAuthService.cs index 9132404a0..61fc7e6e6 100644 --- a/MediaBrowser.Controller/Net/IAuthService.cs +++ b/MediaBrowser.Controller/Net/IAuthService.cs @@ -9,6 +9,6 @@ namespace MediaBrowser.Controller.Net public interface IAuthService { void Authenticate(IRequest request, IAuthenticationAttributes authAttribtues); - User? Authenticate(HttpRequest request, IAuthenticationAttributes authAttribtues); + Jellyfin.Data.Entities.User? Authenticate(HttpRequest request, IAuthenticationAttributes authAttribtues); } } diff --git a/MediaBrowser.Controller/Net/ISessionContext.cs b/MediaBrowser.Controller/Net/ISessionContext.cs index 5c3c19f6b..421ac3fe2 100644 --- a/MediaBrowser.Controller/Net/ISessionContext.cs +++ b/MediaBrowser.Controller/Net/ISessionContext.cs @@ -1,4 +1,4 @@ -using MediaBrowser.Controller.Entities; +using Jellyfin.Data.Entities; using MediaBrowser.Controller.Session; using MediaBrowser.Model.Services; diff --git a/MediaBrowser.Controller/Notifications/INotificationService.cs b/MediaBrowser.Controller/Notifications/INotificationService.cs index 8c6019923..2bc751758 100644 --- a/MediaBrowser.Controller/Notifications/INotificationService.cs +++ b/MediaBrowser.Controller/Notifications/INotificationService.cs @@ -25,6 +25,6 @@ namespace MediaBrowser.Controller.Notifications /// /// The user. /// true if [is enabled for user] [the specified user identifier]; otherwise, false. - bool IsEnabledForUser(User user); + bool IsEnabledForUser(Jellyfin.Data.Entities.User user); } } diff --git a/MediaBrowser.Controller/Notifications/UserNotification.cs b/MediaBrowser.Controller/Notifications/UserNotification.cs index 3f46468b3..a1029589b 100644 --- a/MediaBrowser.Controller/Notifications/UserNotification.cs +++ b/MediaBrowser.Controller/Notifications/UserNotification.cs @@ -1,5 +1,5 @@ using System; -using MediaBrowser.Controller.Entities; +using Jellyfin.Data.Entities; using MediaBrowser.Model.Notifications; namespace MediaBrowser.Controller.Notifications diff --git a/MediaBrowser.Controller/Persistence/IUserRepository.cs b/MediaBrowser.Controller/Persistence/IUserRepository.cs deleted file mode 100644 index cd23e5223..000000000 --- a/MediaBrowser.Controller/Persistence/IUserRepository.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System.Collections.Generic; -using MediaBrowser.Controller.Entities; - -namespace MediaBrowser.Controller.Persistence -{ - /// - /// Provides an interface to implement a User repository - /// - public interface IUserRepository : IRepository - { - /// - /// Deletes the user. - /// - /// The user. - /// Task. - void DeleteUser(User user); - - /// - /// Retrieves all users. - /// - /// IEnumerable{User}. - List RetrieveAllUsers(); - - void CreateUser(User user); - void UpdateUser(User user); - } -} diff --git a/MediaBrowser.Controller/Playlists/Playlist.cs b/MediaBrowser.Controller/Playlists/Playlist.cs index 3b08e72b9..03bdf1eaf 100644 --- a/MediaBrowser.Controller/Playlists/Playlist.cs +++ b/MediaBrowser.Controller/Playlists/Playlist.cs @@ -78,7 +78,7 @@ namespace MediaBrowser.Controller.Playlists return 1; } - public override bool IsAuthorizedToDelete(User user, List allCollectionFolders) + public override bool IsAuthorizedToDelete(Jellyfin.Data.Entities.User user, List allCollectionFolders) { return true; } @@ -99,7 +99,7 @@ namespace MediaBrowser.Controller.Playlists return Task.CompletedTask; } - public override List GetChildren(User user, bool includeLinkedChildren, InternalItemsQuery query) + public override List GetChildren(Jellyfin.Data.Entities.User user, bool includeLinkedChildren, InternalItemsQuery query) { return GetPlayableItems(user, query); } @@ -109,7 +109,7 @@ namespace MediaBrowser.Controller.Playlists return new List(); } - public override IEnumerable GetRecursiveChildren(User user, InternalItemsQuery query) + public override IEnumerable GetRecursiveChildren(Jellyfin.Data.Entities.User user, InternalItemsQuery query) { return GetPlayableItems(user, query); } @@ -119,7 +119,7 @@ namespace MediaBrowser.Controller.Playlists return GetLinkedChildrenInfos(); } - private List GetPlayableItems(User user, InternalItemsQuery query) + private List GetPlayableItems(Jellyfin.Data.Entities.User user, InternalItemsQuery query) { if (query == null) { @@ -131,7 +131,7 @@ namespace MediaBrowser.Controller.Playlists return base.GetChildren(user, true, query); } - public static List GetPlaylistItems(string playlistMediaType, IEnumerable inputItems, User user, DtoOptions options) + public static List GetPlaylistItems(string playlistMediaType, IEnumerable inputItems, Jellyfin.Data.Entities.User user, DtoOptions options) { if (user != null) { @@ -149,7 +149,7 @@ namespace MediaBrowser.Controller.Playlists return list; } - private static IEnumerable GetPlaylistItems(BaseItem item, User user, string mediaType, DtoOptions options) + private static IEnumerable GetPlaylistItems(BaseItem item, Jellyfin.Data.Entities.User user, string mediaType, DtoOptions options) { if (item is MusicGenre musicGenre) { @@ -222,7 +222,7 @@ namespace MediaBrowser.Controller.Playlists } } - public override bool IsVisible(User user) + public override bool IsVisible(Jellyfin.Data.Entities.User user) { if (!IsSharedItem) { @@ -241,18 +241,10 @@ namespace MediaBrowser.Controller.Playlists } var userId = user.Id.ToString("N", CultureInfo.InvariantCulture); - foreach (var share in shares) - { - if (string.Equals(share.UserId, userId, StringComparison.OrdinalIgnoreCase)) - { - return true; - } - } - - return false; + return shares.Any(share => string.Equals(share.UserId, userId, StringComparison.OrdinalIgnoreCase)); } - public override bool IsVisibleStandalone(User user) + public override bool IsVisibleStandalone(Jellyfin.Data.Entities.User user) { if (!IsSharedItem) { diff --git a/MediaBrowser.Controller/Providers/IProviderManager.cs b/MediaBrowser.Controller/Providers/IProviderManager.cs index 254b27460..955db0278 100644 --- a/MediaBrowser.Controller/Providers/IProviderManager.cs +++ b/MediaBrowser.Controller/Providers/IProviderManager.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.IO; using System.Threading; using System.Threading.Tasks; +using Jellyfin.Data.Entities; using MediaBrowser.Common.Net; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; @@ -70,6 +71,8 @@ namespace MediaBrowser.Controller.Providers /// Task. Task SaveImage(BaseItem item, string source, string mimeType, ImageType type, int? imageIndex, bool? saveLocallyWithMedia, CancellationToken cancellationToken); + Task SaveImage(User user, Stream source, string mimeType, string path); + /// /// Adds the metadata providers. /// diff --git a/MediaBrowser.Controller/Session/ISessionManager.cs b/MediaBrowser.Controller/Session/ISessionManager.cs index 771027103..32e62db14 100644 --- a/MediaBrowser.Controller/Session/ISessionManager.cs +++ b/MediaBrowser.Controller/Session/ISessionManager.cs @@ -74,7 +74,7 @@ namespace MediaBrowser.Controller.Session /// Name of the device. /// The remote end point. /// The user. - SessionInfo LogSessionActivity(string appName, string appVersion, string deviceId, string deviceName, string remoteEndPoint, User user); + SessionInfo LogSessionActivity(string appName, string appVersion, string deviceId, string deviceName, string remoteEndPoint, Jellyfin.Data.Entities.User user); void UpdateDeviceName(string sessionId, string reportedDeviceName); diff --git a/MediaBrowser.Controller/Sorting/IUserBaseItemComparer.cs b/MediaBrowser.Controller/Sorting/IUserBaseItemComparer.cs index 1e2df37bf..f079bc7ea 100644 --- a/MediaBrowser.Controller/Sorting/IUserBaseItemComparer.cs +++ b/MediaBrowser.Controller/Sorting/IUserBaseItemComparer.cs @@ -12,7 +12,7 @@ namespace MediaBrowser.Controller.Sorting /// Gets or sets the user. /// /// The user. - User User { get; set; } + Jellyfin.Data.Entities.User User { get; set; } /// /// Gets or sets the user manager. diff --git a/MediaBrowser.Model/Configuration/AccessSchedule.cs b/MediaBrowser.Model/Configuration/AccessSchedule.cs index 120c47dbc..7bd355449 100644 --- a/MediaBrowser.Model/Configuration/AccessSchedule.cs +++ b/MediaBrowser.Model/Configuration/AccessSchedule.cs @@ -1,3 +1,5 @@ +using Jellyfin.Data.Enums; + #pragma warning disable CS1591 namespace MediaBrowser.Model.Configuration diff --git a/MediaBrowser.Model/Configuration/DynamicDayOfWeek.cs b/MediaBrowser.Model/Configuration/DynamicDayOfWeek.cs deleted file mode 100644 index 71b16cfba..000000000 --- a/MediaBrowser.Model/Configuration/DynamicDayOfWeek.cs +++ /dev/null @@ -1,18 +0,0 @@ -#pragma warning disable CS1591 - -namespace MediaBrowser.Model.Configuration -{ - public enum DynamicDayOfWeek - { - Sunday = 0, - Monday = 1, - Tuesday = 2, - Wednesday = 3, - Thursday = 4, - Friday = 5, - Saturday = 6, - Everyday = 7, - Weekday = 8, - Weekend = 9 - } -} diff --git a/MediaBrowser.Model/Configuration/SubtitlePlaybackMode.cs b/MediaBrowser.Model/Configuration/SubtitlePlaybackMode.cs deleted file mode 100644 index f0aa2b98c..000000000 --- a/MediaBrowser.Model/Configuration/SubtitlePlaybackMode.cs +++ /dev/null @@ -1,13 +0,0 @@ -#pragma warning disable CS1591 - -namespace MediaBrowser.Model.Configuration -{ - public enum SubtitlePlaybackMode - { - Default = 0, - Always = 1, - OnlyForced = 2, - None = 3, - Smart = 4 - } -} diff --git a/MediaBrowser.Model/Configuration/UnratedItem.cs b/MediaBrowser.Model/Configuration/UnratedItem.cs deleted file mode 100644 index e1d1a363d..000000000 --- a/MediaBrowser.Model/Configuration/UnratedItem.cs +++ /dev/null @@ -1,17 +0,0 @@ -#pragma warning disable CS1591 - -namespace MediaBrowser.Model.Configuration -{ - public enum UnratedItem - { - Movie, - Trailer, - Series, - Music, - Book, - LiveTvChannel, - LiveTvProgram, - ChannelContent, - Other - } -} diff --git a/MediaBrowser.Model/Configuration/UserConfiguration.cs b/MediaBrowser.Model/Configuration/UserConfiguration.cs index a475c9910..79cf0a065 100644 --- a/MediaBrowser.Model/Configuration/UserConfiguration.cs +++ b/MediaBrowser.Model/Configuration/UserConfiguration.cs @@ -1,6 +1,7 @@ #pragma warning disable CS1591 using System; +using Jellyfin.Data.Enums; namespace MediaBrowser.Model.Configuration { diff --git a/MediaBrowser.Model/Notifications/NotificationOptions.cs b/MediaBrowser.Model/Notifications/NotificationOptions.cs index 79a128e9b..b3c46ace2 100644 --- a/MediaBrowser.Model/Notifications/NotificationOptions.cs +++ b/MediaBrowser.Model/Notifications/NotificationOptions.cs @@ -1,6 +1,7 @@ #pragma warning disable CS1591 using System; +using Jellyfin.Data.Enums; using MediaBrowser.Model.Extensions; using MediaBrowser.Model.Users; @@ -109,7 +110,7 @@ namespace MediaBrowser.Model.Notifications !ListHelper.ContainsIgnoreCase(opt.DisabledMonitorUsers, userId.ToString("")); } - public bool IsEnabledToSendToUser(string type, string userId, UserPolicy userPolicy) + public bool IsEnabledToSendToUser(string type, string userId, Jellyfin.Data.Entities.User user) { NotificationOption opt = GetOptions(type); @@ -120,7 +121,7 @@ namespace MediaBrowser.Model.Notifications return true; } - if (opt.SendToUserMode == SendToUserType.Admins && userPolicy.IsAdministrator) + if (opt.SendToUserMode == SendToUserType.Admins && user.HasPermission(PermissionKind.IsAdministrator)) { return true; } diff --git a/MediaBrowser.Model/Users/UserPolicy.cs b/MediaBrowser.Model/Users/UserPolicy.cs index ae2b3fd4e..8d94d3971 100644 --- a/MediaBrowser.Model/Users/UserPolicy.cs +++ b/MediaBrowser.Model/Users/UserPolicy.cs @@ -1,7 +1,8 @@ #pragma warning disable CS1591 using System; -using MediaBrowser.Model.Configuration; +using Jellyfin.Data.Entities; +using Jellyfin.Data.Enums; namespace MediaBrowser.Model.Users { @@ -33,7 +34,7 @@ namespace MediaBrowser.Model.Users public string[] BlockedTags { get; set; } public bool EnableUserPreferenceAccess { get; set; } - public AccessSchedule[] AccessSchedules { get; set; } + public Jellyfin.Data.Entities.AccessSchedule[] AccessSchedules { get; set; } public UnratedItem[] BlockUnratedItems { get; set; } public bool EnableRemoteControlOfOtherUsers { get; set; } public bool EnableSharedDeviceControl { get; set; } @@ -77,7 +78,7 @@ namespace MediaBrowser.Model.Users public string[] BlockedChannels { get; set; } public int RemoteClientBitrateLimit { get; set; } - public string AuthenticationProviderId { get; set; } + public string AuthenticatioIsnProviderId { get; set; } public string PasswordResetProviderId { get; set; } public UserPolicy() diff --git a/MediaBrowser.Providers/Manager/ImageSaver.cs b/MediaBrowser.Providers/Manager/ImageSaver.cs index 3ab621ba4..6bed38780 100644 --- a/MediaBrowser.Providers/Manager/ImageSaver.cs +++ b/MediaBrowser.Providers/Manager/ImageSaver.cs @@ -5,17 +5,21 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; +using Jellyfin.Data.Entities; using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; -using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Entities; using MediaBrowser.Model.IO; using MediaBrowser.Model.Net; using Microsoft.Extensions.Logging; +using Episode = MediaBrowser.Controller.Entities.TV.Episode; +using MusicAlbum = MediaBrowser.Controller.Entities.Audio.MusicAlbum; +using Person = MediaBrowser.Controller.Entities.Person; +using Season = MediaBrowser.Controller.Entities.TV.Season; namespace MediaBrowser.Providers.Manager { @@ -78,11 +82,6 @@ namespace MediaBrowser.Providers.Manager var saveLocally = item.SupportsLocalMetadata && item.IsSaveLocalMetadataEnabled() && !item.ExtraType.HasValue && !(item is Audio); - if (item is User) - { - saveLocally = true; - } - if (type != ImageType.Primary && item is Episode) { saveLocally = false; @@ -136,7 +135,7 @@ namespace MediaBrowser.Providers.Manager var savedPaths = new List(); - using (source) + await using (source) { var currentPathIndex = 0; @@ -172,7 +171,6 @@ namespace MediaBrowser.Providers.Manager } catch (FileNotFoundException) { - } finally { @@ -181,6 +179,16 @@ namespace MediaBrowser.Providers.Manager } } + public async Task SaveImage(User user, Stream source, string mimeType, string path) + { + if (string.IsNullOrEmpty(mimeType)) + { + throw new ArgumentNullException(nameof(mimeType)); + } + + await SaveImageToLocation(source, path, path, CancellationToken.None).ConfigureAwait(false); + } + private async Task SaveImageToLocation(Stream source, string path, string retryPath, CancellationToken cancellationToken) { try @@ -244,7 +252,7 @@ namespace MediaBrowser.Providers.Manager _fileSystem.SetAttributes(path, false, false); - using (var fs = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous)) + await using (var fs = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous)) { await source.CopyToAsync(fs, IODefaults.CopyToBufferSize, cancellationToken).ConfigureAwait(false); } @@ -439,7 +447,6 @@ namespace MediaBrowser.Providers.Manager { path = Path.Combine(Path.GetDirectoryName(item.Path), "metadata", filename + extension); } - else if (item.IsInMixedFolder) { path = GetSavePathForItemInMixedFolder(item, type, filename, extension); diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs index cfff89767..f4e875a24 100644 --- a/MediaBrowser.Providers/Manager/ProviderManager.cs +++ b/MediaBrowser.Providers/Manager/ProviderManager.cs @@ -8,6 +8,7 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; +using Jellyfin.Data.Entities; using MediaBrowser.Common.Net; using MediaBrowser.Common.Progress; using MediaBrowser.Controller; @@ -16,7 +17,6 @@ using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Entities.Movies; -using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Providers; using MediaBrowser.Controller.Subtitles; @@ -28,6 +28,12 @@ using MediaBrowser.Model.Providers; using MediaBrowser.Model.Serialization; using Microsoft.Extensions.Logging; using Priority_Queue; +using Book = MediaBrowser.Controller.Entities.Book; +using Episode = MediaBrowser.Controller.Entities.TV.Episode; +using Movie = MediaBrowser.Controller.Entities.Movies.Movie; +using MusicAlbum = MediaBrowser.Controller.Entities.Audio.MusicAlbum; +using Season = MediaBrowser.Controller.Entities.TV.Season; +using Series = MediaBrowser.Controller.Entities.TV.Series; namespace MediaBrowser.Providers.Manager { @@ -182,6 +188,12 @@ namespace MediaBrowser.Providers.Manager return new ImageSaver(_configurationManager, _libraryMonitor, _fileSystem, _logger).SaveImage(item, fileStream, mimeType, type, imageIndex, saveLocallyWithMedia, cancellationToken); } + public Task SaveImage(User user, Stream source, string mimeType, string path) + { + return new ImageSaver(_configurationManager, _libraryMonitor, _fileSystem, _logger) + .SaveImage(user, source, mimeType, path); + } + public async Task> GetAvailableRemoteImages(BaseItem item, RemoteImageQuery query, CancellationToken cancellationToken) { var providers = GetRemoteImageProviders(item, query.IncludeDisabledProviders); diff --git a/MediaBrowser.Providers/Users/UserMetadataService.cs b/MediaBrowser.Providers/Users/UserMetadataService.cs deleted file mode 100644 index fb6c91b6c..000000000 --- a/MediaBrowser.Providers/Users/UserMetadataService.cs +++ /dev/null @@ -1,30 +0,0 @@ -using MediaBrowser.Controller.Configuration; -using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Library; -using MediaBrowser.Controller.Providers; -using MediaBrowser.Model.Entities; -using MediaBrowser.Model.IO; -using MediaBrowser.Providers.Manager; -using Microsoft.Extensions.Logging; - -namespace MediaBrowser.Providers.Users -{ - public class UserMetadataService : MetadataService - { - public UserMetadataService( - IServerConfigurationManager serverConfigurationManager, - ILogger logger, - IProviderManager providerManager, - IFileSystem fileSystem, - ILibraryManager libraryManager) - : base(serverConfigurationManager, logger, providerManager, fileSystem, libraryManager) - { - } - - /// - protected override void MergeData(MetadataResult source, MetadataResult target, MetadataFields[] lockedFields, bool replaceData, bool mergeMetadataSettings) - { - ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings); - } - } -} diff --git a/tests/Jellyfin.Api.Tests/Auth/CustomAuthenticationHandlerTests.cs b/tests/Jellyfin.Api.Tests/Auth/CustomAuthenticationHandlerTests.cs index 3b3d03c8b..0cb8d8be6 100644 --- a/tests/Jellyfin.Api.Tests/Auth/CustomAuthenticationHandlerTests.cs +++ b/tests/Jellyfin.Api.Tests/Auth/CustomAuthenticationHandlerTests.cs @@ -7,6 +7,7 @@ using AutoFixture; using AutoFixture.AutoMoq; using Jellyfin.Api.Auth; using Jellyfin.Api.Constants; +using Jellyfin.Data.Enums; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Net; using Microsoft.AspNetCore.Authentication; @@ -83,7 +84,7 @@ namespace Jellyfin.Api.Tests.Auth a => a.Authenticate( It.IsAny(), It.IsAny())) - .Returns((User?)null); + .Returns((Jellyfin.Data.Entities.User?)null); var authenticateResult = await _sut.AuthenticateAsync(); @@ -124,7 +125,7 @@ namespace Jellyfin.Api.Tests.Auth var user = SetupUser(); var authenticateResult = await _sut.AuthenticateAsync(); - Assert.True(authenticateResult.Principal.HasClaim(ClaimTypes.Name, user.Name)); + Assert.True(authenticateResult.Principal.HasClaim(ClaimTypes.Name, user.Username)); } [Theory] @@ -135,7 +136,7 @@ namespace Jellyfin.Api.Tests.Auth var user = SetupUser(isAdmin); var authenticateResult = await _sut.AuthenticateAsync(); - var expectedRole = user.Policy.IsAdministrator ? UserRoles.Administrator : UserRoles.User; + var expectedRole = user.HasPermission(PermissionKind.IsAdministrator) ? UserRoles.Administrator : UserRoles.User; Assert.True(authenticateResult.Principal.HasClaim(ClaimTypes.Role, expectedRole)); } @@ -148,10 +149,10 @@ namespace Jellyfin.Api.Tests.Auth Assert.Equal(_scheme.Name, authenticatedResult.Ticket.AuthenticationScheme); } - private User SetupUser(bool isAdmin = false) + private Jellyfin.Data.Entities.User SetupUser(bool isAdmin = false) { - var user = _fixture.Create(); - user.Policy.IsAdministrator = isAdmin; + var user = _fixture.Create(); + user.SetPermission(PermissionKind.IsAdministrator, isAdmin); _jellyfinAuthServiceMock.Setup( a => a.Authenticate( -- cgit v1.2.3 From 51cdb30741e5ad3d6ec9dc8a5383dc84d60f747a Mon Sep 17 00:00:00 2001 From: Mark Monteiro Date: Wed, 13 May 2020 09:46:29 -0400 Subject: Apply documentation suggestions from code review Co-authored-by: Vasily --- MediaBrowser.Controller/IServerApplicationHost.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/IServerApplicationHost.cs b/MediaBrowser.Controller/IServerApplicationHost.cs index 4f0ff1ee1..db330210a 100644 --- a/MediaBrowser.Controller/IServerApplicationHost.cs +++ b/MediaBrowser.Controller/IServerApplicationHost.cs @@ -72,7 +72,7 @@ namespace MediaBrowser.Controller Task GetLocalApiUrl(CancellationToken cancellationToken); /// - /// Gets a local (LAN) URL that can be used to access the API using the loop-back IP address (127.0.0.1) + /// 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). /// /// The API URL. @@ -87,6 +87,7 @@ namespace MediaBrowser.Controller /// /// 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. /// /// The hostname to use in the URL. /// -- cgit v1.2.3 From 511d20a100398baca38f24adfabc56f6f3cfac9c Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Wed, 13 May 2020 15:03:35 -0400 Subject: Apply review suggestions --- .../Activity/ActivityLogEntryPoint.cs | 110 ++++++--------------- .../Devices/DeviceManager.cs | 105 -------------------- Jellyfin.Data/Entities/ActivityLog.cs | 47 +++++---- .../Activity/ActivityManager.cs | 2 +- .../Migrations/Routines/MigrateActivityLogDb.cs | 67 ++++++------- MediaBrowser.Api/Devices/DeviceService.cs | 36 ------- MediaBrowser.Api/Library/LibraryService.cs | 4 +- MediaBrowser.Api/System/ActivityLogService.cs | 6 -- MediaBrowser.Controller/Devices/IDeviceManager.cs | 21 ---- MediaBrowser.sln | 4 +- 10 files changed, 88 insertions(+), 314 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs b/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs index 54894fd65..3983824a3 100644 --- a/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs +++ b/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs @@ -8,7 +8,6 @@ using Jellyfin.Data.Entities; using MediaBrowser.Common.Plugins; using MediaBrowser.Common.Updates; using MediaBrowser.Controller.Authentication; -using MediaBrowser.Controller.Devices; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Plugins; using MediaBrowser.Controller.Session; @@ -30,7 +29,7 @@ namespace Emby.Server.Implementations.Activity /// public sealed class ActivityLogEntryPoint : IServerEntryPoint { - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IInstallationManager _installationManager; private readonly ISessionManager _sessionManager; private readonly ITaskManager _taskManager; @@ -38,14 +37,12 @@ namespace Emby.Server.Implementations.Activity private readonly ILocalizationManager _localization; private readonly ISubtitleManager _subManager; private readonly IUserManager _userManager; - private readonly IDeviceManager _deviceManager; /// /// Initializes a new instance of the class. /// /// The logger. /// The session manager. - /// The device manager. /// The task manager. /// The activity manager. /// The localization manager. @@ -55,7 +52,6 @@ namespace Emby.Server.Implementations.Activity public ActivityLogEntryPoint( ILogger logger, ISessionManager sessionManager, - IDeviceManager deviceManager, ITaskManager taskManager, IActivityManager activityManager, ILocalizationManager localization, @@ -65,7 +61,6 @@ namespace Emby.Server.Implementations.Activity { _logger = logger; _sessionManager = sessionManager; - _deviceManager = deviceManager; _taskManager = taskManager; _activityManager = activityManager; _localization = localization; @@ -99,36 +94,18 @@ namespace Emby.Server.Implementations.Activity _userManager.UserPolicyUpdated += OnUserPolicyUpdated; _userManager.UserLockedOut += OnUserLockedOut; - _deviceManager.CameraImageUploaded += OnCameraImageUploaded; - return Task.CompletedTask; } - private async void OnCameraImageUploaded(object sender, GenericEventArgs e) - { - await CreateLogEntry(new ActivityLog( - string.Format( - CultureInfo.InvariantCulture, - _localization.GetLocalizedString("CameraImageUploadedFrom"), - e.Argument.Device.Name), - NotificationType.CameraImageUploaded.ToString(), - Guid.Empty, - DateTime.UtcNow, - LogLevel.Trace)) - .ConfigureAwait(false); - } - private async void OnUserLockedOut(object sender, GenericEventArgs e) { await CreateLogEntry(new ActivityLog( - string.Format( - CultureInfo.InvariantCulture, - _localization.GetLocalizedString("UserLockedOutWithName"), - e.Argument.Name), - NotificationType.UserLockedOut.ToString(), - e.Argument.Id, - DateTime.UtcNow, - LogLevel.Trace)) + string.Format( + CultureInfo.InvariantCulture, + _localization.GetLocalizedString("UserLockedOutWithName"), + e.Argument.Name), + NotificationType.UserLockedOut.ToString(), + e.Argument.Id)) .ConfigureAwait(false); } @@ -139,11 +116,9 @@ namespace Emby.Server.Implementations.Activity CultureInfo.InvariantCulture, _localization.GetLocalizedString("SubtitleDownloadFailureFromForItem"), e.Provider, - Emby.Notifications.NotificationEntryPoint.GetItemName(e.Item)), + Notifications.NotificationEntryPoint.GetItemName(e.Item)), "SubtitleDownloadFailure", - Guid.Empty, - DateTime.UtcNow, - LogLevel.Trace) + Guid.Empty) { ItemId = e.Item.Id.ToString("N", CultureInfo.InvariantCulture), ShortOverview = e.Exception.Message @@ -181,9 +156,7 @@ namespace Emby.Server.Implementations.Activity GetItemName(item), e.DeviceName), GetPlaybackStoppedNotificationType(item.MediaType), - user.Id, - DateTime.UtcNow, - LogLevel.Trace)) + user.Id)) .ConfigureAwait(false); } @@ -218,9 +191,7 @@ namespace Emby.Server.Implementations.Activity GetItemName(item), e.DeviceName), GetPlaybackNotificationType(item.MediaType), - user.Id, - DateTime.UtcNow, - LogLevel.Trace)) + user.Id)) .ConfigureAwait(false); } @@ -287,9 +258,7 @@ namespace Emby.Server.Implementations.Activity session.UserName, session.DeviceName), "SessionEnded", - session.UserId, - DateTime.UtcNow, - LogLevel.Trace) + session.UserId) { ShortOverview = string.Format( CultureInfo.InvariantCulture, @@ -308,9 +277,7 @@ namespace Emby.Server.Implementations.Activity _localization.GetLocalizedString("AuthenticationSucceededWithUserName"), user.Name), "AuthenticationSucceeded", - user.Id, - DateTime.UtcNow, - LogLevel.Trace) + user.Id) { ShortOverview = string.Format( CultureInfo.InvariantCulture, @@ -327,10 +294,9 @@ namespace Emby.Server.Implementations.Activity _localization.GetLocalizedString("FailedLoginAttemptWithUserName"), e.Argument.Username), "AuthenticationFailed", - Guid.Empty, - DateTime.UtcNow, - LogLevel.Error) + Guid.Empty) { + LogSeverity = LogLevel.Error, ShortOverview = string.Format( CultureInfo.InvariantCulture, _localization.GetLocalizedString("LabelIpAddressValue"), @@ -346,9 +312,7 @@ namespace Emby.Server.Implementations.Activity _localization.GetLocalizedString("UserPolicyUpdatedWithName"), e.Argument.Name), "UserPolicyUpdated", - e.Argument.Id, - DateTime.UtcNow, - LogLevel.Trace)) + e.Argument.Id)) .ConfigureAwait(false); } @@ -360,9 +324,7 @@ namespace Emby.Server.Implementations.Activity _localization.GetLocalizedString("UserDeletedWithName"), e.Argument.Name), "UserDeleted", - Guid.Empty, - DateTime.UtcNow, - LogLevel.Trace)) + Guid.Empty)) .ConfigureAwait(false); } @@ -374,9 +336,8 @@ namespace Emby.Server.Implementations.Activity _localization.GetLocalizedString("UserPasswordChangedWithName"), e.Argument.Name), "UserPasswordChanged", - e.Argument.Id, - DateTime.UtcNow, - LogLevel.Trace)).ConfigureAwait(false); + e.Argument.Id)) + .ConfigureAwait(false); } private async void OnUserCreated(object sender, GenericEventArgs e) @@ -387,9 +348,7 @@ namespace Emby.Server.Implementations.Activity _localization.GetLocalizedString("UserCreatedWithName"), e.Argument.Name), "UserCreated", - e.Argument.Id, - DateTime.UtcNow, - LogLevel.Trace)) + e.Argument.Id)) .ConfigureAwait(false); } @@ -409,9 +368,7 @@ namespace Emby.Server.Implementations.Activity session.UserName, session.DeviceName), "SessionStarted", - session.UserId, - DateTime.UtcNow, - LogLevel.Trace) + session.UserId) { ShortOverview = string.Format( CultureInfo.InvariantCulture, @@ -428,9 +385,7 @@ namespace Emby.Server.Implementations.Activity _localization.GetLocalizedString("PluginUpdatedWithName"), e.Argument.Item1.Name), NotificationType.PluginUpdateInstalled.ToString(), - Guid.Empty, - DateTime.UtcNow, - LogLevel.Trace) + Guid.Empty) { ShortOverview = string.Format( CultureInfo.InvariantCulture, @@ -448,9 +403,7 @@ namespace Emby.Server.Implementations.Activity _localization.GetLocalizedString("PluginUninstalledWithName"), e.Argument.Name), NotificationType.PluginUninstalled.ToString(), - Guid.Empty, - DateTime.UtcNow, - LogLevel.Trace)) + Guid.Empty)) .ConfigureAwait(false); } @@ -462,9 +415,7 @@ namespace Emby.Server.Implementations.Activity _localization.GetLocalizedString("PluginInstalledWithName"), e.Argument.name), NotificationType.PluginInstalled.ToString(), - Guid.Empty, - DateTime.UtcNow, - LogLevel.Trace) + Guid.Empty) { ShortOverview = string.Format( CultureInfo.InvariantCulture, @@ -483,9 +434,7 @@ namespace Emby.Server.Implementations.Activity _localization.GetLocalizedString("NameInstallFailed"), installationInfo.Name), NotificationType.InstallationFailed.ToString(), - Guid.Empty, - DateTime.UtcNow, - LogLevel.Trace) + Guid.Empty) { ShortOverview = string.Format( CultureInfo.InvariantCulture, @@ -529,10 +478,9 @@ namespace Emby.Server.Implementations.Activity await CreateLogEntry(new ActivityLog( string.Format(CultureInfo.InvariantCulture, _localization.GetLocalizedString("ScheduledTaskFailedWithName"), task.Name), NotificationType.TaskFailed.ToString(), - Guid.Empty, - DateTime.UtcNow, - LogLevel.Error) + Guid.Empty) { + LogSeverity = LogLevel.Error, Overview = string.Join(Environment.NewLine, vals), ShortOverview = runningTime }).ConfigureAwait(false); @@ -567,8 +515,6 @@ namespace Emby.Server.Implementations.Activity _userManager.UserDeleted -= OnUserDeleted; _userManager.UserPolicyUpdated -= OnUserPolicyUpdated; _userManager.UserLockedOut -= OnUserLockedOut; - - _deviceManager.CameraImageUploaded -= OnCameraImageUploaded; } /// @@ -588,7 +534,7 @@ namespace Emby.Server.Implementations.Activity { int years = days / DaysInYear; values.Add(CreateValueString(years, "year")); - days = days % DaysInYear; + days %= DaysInYear; } // Number of months diff --git a/Emby.Server.Implementations/Devices/DeviceManager.cs b/Emby.Server.Implementations/Devices/DeviceManager.cs index 579cb895e..7017be6eb 100644 --- a/Emby.Server.Implementations/Devices/DeviceManager.cs +++ b/Emby.Server.Implementations/Devices/DeviceManager.cs @@ -34,7 +34,6 @@ namespace Emby.Server.Implementations.Devices private readonly IJsonSerializer _json; private readonly IUserManager _userManager; private readonly IFileSystem _fileSystem; - private readonly ILibraryMonitor _libraryMonitor; private readonly IServerConfigurationManager _config; private readonly ILibraryManager _libraryManager; private readonly ILocalizationManager _localizationManager; @@ -43,9 +42,6 @@ namespace Emby.Server.Implementations.Devices public event EventHandler>> DeviceOptionsUpdated; - public event EventHandler> CameraImageUploaded; - - private readonly object _cameraUploadSyncLock = new object(); private readonly object _capabilitiesSyncLock = new object(); public DeviceManager( @@ -55,13 +51,11 @@ namespace Emby.Server.Implementations.Devices ILocalizationManager localizationManager, IUserManager userManager, IFileSystem fileSystem, - ILibraryMonitor libraryMonitor, IServerConfigurationManager config) { _json = json; _userManager = userManager; _fileSystem = fileSystem; - _libraryMonitor = libraryMonitor; _config = config; _libraryManager = libraryManager; _localizationManager = localizationManager; @@ -194,105 +188,6 @@ namespace Emby.Server.Implementations.Devices return Path.Combine(GetDevicesPath(), id.GetMD5().ToString("N", CultureInfo.InvariantCulture)); } - public ContentUploadHistory GetCameraUploadHistory(string deviceId) - { - var path = Path.Combine(GetDevicePath(deviceId), "camerauploads.json"); - - lock (_cameraUploadSyncLock) - { - try - { - return _json.DeserializeFromFile(path); - } - catch (IOException) - { - return new ContentUploadHistory - { - DeviceId = deviceId - }; - } - } - } - - public async Task AcceptCameraUpload(string deviceId, Stream stream, LocalFileInfo file) - { - var device = GetDevice(deviceId, false); - var uploadPathInfo = GetUploadPath(device); - - var path = uploadPathInfo.Item1; - - if (!string.IsNullOrWhiteSpace(file.Album)) - { - path = Path.Combine(path, _fileSystem.GetValidFilename(file.Album)); - } - - path = Path.Combine(path, file.Name); - path = Path.ChangeExtension(path, MimeTypes.ToExtension(file.MimeType) ?? "jpg"); - - Directory.CreateDirectory(Path.GetDirectoryName(path)); - - await EnsureLibraryFolder(uploadPathInfo.Item2, uploadPathInfo.Item3).ConfigureAwait(false); - - _libraryMonitor.ReportFileSystemChangeBeginning(path); - - try - { - using (var fs = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read)) - { - await stream.CopyToAsync(fs).ConfigureAwait(false); - } - - AddCameraUpload(deviceId, file); - } - finally - { - _libraryMonitor.ReportFileSystemChangeComplete(path, true); - } - - if (CameraImageUploaded != null) - { - CameraImageUploaded?.Invoke(this, new GenericEventArgs - { - Argument = new CameraImageUploadInfo - { - Device = device, - FileInfo = file - } - }); - } - } - - private void AddCameraUpload(string deviceId, LocalFileInfo file) - { - var path = Path.Combine(GetDevicePath(deviceId), "camerauploads.json"); - Directory.CreateDirectory(Path.GetDirectoryName(path)); - - lock (_cameraUploadSyncLock) - { - ContentUploadHistory history; - - try - { - history = _json.DeserializeFromFile(path); - } - catch (IOException) - { - history = new ContentUploadHistory - { - DeviceId = deviceId - }; - } - - history.DeviceId = deviceId; - - var list = history.FilesUploaded.ToList(); - list.Add(file); - history.FilesUploaded = list.ToArray(); - - _json.SerializeToFile(history, path); - } - } - internal Task EnsureLibraryFolder(string path, string name) { var existingFolders = _libraryManager diff --git a/Jellyfin.Data/Entities/ActivityLog.cs b/Jellyfin.Data/Entities/ActivityLog.cs index 633838991..df3026a77 100644 --- a/Jellyfin.Data/Entities/ActivityLog.cs +++ b/Jellyfin.Data/Entities/ActivityLog.cs @@ -1,15 +1,10 @@ using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.ComponentModel; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -using System.Linq; -using System.Runtime.CompilerServices; +using Microsoft.Extensions.Logging; namespace Jellyfin.Data.Entities { - [Table("ActivityLog")] public partial class ActivityLog { partial void Init(); @@ -35,23 +30,26 @@ namespace Jellyfin.Data.Entities /// /// /// - /// + /// /// - /// - public ActivityLog(string name, string type, Guid userid, DateTime datecreated, Microsoft.Extensions.Logging.LogLevel logseverity) + /// + public ActivityLog(string name, string type, Guid userId) { - if (string.IsNullOrEmpty(name)) throw new ArgumentNullException(nameof(name)); - this.Name = name; - - if (string.IsNullOrEmpty(type)) throw new ArgumentNullException(nameof(type)); - this.Type = type; - - this.UserId = userid; + if (string.IsNullOrEmpty(name)) + { + throw new ArgumentNullException(nameof(name)); + } - this.DateCreated = datecreated; - - this.LogSeverity = logseverity; + if (string.IsNullOrEmpty(type)) + { + throw new ArgumentNullException(nameof(type)); + } + this.Name = name; + this.Type = type; + this.UserId = userId; + this.DateCreated = DateTime.UtcNow; + this.LogSeverity = LogLevel.Trace; Init(); } @@ -61,12 +59,12 @@ namespace Jellyfin.Data.Entities /// /// /// - /// + /// /// /// - public static ActivityLog Create(string name, string type, Guid userid, DateTime datecreated, Microsoft.Extensions.Logging.LogLevel logseverity) + public static ActivityLog Create(string name, string type, Guid userId) { - return new ActivityLog(name, type, userid, datecreated, logseverity); + return new ActivityLog(name, type, userId); } /************************************************************************* @@ -134,10 +132,10 @@ namespace Jellyfin.Data.Entities /// Required /// [Required] - public Microsoft.Extensions.Logging.LogLevel LogSeverity { get; set; } + public LogLevel LogSeverity { get; set; } /// - /// Required, ConcurrenyToken + /// Required, ConcurrencyToken. /// [ConcurrencyCheck] [Required] @@ -147,7 +145,6 @@ namespace Jellyfin.Data.Entities { RowVersion++; } - } } diff --git a/Jellyfin.Server.Implementations/Activity/ActivityManager.cs b/Jellyfin.Server.Implementations/Activity/ActivityManager.cs index d7bbf793c..531b529dc 100644 --- a/Jellyfin.Server.Implementations/Activity/ActivityManager.cs +++ b/Jellyfin.Server.Implementations/Activity/ActivityManager.cs @@ -14,7 +14,7 @@ namespace Jellyfin.Server.Implementations.Activity /// public class ActivityManager : IActivityManager { - private JellyfinDbProvider _provider; + private readonly JellyfinDbProvider _provider; /// /// Initializes a new instance of the class. diff --git a/Jellyfin.Server/Migrations/Routines/MigrateActivityLogDb.cs b/Jellyfin.Server/Migrations/Routines/MigrateActivityLogDb.cs index fe7ef01ee..faa163d19 100644 --- a/Jellyfin.Server/Migrations/Routines/MigrateActivityLogDb.cs +++ b/Jellyfin.Server/Migrations/Routines/MigrateActivityLogDb.cs @@ -1,6 +1,5 @@ -#pragma warning disable CS1591 - using System; +using System.Collections.Generic; using System.IO; using Emby.Server.Implementations.Data; using Jellyfin.Data.Entities; @@ -12,6 +11,9 @@ using SQLitePCL.pretty; namespace Jellyfin.Server.Migrations.Routines { + /// + /// The migration routine for migrating the activity log database to EF Core. + /// public class MigrateActivityLogDb : IMigrationRoutine { private const string DbFilename = "activitylog.db"; @@ -20,6 +22,12 @@ namespace Jellyfin.Server.Migrations.Routines private readonly JellyfinDbProvider _provider; private readonly IServerApplicationPaths _paths; + /// + /// Initializes a new instance of the class. + /// + /// The logger. + /// The server application paths. + /// The database provider. public MigrateActivityLogDb(ILogger logger, IServerApplicationPaths paths, JellyfinDbProvider provider) { _logger = logger; @@ -27,19 +35,35 @@ namespace Jellyfin.Server.Migrations.Routines _paths = paths; } + /// public Guid Id => Guid.Parse("3793eb59-bc8c-456c-8b9f-bd5a62a42978"); + /// public string Name => "MigrateActivityLogDatabase"; + /// public void Perform() { + var logLevelDictionary = new Dictionary(StringComparer.OrdinalIgnoreCase) + { + { "None", LogLevel.None }, + { "Trace", LogLevel.Trace }, + { "Debug", LogLevel.Debug }, + { "Information", LogLevel.Information }, + { "Info", LogLevel.Information }, + { "Warn", LogLevel.Warning }, + { "Warning", LogLevel.Warning }, + { "Error", LogLevel.Error }, + { "Critical", LogLevel.Critical } + }; + var dataPath = _paths.DataPath; using (var connection = SQLite3.Open( Path.Combine(dataPath, DbFilename), ConnectionFlags.ReadOnly, null)) { - _logger.LogInformation("Migrating the database may take a while, do not stop Jellyfin."); + _logger.LogWarning("Migrating the activity database may take a while, do not stop Jellyfin."); using var dbContext = _provider.CreateContext(); var queryResult = connection.Query("SELECT * FROM ActivityLog ORDER BY Id ASC"); @@ -56,9 +80,11 @@ namespace Jellyfin.Server.Migrations.Routines var newEntry = new ActivityLog( entry[1].ToString(), entry[4].ToString(), - entry[6].SQLiteType == SQLiteType.Null ? Guid.Empty : Guid.Parse(entry[6].ToString()), - entry[7].ReadDateTime(), - ParseLogLevel(entry[8].ToString())); + entry[6].SQLiteType == SQLiteType.Null ? Guid.Empty : Guid.Parse(entry[6].ToString())) + { + DateCreated = entry[7].ReadDateTime(), + LogSeverity = logLevelDictionary[entry[8].ToString()] + }; if (entry[2].SQLiteType != SQLiteType.Null) { @@ -75,6 +101,8 @@ namespace Jellyfin.Server.Migrations.Routines newEntry.ItemId = entry[5].ToString(); } + // Since code references the Id of the entries, this needs to be inserted in order. + // In order to do that, this is needed because EF Core doesn't provide a way to guarantee ordering for bulk inserts. dbContext.ActivityLogs.Add(newEntry); dbContext.SaveChanges(); } @@ -89,32 +117,5 @@ namespace Jellyfin.Server.Migrations.Routines _logger.LogError(e, "Error renaming legacy activity log database to 'activitylog.db.old'"); } } - - private LogLevel ParseLogLevel(string entry) - { - if (string.Equals(entry, "Debug", StringComparison.OrdinalIgnoreCase)) - { - return LogLevel.Debug; - } - - if (string.Equals(entry, "Information", StringComparison.OrdinalIgnoreCase) - || string.Equals(entry, "Info", StringComparison.OrdinalIgnoreCase)) - { - return LogLevel.Information; - } - - if (string.Equals(entry, "Warning", StringComparison.OrdinalIgnoreCase) - || string.Equals(entry, "Warn", StringComparison.OrdinalIgnoreCase)) - { - return LogLevel.Warning; - } - - if (string.Equals(entry, "Error", StringComparison.OrdinalIgnoreCase)) - { - return LogLevel.Error; - } - - return LogLevel.Trace; - } } } diff --git a/MediaBrowser.Api/Devices/DeviceService.cs b/MediaBrowser.Api/Devices/DeviceService.cs index 7004a2559..53eb9667d 100644 --- a/MediaBrowser.Api/Devices/DeviceService.cs +++ b/MediaBrowser.Api/Devices/DeviceService.cs @@ -1,5 +1,4 @@ using System.IO; -using System.Threading.Tasks; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Devices; using MediaBrowser.Controller.Net; @@ -116,11 +115,6 @@ namespace MediaBrowser.Api.Devices return _deviceManager.GetDeviceOptions(request.Id); } - public object Get(GetCameraUploads request) - { - return ToOptimizedResult(_deviceManager.GetCameraUploadHistory(request.DeviceId)); - } - public void Delete(DeleteDevice request) { var sessions = _authRepo.Get(new AuthenticationInfoQuery @@ -134,35 +128,5 @@ namespace MediaBrowser.Api.Devices _sessionManager.Logout(session); } } - - public Task Post(PostCameraUpload request) - { - var deviceId = Request.QueryString["DeviceId"]; - var album = Request.QueryString["Album"]; - var id = Request.QueryString["Id"]; - var name = Request.QueryString["Name"]; - var req = Request.Response.HttpContext.Request; - - if (req.HasFormContentType) - { - var file = req.Form.Files.Count == 0 ? null : req.Form.Files[0]; - - return _deviceManager.AcceptCameraUpload(deviceId, file.OpenReadStream(), new LocalFileInfo - { - MimeType = file.ContentType, - Album = album, - Name = name, - Id = id - }); - } - - return _deviceManager.AcceptCameraUpload(deviceId, request.RequestStream, new LocalFileInfo - { - MimeType = Request.ContentType, - Album = album, - Name = name, - Id = id - }); - } } } diff --git a/MediaBrowser.Api/Library/LibraryService.cs b/MediaBrowser.Api/Library/LibraryService.cs index 997b1c45a..93852e970 100644 --- a/MediaBrowser.Api/Library/LibraryService.cs +++ b/MediaBrowser.Api/Library/LibraryService.cs @@ -762,9 +762,7 @@ namespace MediaBrowser.Api.Library _activityManager.Create(new Jellyfin.Data.Entities.ActivityLog( string.Format(_localization.GetLocalizedString("UserDownloadingItemWithValues"), user.Name, item.Name), "UserDownloadingContent", - auth.UserId, - DateTime.UtcNow, - LogLevel.Trace) + auth.UserId) { ShortOverview = string.Format(_localization.GetLocalizedString("AppDeviceValues"), auth.Client, auth.Device), }); diff --git a/MediaBrowser.Api/System/ActivityLogService.cs b/MediaBrowser.Api/System/ActivityLogService.cs index 0a5fc9433..f2c37d711 100644 --- a/MediaBrowser.Api/System/ActivityLogService.cs +++ b/MediaBrowser.Api/System/ActivityLogService.cs @@ -1,5 +1,3 @@ -using System; -using System.Globalization; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Net; using MediaBrowser.Model.Activity; @@ -49,10 +47,6 @@ namespace MediaBrowser.Api.System public object Get(GetActivityLogs request) { - DateTime? minDate = string.IsNullOrWhiteSpace(request.MinDate) ? - (DateTime?)null : - DateTime.Parse(request.MinDate, null, DateTimeStyles.RoundtripKind).ToUniversalTime(); - var result = _activityManager.GetPagedResult(request.StartIndex, request.Limit); return ToOptimizedResult(result); diff --git a/MediaBrowser.Controller/Devices/IDeviceManager.cs b/MediaBrowser.Controller/Devices/IDeviceManager.cs index 77d567631..4256bdb10 100644 --- a/MediaBrowser.Controller/Devices/IDeviceManager.cs +++ b/MediaBrowser.Controller/Devices/IDeviceManager.cs @@ -11,11 +11,6 @@ namespace MediaBrowser.Controller.Devices { public interface IDeviceManager { - /// - /// Occurs when [camera image uploaded]. - /// - event EventHandler> CameraImageUploaded; - /// /// Saves the capabilities. /// @@ -45,22 +40,6 @@ namespace MediaBrowser.Controller.Devices /// IEnumerable<DeviceInfo>. QueryResult GetDevices(DeviceQuery query); - /// - /// Gets the upload history. - /// - /// The device identifier. - /// ContentUploadHistory. - ContentUploadHistory GetCameraUploadHistory(string deviceId); - - /// - /// Accepts the upload. - /// - /// The device identifier. - /// The stream. - /// The file. - /// Task. - Task AcceptCameraUpload(string deviceId, Stream stream, LocalFileInfo file); - /// /// Determines whether this instance [can access device] the specified user identifier. /// diff --git a/MediaBrowser.sln b/MediaBrowser.sln index 210e2b644..e100c0b1c 100644 --- a/MediaBrowser.sln +++ b/MediaBrowser.sln @@ -1,6 +1,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.30011.22 +# Visual Studio 15 +VisualStudioVersion = 15.0.26730.3 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Jellyfin.Server", "Jellyfin.Server\Jellyfin.Server.csproj", "{07E39F42-A2C6-4B32-AF8C-725F957A73FF}" EndProject -- cgit v1.2.3 From 1e9b2613c690f4afe561eb8401705834bb51b6b8 Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Wed, 13 May 2020 15:35:14 -0400 Subject: Remove more unused code --- .../Devices/DeviceManager.cs | 58 +--------------------- MediaBrowser.Controller/Devices/IDeviceManager.cs | 2 - 2 files changed, 2 insertions(+), 58 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/Devices/DeviceManager.cs b/Emby.Server.Implementations/Devices/DeviceManager.cs index 7017be6eb..158cc6a74 100644 --- a/Emby.Server.Implementations/Devices/DeviceManager.cs +++ b/Emby.Server.Implementations/Devices/DeviceManager.cs @@ -20,7 +20,6 @@ using MediaBrowser.Model.Entities; using MediaBrowser.Model.Events; using MediaBrowser.Model.Globalization; using MediaBrowser.Model.IO; -using MediaBrowser.Model.Net; using MediaBrowser.Model.Querying; using MediaBrowser.Model.Serialization; using MediaBrowser.Model.Session; @@ -220,41 +219,6 @@ namespace Emby.Server.Implementations.Devices return _libraryManager.AddVirtualFolder(name, CollectionType.HomeVideos, libraryOptions, true); } - private Tuple GetUploadPath(DeviceInfo device) - { - var config = _config.GetUploadOptions(); - var path = config.CameraUploadPath; - - if (string.IsNullOrWhiteSpace(path)) - { - path = DefaultCameraUploadsPath; - } - - var topLibraryPath = path; - - if (config.EnableCameraUploadSubfolders) - { - path = Path.Combine(path, _fileSystem.GetValidFilename(device.Name)); - } - - return new Tuple(path, topLibraryPath, null); - } - - internal string GetUploadsPath() - { - var config = _config.GetUploadOptions(); - var path = config.CameraUploadPath; - - if (string.IsNullOrWhiteSpace(path)) - { - path = DefaultCameraUploadsPath; - } - - return path; - } - - private string DefaultCameraUploadsPath => Path.Combine(_config.CommonApplicationPaths.DataPath, "camerauploads"); - public bool CanAccessDevice(User user, string deviceId) { if (user == null) @@ -311,27 +275,9 @@ namespace Emby.Server.Implementations.Devices _logger = logger; } - public async Task RunAsync() + public Task RunAsync() { - if (!_config.Configuration.CameraUploadUpgraded && _config.Configuration.IsStartupWizardCompleted) - { - var path = _deviceManager.GetUploadsPath(); - - if (Directory.Exists(path)) - { - try - { - await _deviceManager.EnsureLibraryFolder(path, null).ConfigureAwait(false); - } - catch (Exception ex) - { - _logger.LogError(ex, "Error creating camera uploads library"); - } - - _config.Configuration.CameraUploadUpgraded = true; - _config.SaveConfiguration(); - } - } + return Task.CompletedTask; } #region IDisposable Support diff --git a/MediaBrowser.Controller/Devices/IDeviceManager.cs b/MediaBrowser.Controller/Devices/IDeviceManager.cs index 4256bdb10..ef3f43c75 100644 --- a/MediaBrowser.Controller/Devices/IDeviceManager.cs +++ b/MediaBrowser.Controller/Devices/IDeviceManager.cs @@ -1,6 +1,4 @@ using System; -using System.IO; -using System.Threading.Tasks; using MediaBrowser.Controller.Entities; using MediaBrowser.Model.Devices; using MediaBrowser.Model.Events; -- cgit v1.2.3 From 3cb6fd8a2754837c787213c008ad84a973eb7cab Mon Sep 17 00:00:00 2001 From: Frank Riley Date: Thu, 7 May 2020 20:36:50 -0700 Subject: Fix #3083: Set the Access-Control-Allow-Origin header to the request origin/host header if possible --- .../HttpServer/HttpListenerHost.cs | 35 +++++++++++++++++++--- .../HttpServer/ResponseFilter.cs | 19 +++++++++--- MediaBrowser.Controller/Net/IHttpServer.cs | 8 +++++ 3 files changed, 54 insertions(+), 8 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs index 81e793f5c..48cec8741 100644 --- a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs +++ b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs @@ -28,6 +28,7 @@ using Microsoft.AspNetCore.WebUtilities; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Primitives; using ServiceStack.Text.Jsv; namespace Emby.Server.Implementations.HttpServer @@ -454,9 +455,10 @@ namespace Emby.Server.Implementations.HttpServer if (string.Equals(httpReq.Verb, "OPTIONS", StringComparison.OrdinalIgnoreCase)) { httpRes.StatusCode = 200; - httpRes.Headers.Add("Access-Control-Allow-Origin", "*"); - httpRes.Headers.Add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, PATCH, OPTIONS"); - httpRes.Headers.Add("Access-Control-Allow-Headers", "Content-Type, Authorization, Range, X-MediaBrowser-Token, X-Emby-Authorization"); + foreach(KeyValuePair header in GetCorsHeaders(httpReq)) + { + httpRes.Headers.Add(header.Key, header.Value); + } httpRes.ContentType = "text/plain"; await httpRes.WriteAsync(string.Empty, cancellationToken).ConfigureAwait(false); return; @@ -576,6 +578,31 @@ namespace Emby.Server.Implementations.HttpServer } } + /// + /// Get the default CORS headers + /// + /// + /// + public IDictionary GetCorsHeaders(IRequest req) + { + var origin = req.Headers["Origin"]; + if (origin == StringValues.Empty) + { + origin = req.Headers["Host"]; + if (origin == StringValues.Empty) + { + origin = "*"; + } + } + + var headers = new Dictionary(); + headers.Add("Access-Control-Allow-Origin", origin); + headers.Add("Access-Control-Allow-Credentials", "true"); + headers.Add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, PATCH, OPTIONS"); + headers.Add("Access-Control-Allow-Headers", "Content-Type, Authorization, Range, X-MediaBrowser-Token, X-Emby-Authorization, Cookie"); + return headers; + } + // Entry point for HttpListener public ServiceHandler GetServiceHandler(IHttpRequest httpReq) { @@ -622,7 +649,7 @@ namespace Emby.Server.Implementations.HttpServer ResponseFilters = new Action[] { - new ResponseFilter(_logger).FilterResponse + new ResponseFilter(this, _logger).FilterResponse }; } diff --git a/Emby.Server.Implementations/HttpServer/ResponseFilter.cs b/Emby.Server.Implementations/HttpServer/ResponseFilter.cs index 4089aa578..2d4b31ef4 100644 --- a/Emby.Server.Implementations/HttpServer/ResponseFilter.cs +++ b/Emby.Server.Implementations/HttpServer/ResponseFilter.cs @@ -1,6 +1,8 @@ using System; +using System.Collections.Generic; using System.Globalization; using System.Text; +using MediaBrowser.Controller.Net; using MediaBrowser.Model.Services; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; @@ -13,14 +15,17 @@ namespace Emby.Server.Implementations.HttpServer /// public class ResponseFilter { + private readonly IHttpServer _server; private readonly ILogger _logger; /// /// Initializes a new instance of the class. /// + /// The HTTP server. /// The logger. - public ResponseFilter(ILogger logger) + public ResponseFilter(IHttpServer server, ILogger logger) { + _server = server; _logger = logger; } @@ -32,10 +37,16 @@ namespace Emby.Server.Implementations.HttpServer /// The dto. public void FilterResponse(IRequest req, HttpResponse res, object dto) { + foreach(KeyValuePair header in _server.GetCorsHeaders(req)) + { + res.Headers.Add(header.Key, header.Value); + } // Try to prevent compatibility view - res.Headers.Add("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.Headers.Add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, PATCH, OPTIONS"); - res.Headers.Add("Access-Control-Allow-Origin", "*"); + res.Headers["Access-Control-Allow-Headers"] = ("Accept, Accept-Language, Authorization, Cache-Control, " + + "Content-Disposition, Content-Encoding, Content-Language, Content-Length, Content-MD5, Content-Range, " + + "Content-Type, Cookie, 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"); if (dto is Exception exception) { diff --git a/MediaBrowser.Controller/Net/IHttpServer.cs b/MediaBrowser.Controller/Net/IHttpServer.cs index f1c441761..eb2b4670a 100644 --- a/MediaBrowser.Controller/Net/IHttpServer.cs +++ b/MediaBrowser.Controller/Net/IHttpServer.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; using MediaBrowser.Model.Events; +using MediaBrowser.Model.Services; using Microsoft.AspNetCore.Http; namespace MediaBrowser.Controller.Net @@ -38,5 +39,12 @@ namespace MediaBrowser.Controller.Net /// /// Task RequestHandler(HttpContext context); + + /// + /// Get the default CORS headers + /// + /// + /// + IDictionary GetCorsHeaders(IRequest req); } } -- cgit v1.2.3 From 9ee10d22c8ccbeb9eb4112b1a9f520d5ed998013 Mon Sep 17 00:00:00 2001 From: Frank Riley Date: Thu, 14 May 2020 16:03:45 -0700 Subject: Rename function --- Emby.Server.Implementations/HttpServer/HttpListenerHost.cs | 4 ++-- Emby.Server.Implementations/HttpServer/ResponseFilter.cs | 2 +- MediaBrowser.Controller/Net/IHttpServer.cs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs index 958bb1e1d..794d55c04 100644 --- a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs +++ b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs @@ -455,7 +455,7 @@ namespace Emby.Server.Implementations.HttpServer if (string.Equals(httpReq.Verb, "OPTIONS", StringComparison.OrdinalIgnoreCase)) { httpRes.StatusCode = 200; - foreach(var (key, value) in GetCorsHeaders(httpReq)) + foreach(var (key, value) in GetDefaultCorsHeaders(httpReq)) { httpRes.Headers.Add(key, value); } @@ -583,7 +583,7 @@ namespace Emby.Server.Implementations.HttpServer /// /// /// - public IDictionary GetCorsHeaders(IRequest req) + public IDictionary GetDefaultCorsHeaders(IRequest req) { var origin = req.Headers["Origin"]; if (origin == StringValues.Empty) diff --git a/Emby.Server.Implementations/HttpServer/ResponseFilter.cs b/Emby.Server.Implementations/HttpServer/ResponseFilter.cs index c94e905af..85c3db9b2 100644 --- a/Emby.Server.Implementations/HttpServer/ResponseFilter.cs +++ b/Emby.Server.Implementations/HttpServer/ResponseFilter.cs @@ -37,7 +37,7 @@ namespace Emby.Server.Implementations.HttpServer /// The dto. public void FilterResponse(IRequest req, HttpResponse res, object dto) { - foreach(var (key, value) in _server.GetCorsHeaders(req)) + foreach(var (key, value) in _server.GetDefaultCorsHeaders(req)) { res.Headers.Add(key, value); } diff --git a/MediaBrowser.Controller/Net/IHttpServer.cs b/MediaBrowser.Controller/Net/IHttpServer.cs index eb2b4670a..efb5f4ac3 100644 --- a/MediaBrowser.Controller/Net/IHttpServer.cs +++ b/MediaBrowser.Controller/Net/IHttpServer.cs @@ -45,6 +45,6 @@ namespace MediaBrowser.Controller.Net /// /// /// - IDictionary GetCorsHeaders(IRequest req); + IDictionary GetDefaultCorsHeaders(IRequest req); } } -- cgit v1.2.3 From 3ed76d7e083940b53011c7a11a52cdb71d7aa715 Mon Sep 17 00:00:00 2001 From: Mark Monteiro Date: Sun, 17 May 2020 13:33:38 -0400 Subject: Update to .NET Core 3.1.4 --- Emby.Server.Implementations/Emby.Server.Implementations.csproj | 8 ++++---- Jellyfin.Api/Jellyfin.Api.csproj | 2 +- Jellyfin.Data/Jellyfin.Data.csproj | 4 ++-- .../Jellyfin.Server.Implementations.csproj | 7 +++++-- Jellyfin.Server/Jellyfin.Server.csproj | 4 ++-- MediaBrowser.Common/MediaBrowser.Common.csproj | 4 ++-- MediaBrowser.Controller/MediaBrowser.Controller.csproj | 4 ++-- MediaBrowser.Model/MediaBrowser.Model.csproj | 4 ++-- MediaBrowser.Providers/MediaBrowser.Providers.csproj | 4 ++-- tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj | 2 +- tests/MediaBrowser.Api.Tests/MediaBrowser.Api.Tests.csproj | 2 +- 11 files changed, 24 insertions(+), 21 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj index 896e4310e..e95228b70 100644 --- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj +++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj @@ -34,10 +34,10 @@ - - - - + + + + diff --git a/Jellyfin.Api/Jellyfin.Api.csproj b/Jellyfin.Api/Jellyfin.Api.csproj index a582a209c..25d5d0c89 100644 --- a/Jellyfin.Api/Jellyfin.Api.csproj +++ b/Jellyfin.Api/Jellyfin.Api.csproj @@ -13,7 +13,7 @@ - + diff --git a/Jellyfin.Data/Jellyfin.Data.csproj b/Jellyfin.Data/Jellyfin.Data.csproj index b2a3f7eb3..9157c3ead 100644 --- a/Jellyfin.Data/Jellyfin.Data.csproj +++ b/Jellyfin.Data/Jellyfin.Data.csproj @@ -19,8 +19,8 @@ - - + + diff --git a/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj b/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj index 149ca5020..8486fc2df 100644 --- a/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj +++ b/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj @@ -26,8 +26,11 @@ - - + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/Jellyfin.Server/Jellyfin.Server.csproj b/Jellyfin.Server/Jellyfin.Server.csproj index 9eec6ed4e..c93aa837e 100644 --- a/Jellyfin.Server/Jellyfin.Server.csproj +++ b/Jellyfin.Server/Jellyfin.Server.csproj @@ -41,8 +41,8 @@ - - + + diff --git a/MediaBrowser.Common/MediaBrowser.Common.csproj b/MediaBrowser.Common/MediaBrowser.Common.csproj index 69864106c..a597b9052 100644 --- a/MediaBrowser.Common/MediaBrowser.Common.csproj +++ b/MediaBrowser.Common/MediaBrowser.Common.csproj @@ -17,8 +17,8 @@ - - + + diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index 4e7d02737..223bbe1de 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -13,8 +13,8 @@ - - + + diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj index 5c6e313e0..461f59672 100644 --- a/MediaBrowser.Model/MediaBrowser.Model.csproj +++ b/MediaBrowser.Model/MediaBrowser.Model.csproj @@ -21,9 +21,9 @@ - + - + diff --git a/MediaBrowser.Providers/MediaBrowser.Providers.csproj b/MediaBrowser.Providers/MediaBrowser.Providers.csproj index 1b3df63b6..5073b4015 100644 --- a/MediaBrowser.Providers/MediaBrowser.Providers.csproj +++ b/MediaBrowser.Providers/MediaBrowser.Providers.csproj @@ -16,8 +16,8 @@ - - + + diff --git a/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj b/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj index fb76f34d0..9c4b7b0b0 100644 --- a/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj +++ b/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj @@ -16,7 +16,7 @@ - + diff --git a/tests/MediaBrowser.Api.Tests/MediaBrowser.Api.Tests.csproj b/tests/MediaBrowser.Api.Tests/MediaBrowser.Api.Tests.csproj index f30e48690..60c392314 100644 --- a/tests/MediaBrowser.Api.Tests/MediaBrowser.Api.Tests.csproj +++ b/tests/MediaBrowser.Api.Tests/MediaBrowser.Api.Tests.csproj @@ -8,7 +8,7 @@ - + -- cgit v1.2.3 From 526e47c3624aca76234006b031b74e595f295cc8 Mon Sep 17 00:00:00 2001 From: Mark Monteiro Date: Sun, 17 May 2020 14:22:36 -0400 Subject: Clean up documentation --- .../Providers/ExternalIdMediaType.cs | 60 +++++++++++++++++----- MediaBrowser.Controller/Providers/IExternalId.cs | 21 ++++++-- MediaBrowser.Model/Providers/ExternalIdInfo.cs | 2 +- 3 files changed, 63 insertions(+), 20 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/Providers/ExternalIdMediaType.cs b/MediaBrowser.Controller/Providers/ExternalIdMediaType.cs index 470f1e24c..dc87aefc8 100644 --- a/MediaBrowser.Controller/Providers/ExternalIdMediaType.cs +++ b/MediaBrowser.Controller/Providers/ExternalIdMediaType.cs @@ -1,45 +1,77 @@ namespace MediaBrowser.Controller.Providers { - /// The specific media type of an . + /// + /// The specific media type of an . + /// + /// + /// This is used as a translation key for clients. + /// public enum ExternalIdMediaType { - /// There is no specific media type + /// + /// There is no specific media type associated with the external id, or the external provider only has one + /// id type so there is no need to be specific. + /// None, - /// A music album + /// + /// A music album. + /// Album, - /// The artist of a music album + /// + /// The artist of a music album. + /// AlbumArtist, - /// The artist of a media item + /// + /// The artist of a media item. + /// Artist, - /// A boxed set of media + /// + /// A boxed set of media. + /// BoxSet, - /// A series episode + /// + /// A series episode. + /// Episode, - /// A movie + /// + /// A movie. + /// Movie, - /// An alternative artist apart from the main artist + /// + /// An alternative artist apart from the main artist. + /// OtherArtist, - /// A person + /// + /// A person. + /// Person, - /// A release group + /// + /// A release group. + /// ReleaseGroup, - /// A single season of a series + /// + /// A single season of a series. + /// Season, - /// A series + /// + /// A series. + /// Series, - /// A music track + /// + /// A music track. + /// Track } } diff --git a/MediaBrowser.Controller/Providers/IExternalId.cs b/MediaBrowser.Controller/Providers/IExternalId.cs index c877ffe1f..f362c42eb 100644 --- a/MediaBrowser.Controller/Providers/IExternalId.cs +++ b/MediaBrowser.Controller/Providers/IExternalId.cs @@ -5,19 +5,30 @@ namespace MediaBrowser.Controller.Providers /// Represents and identifier for an external provider. public interface IExternalId { - /// Gets the name used to identify this provider + /// + /// Gets the display name of the provider associated with this ID type. + /// string Name { get; } - /// Gets the unique key to distinguish this provider/type pair. This should be unique across providers. + /// + /// Gets the unique key to distinguish this provider/type pair. This should be unique across providers. + /// + // TODO: This property is not actually unique at the moment. It should be updated to be unique. string Key { get; } - /// Gets the specific media type for this id. + /// + /// Gets the specific media type for this id. + /// ExternalIdMediaType Type { get; } - /// Gets the url format string for this id. + /// + /// Gets the URL format string for this id. + /// string UrlFormatString { get; } - /// Determines whether this id supports a given item type. + /// + /// Determines whether this id supports a given item type. + /// /// The item. /// True if this item is supported, otherwise false. bool Supports(IHasProviderIds item); diff --git a/MediaBrowser.Model/Providers/ExternalIdInfo.cs b/MediaBrowser.Model/Providers/ExternalIdInfo.cs index befcc309b..ca0c857c4 100644 --- a/MediaBrowser.Model/Providers/ExternalIdInfo.cs +++ b/MediaBrowser.Model/Providers/ExternalIdInfo.cs @@ -6,7 +6,7 @@ namespace MediaBrowser.Model.Providers public class ExternalIdInfo { /// - /// Gets or sets the name of the external id provider (IE: IMDB, MusicBrainz, etc). + /// Gets or sets the display name of the external id provider (IE: IMDB, MusicBrainz, etc). /// public string Name { get; set; } -- cgit v1.2.3 From e5c857ac3639c2aba34e59437e501bfdd6b1ba02 Mon Sep 17 00:00:00 2001 From: Mark Monteiro Date: Sun, 17 May 2020 15:29:53 -0400 Subject: Rename external id type 'None' to 'General' --- MediaBrowser.Controller/Providers/ExternalIdMediaType.cs | 2 +- MediaBrowser.Providers/Manager/ProviderManager.cs | 2 +- MediaBrowser.Providers/Movies/MovieExternalIds.cs | 2 +- MediaBrowser.Providers/Music/MusicExternalIds.cs | 2 +- MediaBrowser.Providers/Plugins/AudioDb/ExternalIds.cs | 2 +- MediaBrowser.Providers/TV/TvExternalIds.cs | 4 ++-- 6 files changed, 7 insertions(+), 7 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/Providers/ExternalIdMediaType.cs b/MediaBrowser.Controller/Providers/ExternalIdMediaType.cs index dc87aefc8..43c2b2f22 100644 --- a/MediaBrowser.Controller/Providers/ExternalIdMediaType.cs +++ b/MediaBrowser.Controller/Providers/ExternalIdMediaType.cs @@ -12,7 +12,7 @@ namespace MediaBrowser.Controller.Providers /// There is no specific media type associated with the external id, or the external provider only has one /// id type so there is no need to be specific. /// - None, + General, /// /// A music album. diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs index b0380ae31..49083c01b 100644 --- a/MediaBrowser.Providers/Manager/ProviderManager.cs +++ b/MediaBrowser.Providers/Manager/ProviderManager.cs @@ -908,7 +908,7 @@ namespace MediaBrowser.Providers.Manager { Name = i.Name, Key = i.Key, - Type = i.Type == ExternalIdMediaType.None ? null : i.Type.ToString(), + Type = i.Type == ExternalIdMediaType.General ? null : i.Type.ToString(), UrlFormatString = i.UrlFormatString }); } diff --git a/MediaBrowser.Providers/Movies/MovieExternalIds.cs b/MediaBrowser.Providers/Movies/MovieExternalIds.cs index a7b359a2d..1098b9882 100644 --- a/MediaBrowser.Providers/Movies/MovieExternalIds.cs +++ b/MediaBrowser.Providers/Movies/MovieExternalIds.cs @@ -16,7 +16,7 @@ namespace MediaBrowser.Providers.Movies public string Key => MetadataProviders.Imdb.ToString(); /// - public ExternalIdMediaType Type => ExternalIdMediaType.None; + public ExternalIdMediaType Type => ExternalIdMediaType.General; /// public string UrlFormatString => "https://www.imdb.com/title/{0}"; diff --git a/MediaBrowser.Providers/Music/MusicExternalIds.cs b/MediaBrowser.Providers/Music/MusicExternalIds.cs index 19879411e..351cdb92c 100644 --- a/MediaBrowser.Providers/Music/MusicExternalIds.cs +++ b/MediaBrowser.Providers/Music/MusicExternalIds.cs @@ -13,7 +13,7 @@ namespace MediaBrowser.Providers.Music public string Key => "IMVDb"; /// - public ExternalIdMediaType Type => ExternalIdMediaType.None; + public ExternalIdMediaType Type => ExternalIdMediaType.General; /// public string UrlFormatString => null; diff --git a/MediaBrowser.Providers/Plugins/AudioDb/ExternalIds.cs b/MediaBrowser.Providers/Plugins/AudioDb/ExternalIds.cs index cd65acb76..150149a6b 100644 --- a/MediaBrowser.Providers/Plugins/AudioDb/ExternalIds.cs +++ b/MediaBrowser.Providers/Plugins/AudioDb/ExternalIds.cs @@ -13,7 +13,7 @@ namespace MediaBrowser.Providers.Plugins.AudioDb public string Key => MetadataProviders.AudioDbAlbum.ToString(); /// - public ExternalIdMediaType Type => ExternalIdMediaType.None; + public ExternalIdMediaType Type => ExternalIdMediaType.General; /// public string UrlFormatString => "https://www.theaudiodb.com/album/{0}"; diff --git a/MediaBrowser.Providers/TV/TvExternalIds.cs b/MediaBrowser.Providers/TV/TvExternalIds.cs index 75d8b6bf5..ccdf8bd29 100644 --- a/MediaBrowser.Providers/TV/TvExternalIds.cs +++ b/MediaBrowser.Providers/TV/TvExternalIds.cs @@ -14,7 +14,7 @@ namespace MediaBrowser.Providers.TV public string Key => MetadataProviders.Zap2It.ToString(); /// - public ExternalIdMediaType Type => ExternalIdMediaType.None; + public ExternalIdMediaType Type => ExternalIdMediaType.General; /// public string UrlFormatString => "http://tvlistings.zap2it.com/overview.html?programSeriesId={0}"; @@ -32,7 +32,7 @@ namespace MediaBrowser.Providers.TV public string Key => MetadataProviders.Tvdb.ToString(); /// - public ExternalIdMediaType Type => ExternalIdMediaType.None; + public ExternalIdMediaType Type => ExternalIdMediaType.General; /// public string UrlFormatString => TvdbUtils.TvdbBaseUrl + "?tab=series&id={0}"; -- cgit v1.2.3 From 422d5b2b68bdce4da385a19382a7a52060cb10b2 Mon Sep 17 00:00:00 2001 From: Mark Monteiro Date: Sun, 17 May 2020 15:57:24 -0400 Subject: Move ExternalIdMediaType enum to MediaBrowser.Model --- .../Providers/ExternalIdMediaType.cs | 77 ---------------------- MediaBrowser.Controller/Providers/IExternalId.cs | 1 + .../Providers/ExternalIdMediaType.cs | 77 ++++++++++++++++++++++ MediaBrowser.Providers/Movies/MovieExternalIds.cs | 1 + MediaBrowser.Providers/Music/MusicExternalIds.cs | 1 + .../Plugins/AudioDb/ExternalIds.cs | 1 + .../Plugins/MusicBrainz/ExternalIds.cs | 1 + MediaBrowser.Providers/TV/TvExternalIds.cs | 1 + .../Tmdb/BoxSets/TmdbBoxSetExternalId.cs | 1 + .../Tmdb/Movies/TmdbMovieExternalId.cs | 1 + .../Tmdb/People/TmdbPersonExternalId.cs | 1 + .../Tmdb/TV/TmdbSeriesExternalId.cs | 1 + 12 files changed, 87 insertions(+), 77 deletions(-) delete mode 100644 MediaBrowser.Controller/Providers/ExternalIdMediaType.cs create mode 100644 MediaBrowser.Model/Providers/ExternalIdMediaType.cs (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/Providers/ExternalIdMediaType.cs b/MediaBrowser.Controller/Providers/ExternalIdMediaType.cs deleted file mode 100644 index 43c2b2f22..000000000 --- a/MediaBrowser.Controller/Providers/ExternalIdMediaType.cs +++ /dev/null @@ -1,77 +0,0 @@ -namespace MediaBrowser.Controller.Providers -{ - /// - /// The specific media type of an . - /// - /// - /// This is used as a translation key for clients. - /// - public enum ExternalIdMediaType - { - /// - /// There is no specific media type associated with the external id, or the external provider only has one - /// id type so there is no need to be specific. - /// - General, - - /// - /// A music album. - /// - Album, - - /// - /// The artist of a music album. - /// - AlbumArtist, - - /// - /// The artist of a media item. - /// - Artist, - - /// - /// A boxed set of media. - /// - BoxSet, - - /// - /// A series episode. - /// - Episode, - - /// - /// A movie. - /// - Movie, - - /// - /// An alternative artist apart from the main artist. - /// - OtherArtist, - - /// - /// A person. - /// - Person, - - /// - /// A release group. - /// - ReleaseGroup, - - /// - /// A single season of a series. - /// - Season, - - /// - /// A series. - /// - Series, - - /// - /// A music track. - /// - Track - } -} diff --git a/MediaBrowser.Controller/Providers/IExternalId.cs b/MediaBrowser.Controller/Providers/IExternalId.cs index f362c42eb..0fcf0c09d 100644 --- a/MediaBrowser.Controller/Providers/IExternalId.cs +++ b/MediaBrowser.Controller/Providers/IExternalId.cs @@ -1,4 +1,5 @@ using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Providers; namespace MediaBrowser.Controller.Providers { diff --git a/MediaBrowser.Model/Providers/ExternalIdMediaType.cs b/MediaBrowser.Model/Providers/ExternalIdMediaType.cs new file mode 100644 index 000000000..8c5356c92 --- /dev/null +++ b/MediaBrowser.Model/Providers/ExternalIdMediaType.cs @@ -0,0 +1,77 @@ +namespace MediaBrowser.Model.Providers +{ + /// + /// The specific media type of an . + /// + /// + /// This is used as a translation key for clients. + /// + public enum ExternalIdMediaType + { + /// + /// There is no specific media type associated with the external id, or the external provider only has one + /// id type so there is no need to be specific. + /// + General, + + /// + /// A music album. + /// + Album, + + /// + /// The artist of a music album. + /// + AlbumArtist, + + /// + /// The artist of a media item. + /// + Artist, + + /// + /// A boxed set of media. + /// + BoxSet, + + /// + /// A series episode. + /// + Episode, + + /// + /// A movie. + /// + Movie, + + /// + /// An alternative artist apart from the main artist. + /// + OtherArtist, + + /// + /// A person. + /// + Person, + + /// + /// A release group. + /// + ReleaseGroup, + + /// + /// A single season of a series. + /// + Season, + + /// + /// A series. + /// + Series, + + /// + /// A music track. + /// + Track + } +} diff --git a/MediaBrowser.Providers/Movies/MovieExternalIds.cs b/MediaBrowser.Providers/Movies/MovieExternalIds.cs index 1098b9882..a82394a93 100644 --- a/MediaBrowser.Providers/Movies/MovieExternalIds.cs +++ b/MediaBrowser.Providers/Movies/MovieExternalIds.cs @@ -4,6 +4,7 @@ using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.LiveTv; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Providers; namespace MediaBrowser.Providers.Movies { diff --git a/MediaBrowser.Providers/Music/MusicExternalIds.cs b/MediaBrowser.Providers/Music/MusicExternalIds.cs index 351cdb92c..12323bcbd 100644 --- a/MediaBrowser.Providers/Music/MusicExternalIds.cs +++ b/MediaBrowser.Providers/Music/MusicExternalIds.cs @@ -1,6 +1,7 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Providers; namespace MediaBrowser.Providers.Music { diff --git a/MediaBrowser.Providers/Plugins/AudioDb/ExternalIds.cs b/MediaBrowser.Providers/Plugins/AudioDb/ExternalIds.cs index 150149a6b..126a79a08 100644 --- a/MediaBrowser.Providers/Plugins/AudioDb/ExternalIds.cs +++ b/MediaBrowser.Providers/Plugins/AudioDb/ExternalIds.cs @@ -1,6 +1,7 @@ using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Providers; namespace MediaBrowser.Providers.Plugins.AudioDb { diff --git a/MediaBrowser.Providers/Plugins/MusicBrainz/ExternalIds.cs b/MediaBrowser.Providers/Plugins/MusicBrainz/ExternalIds.cs index 7d74a8d35..5756cb838 100644 --- a/MediaBrowser.Providers/Plugins/MusicBrainz/ExternalIds.cs +++ b/MediaBrowser.Providers/Plugins/MusicBrainz/ExternalIds.cs @@ -1,6 +1,7 @@ using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Providers; using MediaBrowser.Providers.Plugins.MusicBrainz; namespace MediaBrowser.Providers.Music diff --git a/MediaBrowser.Providers/TV/TvExternalIds.cs b/MediaBrowser.Providers/TV/TvExternalIds.cs index ccdf8bd29..4c005666f 100644 --- a/MediaBrowser.Providers/TV/TvExternalIds.cs +++ b/MediaBrowser.Providers/TV/TvExternalIds.cs @@ -1,6 +1,7 @@ using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Providers; using MediaBrowser.Providers.Plugins.TheTvdb; namespace MediaBrowser.Providers.TV diff --git a/MediaBrowser.Providers/Tmdb/BoxSets/TmdbBoxSetExternalId.cs b/MediaBrowser.Providers/Tmdb/BoxSets/TmdbBoxSetExternalId.cs index a83cde93c..6e131029c 100644 --- a/MediaBrowser.Providers/Tmdb/BoxSets/TmdbBoxSetExternalId.cs +++ b/MediaBrowser.Providers/Tmdb/BoxSets/TmdbBoxSetExternalId.cs @@ -2,6 +2,7 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Providers; namespace MediaBrowser.Providers.Tmdb.BoxSets { diff --git a/MediaBrowser.Providers/Tmdb/Movies/TmdbMovieExternalId.cs b/MediaBrowser.Providers/Tmdb/Movies/TmdbMovieExternalId.cs index f9ea00067..cffd33542 100644 --- a/MediaBrowser.Providers/Tmdb/Movies/TmdbMovieExternalId.cs +++ b/MediaBrowser.Providers/Tmdb/Movies/TmdbMovieExternalId.cs @@ -3,6 +3,7 @@ using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.LiveTv; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Providers; namespace MediaBrowser.Providers.Tmdb.Movies { diff --git a/MediaBrowser.Providers/Tmdb/People/TmdbPersonExternalId.cs b/MediaBrowser.Providers/Tmdb/People/TmdbPersonExternalId.cs index 854fd4156..460740254 100644 --- a/MediaBrowser.Providers/Tmdb/People/TmdbPersonExternalId.cs +++ b/MediaBrowser.Providers/Tmdb/People/TmdbPersonExternalId.cs @@ -1,6 +1,7 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Providers; namespace MediaBrowser.Providers.Tmdb.People { diff --git a/MediaBrowser.Providers/Tmdb/TV/TmdbSeriesExternalId.cs b/MediaBrowser.Providers/Tmdb/TV/TmdbSeriesExternalId.cs index 770448c7f..8adcc4d46 100644 --- a/MediaBrowser.Providers/Tmdb/TV/TmdbSeriesExternalId.cs +++ b/MediaBrowser.Providers/Tmdb/TV/TmdbSeriesExternalId.cs @@ -1,6 +1,7 @@ using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Providers; namespace MediaBrowser.Providers.Tmdb.TV { -- cgit v1.2.3 From 67edf1b7f5f423ab5fa53644bacdba6974b430db Mon Sep 17 00:00:00 2001 From: Mark Monteiro Date: Sun, 17 May 2020 15:59:13 -0400 Subject: Do not convert 'Type' value to string unnecessarily, and do not replace 'General' type with null --- MediaBrowser.Controller/Providers/IExternalId.cs | 3 +++ MediaBrowser.Model/Providers/ExternalIdInfo.cs | 9 +++++---- MediaBrowser.Providers/Manager/ProviderManager.cs | 2 +- 3 files changed, 9 insertions(+), 5 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/Providers/IExternalId.cs b/MediaBrowser.Controller/Providers/IExternalId.cs index 0fcf0c09d..149c58847 100644 --- a/MediaBrowser.Controller/Providers/IExternalId.cs +++ b/MediaBrowser.Controller/Providers/IExternalId.cs @@ -20,6 +20,9 @@ namespace MediaBrowser.Controller.Providers /// /// Gets the specific media type for this id. /// + /// + /// This can be used along with the to localize the external id on the client. + /// ExternalIdMediaType Type { get; } /// diff --git a/MediaBrowser.Model/Providers/ExternalIdInfo.cs b/MediaBrowser.Model/Providers/ExternalIdInfo.cs index ca0c857c4..493c6136e 100644 --- a/MediaBrowser.Model/Providers/ExternalIdInfo.cs +++ b/MediaBrowser.Model/Providers/ExternalIdInfo.cs @@ -16,11 +16,12 @@ namespace MediaBrowser.Model.Providers public string Key { get; set; } /// - /// Gets or sets the media type (Album, Artist, etc). - /// This can be null if there is no specific type. - /// This string is also used to localize the media type on the client. + /// Gets or sets the specific media type for this id. /// - public string Type { get; set; } + /// + /// This can be used along with the to localize the external id on the client. + /// + public ExternalIdMediaType Type { get; set; } /// /// Gets or sets the URL format string. diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs index 49083c01b..4ab758123 100644 --- a/MediaBrowser.Providers/Manager/ProviderManager.cs +++ b/MediaBrowser.Providers/Manager/ProviderManager.cs @@ -908,7 +908,7 @@ namespace MediaBrowser.Providers.Manager { Name = i.Name, Key = i.Key, - Type = i.Type == ExternalIdMediaType.General ? null : i.Type.ToString(), + Type = i.Type, UrlFormatString = i.UrlFormatString }); } -- cgit v1.2.3 From c82f7eeca14839cd21e1904f79007c0d24c85f8f Mon Sep 17 00:00:00 2001 From: Mark Monteiro Date: Sun, 17 May 2020 16:24:28 -0400 Subject: Clean up some doc comments --- MediaBrowser.Controller/Providers/IExternalId.cs | 9 ++++++--- MediaBrowser.Model/Providers/ExternalIdInfo.cs | 4 +++- MediaBrowser.Model/Providers/ExternalIdMediaType.cs | 8 ++++---- 3 files changed, 13 insertions(+), 8 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/Providers/IExternalId.cs b/MediaBrowser.Controller/Providers/IExternalId.cs index 149c58847..ae87aab9e 100644 --- a/MediaBrowser.Controller/Providers/IExternalId.cs +++ b/MediaBrowser.Controller/Providers/IExternalId.cs @@ -3,7 +3,9 @@ using MediaBrowser.Model.Providers; namespace MediaBrowser.Controller.Providers { - /// Represents and identifier for an external provider. + /// + /// Represents an identifier for an external provider. + /// public interface IExternalId { /// @@ -14,11 +16,12 @@ namespace MediaBrowser.Controller.Providers /// /// Gets the unique key to distinguish this provider/type pair. This should be unique across providers. /// - // TODO: This property is not actually unique at the moment. It should be updated to be unique. + // TODO: This property is not actually unique across the concrete types at the moment. It should be updated to be unique. string Key { get; } /// - /// Gets the specific media type for this id. + /// Gets the specific media type for this id. This is used to distinguish between the different + /// external id types for providers with multiple ids. /// /// /// This can be used along with the to localize the external id on the client. diff --git a/MediaBrowser.Model/Providers/ExternalIdInfo.cs b/MediaBrowser.Model/Providers/ExternalIdInfo.cs index 493c6136e..92a639546 100644 --- a/MediaBrowser.Model/Providers/ExternalIdInfo.cs +++ b/MediaBrowser.Model/Providers/ExternalIdInfo.cs @@ -13,10 +13,12 @@ namespace MediaBrowser.Model.Providers /// /// Gets or sets the unique key for this id. This key should be unique across all providers. /// + // TODO: This property is not actually unique across the concrete types at the moment. It should be updated to be unique. public string Key { get; set; } /// - /// Gets or sets the specific media type for this id. + /// Gets or sets the specific media type for this id. This is used to distinguish between the different + /// external id types for providers with multiple ids. /// /// /// This can be used along with the to localize the external id on the client. diff --git a/MediaBrowser.Model/Providers/ExternalIdMediaType.cs b/MediaBrowser.Model/Providers/ExternalIdMediaType.cs index 8c5356c92..881cd77fc 100644 --- a/MediaBrowser.Model/Providers/ExternalIdMediaType.cs +++ b/MediaBrowser.Model/Providers/ExternalIdMediaType.cs @@ -1,16 +1,16 @@ namespace MediaBrowser.Model.Providers { /// - /// The specific media type of an . + /// The specific media type of an . /// /// - /// This is used as a translation key for clients. + /// Client applications may use this as a translation key. /// public enum ExternalIdMediaType { /// - /// There is no specific media type associated with the external id, or the external provider only has one - /// id type so there is no need to be specific. + /// There is no specific media type associated with the external id, or this is the default id for the external + /// provider so there is no need to specify a type. /// General, -- cgit v1.2.3 From d06fee75b65def754ce58e8322a59bf8c942b82f Mon Sep 17 00:00:00 2001 From: Mark Monteiro Date: Sun, 17 May 2020 17:35:43 -0400 Subject: Rename Name to ProviderName --- MediaBrowser.Controller/Providers/IExternalId.cs | 4 ++-- MediaBrowser.Model/Providers/ExternalIdInfo.cs | 1 + MediaBrowser.Providers/Manager/ProviderManager.cs | 6 +++--- MediaBrowser.Providers/Movies/MovieExternalIds.cs | 4 ++-- MediaBrowser.Providers/Music/MusicExternalIds.cs | 2 +- MediaBrowser.Providers/Plugins/AudioDb/ExternalIds.cs | 8 ++++---- MediaBrowser.Providers/Plugins/MusicBrainz/ExternalIds.cs | 12 ++++++------ MediaBrowser.Providers/TV/TvExternalIds.cs | 8 ++++---- MediaBrowser.Providers/Tmdb/BoxSets/TmdbBoxSetExternalId.cs | 2 +- MediaBrowser.Providers/Tmdb/Movies/TmdbMovieExternalId.cs | 2 +- MediaBrowser.Providers/Tmdb/People/TmdbPersonExternalId.cs | 2 +- MediaBrowser.Providers/Tmdb/TV/TmdbSeriesExternalId.cs | 2 +- 12 files changed, 27 insertions(+), 26 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/Providers/IExternalId.cs b/MediaBrowser.Controller/Providers/IExternalId.cs index ae87aab9e..96d1e4622 100644 --- a/MediaBrowser.Controller/Providers/IExternalId.cs +++ b/MediaBrowser.Controller/Providers/IExternalId.cs @@ -11,7 +11,7 @@ namespace MediaBrowser.Controller.Providers /// /// Gets the display name of the provider associated with this ID type. /// - string Name { get; } + string ProviderName { get; } /// /// Gets the unique key to distinguish this provider/type pair. This should be unique across providers. @@ -24,7 +24,7 @@ namespace MediaBrowser.Controller.Providers /// external id types for providers with multiple ids. /// /// - /// This can be used along with the to localize the external id on the client. + /// This can be used along with the to localize the external id on the client. /// ExternalIdMediaType Type { get; } diff --git a/MediaBrowser.Model/Providers/ExternalIdInfo.cs b/MediaBrowser.Model/Providers/ExternalIdInfo.cs index 92a639546..445c86d73 100644 --- a/MediaBrowser.Model/Providers/ExternalIdInfo.cs +++ b/MediaBrowser.Model/Providers/ExternalIdInfo.cs @@ -8,6 +8,7 @@ namespace MediaBrowser.Model.Providers /// /// Gets or sets the display name of the external id provider (IE: IMDB, MusicBrainz, etc). /// + // TODO: This should be renamed to ProviderName public string Name { get; set; } /// diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs index 4ab758123..95133a9a7 100644 --- a/MediaBrowser.Providers/Manager/ProviderManager.cs +++ b/MediaBrowser.Providers/Manager/ProviderManager.cs @@ -96,7 +96,7 @@ namespace MediaBrowser.Providers.Manager _metadataServices = metadataServices.OrderBy(i => i.Order).ToArray(); _metadataProviders = metadataProviders.ToArray(); - _externalIds = externalIds.OrderBy(i => i.Name).ToArray(); + _externalIds = externalIds.OrderBy(i => i.ProviderName).ToArray(); _savers = metadataSavers.Where(i => { @@ -891,7 +891,7 @@ namespace MediaBrowser.Providers.Manager return new ExternalUrl { - Name = i.Name, + Name = i.ProviderName, Url = string.Format( CultureInfo.InvariantCulture, i.UrlFormatString, @@ -906,7 +906,7 @@ namespace MediaBrowser.Providers.Manager return GetExternalIds(item) .Select(i => new ExternalIdInfo { - Name = i.Name, + Name = i.ProviderName, Key = i.Key, Type = i.Type, UrlFormatString = i.UrlFormatString diff --git a/MediaBrowser.Providers/Movies/MovieExternalIds.cs b/MediaBrowser.Providers/Movies/MovieExternalIds.cs index a82394a93..2b0c0d1c2 100644 --- a/MediaBrowser.Providers/Movies/MovieExternalIds.cs +++ b/MediaBrowser.Providers/Movies/MovieExternalIds.cs @@ -11,7 +11,7 @@ namespace MediaBrowser.Providers.Movies public class ImdbExternalId : IExternalId { /// - public string Name => "IMDb"; + public string ProviderName => "IMDb"; /// public string Key => MetadataProviders.Imdb.ToString(); @@ -38,7 +38,7 @@ namespace MediaBrowser.Providers.Movies public class ImdbPersonExternalId : IExternalId { /// - public string Name => "IMDb"; + public string ProviderName => "IMDb"; /// public string Key => MetadataProviders.Imdb.ToString(); diff --git a/MediaBrowser.Providers/Music/MusicExternalIds.cs b/MediaBrowser.Providers/Music/MusicExternalIds.cs index 12323bcbd..4490d0f05 100644 --- a/MediaBrowser.Providers/Music/MusicExternalIds.cs +++ b/MediaBrowser.Providers/Music/MusicExternalIds.cs @@ -8,7 +8,7 @@ namespace MediaBrowser.Providers.Music public class ImvdbId : IExternalId { /// - public string Name => "IMVDb"; + public string ProviderName => "IMVDb"; /// public string Key => "IMVDb"; diff --git a/MediaBrowser.Providers/Plugins/AudioDb/ExternalIds.cs b/MediaBrowser.Providers/Plugins/AudioDb/ExternalIds.cs index 126a79a08..e299eb3ee 100644 --- a/MediaBrowser.Providers/Plugins/AudioDb/ExternalIds.cs +++ b/MediaBrowser.Providers/Plugins/AudioDb/ExternalIds.cs @@ -8,7 +8,7 @@ namespace MediaBrowser.Providers.Plugins.AudioDb public class AudioDbAlbumExternalId : IExternalId { /// - public string Name => "TheAudioDb"; + public string ProviderName => "TheAudioDb"; /// public string Key => MetadataProviders.AudioDbAlbum.ToString(); @@ -26,7 +26,7 @@ namespace MediaBrowser.Providers.Plugins.AudioDb public class AudioDbOtherAlbumExternalId : IExternalId { /// - public string Name => "TheAudioDb"; + public string ProviderName => "TheAudioDb"; /// public string Key => MetadataProviders.AudioDbAlbum.ToString(); @@ -44,7 +44,7 @@ namespace MediaBrowser.Providers.Plugins.AudioDb public class AudioDbArtistExternalId : IExternalId { /// - public string Name => "TheAudioDb"; + public string ProviderName => "TheAudioDb"; /// public string Key => MetadataProviders.AudioDbArtist.ToString(); @@ -62,7 +62,7 @@ namespace MediaBrowser.Providers.Plugins.AudioDb public class AudioDbOtherArtistExternalId : IExternalId { /// - public string Name => "TheAudioDb"; + public string ProviderName => "TheAudioDb"; /// public string Key => MetadataProviders.AudioDbArtist.ToString(); diff --git a/MediaBrowser.Providers/Plugins/MusicBrainz/ExternalIds.cs b/MediaBrowser.Providers/Plugins/MusicBrainz/ExternalIds.cs index 5756cb838..247e87fd5 100644 --- a/MediaBrowser.Providers/Plugins/MusicBrainz/ExternalIds.cs +++ b/MediaBrowser.Providers/Plugins/MusicBrainz/ExternalIds.cs @@ -9,7 +9,7 @@ namespace MediaBrowser.Providers.Music public class MusicBrainzReleaseGroupExternalId : IExternalId { /// - public string Name => "MusicBrainz"; + public string ProviderName => "MusicBrainz"; /// public string Key => MetadataProviders.MusicBrainzReleaseGroup.ToString(); @@ -27,7 +27,7 @@ namespace MediaBrowser.Providers.Music public class MusicBrainzAlbumArtistExternalId : IExternalId { /// - public string Name => "MusicBrainz"; + public string ProviderName => "MusicBrainz"; /// public string Key => MetadataProviders.MusicBrainzAlbumArtist.ToString(); @@ -45,7 +45,7 @@ namespace MediaBrowser.Providers.Music public class MusicBrainzAlbumExternalId : IExternalId { /// - public string Name => "MusicBrainz"; + public string ProviderName => "MusicBrainz"; /// public string Key => MetadataProviders.MusicBrainzAlbum.ToString(); @@ -63,7 +63,7 @@ namespace MediaBrowser.Providers.Music public class MusicBrainzArtistExternalId : IExternalId { /// - public string Name => "MusicBrainz"; + public string ProviderName => "MusicBrainz"; /// public string Key => MetadataProviders.MusicBrainzArtist.ToString(); @@ -81,7 +81,7 @@ namespace MediaBrowser.Providers.Music public class MusicBrainzOtherArtistExternalId : IExternalId { /// - public string Name => "MusicBrainz"; + public string ProviderName => "MusicBrainz"; /// @@ -100,7 +100,7 @@ namespace MediaBrowser.Providers.Music public class MusicBrainzTrackId : IExternalId { /// - public string Name => "MusicBrainz"; + public string ProviderName => "MusicBrainz"; /// public string Key => MetadataProviders.MusicBrainzTrack.ToString(); diff --git a/MediaBrowser.Providers/TV/TvExternalIds.cs b/MediaBrowser.Providers/TV/TvExternalIds.cs index 4c005666f..12ad3d8a2 100644 --- a/MediaBrowser.Providers/TV/TvExternalIds.cs +++ b/MediaBrowser.Providers/TV/TvExternalIds.cs @@ -9,7 +9,7 @@ namespace MediaBrowser.Providers.TV public class Zap2ItExternalId : IExternalId { /// - public string Name => "Zap2It"; + public string ProviderName => "Zap2It"; /// public string Key => MetadataProviders.Zap2It.ToString(); @@ -27,7 +27,7 @@ namespace MediaBrowser.Providers.TV public class TvdbExternalId : IExternalId { /// - public string Name => "TheTVDB"; + public string ProviderName => "TheTVDB"; /// public string Key => MetadataProviders.Tvdb.ToString(); @@ -46,7 +46,7 @@ namespace MediaBrowser.Providers.TV public class TvdbSeasonExternalId : IExternalId { /// - public string Name => "TheTVDB"; + public string ProviderName => "TheTVDB"; /// public string Key => MetadataProviders.Tvdb.ToString(); @@ -64,7 +64,7 @@ namespace MediaBrowser.Providers.TV public class TvdbEpisodeExternalId : IExternalId { /// - public string Name => "TheTVDB"; + public string ProviderName => "TheTVDB"; /// public string Key => MetadataProviders.Tvdb.ToString(); diff --git a/MediaBrowser.Providers/Tmdb/BoxSets/TmdbBoxSetExternalId.cs b/MediaBrowser.Providers/Tmdb/BoxSets/TmdbBoxSetExternalId.cs index 6e131029c..1d3c80536 100644 --- a/MediaBrowser.Providers/Tmdb/BoxSets/TmdbBoxSetExternalId.cs +++ b/MediaBrowser.Providers/Tmdb/BoxSets/TmdbBoxSetExternalId.cs @@ -9,7 +9,7 @@ namespace MediaBrowser.Providers.Tmdb.BoxSets public class TmdbBoxSetExternalId : IExternalId { /// - public string Name => TmdbUtils.ProviderName; + public string ProviderName => TmdbUtils.ProviderName; /// public string Key => MetadataProviders.TmdbCollection.ToString(); diff --git a/MediaBrowser.Providers/Tmdb/Movies/TmdbMovieExternalId.cs b/MediaBrowser.Providers/Tmdb/Movies/TmdbMovieExternalId.cs index cffd33542..75e71dda4 100644 --- a/MediaBrowser.Providers/Tmdb/Movies/TmdbMovieExternalId.cs +++ b/MediaBrowser.Providers/Tmdb/Movies/TmdbMovieExternalId.cs @@ -10,7 +10,7 @@ namespace MediaBrowser.Providers.Tmdb.Movies public class TmdbMovieExternalId : IExternalId { /// - public string Name => TmdbUtils.ProviderName; + public string ProviderName => TmdbUtils.ProviderName; /// public string Key => MetadataProviders.Tmdb.ToString(); diff --git a/MediaBrowser.Providers/Tmdb/People/TmdbPersonExternalId.cs b/MediaBrowser.Providers/Tmdb/People/TmdbPersonExternalId.cs index 460740254..a8685d669 100644 --- a/MediaBrowser.Providers/Tmdb/People/TmdbPersonExternalId.cs +++ b/MediaBrowser.Providers/Tmdb/People/TmdbPersonExternalId.cs @@ -8,7 +8,7 @@ namespace MediaBrowser.Providers.Tmdb.People public class TmdbPersonExternalId : IExternalId { /// - public string Name => TmdbUtils.ProviderName; + public string ProviderName => TmdbUtils.ProviderName; /// public string Key => MetadataProviders.Tmdb.ToString(); diff --git a/MediaBrowser.Providers/Tmdb/TV/TmdbSeriesExternalId.cs b/MediaBrowser.Providers/Tmdb/TV/TmdbSeriesExternalId.cs index 8adcc4d46..fd6dd9b41 100644 --- a/MediaBrowser.Providers/Tmdb/TV/TmdbSeriesExternalId.cs +++ b/MediaBrowser.Providers/Tmdb/TV/TmdbSeriesExternalId.cs @@ -8,7 +8,7 @@ namespace MediaBrowser.Providers.Tmdb.TV public class TmdbSeriesExternalId : IExternalId { /// - public string Name => TmdbUtils.ProviderName; + public string ProviderName => TmdbUtils.ProviderName; /// public string Key => MetadataProviders.Tmdb.ToString(); -- cgit v1.2.3 From b9fc0d26287e46017515e4ac3e569ca2c60f622f Mon Sep 17 00:00:00 2001 From: Jesús Higueras Date: Mon, 23 Mar 2020 20:05:49 +0100 Subject: Add BlurHash support to backend --- Emby.Drawing/ImageProcessor.cs | 4 ++ Emby.Drawing/NullImageEncoder.cs | 6 +++ .../Data/SqliteItemRepository.cs | 17 +++++++- Emby.Server.Implementations/Dto/DtoService.cs | 7 ++++ .../Library/LibraryManager.cs | 30 +++++++++++++- Jellyfin.Drawing.Skia/Jellyfin.Drawing.Skia.csproj | 2 + Jellyfin.Drawing.Skia/SkiaEncoder.cs | 48 +++++++++++++++++++++- MediaBrowser.Api/Images/ImageService.cs | 7 +++- MediaBrowser.Controller/Drawing/IImageEncoder.cs | 7 ++++ MediaBrowser.Controller/Drawing/IImageProcessor.cs | 7 ++++ MediaBrowser.Controller/Entities/BaseItem.cs | 1 + MediaBrowser.Controller/Entities/ItemImageInfo.cs | 6 +++ MediaBrowser.Model/Dto/BaseItemDto.cs | 6 +++ MediaBrowser.Model/Dto/ImageInfo.cs | 6 +++ 14 files changed, 149 insertions(+), 5 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Drawing/ImageProcessor.cs b/Emby.Drawing/ImageProcessor.cs index 0b3bbe29e..1237b603b 100644 --- a/Emby.Drawing/ImageProcessor.cs +++ b/Emby.Drawing/ImageProcessor.cs @@ -313,6 +313,10 @@ namespace Emby.Drawing public ImageDimensions GetImageDimensions(string path) => _imageEncoder.GetImageSize(path); + /// + public string GetImageHash(string path) + => _imageEncoder.GetImageHash(path); + /// public string GetImageCacheTag(BaseItem item, ItemImageInfo image) => (item.Path + image.DateModified.Ticks).GetMD5().ToString("N", CultureInfo.InvariantCulture); diff --git a/Emby.Drawing/NullImageEncoder.cs b/Emby.Drawing/NullImageEncoder.cs index 5af7f1622..fa89b4c63 100644 --- a/Emby.Drawing/NullImageEncoder.cs +++ b/Emby.Drawing/NullImageEncoder.cs @@ -42,5 +42,11 @@ namespace Emby.Drawing { throw new NotImplementedException(); } + + /// + public string GetImageHash(string inputPath) + { + throw new NotImplementedException(); + } } } diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index ca5cd6fdd..5a43a138b 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -1144,12 +1144,18 @@ namespace Emby.Server.Implementations.Data var delimeter = "*"; var path = image.Path; + var hash = image.Hash; if (path == null) { path = string.Empty; } + if (hash == null) + { + hash = string.Empty; + } + return GetPathToSave(path) + delimeter + image.DateModified.Ticks.ToString(CultureInfo.InvariantCulture) + @@ -1158,7 +1164,11 @@ namespace Emby.Server.Implementations.Data delimeter + image.Width.ToString(CultureInfo.InvariantCulture) + delimeter + - image.Height.ToString(CultureInfo.InvariantCulture); + image.Height.ToString(CultureInfo.InvariantCulture) + + delimeter + + // Replace delimiters with other characters. + // This can be removed when we migrate to a proper DB. + hash.Replace('*', '/').Replace('|', '\\'); } public ItemImageInfo ItemImageInfoFromValueString(string value) @@ -1192,6 +1202,11 @@ namespace Emby.Server.Implementations.Data image.Width = width; image.Height = height; } + + if (parts.Length >= 6) + { + image.Hash = parts[5].Replace('/', '*').Replace('\\', '|'); + } } return image; diff --git a/Emby.Server.Implementations/Dto/DtoService.cs b/Emby.Server.Implementations/Dto/DtoService.cs index c4b65d265..a34a3a192 100644 --- a/Emby.Server.Implementations/Dto/DtoService.cs +++ b/Emby.Server.Implementations/Dto/DtoService.cs @@ -718,6 +718,7 @@ namespace Emby.Server.Implementations.Dto if (options.EnableImages) { dto.ImageTags = new Dictionary(); + dto.ImageHashes = new Dictionary(); // Prevent implicitly captured closure var currentItem = item; @@ -732,6 +733,12 @@ namespace Emby.Server.Implementations.Dto { dto.ImageTags[image.Type] = tag; } + + var hash = image.Hash; + if (hash != null && hash.Length > 0) + { + dto.ImageHashes[tag] = image.Hash; + } } } } diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index 0b86b2db7..bc35b0410 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -21,6 +21,7 @@ using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Progress; using MediaBrowser.Controller; using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; @@ -35,6 +36,7 @@ using MediaBrowser.Controller.Resolvers; using MediaBrowser.Controller.Sorting; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Dlna; +using MediaBrowser.Model.Drawing; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; using MediaBrowser.Model.IO; @@ -109,6 +111,18 @@ namespace Emby.Server.Implementations.Library /// The comparers. private IBaseItemComparer[] Comparers { get; set; } + /// + /// Gets or sets the active item repository + /// + /// The item repository. + public IItemRepository ItemRepository { get; set; } + + /// + /// Gets or sets the active image processor + /// + /// The image processor. + public IImageProcessor ImageProcessor { get; set; } + /// /// Occurs when [item added]. /// @@ -1817,7 +1831,19 @@ namespace Emby.Server.Implementations.Library public void UpdateImages(BaseItem item) { - _itemRepository.SaveImages(item); + item.ImageInfos + .Where(i => (i.Width == 0 || i.Height == 0)) + .ToList() + .ForEach(x => + { + string blurhash = ImageProcessor.GetImageHash(x.Path); + ImageDimensions size = ImageProcessor.GetImageDimensions(item, x, true); + x.Width = size.Width; + x.Height = size.Height; + x.Hash = blurhash; + }); + + ItemRepository.SaveImages(item); RegisterItem(item); } @@ -1839,7 +1865,7 @@ namespace Emby.Server.Implementations.Library item.DateLastSaved = DateTime.UtcNow; - RegisterItem(item); + UpdateImages(item); } _itemRepository.SaveItems(itemsList, cancellationToken); diff --git a/Jellyfin.Drawing.Skia/Jellyfin.Drawing.Skia.csproj b/Jellyfin.Drawing.Skia/Jellyfin.Drawing.Skia.csproj index a6e1f490a..9f0e3a004 100644 --- a/Jellyfin.Drawing.Skia/Jellyfin.Drawing.Skia.csproj +++ b/Jellyfin.Drawing.Skia/Jellyfin.Drawing.Skia.csproj @@ -21,6 +21,8 @@ + + diff --git a/Jellyfin.Drawing.Skia/SkiaEncoder.cs b/Jellyfin.Drawing.Skia/SkiaEncoder.cs index 5c7462ee2..1d7307863 100644 --- a/Jellyfin.Drawing.Skia/SkiaEncoder.cs +++ b/Jellyfin.Drawing.Skia/SkiaEncoder.cs @@ -1,7 +1,11 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO; +using System.Linq; +using System.Threading.Tasks; +using Blurhash.Core; using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Extensions; @@ -15,7 +19,7 @@ namespace Jellyfin.Drawing.Skia /// /// Image encoder that uses to manipulate images. /// - public class SkiaEncoder : IImageEncoder + public class SkiaEncoder : CoreEncoder, IImageEncoder { private static readonly HashSet _transparentImageTypes = new HashSet(StringComparer.OrdinalIgnoreCase) { ".png", ".gif", ".webp" }; @@ -229,6 +233,48 @@ namespace Jellyfin.Drawing.Skia } } + /// + /// The path is null. + /// The path is not valid. + /// The file at the specified path could not be used to generate a codec. + [SuppressMessage("Microsoft.Performance", "CA1814:PreferJaggedArraysOverMultidimensional")] + public string GetImageHash(string path) + { + if (path == null) + { + throw new ArgumentNullException(nameof(path)); + } + + if (!File.Exists(path)) + { + throw new FileNotFoundException("File not found", path); + } + + using (var bitmap = GetBitmap(path, false, false, null)) + { + if (bitmap == null) + { + throw new ArgumentOutOfRangeException($"Skia unable to read image {path}"); + } + + var width = bitmap.Width; + var height = bitmap.Height; + var pixels = new Pixel[width, height]; + Parallel.ForEach(Enumerable.Range(0, height), y => + { + for (var x = 0; x < width; x++) + { + var color = bitmap.GetPixel(x, y); + pixels[x, y].Red = MathUtils.SRgbToLinear(color.Red); + pixels[x, y].Green = MathUtils.SRgbToLinear(color.Green); + pixels[x, y].Blue = MathUtils.SRgbToLinear(color.Blue); + } + }); + + return CoreEncode(pixels, 4, 4); + } + } + private static bool HasDiacritics(string text) => !string.Equals(text, text.RemoveDiacritics(), StringComparison.Ordinal); diff --git a/MediaBrowser.Api/Images/ImageService.cs b/MediaBrowser.Api/Images/ImageService.cs index 2e9b3e6cb..ecfe2ed76 100644 --- a/MediaBrowser.Api/Images/ImageService.cs +++ b/MediaBrowser.Api/Images/ImageService.cs @@ -323,6 +323,7 @@ namespace MediaBrowser.Api.Images { int? width = null; int? height = null; + string? blurhash = null; long length = 0; try @@ -332,7 +333,10 @@ namespace MediaBrowser.Api.Images var fileInfo = _fileSystem.GetFileInfo(info.Path); length = fileInfo.Length; - ImageDimensions size = _imageProcessor.GetImageDimensions(item, info); + blurhash = _imageProcessor.GetImageHash(info.Path); + info.Hash = blurhash; // TODO: this doesn't seem like the right thing to do + + ImageDimensions size = _imageProcessor.GetImageDimensions(item, info, true); _libraryManager.UpdateImages(item); width = size.Width; height = size.Height; @@ -358,6 +362,7 @@ namespace MediaBrowser.Api.Images ImageType = info.Type, ImageTag = _imageProcessor.GetImageCacheTag(item, info), Size = length, + Hash = blurhash, Width = width, Height = height }; diff --git a/MediaBrowser.Controller/Drawing/IImageEncoder.cs b/MediaBrowser.Controller/Drawing/IImageEncoder.cs index 88e67b648..1d3f0d3b4 100644 --- a/MediaBrowser.Controller/Drawing/IImageEncoder.cs +++ b/MediaBrowser.Controller/Drawing/IImageEncoder.cs @@ -43,6 +43,13 @@ namespace MediaBrowser.Controller.Drawing /// The image dimensions. ImageDimensions GetImageSize(string path); + /// + /// Get the blurhash of an image. + /// + /// The filepath of the image. + /// The blurhash. + string GetImageHash(string path); + /// /// Encode an image. /// diff --git a/MediaBrowser.Controller/Drawing/IImageProcessor.cs b/MediaBrowser.Controller/Drawing/IImageProcessor.cs index 36c746624..be5906cbc 100644 --- a/MediaBrowser.Controller/Drawing/IImageProcessor.cs +++ b/MediaBrowser.Controller/Drawing/IImageProcessor.cs @@ -32,6 +32,13 @@ namespace MediaBrowser.Controller.Drawing /// ImageDimensions ImageDimensions GetImageDimensions(string path); + /// + /// Gets the blurhash of the image. + /// + /// Path to the image file. + /// BlurHash + String GetImageHash(string path); + /// /// Gets the dimensions of the image. /// diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 7ed8fa767..e5f6ea09d 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -2222,6 +2222,7 @@ namespace MediaBrowser.Controller.Entities existingImage.DateModified = image.DateModified; existingImage.Width = image.Width; existingImage.Height = image.Height; + existingImage.Hash = image.Hash; } else { diff --git a/MediaBrowser.Controller/Entities/ItemImageInfo.cs b/MediaBrowser.Controller/Entities/ItemImageInfo.cs index fc46dec2e..ba0297107 100644 --- a/MediaBrowser.Controller/Entities/ItemImageInfo.cs +++ b/MediaBrowser.Controller/Entities/ItemImageInfo.cs @@ -28,6 +28,12 @@ namespace MediaBrowser.Controller.Entities public int Height { get; set; } + /// + /// Gets or sets the blurhash. + /// + /// The blurhash. + public string Hash { get; set; } + [JsonIgnore] public bool IsLocalFile => Path == null || !Path.StartsWith("http", StringComparison.OrdinalIgnoreCase); } diff --git a/MediaBrowser.Model/Dto/BaseItemDto.cs b/MediaBrowser.Model/Dto/BaseItemDto.cs index 607355d8d..8c6c9683a 100644 --- a/MediaBrowser.Model/Dto/BaseItemDto.cs +++ b/MediaBrowser.Model/Dto/BaseItemDto.cs @@ -510,6 +510,12 @@ namespace MediaBrowser.Model.Dto /// The series thumb image tag. public string SeriesThumbImageTag { get; set; } + /// + /// Gets or sets the blurhash for the image tags. + /// + /// The blurhashes. + public Dictionary ImageHashes { get; set; } + /// /// Gets or sets the series studio. /// diff --git a/MediaBrowser.Model/Dto/ImageInfo.cs b/MediaBrowser.Model/Dto/ImageInfo.cs index 57942ac23..39bdc09ed 100644 --- a/MediaBrowser.Model/Dto/ImageInfo.cs +++ b/MediaBrowser.Model/Dto/ImageInfo.cs @@ -30,6 +30,12 @@ namespace MediaBrowser.Model.Dto /// The path. public string Path { get; set; } + /// + /// Gets or sets the blurhash. + /// + /// The blurhash. + public string Hash { get; set; } + /// /// Gets or sets the height. /// -- cgit v1.2.3 From fe480caf5486a21d7ef152009e5c3e08364e0f33 Mon Sep 17 00:00:00 2001 From: Jesús Higueras Date: Wed, 25 Mar 2020 17:26:53 +0100 Subject: Add endpoint to update all items in library --- .../Library/LibraryManager.cs | 28 ++++++++++++++++++++++ MediaBrowser.Api/ItemUpdateService.cs | 6 +++++ MediaBrowser.Controller/Library/ILibraryManager.cs | 1 + 3 files changed, 35 insertions(+) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index bc35b0410..0a97e007c 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -1911,6 +1911,34 @@ namespace Emby.Server.Implementations.Library UpdateItems(new[] { item }, parent, updateReason, cancellationToken); } + /// + /// Updates everything in the database. + /// + public void UpdateAll() + { + Task.Run(() => + { + var items = ItemRepository.GetItemList(new InternalItemsQuery { + Recursive = true + }); + foreach (var item in items) + { + _logger.LogDebug("Updating item {Name} ({ItemId})", + item.Name, + item.Id); + try + { + item.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None); + } + catch (Exception ex) + { + _logger.LogError(ex, "Updating item {ItemId} failed", item.Id); + } + } + _logger.LogDebug("All items have been updated"); + }); + } + /// /// Reports the item removed. /// diff --git a/MediaBrowser.Api/ItemUpdateService.cs b/MediaBrowser.Api/ItemUpdateService.cs index 2db6d717a..808627b41 100644 --- a/MediaBrowser.Api/ItemUpdateService.cs +++ b/MediaBrowser.Api/ItemUpdateService.cs @@ -198,6 +198,12 @@ namespace MediaBrowser.Api public void Post(UpdateItem request) { + if (request.ItemId == "*") + { + // Special case: Refresh everything in database. Probably not a great idea to run often. + _libraryManager.UpdateAll(); + return; + } var item = _libraryManager.GetItemById(request.ItemId); var newLockData = request.LockData ?? false; diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs index 2e1c97f67..559a5415f 100644 --- a/MediaBrowser.Controller/Library/ILibraryManager.cs +++ b/MediaBrowser.Controller/Library/ILibraryManager.cs @@ -196,6 +196,7 @@ namespace MediaBrowser.Controller.Library /// void UpdateItems(IEnumerable items, BaseItem parent, ItemUpdateType updateReason, CancellationToken cancellationToken); void UpdateItem(BaseItem item, BaseItem parent, ItemUpdateType updateReason, CancellationToken cancellationToken); + void UpdateAll(); /// /// Retrieves the item. -- cgit v1.2.3 From a226a4ee03d974615a6fa26b936a93458a255b70 Mon Sep 17 00:00:00 2001 From: Vasily Date: Tue, 19 May 2020 14:50:14 +0300 Subject: Compute hash only when one is not computed in DB, small optimizations here and there --- .../Data/SqliteItemRepository.cs | 16 ++---- .../Library/LibraryManager.cs | 59 ++++++++-------------- MediaBrowser.Api/Images/ImageService.cs | 22 ++++---- MediaBrowser.Api/ItemUpdateService.cs | 6 --- MediaBrowser.Controller/Library/ILibraryManager.cs | 2 +- 5 files changed, 37 insertions(+), 68 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index 5a43a138b..10eb96b10 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -1141,20 +1141,10 @@ namespace Emby.Server.Implementations.Data public string ToValueString(ItemImageInfo image) { - var delimeter = "*"; + const string delimeter = "*"; - var path = image.Path; - var hash = image.Hash; - - if (path == null) - { - path = string.Empty; - } - - if (hash == null) - { - hash = string.Empty; - } + var path = image.Path ?? string.Empty; + var hash = image.Hash ?? string.Empty; return GetPathToSave(path) + delimeter + diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index e1cb282cc..c48664a31 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -1825,17 +1825,26 @@ namespace Emby.Server.Implementations.Library public void UpdateImages(BaseItem item) { - item.ImageInfos - .Where(i => (i.Width == 0 || i.Height == 0)) - .ToList() - .ForEach(x => - { - string blurhash = ImageProcessor.GetImageHash(x.Path); - ImageDimensions size = ImageProcessor.GetImageDimensions(item, x); - x.Width = size.Width; - x.Height = size.Height; - x.Hash = blurhash; - }); + if (item == null) + { + throw new ArgumentNullException(nameof(item)); + } + + var outdated = item.ImageInfos + .Where(i => (i.Width == 0 || i.Height == 0 || string.IsNullOrEmpty(i.Hash))) + .ToList(); + if (outdated.Count == 0) + { + return; + } + + outdated.ForEach(img => + { + ImageDimensions size = ImageProcessor.GetImageDimensions(item, img); + img.Width = size.Width; + img.Height = size.Height; + img.Hash = ImageProcessor.GetImageHash(img.Path); + }); _itemRepository.SaveImages(item); @@ -1905,34 +1914,6 @@ namespace Emby.Server.Implementations.Library UpdateItems(new[] { item }, parent, updateReason, cancellationToken); } - /// - /// Updates everything in the database. - /// - public void UpdateAll() - { - Task.Run(() => - { - var items = _itemRepository.GetItemList(new InternalItemsQuery { - Recursive = true - }); - foreach (var item in items) - { - _logger.LogDebug("Updating item {Name} ({ItemId})", - item.Name, - item.Id); - try - { - item.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None); - } - catch (Exception ex) - { - _logger.LogError(ex, "Updating item {ItemId} failed", item.Id); - } - } - _logger.LogDebug("All items have been updated"); - }); - } - /// /// Reports the item removed. /// diff --git a/MediaBrowser.Api/Images/ImageService.cs b/MediaBrowser.Api/Images/ImageService.cs index 09b99781b..559db550b 100644 --- a/MediaBrowser.Api/Images/ImageService.cs +++ b/MediaBrowser.Api/Images/ImageService.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; +using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Common.Extensions; @@ -280,9 +281,16 @@ namespace MediaBrowser.Api.Images public List GetItemImageInfos(BaseItem item) { var list = new List(); - var itemImages = item.ImageInfos; + if (itemImages.Length == 0) + { + // short-circuit + return list; + } + + _libraryManager.UpdateImages(item); // this makes sure dimensions and hashes are correct + foreach (var image in itemImages) { if (!item.AllowsMultipleImages(image.Type)) @@ -323,7 +331,7 @@ namespace MediaBrowser.Api.Images { int? width = null; int? height = null; - string? blurhash = null; + string blurhash = null; long length = 0; try @@ -333,13 +341,9 @@ namespace MediaBrowser.Api.Images var fileInfo = _fileSystem.GetFileInfo(info.Path); length = fileInfo.Length; - blurhash = _imageProcessor.GetImageHash(info.Path); - info.Hash = blurhash; // TODO: this doesn't seem like the right thing to do - - ImageDimensions size = _imageProcessor.GetImageDimensions(item, info); - _libraryManager.UpdateImages(item); - width = size.Width; - height = size.Height; + blurhash = info.Hash; + width = info.Width; + height = info.Height; if (width <= 0 || height <= 0) { diff --git a/MediaBrowser.Api/ItemUpdateService.cs b/MediaBrowser.Api/ItemUpdateService.cs index 808627b41..2db6d717a 100644 --- a/MediaBrowser.Api/ItemUpdateService.cs +++ b/MediaBrowser.Api/ItemUpdateService.cs @@ -198,12 +198,6 @@ namespace MediaBrowser.Api public void Post(UpdateItem request) { - if (request.ItemId == "*") - { - // Special case: Refresh everything in database. Probably not a great idea to run often. - _libraryManager.UpdateAll(); - return; - } var item = _libraryManager.GetItemById(request.ItemId); var newLockData = request.LockData ?? false; diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs index 559a5415f..81160efec 100644 --- a/MediaBrowser.Controller/Library/ILibraryManager.cs +++ b/MediaBrowser.Controller/Library/ILibraryManager.cs @@ -195,8 +195,8 @@ namespace MediaBrowser.Controller.Library /// Updates the item. /// void UpdateItems(IEnumerable items, BaseItem parent, ItemUpdateType updateReason, CancellationToken cancellationToken); + void UpdateItem(BaseItem item, BaseItem parent, ItemUpdateType updateReason, CancellationToken cancellationToken); - void UpdateAll(); /// /// Retrieves the item. -- cgit v1.2.3 From 2b1ae7ac5834054866aa485b18f85f1793f7b8b4 Mon Sep 17 00:00:00 2001 From: Vasily Date: Tue, 19 May 2020 15:42:50 +0300 Subject: Fix code smells --- Emby.Drawing/NullImageEncoder.cs | 2 +- MediaBrowser.Controller/Drawing/IImageProcessor.cs | 15 ++++++++------- 2 files changed, 9 insertions(+), 8 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Drawing/NullImageEncoder.cs b/Emby.Drawing/NullImageEncoder.cs index fa89b4c63..54de7212a 100644 --- a/Emby.Drawing/NullImageEncoder.cs +++ b/Emby.Drawing/NullImageEncoder.cs @@ -44,7 +44,7 @@ namespace Emby.Drawing } /// - public string GetImageHash(string inputPath) + public string GetImageHash(string path) { throw new NotImplementedException(); } diff --git a/MediaBrowser.Controller/Drawing/IImageProcessor.cs b/MediaBrowser.Controller/Drawing/IImageProcessor.cs index be5906cbc..e38eaf760 100644 --- a/MediaBrowser.Controller/Drawing/IImageProcessor.cs +++ b/MediaBrowser.Controller/Drawing/IImageProcessor.cs @@ -32,13 +32,6 @@ namespace MediaBrowser.Controller.Drawing /// ImageDimensions ImageDimensions GetImageDimensions(string path); - /// - /// Gets the blurhash of the image. - /// - /// Path to the image file. - /// BlurHash - String GetImageHash(string path); - /// /// Gets the dimensions of the image. /// @@ -47,6 +40,13 @@ namespace MediaBrowser.Controller.Drawing /// ImageDimensions ImageDimensions GetImageDimensions(BaseItem item, ItemImageInfo info); + /// + /// Gets the blurhash of the image. + /// + /// Path to the image file. + /// BlurHash + String GetImageHash(string path); + /// /// Gets the image cache tag. /// @@ -54,6 +54,7 @@ namespace MediaBrowser.Controller.Drawing /// The image. /// Guid. string GetImageCacheTag(BaseItem item, ItemImageInfo image); + string GetImageCacheTag(BaseItem item, ChapterInfo info); /// -- cgit v1.2.3 From 7d9d54d2ecad14eaec14b00ca73c479d4d64c34f Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Wed, 20 May 2020 12:09:52 -0400 Subject: Fix profile images. --- Jellyfin.Data/Entities/ImageInfo.cs | 12 +++--------- Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs | 2 +- MediaBrowser.Api/Images/ImageService.cs | 13 ++++++++++++- MediaBrowser.Controller/Drawing/ImageHelper.cs | 1 + MediaBrowser.Model/Entities/ImageType.cs | 7 ++++++- 5 files changed, 23 insertions(+), 12 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Jellyfin.Data/Entities/ImageInfo.cs b/Jellyfin.Data/Entities/ImageInfo.cs index 659369545..8bbce95e4 100644 --- a/Jellyfin.Data/Entities/ImageInfo.cs +++ b/Jellyfin.Data/Entities/ImageInfo.cs @@ -6,11 +6,9 @@ namespace Jellyfin.Data.Entities { public class ImageInfo { - public ImageInfo(string path, int width, int height) + public ImageInfo(string path) { Path = path; - Width = width; - Height = height; LastModified = DateTime.UtcNow; } @@ -20,14 +18,10 @@ namespace Jellyfin.Data.Entities public int Id { get; protected set; } [Required] + [MaxLength(512)] + [StringLength(512)] public string Path { get; set; } - [Required] - public int Width { get; set; } - - [Required] - public int Height { get; set; } - [Required] public DateTime LastModified { get; set; } } diff --git a/Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs b/Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs index 987c85f4c..a1895247f 100644 --- a/Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs +++ b/Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs @@ -118,7 +118,7 @@ namespace Jellyfin.Server.Migrations.Routines { ItemImageInfo info = mockup.ImageInfos[0]; - user.ProfileImage = new ImageInfo(info.Path, info.Width, info.Height) + user.ProfileImage = new ImageInfo(info.Path) { LastModified = info.DateModified }; diff --git a/MediaBrowser.Api/Images/ImageService.cs b/MediaBrowser.Api/Images/ImageService.cs index 1392184df..149c4cb9b 100644 --- a/MediaBrowser.Api/Images/ImageService.cs +++ b/MediaBrowser.Api/Images/ImageService.cs @@ -471,8 +471,17 @@ namespace MediaBrowser.Api.Images AssertCanUpdateUser(_authContext, _userManager, userId, true); var user = _userManager.GetUserById(userId); + try + { + File.Delete(user.ProfileImage.Path); + } + catch (IOException e) + { + // TODO: Log this + } user.ProfileImage = null; + _userManager.UpdateUser(user); } /// @@ -639,6 +648,7 @@ namespace MediaBrowser.Api.Images IDictionary headers, bool isHeadRequest) { + info.Type = ImageType.Profile; var options = new ImageProcessingOptions { CropWhiteSpace = true, @@ -886,9 +896,10 @@ namespace MediaBrowser.Api.Images // Handle image/png; charset=utf-8 mimeType = mimeType.Split(';').FirstOrDefault(); var userDataPath = Path.Combine(ServerConfigurationManager.ApplicationPaths.UserConfigurationDirectoryPath, user.Username); + user.ProfileImage = new Jellyfin.Data.Entities.ImageInfo(Path.Combine(userDataPath, "profile" + MimeTypes.ToExtension(mimeType))); await _providerManager - .SaveImage(user, memoryStream, mimeType, Path.Combine(userDataPath, "profile" + MimeTypes.ToExtension(mimeType))) + .SaveImage(user, memoryStream, mimeType, user.ProfileImage.Path) .ConfigureAwait(false); await _userManager.UpdateUserAsync(user); } diff --git a/MediaBrowser.Controller/Drawing/ImageHelper.cs b/MediaBrowser.Controller/Drawing/ImageHelper.cs index d5a5f547e..c87a248b5 100644 --- a/MediaBrowser.Controller/Drawing/ImageHelper.cs +++ b/MediaBrowser.Controller/Drawing/ImageHelper.cs @@ -57,6 +57,7 @@ namespace MediaBrowser.Controller.Drawing case ImageType.BoxRear: case ImageType.Disc: case ImageType.Menu: + case ImageType.Profile: return 1; case ImageType.Logo: return 2.58; diff --git a/MediaBrowser.Model/Entities/ImageType.cs b/MediaBrowser.Model/Entities/ImageType.cs index d89a4b3ad..6ea9ee419 100644 --- a/MediaBrowser.Model/Entities/ImageType.cs +++ b/MediaBrowser.Model/Entities/ImageType.cs @@ -63,6 +63,11 @@ namespace MediaBrowser.Model.Entities /// /// The box rear. /// - BoxRear = 11 + BoxRear = 11, + + /// + /// The user profile image. + /// + Profile = 12 } } -- cgit v1.2.3 From c464f700dbfa72d6f88310023759050867577e6a Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Wed, 20 May 2020 13:07:53 -0400 Subject: Remove redundant qualifiers --- Emby.Dlna/ContentDirectory/ContentDirectory.cs | 7 ++- Emby.Dlna/ContentDirectory/ControlHandler.cs | 72 ++++++++++++---------- Emby.Dlna/Didl/DidlBuilder.cs | 23 ++++--- Emby.Dlna/PlayTo/PlayToController.cs | 4 +- Emby.Notifications/NotificationManager.cs | 7 ++- .../Channels/ChannelManager.cs | 10 ++- .../Collections/CollectionManager.cs | 5 +- Emby.Server.Implementations/Dto/DtoService.cs | 29 +++++---- .../EntryPoints/LibraryChangedNotifier.cs | 3 +- .../HttpServer/Security/SessionContext.cs | 6 +- .../Library/LibraryManager.cs | 23 ++++--- .../Library/MediaSourceManager.cs | 15 ++--- .../Library/MusicManager.cs | 18 +++--- .../Library/SearchEngine.cs | 7 ++- .../Library/UserDataManager.cs | 11 ++-- .../Library/UserViewManager.cs | 5 +- .../LiveTv/LiveTvManager.cs | 25 ++++---- .../Playlists/ManualPlaylistsFolder.cs | 5 +- .../Playlists/PlaylistManager.cs | 7 ++- .../Sorting/DateLastMediaAddedComparer.cs | 3 +- .../Sorting/DatePlayedComparer.cs | 3 +- .../Sorting/IsFavoriteOrLikeComparer.cs | 3 +- .../Sorting/IsPlayedComparer.cs | 3 +- .../Sorting/IsUnplayedComparer.cs | 3 +- .../Sorting/PlayCountComparer.cs | 3 +- Emby.Server.Implementations/TV/TVSeriesManager.cs | 8 ++- .../Users/DefaultAuthenticationProvider.cs | 15 ++--- .../Users/InvalidAuthProvider.cs | 9 +-- MediaBrowser.Api/FilterService.cs | 3 +- MediaBrowser.Api/Library/LibraryService.cs | 15 +++-- MediaBrowser.Api/Movies/MoviesService.cs | 26 ++------ MediaBrowser.Api/Music/InstantMixService.cs | 3 +- MediaBrowser.Api/SuggestionsService.cs | 3 +- .../UserLibrary/BaseItemsByNameService.cs | 5 +- MediaBrowser.Api/UserLibrary/ItemsService.cs | 7 ++- MediaBrowser.Api/UserLibrary/PlaystateService.cs | 4 +- MediaBrowser.Controller/Channels/Channel.cs | 5 +- .../Collections/ICollectionManager.cs | 3 +- MediaBrowser.Controller/Drawing/IImageProcessor.cs | 3 +- MediaBrowser.Controller/Dto/IDtoService.cs | 9 +-- .../Entities/Audio/MusicAlbum.cs | 5 +- .../Entities/Audio/MusicArtist.cs | 13 ++-- MediaBrowser.Controller/Entities/BaseItem.cs | 45 +++++++------- MediaBrowser.Controller/Entities/Folder.cs | 40 ++++++------ .../Entities/InternalItemsQuery.cs | 7 ++- MediaBrowser.Controller/Entities/Movies/BoxSet.cs | 15 ++--- MediaBrowser.Controller/Entities/TV/Season.cs | 13 ++-- MediaBrowser.Controller/Entities/TV/Series.cs | 19 +++--- MediaBrowser.Controller/Entities/UserRootFolder.cs | 5 +- MediaBrowser.Controller/Entities/UserView.cs | 27 ++++---- .../Entities/UserViewBuilder.cs | 46 +++++++------- MediaBrowser.Controller/Library/ILibraryManager.cs | 18 +++--- .../Library/IMediaSourceManager.cs | 7 ++- MediaBrowser.Controller/Library/IMusicManager.cs | 7 ++- .../Library/IUserDataManager.cs | 9 +-- .../Library/PlaybackProgressEventArgs.cs | 5 +- MediaBrowser.Controller/LiveTv/ILiveTvManager.cs | 13 ++-- .../MediaEncoding/EncodingJobInfo.cs | 3 +- MediaBrowser.Controller/Net/IAuthService.cs | 5 +- .../Notifications/INotificationService.cs | 4 +- MediaBrowser.Controller/Playlists/Playlist.cs | 17 ++--- .../Notifications/NotificationOptions.cs | 3 +- .../Auth/CustomAuthenticationHandlerTests.cs | 7 ++- 63 files changed, 415 insertions(+), 336 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Dlna/ContentDirectory/ContentDirectory.cs b/Emby.Dlna/ContentDirectory/ContentDirectory.cs index ea577a905..b1ce7e8ec 100644 --- a/Emby.Dlna/ContentDirectory/ContentDirectory.cs +++ b/Emby.Dlna/ContentDirectory/ContentDirectory.cs @@ -4,12 +4,12 @@ using System; using System.Linq; using System.Threading.Tasks; using Emby.Dlna.Service; +using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; using MediaBrowser.Common.Net; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Dlna; using MediaBrowser.Controller.Drawing; -using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Controller.TV; @@ -33,7 +33,8 @@ namespace Emby.Dlna.ContentDirectory private readonly IMediaEncoder _mediaEncoder; private readonly ITVSeriesManager _tvSeriesManager; - public ContentDirectory(IDlnaManager dlna, + public ContentDirectory( + IDlnaManager dlna, IUserDataManager userDataManager, IImageProcessor imageProcessor, ILibraryManager libraryManager, @@ -106,7 +107,7 @@ namespace Emby.Dlna.ContentDirectory .ProcessControlRequestAsync(request); } - private Jellyfin.Data.Entities.User GetUser(DeviceProfile profile) + private User GetUser(DeviceProfile profile) { if (!string.IsNullOrEmpty(profile.UserId)) { diff --git a/Emby.Dlna/ContentDirectory/ControlHandler.cs b/Emby.Dlna/ContentDirectory/ControlHandler.cs index 32bda2fe1..27585eafa 100644 --- a/Emby.Dlna/ContentDirectory/ControlHandler.cs +++ b/Emby.Dlna/ContentDirectory/ControlHandler.cs @@ -10,6 +10,7 @@ using System.Threading; using System.Xml; using Emby.Dlna.Didl; using Emby.Dlna.Service; +using Jellyfin.Data.Entities; using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Drawing; @@ -17,7 +18,6 @@ using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Entities.Movies; -using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.LiveTv; using MediaBrowser.Controller.MediaEncoding; @@ -28,6 +28,12 @@ using MediaBrowser.Model.Entities; using MediaBrowser.Model.Globalization; using MediaBrowser.Model.Querying; using Microsoft.Extensions.Logging; +using Book = MediaBrowser.Controller.Entities.Book; +using Episode = MediaBrowser.Controller.Entities.TV.Episode; +using Genre = MediaBrowser.Controller.Entities.Genre; +using Movie = MediaBrowser.Controller.Entities.Movies.Movie; +using MusicAlbum = MediaBrowser.Controller.Entities.Audio.MusicAlbum; +using Series = MediaBrowser.Controller.Entities.TV.Series; namespace Emby.Dlna.ContentDirectory { @@ -36,7 +42,7 @@ namespace Emby.Dlna.ContentDirectory private readonly ILibraryManager _libraryManager; private readonly IUserDataManager _userDataManager; private readonly IServerConfigurationManager _config; - private readonly Jellyfin.Data.Entities.User _user; + private readonly User _user; private readonly IUserViewManager _userViewManager; private readonly ITVSeriesManager _tvSeriesManager; @@ -59,7 +65,7 @@ namespace Emby.Dlna.ContentDirectory string accessToken, IImageProcessor imageProcessor, IUserDataManager userDataManager, - Jellyfin.Data.Entities.User user, + User user, int systemUpdateId, IServerConfigurationManager config, ILocalizationManager localization, @@ -432,7 +438,7 @@ namespace Emby.Dlna.ContentDirectory xmlWriter.WriteElementString("UpdateID", _systemUpdateId.ToString(CultureInfo.InvariantCulture)); } - private QueryResult GetChildrenSorted(BaseItem item, Jellyfin.Data.Entities.User user, SearchCriteria search, SortCriteria sort, int? startIndex, int? limit) + private QueryResult GetChildrenSorted(BaseItem item, User user, SearchCriteria search, SortCriteria sort, int? startIndex, int? limit) { var folder = (Folder)item; @@ -489,7 +495,7 @@ namespace Emby.Dlna.ContentDirectory return new DtoOptions(true); } - private QueryResult GetUserItems(BaseItem item, StubType? stubType, Jellyfin.Data.Entities.User user, SortCriteria sort, int? startIndex, int? limit) + private QueryResult GetUserItems(BaseItem item, StubType? stubType, User user, SortCriteria sort, int? startIndex, int? limit) { if (item is MusicGenre) { @@ -558,7 +564,7 @@ namespace Emby.Dlna.ContentDirectory return ToResult(queryResult); } - private QueryResult GetLiveTvChannels(Jellyfin.Data.Entities.User user, SortCriteria sort, int? startIndex, int? limit) + private QueryResult GetLiveTvChannels(User user, SortCriteria sort, int? startIndex, int? limit) { var query = new InternalItemsQuery(user) { @@ -574,7 +580,7 @@ namespace Emby.Dlna.ContentDirectory return ToResult(result); } - private QueryResult GetMusicFolders(BaseItem item, Jellyfin.Data.Entities.User user, StubType? stubType, SortCriteria sort, int? startIndex, int? limit) + private QueryResult GetMusicFolders(BaseItem item, User user, StubType? stubType, SortCriteria sort, int? startIndex, int? limit) { var query = new InternalItemsQuery(user) { @@ -692,7 +698,7 @@ namespace Emby.Dlna.ContentDirectory }; } - private QueryResult GetMovieFolders(BaseItem item, Jellyfin.Data.Entities.User user, StubType? stubType, SortCriteria sort, int? startIndex, int? limit) + private QueryResult GetMovieFolders(BaseItem item, User user, StubType? stubType, SortCriteria sort, int? startIndex, int? limit) { var query = new InternalItemsQuery(user) { @@ -766,7 +772,7 @@ namespace Emby.Dlna.ContentDirectory }; } - private QueryResult GetFolders(Jellyfin.Data.Entities.User user, int? startIndex, int? limit) + private QueryResult GetFolders(User user, int? startIndex, int? limit) { var folders = _libraryManager.GetUserRootFolder().GetChildren(user, true) .OrderBy(i => i.SortName) @@ -783,7 +789,7 @@ namespace Emby.Dlna.ContentDirectory }, startIndex, limit); } - private QueryResult GetTvFolders(BaseItem item, Jellyfin.Data.Entities.User user, StubType? stubType, SortCriteria sort, int? startIndex, int? limit) + private QueryResult GetTvFolders(BaseItem item, User user, StubType? stubType, SortCriteria sort, int? startIndex, int? limit) { var query = new InternalItemsQuery(user) { @@ -871,7 +877,7 @@ namespace Emby.Dlna.ContentDirectory }; } - private QueryResult GetMovieContinueWatching(BaseItem parent, Jellyfin.Data.Entities.User user, InternalItemsQuery query) + private QueryResult GetMovieContinueWatching(BaseItem parent, User user, InternalItemsQuery query) { query.Recursive = true; query.Parent = parent; @@ -891,7 +897,7 @@ namespace Emby.Dlna.ContentDirectory return ToResult(result); } - private QueryResult GetSeries(BaseItem parent, Jellyfin.Data.Entities.User user, InternalItemsQuery query) + private QueryResult GetSeries(BaseItem parent, User user, InternalItemsQuery query) { query.Recursive = true; query.Parent = parent; @@ -904,7 +910,7 @@ namespace Emby.Dlna.ContentDirectory return ToResult(result); } - private QueryResult GetMovieMovies(BaseItem parent, Jellyfin.Data.Entities.User user, InternalItemsQuery query) + private QueryResult GetMovieMovies(BaseItem parent, User user, InternalItemsQuery query) { query.Recursive = true; query.Parent = parent; @@ -917,7 +923,7 @@ namespace Emby.Dlna.ContentDirectory return ToResult(result); } - private QueryResult GetMovieCollections(Jellyfin.Data.Entities.User user, InternalItemsQuery query) + private QueryResult GetMovieCollections(User user, InternalItemsQuery query) { query.Recursive = true; //query.Parent = parent; @@ -930,7 +936,7 @@ namespace Emby.Dlna.ContentDirectory return ToResult(result); } - private QueryResult GetMusicAlbums(BaseItem parent, Jellyfin.Data.Entities.User user, InternalItemsQuery query) + private QueryResult GetMusicAlbums(BaseItem parent, User user, InternalItemsQuery query) { query.Recursive = true; query.Parent = parent; @@ -943,7 +949,7 @@ namespace Emby.Dlna.ContentDirectory return ToResult(result); } - private QueryResult GetMusicSongs(BaseItem parent, Jellyfin.Data.Entities.User user, InternalItemsQuery query) + private QueryResult GetMusicSongs(BaseItem parent, User user, InternalItemsQuery query) { query.Recursive = true; query.Parent = parent; @@ -956,7 +962,7 @@ namespace Emby.Dlna.ContentDirectory return ToResult(result); } - private QueryResult GetFavoriteSongs(BaseItem parent, Jellyfin.Data.Entities.User user, InternalItemsQuery query) + private QueryResult GetFavoriteSongs(BaseItem parent, User user, InternalItemsQuery query) { query.Recursive = true; query.Parent = parent; @@ -969,7 +975,7 @@ namespace Emby.Dlna.ContentDirectory return ToResult(result); } - private QueryResult GetFavoriteSeries(BaseItem parent, Jellyfin.Data.Entities.User user, InternalItemsQuery query) + private QueryResult GetFavoriteSeries(BaseItem parent, User user, InternalItemsQuery query) { query.Recursive = true; query.Parent = parent; @@ -982,7 +988,7 @@ namespace Emby.Dlna.ContentDirectory return ToResult(result); } - private QueryResult GetFavoriteEpisodes(BaseItem parent, Jellyfin.Data.Entities.User user, InternalItemsQuery query) + private QueryResult GetFavoriteEpisodes(BaseItem parent, User user, InternalItemsQuery query) { query.Recursive = true; query.Parent = parent; @@ -995,7 +1001,7 @@ namespace Emby.Dlna.ContentDirectory return ToResult(result); } - private QueryResult GetMovieFavorites(BaseItem parent, Jellyfin.Data.Entities.User user, InternalItemsQuery query) + private QueryResult GetMovieFavorites(BaseItem parent, User user, InternalItemsQuery query) { query.Recursive = true; query.Parent = parent; @@ -1008,7 +1014,7 @@ namespace Emby.Dlna.ContentDirectory return ToResult(result); } - private QueryResult GetFavoriteAlbums(BaseItem parent, Jellyfin.Data.Entities.User user, InternalItemsQuery query) + private QueryResult GetFavoriteAlbums(BaseItem parent, User user, InternalItemsQuery query) { query.Recursive = true; query.Parent = parent; @@ -1021,7 +1027,7 @@ namespace Emby.Dlna.ContentDirectory return ToResult(result); } - private QueryResult GetGenres(BaseItem parent, Jellyfin.Data.Entities.User user, InternalItemsQuery query) + private QueryResult GetGenres(BaseItem parent, User user, InternalItemsQuery query) { var genresResult = _libraryManager.GetGenres(new InternalItemsQuery(user) { @@ -1039,7 +1045,7 @@ namespace Emby.Dlna.ContentDirectory return ToResult(result); } - private QueryResult GetMusicGenres(BaseItem parent, Jellyfin.Data.Entities.User user, InternalItemsQuery query) + private QueryResult GetMusicGenres(BaseItem parent, User user, InternalItemsQuery query) { var genresResult = _libraryManager.GetMusicGenres(new InternalItemsQuery(user) { @@ -1057,7 +1063,7 @@ namespace Emby.Dlna.ContentDirectory return ToResult(result); } - private QueryResult GetMusicAlbumArtists(BaseItem parent, Jellyfin.Data.Entities.User user, InternalItemsQuery query) + private QueryResult GetMusicAlbumArtists(BaseItem parent, User user, InternalItemsQuery query) { var artists = _libraryManager.GetAlbumArtists(new InternalItemsQuery(user) { @@ -1075,7 +1081,7 @@ namespace Emby.Dlna.ContentDirectory return ToResult(result); } - private QueryResult GetMusicArtists(BaseItem parent, Jellyfin.Data.Entities.User user, InternalItemsQuery query) + private QueryResult GetMusicArtists(BaseItem parent, User user, InternalItemsQuery query) { var artists = _libraryManager.GetArtists(new InternalItemsQuery(user) { @@ -1093,7 +1099,7 @@ namespace Emby.Dlna.ContentDirectory return ToResult(result); } - private QueryResult GetFavoriteArtists(BaseItem parent, Jellyfin.Data.Entities.User user, InternalItemsQuery query) + private QueryResult GetFavoriteArtists(BaseItem parent, User user, InternalItemsQuery query) { var artists = _libraryManager.GetArtists(new InternalItemsQuery(user) { @@ -1112,7 +1118,7 @@ namespace Emby.Dlna.ContentDirectory return ToResult(result); } - private QueryResult GetMusicPlaylists(Jellyfin.Data.Entities.User user, InternalItemsQuery query) + private QueryResult GetMusicPlaylists(User user, InternalItemsQuery query) { query.Parent = null; query.IncludeItemTypes = new[] { nameof(Playlist) }; @@ -1124,7 +1130,7 @@ namespace Emby.Dlna.ContentDirectory return ToResult(result); } - private QueryResult GetMusicLatest(BaseItem parent, Jellyfin.Data.Entities.User user, InternalItemsQuery query) + private QueryResult GetMusicLatest(BaseItem parent, User user, InternalItemsQuery query) { query.OrderBy = Array.Empty<(string, SortOrder)>(); @@ -1154,7 +1160,7 @@ namespace Emby.Dlna.ContentDirectory return ToResult(result); } - private QueryResult GetTvLatest(BaseItem parent, Jellyfin.Data.Entities.User user, InternalItemsQuery query) + private QueryResult GetTvLatest(BaseItem parent, User user, InternalItemsQuery query) { query.OrderBy = Array.Empty<(string, SortOrder)>(); @@ -1170,7 +1176,7 @@ namespace Emby.Dlna.ContentDirectory return ToResult(items); } - private QueryResult GetMovieLatest(BaseItem parent, Jellyfin.Data.Entities.User user, InternalItemsQuery query) + private QueryResult GetMovieLatest(BaseItem parent, User user, InternalItemsQuery query) { query.OrderBy = Array.Empty<(string, SortOrder)>(); @@ -1187,7 +1193,7 @@ namespace Emby.Dlna.ContentDirectory return ToResult(items); } - private QueryResult GetMusicArtistItems(BaseItem item, Guid parentId, Jellyfin.Data.Entities.User user, SortCriteria sort, int? startIndex, int? limit) + private QueryResult GetMusicArtistItems(BaseItem item, Guid parentId, User user, SortCriteria sort, int? startIndex, int? limit) { var query = new InternalItemsQuery(user) { @@ -1207,7 +1213,7 @@ namespace Emby.Dlna.ContentDirectory return ToResult(result); } - private QueryResult GetGenreItems(BaseItem item, Guid parentId, Jellyfin.Data.Entities.User user, SortCriteria sort, int? startIndex, int? limit) + private QueryResult GetGenreItems(BaseItem item, Guid parentId, User user, SortCriteria sort, int? startIndex, int? limit) { var query = new InternalItemsQuery(user) { @@ -1231,7 +1237,7 @@ namespace Emby.Dlna.ContentDirectory return ToResult(result); } - private QueryResult GetMusicGenreItems(BaseItem item, Guid parentId, Jellyfin.Data.Entities.User user, SortCriteria sort, int? startIndex, int? limit) + private QueryResult GetMusicGenreItems(BaseItem item, Guid parentId, User user, SortCriteria sort, int? startIndex, int? limit) { var query = new InternalItemsQuery(user) { diff --git a/Emby.Dlna/Didl/DidlBuilder.cs b/Emby.Dlna/Didl/DidlBuilder.cs index 24932ced9..6cedb3ef0 100644 --- a/Emby.Dlna/Didl/DidlBuilder.cs +++ b/Emby.Dlna/Didl/DidlBuilder.cs @@ -7,12 +7,12 @@ using System.Linq; using System.Text; using System.Xml; using Emby.Dlna.ContentDirectory; +using Jellyfin.Data.Entities; using MediaBrowser.Controller.Channels; using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Entities.Movies; -using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Controller.Playlists; @@ -22,6 +22,13 @@ using MediaBrowser.Model.Entities; using MediaBrowser.Model.Globalization; using MediaBrowser.Model.Net; using Microsoft.Extensions.Logging; +using Episode = MediaBrowser.Controller.Entities.TV.Episode; +using Genre = MediaBrowser.Controller.Entities.Genre; +using Movie = MediaBrowser.Controller.Entities.Movies.Movie; +using MusicAlbum = MediaBrowser.Controller.Entities.Audio.MusicAlbum; +using Season = MediaBrowser.Controller.Entities.TV.Season; +using Series = MediaBrowser.Controller.Entities.TV.Series; +using XmlAttribute = MediaBrowser.Model.Dlna.XmlAttribute; namespace Emby.Dlna.Didl { @@ -38,7 +45,7 @@ namespace Emby.Dlna.Didl private readonly IImageProcessor _imageProcessor; private readonly string _serverAddress; private readonly string _accessToken; - private readonly Jellyfin.Data.Entities.User _user; + private readonly User _user; private readonly IUserDataManager _userDataManager; private readonly ILocalizationManager _localization; private readonly IMediaSourceManager _mediaSourceManager; @@ -48,7 +55,7 @@ namespace Emby.Dlna.Didl public DidlBuilder( DeviceProfile profile, - Jellyfin.Data.Entities.User user, + User user, IImageProcessor imageProcessor, string serverAddress, string accessToken, @@ -77,7 +84,7 @@ namespace Emby.Dlna.Didl return url + "&dlnaheaders=true"; } - public string GetItemDidl(BaseItem item, Jellyfin.Data.Entities.User user, BaseItem context, string deviceId, Filter filter, StreamInfo streamInfo) + public string GetItemDidl(BaseItem item, User user, BaseItem context, string deviceId, Filter filter, StreamInfo streamInfo) { var settings = new XmlWriterSettings { @@ -131,7 +138,7 @@ namespace Emby.Dlna.Didl public void WriteItemElement( XmlWriter writer, BaseItem item, - Jellyfin.Data.Entities.User user, + User user, BaseItem context, StubType? contextStubType, string deviceId, @@ -420,7 +427,6 @@ namespace Emby.Dlna.Didl case StubType.FavoriteSeries: return _localization.GetLocalizedString("HeaderFavoriteShows"); case StubType.FavoriteEpisodes: return _localization.GetLocalizedString("HeaderFavoriteEpisodes"); case StubType.Series: return _localization.GetLocalizedString("Shows"); - default: break; } } @@ -662,14 +668,14 @@ namespace Emby.Dlna.Didl writer.WriteFullEndElement(); } - private void AddSamsungBookmarkInfo(BaseItem item, Jellyfin.Data.Entities.User user, XmlWriter writer, StreamInfo streamInfo) + private void AddSamsungBookmarkInfo(BaseItem item, User user, XmlWriter writer, StreamInfo streamInfo) { if (!item.SupportsPositionTicksResume || item is Folder) { return; } - MediaBrowser.Model.Dlna.XmlAttribute secAttribute = null; + XmlAttribute secAttribute = null; foreach (var attribute in _profile.XmlRootAttributes) { if (string.Equals(attribute.Name, "xmlns:sec", StringComparison.OrdinalIgnoreCase)) @@ -994,7 +1000,6 @@ namespace Emby.Dlna.Didl } AddImageResElement(item, writer, 160, 160, "jpg", "JPEG_TN"); - } private void AddImageResElement( diff --git a/Emby.Dlna/PlayTo/PlayToController.cs b/Emby.Dlna/PlayTo/PlayToController.cs index db786833f..1c38fca16 100644 --- a/Emby.Dlna/PlayTo/PlayToController.cs +++ b/Emby.Dlna/PlayTo/PlayToController.cs @@ -7,6 +7,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using Emby.Dlna.Didl; +using Jellyfin.Data.Entities; using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Dlna; using MediaBrowser.Controller.Drawing; @@ -22,6 +23,7 @@ using MediaBrowser.Model.Globalization; using MediaBrowser.Model.Session; using Microsoft.AspNetCore.WebUtilities; using Microsoft.Extensions.Logging; +using Photo = MediaBrowser.Controller.Entities.Photo; namespace Emby.Dlna.PlayTo { @@ -443,7 +445,7 @@ namespace Emby.Dlna.PlayTo private PlaylistItem CreatePlaylistItem( BaseItem item, - Jellyfin.Data.Entities.User user, + User user, long startPostionTicks, string mediaSourceId, int? audioStreamIndex, diff --git a/Emby.Notifications/NotificationManager.cs b/Emby.Notifications/NotificationManager.cs index 9a9bc4415..2dc4fd929 100644 --- a/Emby.Notifications/NotificationManager.cs +++ b/Emby.Notifications/NotificationManager.cs @@ -4,6 +4,7 @@ using System.Globalization; using System.Linq; using System.Threading; using System.Threading.Tasks; +using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Extensions; @@ -82,7 +83,7 @@ namespace Emby.Notifications private Task SendNotification( NotificationRequest request, INotificationService service, - IEnumerable users, + IEnumerable users, string title, string description, CancellationToken cancellationToken) @@ -130,7 +131,7 @@ namespace Emby.Notifications INotificationService service, string title, string description, - Jellyfin.Data.Entities.User user, + User user, CancellationToken cancellationToken) { var notification = new UserNotification @@ -155,7 +156,7 @@ namespace Emby.Notifications } } - private bool IsEnabledForUser(INotificationService service, Jellyfin.Data.Entities.User user) + private bool IsEnabledForUser(INotificationService service, User user) { try { diff --git a/Emby.Server.Implementations/Channels/ChannelManager.cs b/Emby.Server.Implementations/Channels/ChannelManager.cs index cb320dcb1..d6d47d63a 100644 --- a/Emby.Server.Implementations/Channels/ChannelManager.cs +++ b/Emby.Server.Implementations/Channels/ChannelManager.cs @@ -6,6 +6,7 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; +using Jellyfin.Data.Entities; using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Progress; using MediaBrowser.Controller.Channels; @@ -13,8 +14,6 @@ using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; -using MediaBrowser.Controller.Entities.Movies; -using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Channels; @@ -24,6 +23,11 @@ using MediaBrowser.Model.IO; using MediaBrowser.Model.Querying; using MediaBrowser.Model.Serialization; using Microsoft.Extensions.Logging; +using Episode = MediaBrowser.Controller.Entities.TV.Episode; +using Movie = MediaBrowser.Controller.Entities.Movies.Movie; +using MusicAlbum = MediaBrowser.Controller.Entities.Audio.MusicAlbum; +using Season = MediaBrowser.Controller.Entities.TV.Season; +using Series = MediaBrowser.Controller.Entities.TV.Series; namespace Emby.Server.Implementations.Channels { @@ -793,7 +797,7 @@ namespace Emby.Server.Implementations.Channels private async Task GetChannelItems( IChannel channel, - Jellyfin.Data.Entities.User user, + User user, string externalFolderId, ChannelItemSortField? sortField, bool sortDescending, diff --git a/Emby.Server.Implementations/Collections/CollectionManager.cs b/Emby.Server.Implementations/Collections/CollectionManager.cs index 61963b633..1b33c9fac 100644 --- a/Emby.Server.Implementations/Collections/CollectionManager.cs +++ b/Emby.Server.Implementations/Collections/CollectionManager.cs @@ -5,6 +5,7 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; +using Jellyfin.Data.Entities; using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Collections; using MediaBrowser.Controller.Configuration; @@ -121,7 +122,7 @@ namespace Emby.Server.Implementations.Collections return EnsureLibraryFolder(GetCollectionsFolderPath(), createIfNeeded); } - private IEnumerable GetCollections(Jellyfin.Data.Entities.User user) + private IEnumerable GetCollections(User user) { var folder = GetCollectionsFolder(false).Result; @@ -325,7 +326,7 @@ namespace Emby.Server.Implementations.Collections } /// - public IEnumerable CollapseItemsWithinBoxSets(IEnumerable items, Jellyfin.Data.Entities.User user) + public IEnumerable CollapseItemsWithinBoxSets(IEnumerable items, User user) { var results = new Dictionary(); diff --git a/Emby.Server.Implementations/Dto/DtoService.cs b/Emby.Server.Implementations/Dto/DtoService.cs index da40bca4c..aeb5b993b 100644 --- a/Emby.Server.Implementations/Dto/DtoService.cs +++ b/Emby.Server.Implementations/Dto/DtoService.cs @@ -6,6 +6,7 @@ using System.Globalization; using System.IO; using System.Linq; using System.Threading.Tasks; +using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; using MediaBrowser.Common; using MediaBrowser.Controller.Channels; @@ -13,8 +14,6 @@ using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; -using MediaBrowser.Controller.Entities.Movies; -using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.LiveTv; using MediaBrowser.Controller.Persistence; @@ -25,6 +24,14 @@ using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Querying; using Microsoft.Extensions.Logging; +using Book = MediaBrowser.Controller.Entities.Book; +using Episode = MediaBrowser.Controller.Entities.TV.Episode; +using Movie = MediaBrowser.Controller.Entities.Movies.Movie; +using MusicAlbum = MediaBrowser.Controller.Entities.Audio.MusicAlbum; +using Person = MediaBrowser.Controller.Entities.Person; +using Photo = MediaBrowser.Controller.Entities.Photo; +using Season = MediaBrowser.Controller.Entities.TV.Season; +using Series = MediaBrowser.Controller.Entities.TV.Series; namespace Emby.Server.Implementations.Dto { @@ -75,7 +82,7 @@ namespace Emby.Server.Implementations.Dto /// The owner. /// Task{DtoBaseItem}. /// item - public BaseItemDto GetBaseItemDto(BaseItem item, ItemFields[] fields, Jellyfin.Data.Entities.User user = null, BaseItem owner = null) + public BaseItemDto GetBaseItemDto(BaseItem item, ItemFields[] fields, User user = null, BaseItem owner = null) { var options = new DtoOptions { @@ -86,7 +93,7 @@ namespace Emby.Server.Implementations.Dto } /// - public IReadOnlyList GetBaseItemDtos(IReadOnlyList items, DtoOptions options, Jellyfin.Data.Entities.User user = null, BaseItem owner = null) + public IReadOnlyList GetBaseItemDtos(IReadOnlyList items, DtoOptions options, User user = null, BaseItem owner = null) { var returnItems = new BaseItemDto[items.Count]; var programTuples = new List<(BaseItem, BaseItemDto)>(); @@ -139,7 +146,7 @@ namespace Emby.Server.Implementations.Dto return returnItems; } - public BaseItemDto GetBaseItemDto(BaseItem item, DtoOptions options, Jellyfin.Data.Entities.User user = null, BaseItem owner = null) + public BaseItemDto GetBaseItemDto(BaseItem item, DtoOptions options, User user = null, BaseItem owner = null) { var dto = GetBaseItemDtoInternal(item, options, user, owner); if (item is LiveTvChannel tvChannel) @@ -173,7 +180,7 @@ namespace Emby.Server.Implementations.Dto return dto; } - private static IList GetTaggedItems(IItemByName byName, Jellyfin.Data.Entities.User user, DtoOptions options) + private static IList GetTaggedItems(IItemByName byName, User user, DtoOptions options) { return byName.GetTaggedItems( new InternalItemsQuery(user) @@ -183,7 +190,7 @@ namespace Emby.Server.Implementations.Dto }); } - private BaseItemDto GetBaseItemDtoInternal(BaseItem item, DtoOptions options, Jellyfin.Data.Entities.User user = null, BaseItem owner = null) + private BaseItemDto GetBaseItemDtoInternal(BaseItem item, DtoOptions options, User user = null, BaseItem owner = null) { var dto = new BaseItemDto { @@ -316,7 +323,7 @@ namespace Emby.Server.Implementations.Dto } } - public BaseItemDto GetItemByNameDto(BaseItem item, DtoOptions options, List taggedItems, Jellyfin.Data.Entities.User user = null) + public BaseItemDto GetItemByNameDto(BaseItem item, DtoOptions options, List taggedItems, User user = null) { var dto = GetBaseItemDtoInternal(item, options, user); @@ -328,7 +335,7 @@ namespace Emby.Server.Implementations.Dto return dto; } - private static void SetItemByNameInfo(BaseItem item, BaseItemDto dto, IList taggedItems, Jellyfin.Data.Entities.User user = null) + private static void SetItemByNameInfo(BaseItem item, BaseItemDto dto, IList taggedItems, User user = null) { if (item is MusicArtist) { @@ -364,7 +371,7 @@ namespace Emby.Server.Implementations.Dto /// /// Attaches the user specific info. /// - private void AttachUserSpecificInfo(BaseItemDto dto, BaseItem item, Jellyfin.Data.Entities.User user, DtoOptions options) + private void AttachUserSpecificInfo(BaseItemDto dto, BaseItem item, User user, DtoOptions options) { if (item.IsFolder) { @@ -423,7 +430,7 @@ namespace Emby.Server.Implementations.Dto } } - private static int GetChildCount(Folder folder, Jellyfin.Data.Entities.User user) + private static int GetChildCount(Folder folder, User user) { // Right now this is too slow to calculate for top level folders on a per-user basis // Just return something so that apps that are expecting a value won't think the folders are empty diff --git a/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs b/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs index 7ece52cad..5c83e6ae9 100644 --- a/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs +++ b/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs @@ -6,6 +6,7 @@ using System.Globalization; using System.Linq; using System.Threading; using System.Threading.Tasks; +using Jellyfin.Data.Entities; using MediaBrowser.Controller.Channels; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; @@ -446,7 +447,7 @@ namespace Emby.Server.Implementations.EntryPoints /// The user. /// if set to true [include if not found]. /// IEnumerable{``0}. - private IEnumerable TranslatePhysicalItemToUserLibrary(T item, Jellyfin.Data.Entities.User user, bool includeIfNotFound = false) + private IEnumerable TranslatePhysicalItemToUserLibrary(T item, User user, bool includeIfNotFound = false) where T : BaseItem { // If the physical root changed, return the user root diff --git a/Emby.Server.Implementations/HttpServer/Security/SessionContext.cs b/Emby.Server.Implementations/HttpServer/Security/SessionContext.cs index 3f8a64f99..03fcfa53d 100644 --- a/Emby.Server.Implementations/HttpServer/Security/SessionContext.cs +++ b/Emby.Server.Implementations/HttpServer/Security/SessionContext.cs @@ -1,7 +1,7 @@ #pragma warning disable CS1591 using System; -using MediaBrowser.Controller.Entities; +using Jellyfin.Data.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Net; using MediaBrowser.Controller.Security; @@ -42,14 +42,14 @@ namespace Emby.Server.Implementations.HttpServer.Security return GetSession((IRequest)requestContext); } - public Jellyfin.Data.Entities.User GetUser(IRequest requestContext) + public User GetUser(IRequest requestContext) { var session = GetSession(requestContext); return session == null || session.UserId.Equals(Guid.Empty) ? null : _userManager.GetUserById(session.UserId); } - public Jellyfin.Data.Entities.User GetUser(object requestContext) + public User GetUser(object requestContext) { return GetUser((IRequest)requestContext); } diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index e7cd7512c..ebba4fb9d 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -17,6 +17,7 @@ using Emby.Server.Implementations.Library.Resolvers; using Emby.Server.Implementations.Library.Validators; using Emby.Server.Implementations.Playlists; using Emby.Server.Implementations.ScheduledTasks; +using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Progress; @@ -25,7 +26,6 @@ using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; -using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.IO; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.LiveTv; @@ -45,6 +45,9 @@ using MediaBrowser.Model.Querying; using MediaBrowser.Model.Tasks; using MediaBrowser.Providers.MediaInfo; using Microsoft.Extensions.Logging; +using Episode = MediaBrowser.Controller.Entities.TV.Episode; +using Genre = MediaBrowser.Controller.Entities.Genre; +using Person = MediaBrowser.Controller.Entities.Person; using SortOrder = MediaBrowser.Model.Entities.SortOrder; using VideoResolver = Emby.Naming.Video.VideoResolver; @@ -1471,7 +1474,7 @@ namespace Emby.Server.Implementations.Library query.Parent = null; } - private void AddUserToQuery(InternalItemsQuery query, Jellyfin.Data.Entities.User user, bool allowExternalContent = true) + private void AddUserToQuery(InternalItemsQuery query, User user, bool allowExternalContent = true) { if (query.AncestorIds.Length == 0 && query.ParentId.Equals(Guid.Empty) && @@ -1492,7 +1495,7 @@ namespace Emby.Server.Implementations.Library } } - private IEnumerable GetTopParentIdsForQuery(BaseItem item, Jellyfin.Data.Entities.User user) + private IEnumerable GetTopParentIdsForQuery(BaseItem item, User user) { if (item is UserView view) { @@ -1559,7 +1562,7 @@ namespace Emby.Server.Implementations.Library /// The item. /// The user. /// IEnumerable{System.String}. - public async Task> GetIntros(BaseItem item, Jellyfin.Data.Entities.User user) + public async Task> GetIntros(BaseItem item, User user) { var tasks = IntroProviders .OrderBy(i => i.GetType().Name.Contains("Default", StringComparison.OrdinalIgnoreCase) ? 1 : 0) @@ -1581,7 +1584,7 @@ namespace Emby.Server.Implementations.Library /// The item. /// The user. /// Task<IEnumerable<IntroInfo>>. - private async Task> GetIntros(IIntroProvider provider, BaseItem item, Jellyfin.Data.Entities.User user) + private async Task> GetIntros(IIntroProvider provider, BaseItem item, User user) { try { @@ -1682,7 +1685,7 @@ namespace Emby.Server.Implementations.Library /// The sort by. /// The sort order. /// IEnumerable{BaseItem}. - public IEnumerable Sort(IEnumerable items, Jellyfin.Data.Entities.User user, IEnumerable sortBy, SortOrder sortOrder) + public IEnumerable Sort(IEnumerable items, User user, IEnumerable sortBy, SortOrder sortOrder) { var isFirst = true; @@ -1705,7 +1708,7 @@ namespace Emby.Server.Implementations.Library return orderedItems ?? items; } - public IEnumerable Sort(IEnumerable items, Jellyfin.Data.Entities.User user, IEnumerable> orderByList) + public IEnumerable Sort(IEnumerable items, User user, IEnumerable> orderByList) { var isFirst = true; @@ -1742,7 +1745,7 @@ namespace Emby.Server.Implementations.Library /// The name. /// The user. /// IBaseItemComparer. - private IBaseItemComparer GetComparer(string name, Jellyfin.Data.Entities.User user) + private IBaseItemComparer GetComparer(string name, User user) { var comparer = Comparers.FirstOrDefault(c => string.Equals(name, c.Name, StringComparison.OrdinalIgnoreCase)); @@ -2074,7 +2077,7 @@ namespace Emby.Server.Implementations.Library private readonly TimeSpan _viewRefreshInterval = TimeSpan.FromHours(24); public UserView GetNamedView( - Jellyfin.Data.Entities.User user, + User user, string name, string viewType, string sortName) @@ -2127,7 +2130,7 @@ namespace Emby.Server.Implementations.Library } public UserView GetNamedView( - Jellyfin.Data.Entities.User user, + User user, string name, Guid parentId, string viewType, diff --git a/Emby.Server.Implementations/Library/MediaSourceManager.cs b/Emby.Server.Implementations/Library/MediaSourceManager.cs index 25af69058..b063db630 100644 --- a/Emby.Server.Implementations/Library/MediaSourceManager.cs +++ b/Emby.Server.Implementations/Library/MediaSourceManager.cs @@ -7,6 +7,7 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; +using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Extensions; @@ -145,7 +146,7 @@ namespace Emby.Server.Implementations.Library }); } - public async Task> GetPlaybackMediaSources(BaseItem item, Jellyfin.Data.Entities.User user, bool allowMediaProbe, bool enablePathSubstitution, CancellationToken cancellationToken) + public async Task> GetPlaybackMediaSources(BaseItem item, User user, bool allowMediaProbe, bool enablePathSubstitution, CancellationToken cancellationToken) { var mediaSources = GetStaticMediaSources(item, enablePathSubstitution, user); @@ -309,7 +310,7 @@ namespace Emby.Server.Implementations.Library return sources.FirstOrDefault(i => string.Equals(i.Id, mediaSourceId, StringComparison.OrdinalIgnoreCase)); } - public List GetStaticMediaSources(BaseItem item, bool enablePathSubstitution, Jellyfin.Data.Entities.User user = null) + public List GetStaticMediaSources(BaseItem item, bool enablePathSubstitution, User user = null) { if (item == null) { @@ -347,7 +348,7 @@ namespace Emby.Server.Implementations.Library return new string[] { language }; } - private void SetDefaultSubtitleStreamIndex(MediaSourceInfo source, UserItemData userData, Jellyfin.Data.Entities.User user, bool allowRememberingSelection) + private void SetDefaultSubtitleStreamIndex(MediaSourceInfo source, UserItemData userData, User user, bool allowRememberingSelection) { if (userData.SubtitleStreamIndex.HasValue && user.RememberSubtitleSelections @@ -380,7 +381,7 @@ namespace Emby.Server.Implementations.Library MediaStreamSelector.SetSubtitleStreamScores(source.MediaStreams, preferredSubs, user.SubtitleMode, audioLangage); } - private void SetDefaultAudioStreamIndex(MediaSourceInfo source, UserItemData userData, Jellyfin.Data.Entities.User user, bool allowRememberingSelection) + private void SetDefaultAudioStreamIndex(MediaSourceInfo source, UserItemData userData, User user, bool allowRememberingSelection) { if (userData.AudioStreamIndex.HasValue && user.RememberAudioSelections && allowRememberingSelection) { @@ -400,7 +401,7 @@ namespace Emby.Server.Implementations.Library source.DefaultAudioStreamIndex = MediaStreamSelector.GetDefaultAudioStreamIndex(source.MediaStreams, preferredAudio, user.PlayDefaultAudioTrack); } - public void SetDefaultAudioAndSubtitleStreamIndexes(BaseItem item, MediaSourceInfo source, Jellyfin.Data.Entities.User user) + public void SetDefaultAudioAndSubtitleStreamIndexes(BaseItem item, MediaSourceInfo source, User user) { // Item would only be null if the app didn't supply ItemId as part of the live stream open request var mediaType = item == null ? MediaType.Video : item.MediaType; @@ -538,7 +539,7 @@ namespace Emby.Server.Implementations.Library mediaSource.RunTimeTicks = null; } - var audioStream = mediaSource.MediaStreams.FirstOrDefault(i => i.Type == MediaBrowser.Model.Entities.MediaStreamType.Audio); + var audioStream = mediaSource.MediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Audio); if (audioStream == null || audioStream.Index == -1) { @@ -549,7 +550,7 @@ namespace Emby.Server.Implementations.Library mediaSource.DefaultAudioStreamIndex = audioStream.Index; } - var videoStream = mediaSource.MediaStreams.FirstOrDefault(i => i.Type == MediaBrowser.Model.Entities.MediaStreamType.Video); + var videoStream = mediaSource.MediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Video); if (videoStream != null) { if (!videoStream.BitRate.HasValue) diff --git a/Emby.Server.Implementations/Library/MusicManager.cs b/Emby.Server.Implementations/Library/MusicManager.cs index ad8c70f5e..0bdc59914 100644 --- a/Emby.Server.Implementations/Library/MusicManager.cs +++ b/Emby.Server.Implementations/Library/MusicManager.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using System.Linq; +using Jellyfin.Data.Entities; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; @@ -10,6 +11,7 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Playlists; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Querying; +using MusicAlbum = MediaBrowser.Controller.Entities.Audio.MusicAlbum; namespace Emby.Server.Implementations.Library { @@ -22,7 +24,7 @@ namespace Emby.Server.Implementations.Library _libraryManager = libraryManager; } - public List GetInstantMixFromSong(Audio item, Jellyfin.Data.Entities.User user, DtoOptions dtoOptions) + public List GetInstantMixFromSong(Audio item, User user, DtoOptions dtoOptions) { var list = new List /// The user. - public Jellyfin.Data.Entities.User User { get; set; } + public User User { get; set; } /// /// Gets or sets the user manager. diff --git a/Emby.Server.Implementations/Sorting/DatePlayedComparer.cs b/Emby.Server.Implementations/Sorting/DatePlayedComparer.cs index 57a1a00d9..5e527ea25 100644 --- a/Emby.Server.Implementations/Sorting/DatePlayedComparer.cs +++ b/Emby.Server.Implementations/Sorting/DatePlayedComparer.cs @@ -1,4 +1,5 @@ using System; +using Jellyfin.Data.Entities; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Sorting; @@ -15,7 +16,7 @@ namespace Emby.Server.Implementations.Sorting /// Gets or sets the user. /// /// The user. - public Jellyfin.Data.Entities.User User { get; set; } + public User User { get; set; } /// /// Gets or sets the user manager. diff --git a/Emby.Server.Implementations/Sorting/IsFavoriteOrLikeComparer.cs b/Emby.Server.Implementations/Sorting/IsFavoriteOrLikeComparer.cs index c9feca7e3..8ae0a613b 100644 --- a/Emby.Server.Implementations/Sorting/IsFavoriteOrLikeComparer.cs +++ b/Emby.Server.Implementations/Sorting/IsFavoriteOrLikeComparer.cs @@ -1,3 +1,4 @@ +using Jellyfin.Data.Entities; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Sorting; @@ -11,7 +12,7 @@ namespace Emby.Server.Implementations.Sorting /// Gets or sets the user. /// /// The user. - public Jellyfin.Data.Entities.User User { get; set; } + public User User { get; set; } /// /// Compares the specified x. diff --git a/Emby.Server.Implementations/Sorting/IsPlayedComparer.cs b/Emby.Server.Implementations/Sorting/IsPlayedComparer.cs index 6f383e65f..3b3c04922 100644 --- a/Emby.Server.Implementations/Sorting/IsPlayedComparer.cs +++ b/Emby.Server.Implementations/Sorting/IsPlayedComparer.cs @@ -1,3 +1,4 @@ +using Jellyfin.Data.Entities; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Sorting; @@ -11,7 +12,7 @@ namespace Emby.Server.Implementations.Sorting /// Gets or sets the user. /// /// The user. - public Jellyfin.Data.Entities.User User { get; set; } + public User User { get; set; } /// /// Compares the specified x. diff --git a/Emby.Server.Implementations/Sorting/IsUnplayedComparer.cs b/Emby.Server.Implementations/Sorting/IsUnplayedComparer.cs index 4845fdc0d..5719356c7 100644 --- a/Emby.Server.Implementations/Sorting/IsUnplayedComparer.cs +++ b/Emby.Server.Implementations/Sorting/IsUnplayedComparer.cs @@ -1,3 +1,4 @@ +using Jellyfin.Data.Entities; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Sorting; @@ -11,7 +12,7 @@ namespace Emby.Server.Implementations.Sorting /// Gets or sets the user. /// /// The user. - public Jellyfin.Data.Entities.User User { get; set; } + public User User { get; set; } /// /// Compares the specified x. diff --git a/Emby.Server.Implementations/Sorting/PlayCountComparer.cs b/Emby.Server.Implementations/Sorting/PlayCountComparer.cs index 99846db61..afbaaf6ab 100644 --- a/Emby.Server.Implementations/Sorting/PlayCountComparer.cs +++ b/Emby.Server.Implementations/Sorting/PlayCountComparer.cs @@ -1,3 +1,4 @@ +using Jellyfin.Data.Entities; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Sorting; @@ -14,7 +15,7 @@ namespace Emby.Server.Implementations.Sorting /// Gets or sets the user. /// /// The user. - public Jellyfin.Data.Entities.User User { get; set; } + public User User { get; set; } /// /// Compares the specified x. diff --git a/Emby.Server.Implementations/TV/TVSeriesManager.cs b/Emby.Server.Implementations/TV/TVSeriesManager.cs index 905a1ea99..570de49db 100644 --- a/Emby.Server.Implementations/TV/TVSeriesManager.cs +++ b/Emby.Server.Implementations/TV/TVSeriesManager.cs @@ -2,15 +2,17 @@ using System; using System.Collections.Generic; using System.Globalization; using System.Linq; +using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.TV; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Querying; +using Episode = MediaBrowser.Controller.Entities.TV.Episode; +using Series = MediaBrowser.Controller.Entities.TV.Series; namespace Emby.Server.Implementations.TV { @@ -139,7 +141,7 @@ namespace Emby.Server.Implementations.TV return GetResult(episodes, request); } - public IEnumerable GetNextUpEpisodes(NextUpQuery request, Jellyfin.Data.Entities.User user, IEnumerable seriesKeys, DtoOptions dtoOptions) + public IEnumerable GetNextUpEpisodes(NextUpQuery request, User user, IEnumerable seriesKeys, DtoOptions dtoOptions) { // Avoid implicitly captured closure var currentUser = user; @@ -188,7 +190,7 @@ namespace Emby.Server.Implementations.TV /// Gets the next up. /// /// Task{Episode}. - private Tuple> GetNextUp(string seriesKey, Jellyfin.Data.Entities.User user, DtoOptions dtoOptions) + private Tuple> GetNextUp(string seriesKey, User user, DtoOptions dtoOptions) { var lastWatchedEpisode = _libraryManager.GetItemList(new InternalItemsQuery(user) { diff --git a/Jellyfin.Server.Implementations/Users/DefaultAuthenticationProvider.cs b/Jellyfin.Server.Implementations/Users/DefaultAuthenticationProvider.cs index 38494727c..df730731a 100644 --- a/Jellyfin.Server.Implementations/Users/DefaultAuthenticationProvider.cs +++ b/Jellyfin.Server.Implementations/Users/DefaultAuthenticationProvider.cs @@ -2,6 +2,7 @@ using System; using System.Linq; using System.Text; using System.Threading.Tasks; +using Jellyfin.Data.Entities; using MediaBrowser.Common; using MediaBrowser.Common.Cryptography; using MediaBrowser.Controller.Authentication; @@ -42,7 +43,7 @@ namespace Jellyfin.Server.Implementations.Users /// // This is the version that we need to use for local users. Because reasons. - public Task Authenticate(string username, string password, Data.Entities.User resolvedUser) + public Task Authenticate(string username, string password, User resolvedUser) { if (resolvedUser == null) { @@ -93,11 +94,11 @@ namespace Jellyfin.Server.Implementations.Users } /// - public bool HasPassword(Data.Entities.User user) + public bool HasPassword(User user) => !string.IsNullOrEmpty(user.Password); /// - public Task ChangePassword(Data.Entities.User user, string newPassword) + public Task ChangePassword(User user, string newPassword) { if (string.IsNullOrEmpty(newPassword)) { @@ -112,7 +113,7 @@ namespace Jellyfin.Server.Implementations.Users } /// - public void ChangeEasyPassword(Data.Entities.User user, string newPassword, string newPasswordHash) + public void ChangeEasyPassword(User user, string newPassword, string newPasswordHash) { if (newPassword != null) { @@ -128,7 +129,7 @@ namespace Jellyfin.Server.Implementations.Users } /// - public string GetEasyPasswordHash(Data.Entities.User user) + public string GetEasyPasswordHash(User user) { return string.IsNullOrEmpty(user.EasyPassword) ? null @@ -141,7 +142,7 @@ namespace Jellyfin.Server.Implementations.Users /// The user. /// The string to hash. /// The hashed string. - public string GetHashedString(Data.Entities.User user, string str) + public string GetHashedString(User user, string str) { if (string.IsNullOrEmpty(user.Password)) { @@ -167,7 +168,7 @@ namespace Jellyfin.Server.Implementations.Users /// The user. /// The string to hash. /// The hashed string. - public ReadOnlySpan GetHashed(Data.Entities.User user, string str) + public ReadOnlySpan GetHashed(User user, string str) { if (string.IsNullOrEmpty(user.Password)) { diff --git a/Jellyfin.Server.Implementations/Users/InvalidAuthProvider.cs b/Jellyfin.Server.Implementations/Users/InvalidAuthProvider.cs index e430808bf..b6e65b559 100644 --- a/Jellyfin.Server.Implementations/Users/InvalidAuthProvider.cs +++ b/Jellyfin.Server.Implementations/Users/InvalidAuthProvider.cs @@ -1,4 +1,5 @@ using System.Threading.Tasks; +using Jellyfin.Data.Entities; using MediaBrowser.Controller.Authentication; namespace Jellyfin.Server.Implementations.Users @@ -21,25 +22,25 @@ namespace Jellyfin.Server.Implementations.Users } /// - public bool HasPassword(Data.Entities.User user) + public bool HasPassword(User user) { return true; } /// - public Task ChangePassword(Data.Entities.User user, string newPassword) + public Task ChangePassword(User user, string newPassword) { return Task.CompletedTask; } /// - public void ChangeEasyPassword(Data.Entities.User user, string newPassword, string newPasswordHash) + public void ChangeEasyPassword(User user, string newPassword, string newPasswordHash) { // Nothing here } /// - public string GetEasyPasswordHash(Data.Entities.User user) + public string GetEasyPasswordHash(User user) { return string.Empty; } diff --git a/MediaBrowser.Api/FilterService.cs b/MediaBrowser.Api/FilterService.cs index ac61cd491..bd67ec41f 100644 --- a/MediaBrowser.Api/FilterService.cs +++ b/MediaBrowser.Api/FilterService.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using Jellyfin.Data.Entities; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; @@ -220,7 +221,7 @@ namespace MediaBrowser.Api return result; } - private InternalItemsQuery GetItemsQuery(GetQueryFiltersLegacy request, Jellyfin.Data.Entities.User user) + private InternalItemsQuery GetItemsQuery(GetQueryFiltersLegacy request, User user) { var query = new InternalItemsQuery { diff --git a/MediaBrowser.Api/Library/LibraryService.cs b/MediaBrowser.Api/Library/LibraryService.cs index 50977c48f..3f7fb36e5 100644 --- a/MediaBrowser.Api/Library/LibraryService.cs +++ b/MediaBrowser.Api/Library/LibraryService.cs @@ -6,6 +6,7 @@ using System.Net; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; +using Jellyfin.Data.Entities; using MediaBrowser.Api.Movies; using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Progress; @@ -14,7 +15,6 @@ using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Entities.Movies; -using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Net; using MediaBrowser.Controller.Providers; @@ -27,6 +27,11 @@ using MediaBrowser.Model.Querying; using MediaBrowser.Model.Services; using Microsoft.Extensions.Logging; using Microsoft.Net.Http.Headers; +using Book = MediaBrowser.Controller.Entities.Book; +using Episode = MediaBrowser.Controller.Entities.TV.Episode; +using Movie = MediaBrowser.Controller.Entities.Movies.Movie; +using MusicAlbum = MediaBrowser.Controller.Entities.Audio.MusicAlbum; +using Series = MediaBrowser.Controller.Entities.TV.Series; namespace MediaBrowser.Api.Library { @@ -759,11 +764,11 @@ namespace MediaBrowser.Api.Library }); } - private void LogDownload(BaseItem item, Jellyfin.Data.Entities.User user, AuthorizationInfo auth) + private void LogDownload(BaseItem item, User user, AuthorizationInfo auth) { try { - _activityManager.Create(new Jellyfin.Data.Entities.ActivityLog( + _activityManager.Create(new ActivityLog( string.Format(_localization.GetLocalizedString("UserDownloadingItemWithValues"), user.Username, item.Name), "UserDownloadingContent", auth.UserId) @@ -842,7 +847,7 @@ namespace MediaBrowser.Api.Library return baseItemDtos; } - private BaseItem TranslateParentItem(BaseItem item, Jellyfin.Data.Entities.User user) + private BaseItem TranslateParentItem(BaseItem item, User user) { return item.GetParent() is AggregateFolder ? _libraryManager.GetUserRootFolder().GetChildren(user, true) @@ -884,7 +889,7 @@ namespace MediaBrowser.Api.Library return ToOptimizedResult(counts); } - private int GetCount(Type type, Jellyfin.Data.Entities.User user, GetItemCounts request) + private int GetCount(Type type, User user, GetItemCounts request) { var query = new InternalItemsQuery(user) { diff --git a/MediaBrowser.Api/Movies/MoviesService.cs b/MediaBrowser.Api/Movies/MoviesService.cs index aaabe07f3..a5a6cd633 100644 --- a/MediaBrowser.Api/Movies/MoviesService.cs +++ b/MediaBrowser.Api/Movies/MoviesService.cs @@ -2,11 +2,11 @@ using System; using System.Collections.Generic; using System.Globalization; using System.Linq; +using Jellyfin.Data.Entities; using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.LiveTv; using MediaBrowser.Controller.Net; @@ -15,6 +15,7 @@ using MediaBrowser.Model.Entities; using MediaBrowser.Model.Querying; using MediaBrowser.Model.Services; using Microsoft.Extensions.Logging; +using Movie = MediaBrowser.Controller.Entities.Movies.Movie; namespace MediaBrowser.Api.Movies { @@ -148,12 +149,7 @@ namespace MediaBrowser.Api.Movies return result; } - private IEnumerable GetRecommendationCategories( - Jellyfin.Data.Entities.User user, - string parentId, - int categoryLimit, - int itemLimit, - DtoOptions dtoOptions) + private IEnumerable GetRecommendationCategories(User user, string parentId, int categoryLimit, int itemLimit, DtoOptions dtoOptions) { var categories = new List(); @@ -257,7 +253,7 @@ namespace MediaBrowser.Api.Movies } private IEnumerable GetWithDirector( - Jellyfin.Data.Entities.User user, + User user, IEnumerable names, int itemLimit, DtoOptions dtoOptions, @@ -303,12 +299,7 @@ namespace MediaBrowser.Api.Movies } } - private IEnumerable GetWithActor( - Jellyfin.Data.Entities.User user, - IEnumerable names, - int itemLimit, - DtoOptions dtoOptions, - RecommendationType type) + private IEnumerable GetWithActor(User user, IEnumerable names, int itemLimit, DtoOptions dtoOptions, RecommendationType type) { var itemTypes = new List { typeof(Movie).Name }; if (ServerConfigurationManager.Configuration.EnableExternalContentInSuggestions) @@ -349,12 +340,7 @@ namespace MediaBrowser.Api.Movies } } - private IEnumerable GetSimilarTo( - Jellyfin.Data.Entities.User user, - List baselineItems, - int itemLimit, - DtoOptions dtoOptions, - RecommendationType type) + private IEnumerable GetSimilarTo(User user, List baselineItems, int itemLimit, DtoOptions dtoOptions, RecommendationType type) { var itemTypes = new List { typeof(Movie).Name }; if (ServerConfigurationManager.Configuration.EnableExternalContentInSuggestions) diff --git a/MediaBrowser.Api/Music/InstantMixService.cs b/MediaBrowser.Api/Music/InstantMixService.cs index e00b06e38..7d10c9427 100644 --- a/MediaBrowser.Api/Music/InstantMixService.cs +++ b/MediaBrowser.Api/Music/InstantMixService.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Linq; +using Jellyfin.Data.Entities; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; @@ -171,7 +172,7 @@ namespace MediaBrowser.Api.Music return GetResult(items, user, request, dtoOptions); } - private object GetResult(List items, Jellyfin.Data.Entities.User user, BaseGetSimilarItems request, DtoOptions dtoOptions) + private object GetResult(List items, User user, BaseGetSimilarItems request, DtoOptions dtoOptions) { var list = items; diff --git a/MediaBrowser.Api/SuggestionsService.cs b/MediaBrowser.Api/SuggestionsService.cs index 51fa1eb71..32d3bde5c 100644 --- a/MediaBrowser.Api/SuggestionsService.cs +++ b/MediaBrowser.Api/SuggestionsService.cs @@ -1,5 +1,6 @@ using System; using System.Linq; +using Jellyfin.Data.Entities; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; @@ -78,7 +79,7 @@ namespace MediaBrowser.Api }; } - private QueryResult GetItems(GetSuggestedItems request, Jellyfin.Data.Entities.User user, DtoOptions dtoOptions) + private QueryResult GetItems(GetSuggestedItems request, User user, DtoOptions dtoOptions) { return _libraryManager.GetItemsResult(new InternalItemsQuery(user) { diff --git a/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs b/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs index 11d984a9a..a1ec08467 100644 --- a/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs +++ b/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using Jellyfin.Data.Entities; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; @@ -94,7 +95,7 @@ namespace MediaBrowser.Api.UserLibrary { var dtoOptions = GetDtoOptions(AuthorizationContext, request); - Jellyfin.Data.Entities.User user = null; + User user = null; BaseItem parentItem; if (!request.UserId.Equals(Guid.Empty)) @@ -246,7 +247,7 @@ namespace MediaBrowser.Api.UserLibrary { var dtoOptions = GetDtoOptions(AuthorizationContext, request); - Jellyfin.Data.Entities.User user = null; + User user = null; BaseItem parentItem; if (!request.UserId.Equals(Guid.Empty)) diff --git a/MediaBrowser.Api/UserLibrary/ItemsService.cs b/MediaBrowser.Api/UserLibrary/ItemsService.cs index ca9f7aa82..49d534c36 100644 --- a/MediaBrowser.Api/UserLibrary/ItemsService.cs +++ b/MediaBrowser.Api/UserLibrary/ItemsService.cs @@ -2,11 +2,11 @@ using System; using System.Collections.Generic; using System.Globalization; using System.Linq; +using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Net; using MediaBrowser.Model.Dto; @@ -15,6 +15,7 @@ using MediaBrowser.Model.Globalization; using MediaBrowser.Model.Querying; using MediaBrowser.Model.Services; using Microsoft.Extensions.Logging; +using MusicAlbum = MediaBrowser.Controller.Entities.Audio.MusicAlbum; namespace MediaBrowser.Api.UserLibrary { @@ -180,7 +181,7 @@ namespace MediaBrowser.Api.UserLibrary /// /// Gets the items to serialize. /// - private QueryResult GetQueryResult(GetItems request, DtoOptions dtoOptions, Jellyfin.Data.Entities.User user) + private QueryResult GetQueryResult(GetItems request, DtoOptions dtoOptions, User user) { if (string.Equals(request.IncludeItemTypes, "Playlist", StringComparison.OrdinalIgnoreCase) || string.Equals(request.IncludeItemTypes, "BoxSet", StringComparison.OrdinalIgnoreCase)) @@ -255,7 +256,7 @@ namespace MediaBrowser.Api.UserLibrary }; } - private InternalItemsQuery GetItemsQuery(GetItems request, DtoOptions dtoOptions, Jellyfin.Data.Entities.User user) + private InternalItemsQuery GetItemsQuery(GetItems request, DtoOptions dtoOptions, User user) { var query = new InternalItemsQuery(user) { diff --git a/MediaBrowser.Api/UserLibrary/PlaystateService.cs b/MediaBrowser.Api/UserLibrary/PlaystateService.cs index fb8bda190..ab231626b 100644 --- a/MediaBrowser.Api/UserLibrary/PlaystateService.cs +++ b/MediaBrowser.Api/UserLibrary/PlaystateService.cs @@ -1,8 +1,8 @@ using System; using System.Globalization; using System.Threading.Tasks; +using Jellyfin.Data.Entities; using MediaBrowser.Controller.Configuration; -using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Net; using MediaBrowser.Controller.Session; @@ -437,7 +437,7 @@ namespace MediaBrowser.Api.UserLibrary /// if set to true [was played]. /// The date played. /// Task. - private UserItemDataDto UpdatePlayedStatus(Jellyfin.Data.Entities.User user, string itemId, bool wasPlayed, DateTime? datePlayed) + private UserItemDataDto UpdatePlayedStatus(User user, string itemId, bool wasPlayed, DateTime? datePlayed) { var item = _libraryManager.GetItemById(itemId); diff --git a/MediaBrowser.Controller/Channels/Channel.cs b/MediaBrowser.Controller/Channels/Channel.cs index d6a1fc84e..dbb047804 100644 --- a/MediaBrowser.Controller/Channels/Channel.cs +++ b/MediaBrowser.Controller/Channels/Channel.cs @@ -3,6 +3,7 @@ using System.Globalization; using System.Linq; using System.Text.Json.Serialization; using System.Threading; +using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; using MediaBrowser.Common.Progress; using MediaBrowser.Controller.Entities; @@ -12,7 +13,7 @@ namespace MediaBrowser.Controller.Channels { public class Channel : Folder { - public override bool IsVisible(Jellyfin.Data.Entities.User user) + public override bool IsVisible(User user) { if (user.GetPreference(PreferenceKind.BlockedChannels) != null) { @@ -77,7 +78,7 @@ namespace MediaBrowser.Controller.Channels return false; } - internal static bool IsChannelVisible(BaseItem channelItem, Jellyfin.Data.Entities.User user) + internal static bool IsChannelVisible(BaseItem channelItem, User user) { var channel = ChannelManager.GetChannel(channelItem.ChannelId.ToString("")); diff --git a/MediaBrowser.Controller/Collections/ICollectionManager.cs b/MediaBrowser.Controller/Collections/ICollectionManager.cs index f51c73bd7..701423c0f 100644 --- a/MediaBrowser.Controller/Collections/ICollectionManager.cs +++ b/MediaBrowser.Controller/Collections/ICollectionManager.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using Jellyfin.Data.Entities; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Movies; @@ -51,6 +52,6 @@ namespace MediaBrowser.Controller.Collections /// The items. /// The user. /// IEnumerable{BaseItem}. - IEnumerable CollapseItemsWithinBoxSets(IEnumerable items, Jellyfin.Data.Entities.User user); + IEnumerable CollapseItemsWithinBoxSets(IEnumerable items, User user); } } diff --git a/MediaBrowser.Controller/Drawing/IImageProcessor.cs b/MediaBrowser.Controller/Drawing/IImageProcessor.cs index bdb12402a..c00d1c335 100644 --- a/MediaBrowser.Controller/Drawing/IImageProcessor.cs +++ b/MediaBrowser.Controller/Drawing/IImageProcessor.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.IO; using System.Threading.Tasks; +using Jellyfin.Data.Entities; using MediaBrowser.Controller.Entities; using MediaBrowser.Model.Drawing; using MediaBrowser.Model.Entities; @@ -50,7 +51,7 @@ namespace MediaBrowser.Controller.Drawing string GetImageCacheTag(BaseItem item, ChapterInfo info); - string GetImageCacheTag(Jellyfin.Data.Entities.User user); + string GetImageCacheTag(User user); /// /// Processes the image. diff --git a/MediaBrowser.Controller/Dto/IDtoService.cs b/MediaBrowser.Controller/Dto/IDtoService.cs index 5ac4f05c0..56e6c47c4 100644 --- a/MediaBrowser.Controller/Dto/IDtoService.cs +++ b/MediaBrowser.Controller/Dto/IDtoService.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Jellyfin.Data.Entities; using MediaBrowser.Controller.Entities; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Querying; @@ -38,7 +39,7 @@ namespace MediaBrowser.Controller.Dto /// The fields. /// The user. /// The owner. - BaseItemDto GetBaseItemDto(BaseItem item, ItemFields[] fields, Jellyfin.Data.Entities.User user = null, BaseItem owner = null); + BaseItemDto GetBaseItemDto(BaseItem item, ItemFields[] fields, User user = null, BaseItem owner = null); /// /// Gets the base item dto. @@ -48,7 +49,7 @@ namespace MediaBrowser.Controller.Dto /// The user. /// The owner. /// BaseItemDto. - BaseItemDto GetBaseItemDto(BaseItem item, DtoOptions options, Jellyfin.Data.Entities.User user = null, BaseItem owner = null); + BaseItemDto GetBaseItemDto(BaseItem item, DtoOptions options, User user = null, BaseItem owner = null); /// /// Gets the base item dtos. @@ -57,11 +58,11 @@ namespace MediaBrowser.Controller.Dto /// The options. /// The user. /// The owner. - IReadOnlyList GetBaseItemDtos(IReadOnlyList items, DtoOptions options, Jellyfin.Data.Entities.User user = null, BaseItem owner = null); + IReadOnlyList GetBaseItemDtos(IReadOnlyList items, DtoOptions options, User user = null, BaseItem owner = null); /// /// Gets the item by name dto. /// - BaseItemDto GetItemByNameDto(BaseItem item, DtoOptions options, List taggedItems, Jellyfin.Data.Entities.User user = null); + BaseItemDto GetItemByNameDto(BaseItem item, DtoOptions options, List taggedItems, User user = null); } } diff --git a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs index fbadeafad..15b580896 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Text.Json.Serialization; using System.Threading; using System.Threading.Tasks; +using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Library; @@ -79,7 +80,7 @@ namespace MediaBrowser.Controller.Entities.Audio [JsonIgnore] public IEnumerable /// The user. /// PlayAccess. - public PlayAccess GetPlayAccess(Jellyfin.Data.Entities.User user) + public PlayAccess GetPlayAccess(User user) { if (!user.HasPermission(PermissionKind.EnableMediaPlayback)) { @@ -1214,11 +1215,11 @@ namespace MediaBrowser.Controller.Entities { if (video.IsoType.HasValue) { - if (video.IsoType.Value == Model.Entities.IsoType.BluRay) + if (video.IsoType.Value == IsoType.BluRay) { terms.Add("Bluray"); } - else if (video.IsoType.Value == Model.Entities.IsoType.Dvd) + else if (video.IsoType.Value == IsoType.Dvd) { terms.Add("DVD"); } @@ -1761,7 +1762,7 @@ namespace MediaBrowser.Controller.Entities /// The user. /// true if [is parental allowed] [the specified user]; otherwise, false. /// user - public bool IsParentalAllowed(Jellyfin.Data.Entities.User user) + public bool IsParentalAllowed(User user) { if (user == null) { @@ -1857,7 +1858,7 @@ namespace MediaBrowser.Controller.Entities return list.Distinct(StringComparer.OrdinalIgnoreCase).ToList(); } - private bool IsVisibleViaTags(Jellyfin.Data.Entities.User user) + private bool IsVisibleViaTags(User user) { if (user.GetPreference(PreferenceKind.BlockedTags).Any(i => Tags.Contains(i, StringComparer.OrdinalIgnoreCase))) { @@ -1887,7 +1888,7 @@ namespace MediaBrowser.Controller.Entities /// /// The configuration. /// true if XXXX, false otherwise. - protected virtual bool GetBlockUnratedValue(Jellyfin.Data.Entities.User user) + protected virtual bool GetBlockUnratedValue(User user) { // Don't block plain folders that are unrated. Let the media underneath get blocked // Special folders like series and albums will override this method. @@ -1906,7 +1907,7 @@ namespace MediaBrowser.Controller.Entities /// The user. /// true if the specified user is visible; otherwise, false. /// user - public virtual bool IsVisible(Jellyfin.Data.Entities.User user) + public virtual bool IsVisible(User user) { if (user == null) { @@ -1916,7 +1917,7 @@ namespace MediaBrowser.Controller.Entities return IsParentalAllowed(user); } - public virtual bool IsVisibleStandalone(Jellyfin.Data.Entities.User user) + public virtual bool IsVisibleStandalone(User user) { if (SourceType == SourceType.Channel) { @@ -1929,7 +1930,7 @@ namespace MediaBrowser.Controller.Entities [JsonIgnore] public virtual bool SupportsInheritedParentImages => false; - protected bool IsVisibleStandaloneInternal(Jellyfin.Data.Entities.User user, bool checkFolders) + protected bool IsVisibleStandaloneInternal(User user, bool checkFolders) { if (!IsVisible(user)) { @@ -2127,7 +2128,7 @@ namespace MediaBrowser.Controller.Entities /// Task. /// public virtual void MarkPlayed( - Jellyfin.Data.Entities.User user, + User user, DateTime? datePlayed, bool resetPosition) { @@ -2164,7 +2165,7 @@ namespace MediaBrowser.Controller.Entities /// The user. /// Task. /// - public virtual void MarkUnplayed(Jellyfin.Data.Entities.User user) + public virtual void MarkUnplayed(User user) { if (user == null) { @@ -2540,21 +2541,21 @@ namespace MediaBrowser.Controller.Entities UpdateToRepository(ItemUpdateType.ImageUpdate, CancellationToken.None); } - public virtual bool IsPlayed(Jellyfin.Data.Entities.User user) + public virtual bool IsPlayed(User user) { var userdata = UserDataManager.GetUserData(user, this); return userdata != null && userdata.Played; } - public bool IsFavoriteOrLiked(Jellyfin.Data.Entities.User user) + public bool IsFavoriteOrLiked(User user) { var userdata = UserDataManager.GetUserData(user, this); return userdata != null && (userdata.IsFavorite || (userdata.Likes ?? false)); } - public virtual bool IsUnplayed(Jellyfin.Data.Entities.User user) + public virtual bool IsUnplayed(User user) { if (user == null) { @@ -2620,7 +2621,7 @@ namespace MediaBrowser.Controller.Entities return path; } - public virtual void FillUserDataDtoValues(UserItemDataDto dto, UserItemData userData, BaseItemDto itemDto, Jellyfin.Data.Entities.User user, DtoOptions fields) + public virtual void FillUserDataDtoValues(UserItemDataDto dto, UserItemData userData, BaseItemDto itemDto, User user, DtoOptions fields) { if (RunTimeTicks.HasValue) { @@ -2733,14 +2734,14 @@ namespace MediaBrowser.Controller.Entities return RefreshMetadataForOwnedItem(video, copyTitleMetadata, newOptions, cancellationToken); } - public string GetEtag(Jellyfin.Data.Entities.User user) + public string GetEtag(User user) { var list = GetEtagValues(user); return string.Join("|", list).GetMD5().ToString("N", CultureInfo.InvariantCulture); } - protected virtual List GetEtagValues(Jellyfin.Data.Entities.User user) + protected virtual List GetEtagValues(User user) { return new List { diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index 03644b0c6..399813aa2 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -8,6 +8,7 @@ using System.Linq; using System.Text.Json.Serialization; using System.Threading; using System.Threading.Tasks; +using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; using MediaBrowser.Common.Progress; using MediaBrowser.Controller.Channels; @@ -16,13 +17,16 @@ using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Entities.Movies; -using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Dto; using MediaBrowser.Model.IO; using MediaBrowser.Model.Querying; using Microsoft.Extensions.Logging; +using Episode = MediaBrowser.Controller.Entities.TV.Episode; +using MusicAlbum = MediaBrowser.Controller.Entities.Audio.MusicAlbum; +using Season = MediaBrowser.Controller.Entities.TV.Season; +using Series = MediaBrowser.Controller.Entities.TV.Series; namespace MediaBrowser.Controller.Entities { @@ -174,7 +178,7 @@ namespace MediaBrowser.Controller.Entities [JsonIgnore] public IEnumerable RecursiveChildren => GetRecursiveChildren(); - public override bool IsVisible(Jellyfin.Data.Entities.User user) + public override bool IsVisible(User user) { if (this is ICollectionFolder && !(this is BasePluginFolder)) { @@ -586,7 +590,7 @@ namespace MediaBrowser.Controller.Entities }); } - public virtual int GetChildCount(Jellyfin.Data.Entities.User user) + public virtual int GetChildCount(User user) { if (LinkedChildren.Length > 0) { @@ -611,7 +615,7 @@ namespace MediaBrowser.Controller.Entities return result.TotalRecordCount; } - public virtual int GetRecursiveChildCount(Jellyfin.Data.Entities.User user) + public virtual int GetRecursiveChildCount(User user) { return GetItems(new InternalItemsQuery(user) { @@ -954,7 +958,7 @@ namespace MediaBrowser.Controller.Entities IEnumerable items, InternalItemsQuery query, BaseItem queryParent, - Jellyfin.Data.Entities.User user, + User user, IServerConfigurationManager configurationManager, ICollectionManager collectionManager) { @@ -973,7 +977,7 @@ namespace MediaBrowser.Controller.Entities private static bool CollapseBoxSetItems(InternalItemsQuery query, BaseItem queryParent, - Jellyfin.Data.Entities.User user, + User user, IServerConfigurationManager configurationManager) { // Could end up stuck in a loop like this @@ -1196,7 +1200,7 @@ namespace MediaBrowser.Controller.Entities return true; } - public List GetChildren(Jellyfin.Data.Entities.User user, bool includeLinkedChildren) + public List GetChildren(User user, bool includeLinkedChildren) { if (user == null) { @@ -1206,7 +1210,7 @@ namespace MediaBrowser.Controller.Entities return GetChildren(user, includeLinkedChildren, null); } - public virtual List GetChildren(Jellyfin.Data.Entities.User user, bool includeLinkedChildren, InternalItemsQuery query) + public virtual List GetChildren(User user, bool includeLinkedChildren, InternalItemsQuery query) { if (user == null) { @@ -1226,7 +1230,7 @@ namespace MediaBrowser.Controller.Entities return result.Values.ToList(); } - protected virtual IEnumerable GetEligibleChildrenForRecursiveChildren(Jellyfin.Data.Entities.User user) + protected virtual IEnumerable GetEligibleChildrenForRecursiveChildren(User user) { return Children; } @@ -1235,7 +1239,7 @@ namespace MediaBrowser.Controller.Entities /// Adds the children to list. /// /// true if XXXX, false otherwise - private void AddChildren(Jellyfin.Data.Entities.User user, bool includeLinkedChildren, Dictionary result, bool recursive, InternalItemsQuery query) + private void AddChildren(User user, bool includeLinkedChildren, Dictionary result, bool recursive, InternalItemsQuery query) { foreach (var child in GetEligibleChildrenForRecursiveChildren(user)) { @@ -1284,12 +1288,12 @@ namespace MediaBrowser.Controller.Entities /// if set to true [include linked children]. /// IEnumerable{BaseItem}. /// - public IEnumerable GetRecursiveChildren(Jellyfin.Data.Entities.User user, bool includeLinkedChildren = true) + public IEnumerable GetRecursiveChildren(User user, bool includeLinkedChildren = true) { return GetRecursiveChildren(user, null); } - public virtual IEnumerable GetRecursiveChildren(Jellyfin.Data.Entities.User user, InternalItemsQuery query) + public virtual IEnumerable GetRecursiveChildren(User user, InternalItemsQuery query) { if (user == null) { @@ -1408,7 +1412,7 @@ namespace MediaBrowser.Controller.Entities return false; } - public List GetLinkedChildren(Jellyfin.Data.Entities.User user) + public List GetLinkedChildren(User user) { if (!FilterLinkedChildrenPerUser || user == null) { @@ -1570,7 +1574,7 @@ namespace MediaBrowser.Controller.Entities /// The date played. /// if set to true [reset position]. /// Task. - public override void MarkPlayed(Jellyfin.Data.Entities.User user, + public override void MarkPlayed(User user, DateTime? datePlayed, bool resetPosition) { @@ -1611,7 +1615,7 @@ namespace MediaBrowser.Controller.Entities /// /// The user. /// Task. - public override void MarkUnplayed(Jellyfin.Data.Entities.User user) + public override void MarkUnplayed(User user) { var itemsResult = GetItemList(new InternalItemsQuery { @@ -1629,7 +1633,7 @@ namespace MediaBrowser.Controller.Entities } } - public override bool IsPlayed(Jellyfin.Data.Entities.User user) + public override bool IsPlayed(User user) { var itemsResult = GetItemList(new InternalItemsQuery(user) { @@ -1644,7 +1648,7 @@ namespace MediaBrowser.Controller.Entities .All(i => i.IsPlayed(user)); } - public override bool IsUnplayed(Jellyfin.Data.Entities.User user) + public override bool IsUnplayed(User user) { return !IsPlayed(user); } @@ -1689,7 +1693,7 @@ namespace MediaBrowser.Controller.Entities } } - public override void FillUserDataDtoValues(UserItemDataDto dto, UserItemData userData, BaseItemDto itemDto, Jellyfin.Data.Entities.User user, DtoOptions fields) + public override void FillUserDataDtoValues(UserItemDataDto dto, UserItemData userData, BaseItemDto itemDto, User user, DtoOptions fields) { if (!SupportsUserDataFromChildren) { diff --git a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs index 6a2cafcba..a2dff53ad 100644 --- a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs +++ b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; using MediaBrowser.Controller.Dto; using MediaBrowser.Model.Configuration; @@ -16,7 +17,7 @@ namespace MediaBrowser.Controller.Entities public int? Limit { get; set; } - public Jellyfin.Data.Entities.User User { get; set; } + public User User { get; set; } public BaseItem SimilarTo { get; set; } @@ -214,13 +215,13 @@ namespace MediaBrowser.Controller.Entities Years = Array.Empty(); } - public InternalItemsQuery(Jellyfin.Data.Entities.User user) + public InternalItemsQuery(User user) : this() { SetUser(user); } - public void SetUser(Jellyfin.Data.Entities.User user) + public void SetUser(User user) { if (user != null) { diff --git a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs index 1c1bde3e4..be71bcc3c 100644 --- a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs +++ b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Linq; using System.Text.Json.Serialization; +using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; @@ -44,7 +45,7 @@ namespace MediaBrowser.Controller.Entities.Movies /// The display order. public string DisplayOrder { get; set; } - protected override bool GetBlockUnratedValue(Jellyfin.Data.Entities.User user) + protected override bool GetBlockUnratedValue(User user) { return user.GetPreference(PreferenceKind.BlockUnratedItems).Contains(UnratedItem.Movie.ToString()); } @@ -100,7 +101,7 @@ namespace MediaBrowser.Controller.Entities.Movies [JsonIgnore] public override bool IsPreSorted => true; - public override bool IsAuthorizedToDelete(Jellyfin.Data.Entities.User user, List allCollectionFolders) + public override bool IsAuthorizedToDelete(User user, List allCollectionFolders) { return true; } @@ -110,7 +111,7 @@ namespace MediaBrowser.Controller.Entities.Movies return true; } - public override List GetChildren(Jellyfin.Data.Entities.User user, bool includeLinkedChildren, InternalItemsQuery query) + public override List GetChildren(User user, bool includeLinkedChildren, InternalItemsQuery query) { var children = base.GetChildren(user, includeLinkedChildren, query); @@ -130,7 +131,7 @@ namespace MediaBrowser.Controller.Entities.Movies return LibraryManager.Sort(children, user, new[] { ItemSortBy.ProductionYear, ItemSortBy.PremiereDate, ItemSortBy.SortName }, SortOrder.Ascending).ToList(); } - public override IEnumerable GetRecursiveChildren(Jellyfin.Data.Entities.User user, InternalItemsQuery query) + public override IEnumerable GetRecursiveChildren(User user, InternalItemsQuery query) { var children = base.GetRecursiveChildren(user, query); @@ -148,7 +149,7 @@ namespace MediaBrowser.Controller.Entities.Movies return GetItemLookupInfo(); } - public override bool IsVisible(Jellyfin.Data.Entities.User user) + public override bool IsVisible(User user) { if (IsLegacyBoxSet) { @@ -176,7 +177,7 @@ namespace MediaBrowser.Controller.Entities.Movies return false; } - public override bool IsVisibleStandalone(Jellyfin.Data.Entities.User user) + public override bool IsVisibleStandalone(User user) { if (IsLegacyBoxSet) { @@ -188,7 +189,7 @@ namespace MediaBrowser.Controller.Entities.Movies public Guid[] LibraryFolderIds { get; set; } - private Guid[] GetLibraryFolderIds(Jellyfin.Data.Entities.User user) + private Guid[] GetLibraryFolderIds(User user) { return LibraryManager.GetUserRootFolder().GetChildren(user, true) .Select(i => i.Id) diff --git a/MediaBrowser.Controller/Entities/TV/Season.cs b/MediaBrowser.Controller/Entities/TV/Season.cs index 0d1fec62f..839350fd7 100644 --- a/MediaBrowser.Controller/Entities/TV/Season.cs +++ b/MediaBrowser.Controller/Entities/TV/Season.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Linq; using System.Text.Json.Serialization; +using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Providers; @@ -61,7 +62,7 @@ namespace MediaBrowser.Controller.Entities.TV return list; } - public override int GetChildCount(Jellyfin.Data.Entities.User user) + public override int GetChildCount(User user) { var result = GetChildren(user, true).Count; @@ -144,17 +145,17 @@ namespace MediaBrowser.Controller.Entities.TV /// /// Gets the episodes. /// - public List GetEpisodes(Jellyfin.Data.Entities.User user, DtoOptions options) + public List GetEpisodes(User user, DtoOptions options) { return GetEpisodes(Series, user, options); } - public List GetEpisodes(Series series, Jellyfin.Data.Entities.User user, DtoOptions options) + public List GetEpisodes(Series series, User user, DtoOptions options) { return GetEpisodes(series, user, null, options); } - public List GetEpisodes(Series series, Jellyfin.Data.Entities.User user, IEnumerable allSeriesEpisodes, DtoOptions options) + public List GetEpisodes(Series series, User user, IEnumerable allSeriesEpisodes, DtoOptions options) { return series.GetSeasonEpisodes(this, user, allSeriesEpisodes, options); } @@ -164,12 +165,12 @@ namespace MediaBrowser.Controller.Entities.TV return Series.GetSeasonEpisodes(this, null, null, new DtoOptions(true)); } - public override List GetChildren(Jellyfin.Data.Entities.User user, bool includeLinkedChildren, InternalItemsQuery query) + public override List GetChildren(User user, bool includeLinkedChildren, InternalItemsQuery query) { return GetEpisodes(user, new DtoOptions(true)); } - protected override bool GetBlockUnratedValue(Jellyfin.Data.Entities.User config) + protected override bool GetBlockUnratedValue(User config) { // Don't block. Let either the entire series rating or episode rating determine it return false; diff --git a/MediaBrowser.Controller/Entities/TV/Series.cs b/MediaBrowser.Controller/Entities/TV/Series.cs index 4aed5fbdc..78d376d5c 100644 --- a/MediaBrowser.Controller/Entities/TV/Series.cs +++ b/MediaBrowser.Controller/Entities/TV/Series.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Text.Json.Serialization; using System.Threading; using System.Threading.Tasks; +using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Providers; @@ -110,7 +111,7 @@ namespace MediaBrowser.Controller.Entities.TV return series.GetPresentationUniqueKey(); } - public override int GetChildCount(Jellyfin.Data.Entities.User user) + public override int GetChildCount(User user) { var seriesKey = GetUniqueSeriesKey(this); @@ -130,7 +131,7 @@ namespace MediaBrowser.Controller.Entities.TV return result; } - public override int GetRecursiveChildCount(Jellyfin.Data.Entities.User user) + public override int GetRecursiveChildCount(User user) { var seriesKey = GetUniqueSeriesKey(this); @@ -178,12 +179,12 @@ namespace MediaBrowser.Controller.Entities.TV return list; } - public override List GetChildren(Jellyfin.Data.Entities.User user, bool includeLinkedChildren, InternalItemsQuery query) + public override List GetChildren(User user, bool includeLinkedChildren, InternalItemsQuery query) { return GetSeasons(user, new DtoOptions(true)); } - public List GetSeasons(Jellyfin.Data.Entities.User user, DtoOptions options) + public List GetSeasons(User user, DtoOptions options) { var query = new InternalItemsQuery(user) { @@ -195,7 +196,7 @@ namespace MediaBrowser.Controller.Entities.TV return LibraryManager.GetItemList(query); } - private void SetSeasonQueryOptions(InternalItemsQuery query, Jellyfin.Data.Entities.User user) + private void SetSeasonQueryOptions(InternalItemsQuery query, User user) { var seriesKey = GetUniqueSeriesKey(this); @@ -239,7 +240,7 @@ namespace MediaBrowser.Controller.Entities.TV return LibraryManager.GetItemsResult(query); } - public IEnumerable GetEpisodes(Jellyfin.Data.Entities.User user, DtoOptions options) + public IEnumerable GetEpisodes(User user, DtoOptions options) { var seriesKey = GetUniqueSeriesKey(this); @@ -345,7 +346,7 @@ namespace MediaBrowser.Controller.Entities.TV await ProviderManager.RefreshSingleItem(this, refreshOptions, cancellationToken).ConfigureAwait(false); } - public List GetSeasonEpisodes(Season parentSeason, Jellyfin.Data.Entities.User user, DtoOptions options) + public List GetSeasonEpisodes(Season parentSeason, User user, DtoOptions options) { var queryFromSeries = ConfigurationManager.Configuration.DisplaySpecialsWithinSeasons; @@ -375,7 +376,7 @@ namespace MediaBrowser.Controller.Entities.TV return GetSeasonEpisodes(parentSeason, user, allItems, options); } - public List GetSeasonEpisodes(Season parentSeason, Jellyfin.Data.Entities.User user, IEnumerable allSeriesEpisodes, DtoOptions options) + public List GetSeasonEpisodes(Season parentSeason, User user, IEnumerable allSeriesEpisodes, DtoOptions options) { if (allSeriesEpisodes == null) { @@ -445,7 +446,7 @@ namespace MediaBrowser.Controller.Entities.TV } - protected override bool GetBlockUnratedValue(Jellyfin.Data.Entities.User user) + protected override bool GetBlockUnratedValue(User user) { return user.GetPreference(PreferenceKind.BlockUnratedItems).Contains(UnratedItem.Series.ToString()); } diff --git a/MediaBrowser.Controller/Entities/UserRootFolder.cs b/MediaBrowser.Controller/Entities/UserRootFolder.cs index 9d211540d..39f4e0b6c 100644 --- a/MediaBrowser.Controller/Entities/UserRootFolder.cs +++ b/MediaBrowser.Controller/Entities/UserRootFolder.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Text.Json.Serialization; using System.Threading; using System.Threading.Tasks; +using Jellyfin.Data.Entities; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Library; using MediaBrowser.Model.Querying; @@ -63,7 +64,7 @@ namespace MediaBrowser.Controller.Entities return UserViewBuilder.SortAndPage(result, null, query, LibraryManager, true); } - public override int GetChildCount(Jellyfin.Data.Entities.User user) + public override int GetChildCount(User user) { return GetChildren(user, true).Count; } @@ -74,7 +75,7 @@ namespace MediaBrowser.Controller.Entities [JsonIgnore] public override bool IsPreSorted => true; - protected override IEnumerable GetEligibleChildrenForRecursiveChildren(Jellyfin.Data.Entities.User user) + protected override IEnumerable GetEligibleChildrenForRecursiveChildren(User user) { var list = base.GetEligibleChildrenForRecursiveChildren(user).ToList(); list.AddRange(LibraryManager.RootFolder.VirtualChildren); diff --git a/MediaBrowser.Controller/Entities/UserView.cs b/MediaBrowser.Controller/Entities/UserView.cs index b44e7c191..806006490 100644 --- a/MediaBrowser.Controller/Entities/UserView.cs +++ b/MediaBrowser.Controller/Entities/UserView.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Text.Json.Serialization; using System.Threading.Tasks; +using Jellyfin.Data.Entities; using MediaBrowser.Controller.TV; using MediaBrowser.Model.Querying; @@ -48,7 +49,7 @@ namespace MediaBrowser.Controller.Entities [JsonIgnore] public override bool SupportsPlayedStatus => false; - public override int GetChildCount(Jellyfin.Data.Entities.User user) + public override int GetChildCount(User user) { return GetChildren(user, true).Count; } @@ -70,7 +71,7 @@ namespace MediaBrowser.Controller.Entities .GetUserItems(parent, this, CollectionType, query); } - public override List GetChildren(Jellyfin.Data.Entities.User user, bool includeLinkedChildren, InternalItemsQuery query) + public override List GetChildren(User user, bool includeLinkedChildren, InternalItemsQuery query) { if (query == null) { @@ -93,7 +94,7 @@ namespace MediaBrowser.Controller.Entities return true; } - public override IEnumerable GetRecursiveChildren(Jellyfin.Data.Entities.User user, InternalItemsQuery query) + public override IEnumerable GetRecursiveChildren(User user, InternalItemsQuery query) { query.SetUser(user); query.Recursive = true; @@ -103,14 +104,14 @@ namespace MediaBrowser.Controller.Entities return GetItemList(query); } - protected override IEnumerable GetEligibleChildrenForRecursiveChildren(Jellyfin.Data.Entities.User user) + protected override IEnumerable GetEligibleChildrenForRecursiveChildren(User user) { return GetChildren(user, false); } private static string[] UserSpecificViewTypes = new string[] { - MediaBrowser.Model.Entities.CollectionType.Playlists + Model.Entities.CollectionType.Playlists }; public static bool IsUserSpecific(Folder folder) @@ -139,8 +140,8 @@ namespace MediaBrowser.Controller.Entities private static string[] ViewTypesEligibleForGrouping = new string[] { - MediaBrowser.Model.Entities.CollectionType.Movies, - MediaBrowser.Model.Entities.CollectionType.TvShows, + Model.Entities.CollectionType.Movies, + Model.Entities.CollectionType.TvShows, string.Empty }; @@ -151,12 +152,12 @@ namespace MediaBrowser.Controller.Entities private static string[] OriginalFolderViewTypes = new string[] { - MediaBrowser.Model.Entities.CollectionType.Books, - MediaBrowser.Model.Entities.CollectionType.MusicVideos, - MediaBrowser.Model.Entities.CollectionType.HomeVideos, - MediaBrowser.Model.Entities.CollectionType.Photos, - MediaBrowser.Model.Entities.CollectionType.Music, - MediaBrowser.Model.Entities.CollectionType.BoxSets + Model.Entities.CollectionType.Books, + Model.Entities.CollectionType.MusicVideos, + Model.Entities.CollectionType.HomeVideos, + Model.Entities.CollectionType.Photos, + Model.Entities.CollectionType.Music, + Model.Entities.CollectionType.BoxSets }; public static bool EnableOriginalFolder(string viewType) diff --git a/MediaBrowser.Controller/Entities/UserViewBuilder.cs b/MediaBrowser.Controller/Entities/UserViewBuilder.cs index 0ad8e6b71..b020a44c4 100644 --- a/MediaBrowser.Controller/Entities/UserViewBuilder.cs +++ b/MediaBrowser.Controller/Entities/UserViewBuilder.cs @@ -2,14 +2,18 @@ using System; using System.Collections.Generic; using System.Globalization; using System.Linq; +using Jellyfin.Data.Entities; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities.Movies; -using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.TV; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Querying; using Microsoft.Extensions.Logging; +using Episode = MediaBrowser.Controller.Entities.TV.Episode; +using Movie = MediaBrowser.Controller.Entities.Movies.Movie; +using Season = MediaBrowser.Controller.Entities.TV.Season; +using Series = MediaBrowser.Controller.Entities.TV.Series; namespace MediaBrowser.Controller.Entities { @@ -125,7 +129,7 @@ namespace MediaBrowser.Controller.Entities return 50; } - private QueryResult GetMovieFolders(Folder parent, Jellyfin.Data.Entities.User user, InternalItemsQuery query) + private QueryResult GetMovieFolders(Folder parent, User user, InternalItemsQuery query) { if (query.Recursive) { @@ -153,7 +157,7 @@ namespace MediaBrowser.Controller.Entities return GetResult(list, parent, query); } - private QueryResult GetFavoriteMovies(Folder parent, Jellyfin.Data.Entities.User user, InternalItemsQuery query) + private QueryResult GetFavoriteMovies(Folder parent, User user, InternalItemsQuery query) { query.Recursive = true; query.Parent = parent; @@ -164,7 +168,7 @@ namespace MediaBrowser.Controller.Entities return _libraryManager.GetItemsResult(query); } - private QueryResult GetFavoriteSeries(Folder parent, Jellyfin.Data.Entities.User user, InternalItemsQuery query) + private QueryResult GetFavoriteSeries(Folder parent, User user, InternalItemsQuery query) { query.Recursive = true; query.Parent = parent; @@ -175,7 +179,7 @@ namespace MediaBrowser.Controller.Entities return _libraryManager.GetItemsResult(query); } - private QueryResult GetFavoriteEpisodes(Folder parent, Jellyfin.Data.Entities.User user, InternalItemsQuery query) + private QueryResult GetFavoriteEpisodes(Folder parent, User user, InternalItemsQuery query) { query.Recursive = true; query.Parent = parent; @@ -186,7 +190,7 @@ namespace MediaBrowser.Controller.Entities return _libraryManager.GetItemsResult(query); } - private QueryResult GetMovieMovies(Folder parent, Jellyfin.Data.Entities.User user, InternalItemsQuery query) + private QueryResult GetMovieMovies(Folder parent, User user, InternalItemsQuery query) { query.Recursive = true; query.Parent = parent; @@ -197,7 +201,7 @@ namespace MediaBrowser.Controller.Entities return _libraryManager.GetItemsResult(query); } - private QueryResult GetMovieCollections(Folder parent, Jellyfin.Data.Entities.User user, InternalItemsQuery query) + private QueryResult GetMovieCollections(Folder parent, User user, InternalItemsQuery query) { query.Parent = null; query.IncludeItemTypes = new[] { typeof(BoxSet).Name }; @@ -207,7 +211,7 @@ namespace MediaBrowser.Controller.Entities return _libraryManager.GetItemsResult(query); } - private QueryResult GetMovieLatest(Folder parent, Jellyfin.Data.Entities.User user, InternalItemsQuery query) + private QueryResult GetMovieLatest(Folder parent, User user, InternalItemsQuery query) { query.OrderBy = new[] { ItemSortBy.DateCreated, ItemSortBy.SortName }.Select(i => new ValueTuple(i, SortOrder.Descending)).ToArray(); @@ -220,7 +224,7 @@ namespace MediaBrowser.Controller.Entities return ConvertToResult(_libraryManager.GetItemList(query)); } - private QueryResult GetMovieResume(Folder parent, Jellyfin.Data.Entities.User user, InternalItemsQuery query) + private QueryResult GetMovieResume(Folder parent, User user, InternalItemsQuery query) { query.OrderBy = new[] { ItemSortBy.DatePlayed, ItemSortBy.SortName }.Select(i => new ValueTuple(i, SortOrder.Descending)).ToArray(); query.IsResumable = true; @@ -243,7 +247,7 @@ namespace MediaBrowser.Controller.Entities }; } - private QueryResult GetMovieGenres(Folder parent, Jellyfin.Data.Entities.User user, InternalItemsQuery query) + private QueryResult GetMovieGenres(Folder parent, User user, InternalItemsQuery query) { var genres = parent.QueryRecursive(new InternalItemsQuery(user) { @@ -273,7 +277,7 @@ namespace MediaBrowser.Controller.Entities return GetResult(genres, parent, query); } - private QueryResult GetMovieGenreItems(Folder queryParent, Folder displayParent, Jellyfin.Data.Entities.User user, InternalItemsQuery query) + private QueryResult GetMovieGenreItems(Folder queryParent, Folder displayParent, User user, InternalItemsQuery query) { query.Recursive = true; query.Parent = queryParent; @@ -285,7 +289,7 @@ namespace MediaBrowser.Controller.Entities return _libraryManager.GetItemsResult(query); } - private QueryResult GetTvView(Folder parent, Jellyfin.Data.Entities.User user, InternalItemsQuery query) + private QueryResult GetTvView(Folder parent, User user, InternalItemsQuery query) { if (query.Recursive) { @@ -319,7 +323,7 @@ namespace MediaBrowser.Controller.Entities return GetResult(list, parent, query); } - private QueryResult GetTvLatest(Folder parent, Jellyfin.Data.Entities.User user, InternalItemsQuery query) + private QueryResult GetTvLatest(Folder parent, User user, InternalItemsQuery query) { query.OrderBy = new[] { ItemSortBy.DateCreated, ItemSortBy.SortName }.Select(i => new ValueTuple(i, SortOrder.Descending)).ToArray(); @@ -348,7 +352,7 @@ namespace MediaBrowser.Controller.Entities return result; } - private QueryResult GetTvResume(Folder parent, Jellyfin.Data.Entities.User user, InternalItemsQuery query) + private QueryResult GetTvResume(Folder parent, User user, InternalItemsQuery query) { query.OrderBy = new[] { ItemSortBy.DatePlayed, ItemSortBy.SortName }.Select(i => new ValueTuple(i, SortOrder.Descending)).ToArray(); query.IsResumable = true; @@ -361,7 +365,7 @@ namespace MediaBrowser.Controller.Entities return ConvertToResult(_libraryManager.GetItemList(query)); } - private QueryResult GetTvSeries(Folder parent, Jellyfin.Data.Entities.User user, InternalItemsQuery query) + private QueryResult GetTvSeries(Folder parent, User user, InternalItemsQuery query) { query.Recursive = true; query.Parent = parent; @@ -372,7 +376,7 @@ namespace MediaBrowser.Controller.Entities return _libraryManager.GetItemsResult(query); } - private QueryResult GetTvGenres(Folder parent, Jellyfin.Data.Entities.User user, InternalItemsQuery query) + private QueryResult GetTvGenres(Folder parent, User user, InternalItemsQuery query) { var genres = parent.QueryRecursive(new InternalItemsQuery(user) { @@ -402,7 +406,7 @@ namespace MediaBrowser.Controller.Entities return GetResult(genres, parent, query); } - private QueryResult GetTvGenreItems(Folder queryParent, Folder displayParent, Jellyfin.Data.Entities.User user, InternalItemsQuery query) + private QueryResult GetTvGenreItems(Folder queryParent, Folder displayParent, User user, InternalItemsQuery query) { query.Recursive = true; query.Parent = queryParent; @@ -492,7 +496,7 @@ namespace MediaBrowser.Controller.Entities }; } - public static bool Filter(BaseItem item, Jellyfin.Data.Entities.User user, InternalItemsQuery query, IUserDataManager userDataManager, ILibraryManager libraryManager) + public static bool Filter(BaseItem item, User user, InternalItemsQuery query, IUserDataManager userDataManager, ILibraryManager libraryManager) { if (query.MediaTypes.Length > 0 && !query.MediaTypes.Contains(item.MediaType ?? string.Empty, StringComparer.OrdinalIgnoreCase)) { @@ -950,7 +954,7 @@ namespace MediaBrowser.Controller.Entities return true; } - private IEnumerable GetMediaFolders(Jellyfin.Data.Entities.User user) + private IEnumerable GetMediaFolders(User user) { if (user == null) { @@ -965,7 +969,7 @@ namespace MediaBrowser.Controller.Entities .Where(i => user.IsFolderGrouped(i.Id) && UserView.IsEligibleForGrouping(i)); } - private BaseItem[] GetMediaFolders(Jellyfin.Data.Entities.User user, IEnumerable viewTypes) + private BaseItem[] GetMediaFolders(User user, IEnumerable viewTypes) { if (user == null) { @@ -986,7 +990,7 @@ namespace MediaBrowser.Controller.Entities }).ToArray(); } - private BaseItem[] GetMediaFolders(Folder parent, Jellyfin.Data.Entities.User user, IEnumerable viewTypes) + private BaseItem[] GetMediaFolders(Folder parent, User user, IEnumerable viewTypes) { if (parent == null || parent is UserView) { diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs index ada570bfd..1f7a5861a 100644 --- a/MediaBrowser.Controller/Library/ILibraryManager.cs +++ b/MediaBrowser.Controller/Library/ILibraryManager.cs @@ -2,10 +2,10 @@ using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; +using Jellyfin.Data.Entities; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; -using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Providers; using MediaBrowser.Controller.Resolvers; using MediaBrowser.Controller.Sorting; @@ -14,6 +14,9 @@ using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; using MediaBrowser.Model.IO; using MediaBrowser.Model.Querying; +using Episode = MediaBrowser.Controller.Entities.TV.Episode; +using Genre = MediaBrowser.Controller.Entities.Genre; +using Person = MediaBrowser.Controller.Entities.Person; namespace MediaBrowser.Controller.Library { @@ -28,8 +31,7 @@ namespace MediaBrowser.Controller.Library /// The file information. /// The parent. /// BaseItem. - BaseItem ResolvePath(FileSystemMetadata fileInfo, - Folder parent = null); + BaseItem ResolvePath(FileSystemMetadata fileInfo, Folder parent = null); /// /// Resolves a set of files into a list of BaseItem @@ -141,7 +143,7 @@ namespace MediaBrowser.Controller.Library /// The item. /// The user. /// IEnumerable{System.String}. - Task> GetIntros(BaseItem item, Jellyfin.Data.Entities.User user); + Task> GetIntros(BaseItem item, User user); /// /// Gets all intro files. @@ -172,8 +174,8 @@ namespace MediaBrowser.Controller.Library /// The sort by. /// The sort order. /// IEnumerable{BaseItem}. - IEnumerable Sort(IEnumerable items, Jellyfin.Data.Entities.User user, IEnumerable sortBy, SortOrder sortOrder); - IEnumerable Sort(IEnumerable items, Jellyfin.Data.Entities.User user, IEnumerable> orderBy); + IEnumerable Sort(IEnumerable items, User user, IEnumerable sortBy, SortOrder sortOrder); + IEnumerable Sort(IEnumerable items, User user, IEnumerable> orderBy); /// /// Gets the user root folder. @@ -285,7 +287,7 @@ namespace MediaBrowser.Controller.Library /// Type of the view. /// Name of the sort. UserView GetNamedView( - Jellyfin.Data.Entities.User user, + User user, string name, Guid parentId, string viewType, @@ -299,7 +301,7 @@ namespace MediaBrowser.Controller.Library /// Type of the view. /// Name of the sort. UserView GetNamedView( - Jellyfin.Data.Entities.User user, + User user, string name, string viewType, string sortName); diff --git a/MediaBrowser.Controller/Library/IMediaSourceManager.cs b/MediaBrowser.Controller/Library/IMediaSourceManager.cs index 57368778a..94528ff77 100644 --- a/MediaBrowser.Controller/Library/IMediaSourceManager.cs +++ b/MediaBrowser.Controller/Library/IMediaSourceManager.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.IO; using System.Threading; using System.Threading.Tasks; +using Jellyfin.Data.Entities; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Persistence; using MediaBrowser.Model.Dto; @@ -55,12 +56,12 @@ namespace MediaBrowser.Controller.Library /// /// Gets the playack media sources. /// - Task> GetPlaybackMediaSources(BaseItem item, Jellyfin.Data.Entities.User user, bool allowMediaProbe, bool enablePathSubstitution, CancellationToken cancellationToken); + Task> GetPlaybackMediaSources(BaseItem item, User user, bool allowMediaProbe, bool enablePathSubstitution, CancellationToken cancellationToken); /// /// Gets the static media sources. /// - List GetStaticMediaSources(BaseItem item, bool enablePathSubstitution, Jellyfin.Data.Entities.User user = null); + List GetStaticMediaSources(BaseItem item, bool enablePathSubstitution, User user = null); /// /// Gets the static media source. @@ -100,7 +101,7 @@ namespace MediaBrowser.Controller.Library MediaProtocol GetPathProtocol(string path); - void SetDefaultAudioAndSubtitleStreamIndexes(BaseItem item, MediaSourceInfo source, Jellyfin.Data.Entities.User user); + void SetDefaultAudioAndSubtitleStreamIndexes(BaseItem item, MediaSourceInfo source, User user); Task AddMediaInfoWithProbe(MediaSourceInfo mediaSource, bool isAudio, string cacheKey, bool addProbeDelay, bool isLiveStream, CancellationToken cancellationToken); diff --git a/MediaBrowser.Controller/Library/IMusicManager.cs b/MediaBrowser.Controller/Library/IMusicManager.cs index 0618837bc..36b250ec9 100644 --- a/MediaBrowser.Controller/Library/IMusicManager.cs +++ b/MediaBrowser.Controller/Library/IMusicManager.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Jellyfin.Data.Entities; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; @@ -10,16 +11,16 @@ namespace MediaBrowser.Controller.Library /// /// Gets the instant mix from song. /// - List GetInstantMixFromItem(BaseItem item, Jellyfin.Data.Entities.User user, DtoOptions dtoOptions); + List GetInstantMixFromItem(BaseItem item, User user, DtoOptions dtoOptions); /// /// Gets the instant mix from artist. /// - List GetInstantMixFromArtist(MusicArtist artist, Jellyfin.Data.Entities.User user, DtoOptions dtoOptions); + List GetInstantMixFromArtist(MusicArtist artist, User user, DtoOptions dtoOptions); /// /// Gets the instant mix from genre. /// - List GetInstantMixFromGenres(IEnumerable genres, Jellyfin.Data.Entities.User user, DtoOptions dtoOptions); + List GetInstantMixFromGenres(IEnumerable genres, User user, DtoOptions dtoOptions); } } diff --git a/MediaBrowser.Controller/Library/IUserDataManager.cs b/MediaBrowser.Controller/Library/IUserDataManager.cs index 15da560ef..f5ccad671 100644 --- a/MediaBrowser.Controller/Library/IUserDataManager.cs +++ b/MediaBrowser.Controller/Library/IUserDataManager.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Threading; +using Jellyfin.Data.Entities; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Model.Dto; @@ -27,18 +28,18 @@ namespace MediaBrowser.Controller.Library /// The reason. /// The cancellation token. void SaveUserData(Guid userId, BaseItem item, UserItemData userData, UserDataSaveReason reason, CancellationToken cancellationToken); - void SaveUserData(Jellyfin.Data.Entities.User user, BaseItem item, UserItemData userData, UserDataSaveReason reason, CancellationToken cancellationToken); + void SaveUserData(User user, BaseItem item, UserItemData userData, UserDataSaveReason reason, CancellationToken cancellationToken); - UserItemData GetUserData(Jellyfin.Data.Entities.User user, BaseItem item); + UserItemData GetUserData(User user, BaseItem item); UserItemData GetUserData(Guid userId, BaseItem item); /// /// Gets the user data dto. /// - UserItemDataDto GetUserDataDto(BaseItem item, Jellyfin.Data.Entities.User user); + UserItemDataDto GetUserDataDto(BaseItem item, User user); - UserItemDataDto GetUserDataDto(BaseItem item, BaseItemDto itemDto, Jellyfin.Data.Entities.User user, DtoOptions dto_options); + UserItemDataDto GetUserDataDto(BaseItem item, BaseItemDto itemDto, User user, DtoOptions dto_options); /// /// Get all user data for the given user diff --git a/MediaBrowser.Controller/Library/PlaybackProgressEventArgs.cs b/MediaBrowser.Controller/Library/PlaybackProgressEventArgs.cs index 83c0e3297..b4e205184 100644 --- a/MediaBrowser.Controller/Library/PlaybackProgressEventArgs.cs +++ b/MediaBrowser.Controller/Library/PlaybackProgressEventArgs.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using Jellyfin.Data.Entities; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Session; using MediaBrowser.Model.Dto; @@ -11,7 +12,7 @@ namespace MediaBrowser.Controller.Library /// public class PlaybackProgressEventArgs : EventArgs { - public List Users { get; set; } + public List Users { get; set; } public long? PlaybackPositionTicks { get; set; } public BaseItem Item { get; set; } public BaseItemDto MediaInfo { get; set; } @@ -28,7 +29,7 @@ namespace MediaBrowser.Controller.Library public PlaybackProgressEventArgs() { - Users = new List(); + Users = new List(); } } } diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs index 99fd18bf9..bc3bf78f0 100644 --- a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs +++ b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; +using Jellyfin.Data.Entities; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; @@ -115,7 +116,7 @@ namespace MediaBrowser.Controller.LiveTv /// The cancellation token. /// The user. /// Task{ProgramInfoDto}. - Task GetProgram(string id, CancellationToken cancellationToken, Jellyfin.Data.Entities.User user = null); + Task GetProgram(string id, CancellationToken cancellationToken, User user = null); /// /// Gets the programs. @@ -202,7 +203,7 @@ namespace MediaBrowser.Controller.LiveTv /// Gets the enabled users. /// /// IEnumerable{User}. - IEnumerable GetEnabledUsers(); + IEnumerable GetEnabledUsers(); /// /// Gets the internal channels. @@ -221,7 +222,7 @@ namespace MediaBrowser.Controller.LiveTv /// The fields. /// The user. /// Task. - Task AddInfoToProgramDto(IReadOnlyCollection<(BaseItem, BaseItemDto)> programs, ItemFields[] fields, Jellyfin.Data.Entities.User user = null); + Task AddInfoToProgramDto(IReadOnlyCollection<(BaseItem, BaseItemDto)> programs, ItemFields[] fields, User user = null); /// /// Saves the tuner host. @@ -258,7 +259,7 @@ namespace MediaBrowser.Controller.LiveTv /// The items. /// The options. /// The user. - void AddChannelInfo(IReadOnlyCollection<(BaseItemDto, LiveTvChannel)> items, DtoOptions options, Jellyfin.Data.Entities.User user); + void AddChannelInfo(IReadOnlyCollection<(BaseItemDto, LiveTvChannel)> items, DtoOptions options, User user); Task> GetChannelsForListingsProvider(string id, CancellationToken cancellationToken); Task> GetChannelsFromListingsProviderData(string id, CancellationToken cancellationToken); @@ -277,9 +278,9 @@ namespace MediaBrowser.Controller.LiveTv ActiveRecordingInfo GetActiveRecordingInfo(string path); - void AddInfoToRecordingDto(BaseItem item, BaseItemDto dto, ActiveRecordingInfo activeRecordingInfo, Jellyfin.Data.Entities.User user = null); + void AddInfoToRecordingDto(BaseItem item, BaseItemDto dto, ActiveRecordingInfo activeRecordingInfo, User user = null); - List GetRecordingFolders(Jellyfin.Data.Entities.User user); + List GetRecordingFolders(User user); } public class ActiveRecordingInfo diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs b/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs index dc4361fc3..67241c35b 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Globalization; using System.Linq; +using Jellyfin.Data.Entities; using MediaBrowser.Controller.Entities; using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Drawing; @@ -49,7 +50,7 @@ namespace MediaBrowser.Controller.MediaEncoding public MediaSourceInfo MediaSource { get; set; } - public Jellyfin.Data.Entities.User User { get; set; } + public User User { get; set; } public long? RunTimeTicks { get; set; } diff --git a/MediaBrowser.Controller/Net/IAuthService.cs b/MediaBrowser.Controller/Net/IAuthService.cs index 61fc7e6e6..d8f6d19da 100644 --- a/MediaBrowser.Controller/Net/IAuthService.cs +++ b/MediaBrowser.Controller/Net/IAuthService.cs @@ -1,6 +1,6 @@ #nullable enable -using MediaBrowser.Controller.Entities; +using Jellyfin.Data.Entities; using MediaBrowser.Model.Services; using Microsoft.AspNetCore.Http; @@ -9,6 +9,7 @@ namespace MediaBrowser.Controller.Net public interface IAuthService { void Authenticate(IRequest request, IAuthenticationAttributes authAttribtues); - Jellyfin.Data.Entities.User? Authenticate(HttpRequest request, IAuthenticationAttributes authAttribtues); + + User? Authenticate(HttpRequest request, IAuthenticationAttributes authAttribtues); } } diff --git a/MediaBrowser.Controller/Notifications/INotificationService.cs b/MediaBrowser.Controller/Notifications/INotificationService.cs index 2bc751758..ab5eb13cd 100644 --- a/MediaBrowser.Controller/Notifications/INotificationService.cs +++ b/MediaBrowser.Controller/Notifications/INotificationService.cs @@ -1,6 +1,6 @@ using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Controller.Entities; +using Jellyfin.Data.Entities; namespace MediaBrowser.Controller.Notifications { @@ -25,6 +25,6 @@ namespace MediaBrowser.Controller.Notifications /// /// The user. /// true if [is enabled for user] [the specified user identifier]; otherwise, false. - bool IsEnabledForUser(Jellyfin.Data.Entities.User user); + bool IsEnabledForUser(User user); } } diff --git a/MediaBrowser.Controller/Playlists/Playlist.cs b/MediaBrowser.Controller/Playlists/Playlist.cs index 03bdf1eaf..b1a638883 100644 --- a/MediaBrowser.Controller/Playlists/Playlist.cs +++ b/MediaBrowser.Controller/Playlists/Playlist.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Text.Json.Serialization; using System.Threading; using System.Threading.Tasks; +using Jellyfin.Data.Entities; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; @@ -78,7 +79,7 @@ namespace MediaBrowser.Controller.Playlists return 1; } - public override bool IsAuthorizedToDelete(Jellyfin.Data.Entities.User user, List allCollectionFolders) + public override bool IsAuthorizedToDelete(User user, List allCollectionFolders) { return true; } @@ -99,7 +100,7 @@ namespace MediaBrowser.Controller.Playlists return Task.CompletedTask; } - public override List GetChildren(Jellyfin.Data.Entities.User user, bool includeLinkedChildren, InternalItemsQuery query) + public override List GetChildren(User user, bool includeLinkedChildren, InternalItemsQuery query) { return GetPlayableItems(user, query); } @@ -109,7 +110,7 @@ namespace MediaBrowser.Controller.Playlists return new List(); } - public override IEnumerable GetRecursiveChildren(Jellyfin.Data.Entities.User user, InternalItemsQuery query) + public override IEnumerable GetRecursiveChildren(User user, InternalItemsQuery query) { return GetPlayableItems(user, query); } @@ -119,7 +120,7 @@ namespace MediaBrowser.Controller.Playlists return GetLinkedChildrenInfos(); } - private List GetPlayableItems(Jellyfin.Data.Entities.User user, InternalItemsQuery query) + private List GetPlayableItems(User user, InternalItemsQuery query) { if (query == null) { @@ -131,7 +132,7 @@ namespace MediaBrowser.Controller.Playlists return base.GetChildren(user, true, query); } - public static List GetPlaylistItems(string playlistMediaType, IEnumerable inputItems, Jellyfin.Data.Entities.User user, DtoOptions options) + public static List GetPlaylistItems(string playlistMediaType, IEnumerable inputItems, User user, DtoOptions options) { if (user != null) { @@ -149,7 +150,7 @@ namespace MediaBrowser.Controller.Playlists return list; } - private static IEnumerable GetPlaylistItems(BaseItem item, Jellyfin.Data.Entities.User user, string mediaType, DtoOptions options) + private static IEnumerable GetPlaylistItems(BaseItem item, User user, string mediaType, DtoOptions options) { if (item is MusicGenre musicGenre) { @@ -222,7 +223,7 @@ namespace MediaBrowser.Controller.Playlists } } - public override bool IsVisible(Jellyfin.Data.Entities.User user) + public override bool IsVisible(User user) { if (!IsSharedItem) { @@ -244,7 +245,7 @@ namespace MediaBrowser.Controller.Playlists return shares.Any(share => string.Equals(share.UserId, userId, StringComparison.OrdinalIgnoreCase)); } - public override bool IsVisibleStandalone(Jellyfin.Data.Entities.User user) + public override bool IsVisibleStandalone(User user) { if (!IsSharedItem) { diff --git a/MediaBrowser.Model/Notifications/NotificationOptions.cs b/MediaBrowser.Model/Notifications/NotificationOptions.cs index f4132002b..0d6b0a645 100644 --- a/MediaBrowser.Model/Notifications/NotificationOptions.cs +++ b/MediaBrowser.Model/Notifications/NotificationOptions.cs @@ -4,6 +4,7 @@ using System; using Jellyfin.Data.Enums; using MediaBrowser.Model.Extensions; using System.Linq; +using Jellyfin.Data.Entities; using MediaBrowser.Model.Users; namespace MediaBrowser.Model.Notifications @@ -115,7 +116,7 @@ namespace MediaBrowser.Model.Notifications !opt.DisabledMonitorUsers.Contains(userId.ToString(""), StringComparer.OrdinalIgnoreCase); } - public bool IsEnabledToSendToUser(string type, string userId, Jellyfin.Data.Entities.User user) + public bool IsEnabledToSendToUser(string type, string userId, User user) { NotificationOption opt = GetOptions(type); diff --git a/tests/Jellyfin.Api.Tests/Auth/CustomAuthenticationHandlerTests.cs b/tests/Jellyfin.Api.Tests/Auth/CustomAuthenticationHandlerTests.cs index 0cb8d8be6..4245c3249 100644 --- a/tests/Jellyfin.Api.Tests/Auth/CustomAuthenticationHandlerTests.cs +++ b/tests/Jellyfin.Api.Tests/Auth/CustomAuthenticationHandlerTests.cs @@ -7,6 +7,7 @@ using AutoFixture; using AutoFixture.AutoMoq; using Jellyfin.Api.Auth; using Jellyfin.Api.Constants; +using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Net; @@ -84,7 +85,7 @@ namespace Jellyfin.Api.Tests.Auth a => a.Authenticate( It.IsAny(), It.IsAny())) - .Returns((Jellyfin.Data.Entities.User?)null); + .Returns((User?)null); var authenticateResult = await _sut.AuthenticateAsync(); @@ -149,9 +150,9 @@ namespace Jellyfin.Api.Tests.Auth Assert.Equal(_scheme.Name, authenticatedResult.Ticket.AuthenticationScheme); } - private Jellyfin.Data.Entities.User SetupUser(bool isAdmin = false) + private User SetupUser(bool isAdmin = false) { - var user = _fixture.Create(); + var user = _fixture.Create(); user.SetPermission(PermissionKind.IsAdministrator, isAdmin); _jellyfinAuthServiceMock.Setup( -- cgit v1.2.3 From 3fb4c1356c22c8be03855a161140c21eb395086b Mon Sep 17 00:00:00 2001 From: Vasily Date: Wed, 20 May 2020 23:50:17 +0300 Subject: Make blurhash be computed during regular scans if it was not already computed --- Jellyfin.Drawing.Skia/SkiaEncoder.cs | 2 ++ MediaBrowser.Controller/Entities/BaseItem.cs | 1 + MediaBrowser.Controller/Entities/Folder.cs | 5 +++++ 3 files changed, 8 insertions(+) (limited to 'MediaBrowser.Controller') diff --git a/Jellyfin.Drawing.Skia/SkiaEncoder.cs b/Jellyfin.Drawing.Skia/SkiaEncoder.cs index 99091ea57..7ab0a54df 100644 --- a/Jellyfin.Drawing.Skia/SkiaEncoder.cs +++ b/Jellyfin.Drawing.Skia/SkiaEncoder.cs @@ -246,6 +246,8 @@ namespace Jellyfin.Drawing.Skia throw new FileNotFoundException("File not found", path); } + // Use 4 vertical and 4 horizontal components of DCT of the image. + // See more at https://github.com/woltapp/blurhash/#how-do-i-pick-the-number-of-x-and-y-components return BlurHashEncoder.Encode(4, 4, path); } diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index e5f6ea09d..035ab1dd9 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -1374,6 +1374,7 @@ namespace MediaBrowser.Controller.Entities new List(); var ownedItemsChanged = await RefreshedOwnedItems(options, files, cancellationToken).ConfigureAwait(false); + LibraryManager.UpdateImages(this); // ensure all image properties in DB are fresh if (ownedItemsChanged) { diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index a468e0c35..29040f92e 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -341,6 +341,11 @@ namespace MediaBrowser.Controller.Entities { currentChild.UpdateToRepository(ItemUpdateType.MetadataImport, cancellationToken); } + else + { + // metadata is up-to-date; make sure DB has correct images dimensions and hash + LibraryManager.UpdateImages(currentChild); + } continue; } -- cgit v1.2.3 From 1f83a212886bae879c47b4b4f5b1eb25a28e2ad3 Mon Sep 17 00:00:00 2001 From: Vasily Date: Thu, 21 May 2020 01:43:19 +0300 Subject: Rename Hash to BlurHash in all properties and methods for clarity --- Emby.Drawing/ImageProcessor.cs | 2 +- Emby.Server.Implementations/Data/SqliteItemRepository.cs | 4 ++-- Emby.Server.Implementations/Dto/DtoService.cs | 6 +++--- Emby.Server.Implementations/Library/LibraryManager.cs | 4 ++-- MediaBrowser.Api/Images/ImageService.cs | 2 +- MediaBrowser.Controller/Drawing/IImageProcessor.cs | 2 +- MediaBrowser.Controller/Entities/BaseItem.cs | 2 +- MediaBrowser.Controller/Entities/ItemImageInfo.cs | 2 +- MediaBrowser.Model/Dto/BaseItemDto.cs | 2 +- 9 files changed, 13 insertions(+), 13 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Drawing/ImageProcessor.cs b/Emby.Drawing/ImageProcessor.cs index 1237b603b..35da6f635 100644 --- a/Emby.Drawing/ImageProcessor.cs +++ b/Emby.Drawing/ImageProcessor.cs @@ -314,7 +314,7 @@ namespace Emby.Drawing => _imageEncoder.GetImageSize(path); /// - public string GetImageHash(string path) + public string GetImageBlurHash(string path) => _imageEncoder.GetImageHash(path); /// diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index 10eb96b10..dd60dd222 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -1144,7 +1144,7 @@ namespace Emby.Server.Implementations.Data const string delimeter = "*"; var path = image.Path ?? string.Empty; - var hash = image.Hash ?? string.Empty; + var hash = image.BlurHash ?? string.Empty; return GetPathToSave(path) + delimeter + @@ -1195,7 +1195,7 @@ namespace Emby.Server.Implementations.Data if (parts.Length >= 6) { - image.Hash = parts[5].Replace('/', '*').Replace('\\', '|'); + image.BlurHash = parts[5].Replace('/', '*').Replace('\\', '|'); } } diff --git a/Emby.Server.Implementations/Dto/DtoService.cs b/Emby.Server.Implementations/Dto/DtoService.cs index 07105786b..593e7be7d 100644 --- a/Emby.Server.Implementations/Dto/DtoService.cs +++ b/Emby.Server.Implementations/Dto/DtoService.cs @@ -718,7 +718,7 @@ namespace Emby.Server.Implementations.Dto if (options.EnableImages) { dto.ImageTags = new Dictionary(); - dto.ImageHashes = new Dictionary(); + dto.ImageBlurHashes = new Dictionary(); // Prevent implicitly captured closure var currentItem = item; @@ -733,10 +733,10 @@ namespace Emby.Server.Implementations.Dto dto.ImageTags[image.Type] = tag; } - var hash = image.Hash; + var hash = image.BlurHash; if (!string.IsNullOrEmpty(hash)) { - dto.ImageHashes[tag] = image.Hash; + dto.ImageBlurHashes[tag] = image.BlurHash; } } } diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index 75350ac2a..579fb7edd 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -1829,7 +1829,7 @@ namespace Emby.Server.Implementations.Library } var outdated = item.ImageInfos - .Where(i => (i.IsLocalFile && (i.Width == 0 || i.Height == 0 || string.IsNullOrEmpty(i.Hash)))) + .Where(i => (i.IsLocalFile && (i.Width == 0 || i.Height == 0 || string.IsNullOrEmpty(i.BlurHash)))) .ToList(); if (outdated.Count == 0) { @@ -1842,7 +1842,7 @@ namespace Emby.Server.Implementations.Library ImageDimensions size = _imageProcessor.GetImageDimensions(item, img); img.Width = size.Width; img.Height = size.Height; - img.Hash = _imageProcessor.GetImageHash(img.Path); + img.BlurHash = _imageProcessor.GetImageBlurHash(img.Path); }); _itemRepository.SaveImages(item); diff --git a/MediaBrowser.Api/Images/ImageService.cs b/MediaBrowser.Api/Images/ImageService.cs index 559db550b..d0846bfc3 100644 --- a/MediaBrowser.Api/Images/ImageService.cs +++ b/MediaBrowser.Api/Images/ImageService.cs @@ -341,7 +341,7 @@ namespace MediaBrowser.Api.Images var fileInfo = _fileSystem.GetFileInfo(info.Path); length = fileInfo.Length; - blurhash = info.Hash; + blurhash = info.BlurHash; width = info.Width; height = info.Height; diff --git a/MediaBrowser.Controller/Drawing/IImageProcessor.cs b/MediaBrowser.Controller/Drawing/IImageProcessor.cs index e38eaf760..8800fdf99 100644 --- a/MediaBrowser.Controller/Drawing/IImageProcessor.cs +++ b/MediaBrowser.Controller/Drawing/IImageProcessor.cs @@ -45,7 +45,7 @@ namespace MediaBrowser.Controller.Drawing /// /// Path to the image file. /// BlurHash - String GetImageHash(string path); + string GetImageBlurHash(string path); /// /// Gets the image cache tag. diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 035ab1dd9..07aeb69db 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -2223,7 +2223,7 @@ namespace MediaBrowser.Controller.Entities existingImage.DateModified = image.DateModified; existingImage.Width = image.Width; existingImage.Height = image.Height; - existingImage.Hash = image.Hash; + existingImage.BlurHash = image.BlurHash; } else { diff --git a/MediaBrowser.Controller/Entities/ItemImageInfo.cs b/MediaBrowser.Controller/Entities/ItemImageInfo.cs index ba0297107..12f5db2e0 100644 --- a/MediaBrowser.Controller/Entities/ItemImageInfo.cs +++ b/MediaBrowser.Controller/Entities/ItemImageInfo.cs @@ -32,7 +32,7 @@ namespace MediaBrowser.Controller.Entities /// Gets or sets the blurhash. /// /// The blurhash. - public string Hash { get; set; } + public string BlurHash { get; set; } [JsonIgnore] public bool IsLocalFile => Path == null || !Path.StartsWith("http", StringComparison.OrdinalIgnoreCase); diff --git a/MediaBrowser.Model/Dto/BaseItemDto.cs b/MediaBrowser.Model/Dto/BaseItemDto.cs index 8c6c9683a..df84dcf12 100644 --- a/MediaBrowser.Model/Dto/BaseItemDto.cs +++ b/MediaBrowser.Model/Dto/BaseItemDto.cs @@ -514,7 +514,7 @@ namespace MediaBrowser.Model.Dto /// Gets or sets the blurhash for the image tags. /// /// The blurhashes. - public Dictionary ImageHashes { get; set; } + public Dictionary ImageBlurHashes { get; set; } /// /// Gets or sets the series studio. -- cgit v1.2.3 From 56212e8101ffadcef115a8fa41bae569094f069e Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Fri, 22 May 2020 20:20:18 -0400 Subject: Warnings cleanup --- Jellyfin.Data/Entities/AccessSchedule.cs | 48 ++++++---- Jellyfin.Data/Entities/Permission.cs | 104 +++++++-------------- Jellyfin.Server.Implementations/JellyfinDb.cs | 54 +++++------ .../Drawing/ImageProcessorExtensions.cs | 1 - 4 files changed, 94 insertions(+), 113 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Jellyfin.Data/Entities/AccessSchedule.cs b/Jellyfin.Data/Entities/AccessSchedule.cs index 711e94dd1..4248a34c9 100644 --- a/Jellyfin.Data/Entities/AccessSchedule.cs +++ b/Jellyfin.Data/Entities/AccessSchedule.cs @@ -6,22 +6,18 @@ using Jellyfin.Data.Enums; namespace Jellyfin.Data.Entities { + /// + /// An entity representing a user's access schedule. + /// public class AccessSchedule { - /// - /// Initializes a new instance of the class. - /// Default constructor. Protected due to required properties, but present because EF needs it. - /// - protected AccessSchedule() - { - } - /// /// Initializes a new instance of the class. /// /// The day of the week. /// The start hour. /// The end hour. + /// The associated user's id. public AccessSchedule(DynamicDayOfWeek dayOfWeek, double startHour, double endHour, Guid userId) { UserId = userId; @@ -31,26 +27,31 @@ namespace Jellyfin.Data.Entities } /// - /// Factory method + /// Initializes a new instance of the class. + /// Default constructor. Protected due to required properties, but present because EF needs it. /// - /// The day of the week. - /// The start hour. - /// The end hour. - /// The newly created instance. - public static AccessSchedule CreateInstance(DynamicDayOfWeek dayOfWeek, double startHour, double endHour, Guid userId) + protected AccessSchedule() { - return new AccessSchedule(dayOfWeek, startHour, endHour, userId); } + /// + /// Gets or sets the id of this instance. + /// + /// + /// Identity, Indexed, Required. + /// [JsonIgnore] [Key] [Required] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public int Id { get; set; } + public int Id { get; protected set; } + /// + /// Gets or sets the id of the associated user. + /// [Required] [ForeignKey("Id")] - public Guid UserId { get; set; } + public Guid UserId { get; protected set; } /// /// Gets or sets the day of week. @@ -72,5 +73,18 @@ namespace Jellyfin.Data.Entities /// The end hour. [Required] public double EndHour { get; set; } + + /// + /// Static create function (for use in LINQ queries, etc.) + /// + /// The day of the week. + /// The start hour. + /// The end hour. + /// The associated user's id. + /// The newly created instance. + public static AccessSchedule Create(DynamicDayOfWeek dayOfWeek, double startHour, double endHour, Guid userId) + { + return new AccessSchedule(dayOfWeek, startHour, endHour, userId); + } } } diff --git a/Jellyfin.Data/Entities/Permission.cs b/Jellyfin.Data/Entities/Permission.cs index 706128028..b675e911d 100644 --- a/Jellyfin.Data/Entities/Permission.cs +++ b/Jellyfin.Data/Entities/Permission.cs @@ -1,23 +1,20 @@ -using System; -using System.ComponentModel; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -using System.Runtime.CompilerServices; using Jellyfin.Data.Enums; namespace Jellyfin.Data.Entities { + /// + /// An entity representing whether the associated user has a specific permission. + /// public partial class Permission : ISavingChanges { - partial void Init(); - /// /// Initializes a new instance of the class. - /// Public constructor with required data + /// Public constructor with required data. /// - /// - /// - /// + /// The permission kind. + /// The value of this permission. public Permission(PermissionKind kind, bool value) { Kind = kind; @@ -35,95 +32,66 @@ namespace Jellyfin.Data.Entities Init(); } - /// - /// Static create function (for use in LINQ queries, etc.) - /// - /// - /// - /// - public static Permission Create(PermissionKind kind, bool value) - { - return new Permission(kind, value); - } - /************************************************************************* * Properties *************************************************************************/ /// - /// Identity, Indexed, Required + /// Gets or sets the id of this permission. /// + /// + /// Identity, Indexed, Required. + /// [Key] [Required] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int Id { get; protected set; } /// - /// Backing field for Kind - /// - protected PermissionKind _Kind; - /// - /// When provided in a partial class, allows value of Kind to be changed before setting. - /// - partial void SetKind(PermissionKind oldValue, ref PermissionKind newValue); - /// - /// When provided in a partial class, allows value of Kind to be changed before returning. - /// - partial void GetKind(ref PermissionKind result); - - /// - /// Required + /// Gets or sets the type of this permission. /// + /// + /// Required. + /// [Required] - public PermissionKind Kind - { - get - { - PermissionKind value = _Kind; - GetKind(ref value); - return _Kind = value; - } - - set - { - PermissionKind oldValue = _Kind; - SetKind(oldValue, ref value); - if (oldValue != value) - { - _Kind = value; - OnPropertyChanged(); - } - } - } + public PermissionKind Kind { get; protected set; } /// - /// Required + /// Gets or sets a value indicating whether the associated user has this permission. /// + /// + /// Required. + /// [Required] public bool Value { get; set; } /// - /// Required, ConcurrencyToken. + /// Gets or sets the row version. /// + /// + /// Required, ConcurrencyToken. + /// [ConcurrencyCheck] [Required] public uint RowVersion { get; set; } - public void OnSavingChanges() + /// + /// Static create function (for use in LINQ queries, etc.) + /// + /// The permission kind. + /// The value of this permission. + /// The newly created instance. + public static Permission Create(PermissionKind kind, bool value) { - RowVersion++; + return new Permission(kind, value); } - /************************************************************************* - * Navigation properties - *************************************************************************/ - - public virtual event PropertyChangedEventHandler PropertyChanged; - - protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) + /// + public void OnSavingChanges() { - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + RowVersion++; } + + partial void Init(); } } - diff --git a/Jellyfin.Server.Implementations/JellyfinDb.cs b/Jellyfin.Server.Implementations/JellyfinDb.cs index 7e10d81dc..89fd371f8 100644 --- a/Jellyfin.Server.Implementations/JellyfinDb.cs +++ b/Jellyfin.Server.Implementations/JellyfinDb.cs @@ -1,9 +1,4 @@ #pragma warning disable CS1591 -#pragma warning disable SA1201 // Constuctors should not follow properties -#pragma warning disable SA1516 // Elements should be followed by a blank line -#pragma warning disable SA1623 // Property's documentation should begin with gets or sets -#pragma warning disable SA1629 // Documentation should end with a period -#pragma warning disable SA1648 // Inheritdoc should be used with inheriting class using System.Linq; using Jellyfin.Data; @@ -15,6 +10,19 @@ namespace Jellyfin.Server.Implementations /// public partial class JellyfinDb : DbContext { + /// + /// Initializes a new instance of the class. + /// + /// The database context options. + public JellyfinDb(DbContextOptions options) : base(options) + { + } + + /// + /// Gets or sets the default connection string. + /// + public static string ConnectionString { get; set; } = @"Data Source=jellyfin.db"; + public virtual DbSet ActivityLogs { get; set; } public virtual DbSet Groups { get; set; } @@ -69,17 +77,18 @@ namespace Jellyfin.Server.Implementations public virtual DbSet Tracks { get; set; } public virtual DbSet TrackMetadata { get; set; }*/ - /// - /// Gets or sets the default connection string. - /// - public static string ConnectionString { get; set; } = @"Data Source=jellyfin.db"; - - /// - public JellyfinDb(DbContextOptions options) : base(options) + /// + public override int SaveChanges() { - } + foreach (var saveEntity in ChangeTracker.Entries() + .Where(e => e.State == EntityState.Modified) + .OfType()) + { + saveEntity.OnSavingChanges(); + } - partial void CustomInit(DbContextOptionsBuilder optionsBuilder); + return base.SaveChanges(); + } /// protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) @@ -87,9 +96,6 @@ namespace Jellyfin.Server.Implementations CustomInit(optionsBuilder); } - partial void OnModelCreatingImpl(ModelBuilder modelBuilder); - partial void OnModelCreatedImpl(ModelBuilder modelBuilder); - /// protected override void OnModelCreating(ModelBuilder modelBuilder) { @@ -109,16 +115,10 @@ namespace Jellyfin.Server.Implementations OnModelCreatedImpl(modelBuilder); } - public override int SaveChanges() - { - foreach (var saveEntity in ChangeTracker.Entries() - .Where(e => e.State == EntityState.Modified) - .OfType()) - { - saveEntity.OnSavingChanges(); - } + partial void CustomInit(DbContextOptionsBuilder optionsBuilder); - return base.SaveChanges(); - } + partial void OnModelCreatingImpl(ModelBuilder modelBuilder); + + partial void OnModelCreatedImpl(ModelBuilder modelBuilder); } } diff --git a/MediaBrowser.Controller/Drawing/ImageProcessorExtensions.cs b/MediaBrowser.Controller/Drawing/ImageProcessorExtensions.cs index 9f505be93..df9050de5 100644 --- a/MediaBrowser.Controller/Drawing/ImageProcessorExtensions.cs +++ b/MediaBrowser.Controller/Drawing/ImageProcessorExtensions.cs @@ -1,6 +1,5 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Model.Entities; -using User = Jellyfin.Data.Entities.User; namespace MediaBrowser.Controller.Drawing { -- cgit v1.2.3 From 4f6e5591ece8d9344385d13f923384abfc07b709 Mon Sep 17 00:00:00 2001 From: Mark Monteiro Date: Sat, 23 May 2020 16:08:51 -0400 Subject: Remove 'General' as an ExternalIdMediaType, and instead use 'null' to represent a general external id type --- MediaBrowser.Controller/Providers/IExternalId.cs | 4 +++- MediaBrowser.Model/Providers/ExternalIdInfo.cs | 4 +++- MediaBrowser.Model/Providers/ExternalIdMediaType.cs | 6 ------ MediaBrowser.Providers/Movies/MovieExternalIds.cs | 4 ++-- MediaBrowser.Providers/Music/MusicExternalIds.cs | 2 +- MediaBrowser.Providers/Plugins/AudioDb/ExternalIds.cs | 8 ++++---- MediaBrowser.Providers/Plugins/MusicBrainz/ExternalIds.cs | 12 ++++++------ MediaBrowser.Providers/TV/TvExternalIds.cs | 8 ++++---- MediaBrowser.Providers/Tmdb/BoxSets/TmdbBoxSetExternalId.cs | 2 +- MediaBrowser.Providers/Tmdb/Movies/TmdbMovieExternalId.cs | 2 +- MediaBrowser.Providers/Tmdb/People/TmdbPersonExternalId.cs | 2 +- MediaBrowser.Providers/Tmdb/TV/TmdbSeriesExternalId.cs | 2 +- 12 files changed, 27 insertions(+), 29 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/Providers/IExternalId.cs b/MediaBrowser.Controller/Providers/IExternalId.cs index 96d1e4622..5e38446bc 100644 --- a/MediaBrowser.Controller/Providers/IExternalId.cs +++ b/MediaBrowser.Controller/Providers/IExternalId.cs @@ -22,11 +22,13 @@ namespace MediaBrowser.Controller.Providers /// /// Gets the specific media type for this id. This is used to distinguish between the different /// external id types for providers with multiple ids. + /// A null value indicates there is no specific media type associated with the external id, or this is the + /// default id for the external provider so there is no need to specify a type. /// /// /// This can be used along with the to localize the external id on the client. /// - ExternalIdMediaType Type { get; } + ExternalIdMediaType? Type { get; } /// /// Gets the URL format string for this id. diff --git a/MediaBrowser.Model/Providers/ExternalIdInfo.cs b/MediaBrowser.Model/Providers/ExternalIdInfo.cs index 445c86d73..7687e676f 100644 --- a/MediaBrowser.Model/Providers/ExternalIdInfo.cs +++ b/MediaBrowser.Model/Providers/ExternalIdInfo.cs @@ -20,11 +20,13 @@ namespace MediaBrowser.Model.Providers /// /// Gets or sets the specific media type for this id. This is used to distinguish between the different /// external id types for providers with multiple ids. + /// A null value indicates there is no specific media type associated with the external id, or this is the + /// default id for the external provider so there is no need to specify a type. /// /// /// This can be used along with the to localize the external id on the client. /// - public ExternalIdMediaType Type { get; set; } + public ExternalIdMediaType? Type { get; set; } /// /// Gets or sets the URL format string. diff --git a/MediaBrowser.Model/Providers/ExternalIdMediaType.cs b/MediaBrowser.Model/Providers/ExternalIdMediaType.cs index 56f55d15c..5303c8f58 100644 --- a/MediaBrowser.Model/Providers/ExternalIdMediaType.cs +++ b/MediaBrowser.Model/Providers/ExternalIdMediaType.cs @@ -8,12 +8,6 @@ namespace MediaBrowser.Model.Providers /// public enum ExternalIdMediaType { - /// - /// There is no specific media type associated with the external id, or this is the default id for the external - /// provider so there is no need to specify a type. - /// - General = 0, - /// /// A music album. /// diff --git a/MediaBrowser.Providers/Movies/MovieExternalIds.cs b/MediaBrowser.Providers/Movies/MovieExternalIds.cs index 2b0c0d1c2..b43ae63ab 100644 --- a/MediaBrowser.Providers/Movies/MovieExternalIds.cs +++ b/MediaBrowser.Providers/Movies/MovieExternalIds.cs @@ -17,7 +17,7 @@ namespace MediaBrowser.Providers.Movies public string Key => MetadataProviders.Imdb.ToString(); /// - public ExternalIdMediaType Type => ExternalIdMediaType.General; + public ExternalIdMediaType? Type => null; /// public string UrlFormatString => "https://www.imdb.com/title/{0}"; @@ -44,7 +44,7 @@ namespace MediaBrowser.Providers.Movies public string Key => MetadataProviders.Imdb.ToString(); /// - public ExternalIdMediaType Type => ExternalIdMediaType.Person; + public ExternalIdMediaType? Type => ExternalIdMediaType.Person; /// public string UrlFormatString => "https://www.imdb.com/name/{0}"; diff --git a/MediaBrowser.Providers/Music/MusicExternalIds.cs b/MediaBrowser.Providers/Music/MusicExternalIds.cs index 4490d0f05..42694fdee 100644 --- a/MediaBrowser.Providers/Music/MusicExternalIds.cs +++ b/MediaBrowser.Providers/Music/MusicExternalIds.cs @@ -14,7 +14,7 @@ namespace MediaBrowser.Providers.Music public string Key => "IMVDb"; /// - public ExternalIdMediaType Type => ExternalIdMediaType.General; + public ExternalIdMediaType? Type => null; /// public string UrlFormatString => null; diff --git a/MediaBrowser.Providers/Plugins/AudioDb/ExternalIds.cs b/MediaBrowser.Providers/Plugins/AudioDb/ExternalIds.cs index e299eb3ee..1dd5b21a9 100644 --- a/MediaBrowser.Providers/Plugins/AudioDb/ExternalIds.cs +++ b/MediaBrowser.Providers/Plugins/AudioDb/ExternalIds.cs @@ -14,7 +14,7 @@ namespace MediaBrowser.Providers.Plugins.AudioDb public string Key => MetadataProviders.AudioDbAlbum.ToString(); /// - public ExternalIdMediaType Type => ExternalIdMediaType.General; + public ExternalIdMediaType? Type => null; /// public string UrlFormatString => "https://www.theaudiodb.com/album/{0}"; @@ -32,7 +32,7 @@ namespace MediaBrowser.Providers.Plugins.AudioDb public string Key => MetadataProviders.AudioDbAlbum.ToString(); /// - public ExternalIdMediaType Type => ExternalIdMediaType.Album; + public ExternalIdMediaType? Type => ExternalIdMediaType.Album; /// public string UrlFormatString => "https://www.theaudiodb.com/album/{0}"; @@ -50,7 +50,7 @@ namespace MediaBrowser.Providers.Plugins.AudioDb public string Key => MetadataProviders.AudioDbArtist.ToString(); /// - public ExternalIdMediaType Type => ExternalIdMediaType.Artist; + public ExternalIdMediaType? Type => ExternalIdMediaType.Artist; /// public string UrlFormatString => "https://www.theaudiodb.com/artist/{0}"; @@ -68,7 +68,7 @@ namespace MediaBrowser.Providers.Plugins.AudioDb public string Key => MetadataProviders.AudioDbArtist.ToString(); /// - public ExternalIdMediaType Type => ExternalIdMediaType.OtherArtist; + public ExternalIdMediaType? Type => ExternalIdMediaType.OtherArtist; /// public string UrlFormatString => "https://www.theaudiodb.com/artist/{0}"; diff --git a/MediaBrowser.Providers/Plugins/MusicBrainz/ExternalIds.cs b/MediaBrowser.Providers/Plugins/MusicBrainz/ExternalIds.cs index 247e87fd5..969bdd01d 100644 --- a/MediaBrowser.Providers/Plugins/MusicBrainz/ExternalIds.cs +++ b/MediaBrowser.Providers/Plugins/MusicBrainz/ExternalIds.cs @@ -15,7 +15,7 @@ namespace MediaBrowser.Providers.Music public string Key => MetadataProviders.MusicBrainzReleaseGroup.ToString(); /// - public ExternalIdMediaType Type => ExternalIdMediaType.ReleaseGroup; + public ExternalIdMediaType? Type => ExternalIdMediaType.ReleaseGroup; /// public string UrlFormatString => Plugin.Instance.Configuration.Server + "/release-group/{0}"; @@ -33,7 +33,7 @@ namespace MediaBrowser.Providers.Music public string Key => MetadataProviders.MusicBrainzAlbumArtist.ToString(); /// - public ExternalIdMediaType Type => ExternalIdMediaType.AlbumArtist; + public ExternalIdMediaType? Type => ExternalIdMediaType.AlbumArtist; /// public string UrlFormatString => Plugin.Instance.Configuration.Server + "/artist/{0}"; @@ -51,7 +51,7 @@ namespace MediaBrowser.Providers.Music public string Key => MetadataProviders.MusicBrainzAlbum.ToString(); /// - public ExternalIdMediaType Type => ExternalIdMediaType.Album; + public ExternalIdMediaType? Type => ExternalIdMediaType.Album; /// public string UrlFormatString => Plugin.Instance.Configuration.Server + "/release/{0}"; @@ -69,7 +69,7 @@ namespace MediaBrowser.Providers.Music public string Key => MetadataProviders.MusicBrainzArtist.ToString(); /// - public ExternalIdMediaType Type => ExternalIdMediaType.Artist; + public ExternalIdMediaType? Type => ExternalIdMediaType.Artist; /// public string UrlFormatString => Plugin.Instance.Configuration.Server + "/artist/{0}"; @@ -88,7 +88,7 @@ namespace MediaBrowser.Providers.Music public string Key => MetadataProviders.MusicBrainzArtist.ToString(); /// - public ExternalIdMediaType Type => ExternalIdMediaType.OtherArtist; + public ExternalIdMediaType? Type => ExternalIdMediaType.OtherArtist; /// public string UrlFormatString => Plugin.Instance.Configuration.Server + "/artist/{0}"; @@ -106,7 +106,7 @@ namespace MediaBrowser.Providers.Music public string Key => MetadataProviders.MusicBrainzTrack.ToString(); /// - public ExternalIdMediaType Type => ExternalIdMediaType.Track; + public ExternalIdMediaType? Type => ExternalIdMediaType.Track; /// public string UrlFormatString => Plugin.Instance.Configuration.Server + "/track/{0}"; diff --git a/MediaBrowser.Providers/TV/TvExternalIds.cs b/MediaBrowser.Providers/TV/TvExternalIds.cs index 12ad3d8a2..2bf6020dd 100644 --- a/MediaBrowser.Providers/TV/TvExternalIds.cs +++ b/MediaBrowser.Providers/TV/TvExternalIds.cs @@ -15,7 +15,7 @@ namespace MediaBrowser.Providers.TV public string Key => MetadataProviders.Zap2It.ToString(); /// - public ExternalIdMediaType Type => ExternalIdMediaType.General; + public ExternalIdMediaType? Type => null; /// public string UrlFormatString => "http://tvlistings.zap2it.com/overview.html?programSeriesId={0}"; @@ -33,7 +33,7 @@ namespace MediaBrowser.Providers.TV public string Key => MetadataProviders.Tvdb.ToString(); /// - public ExternalIdMediaType Type => ExternalIdMediaType.General; + public ExternalIdMediaType? Type => null; /// public string UrlFormatString => TvdbUtils.TvdbBaseUrl + "?tab=series&id={0}"; @@ -52,7 +52,7 @@ namespace MediaBrowser.Providers.TV public string Key => MetadataProviders.Tvdb.ToString(); /// - public ExternalIdMediaType Type => ExternalIdMediaType.Season; + public ExternalIdMediaType? Type => ExternalIdMediaType.Season; /// public string UrlFormatString => null; @@ -70,7 +70,7 @@ namespace MediaBrowser.Providers.TV public string Key => MetadataProviders.Tvdb.ToString(); /// - public ExternalIdMediaType Type => ExternalIdMediaType.Episode; + public ExternalIdMediaType? Type => ExternalIdMediaType.Episode; /// public string UrlFormatString => TvdbUtils.TvdbBaseUrl + "?tab=episode&id={0}"; diff --git a/MediaBrowser.Providers/Tmdb/BoxSets/TmdbBoxSetExternalId.cs b/MediaBrowser.Providers/Tmdb/BoxSets/TmdbBoxSetExternalId.cs index 1d3c80536..bfef1e038 100644 --- a/MediaBrowser.Providers/Tmdb/BoxSets/TmdbBoxSetExternalId.cs +++ b/MediaBrowser.Providers/Tmdb/BoxSets/TmdbBoxSetExternalId.cs @@ -15,7 +15,7 @@ namespace MediaBrowser.Providers.Tmdb.BoxSets public string Key => MetadataProviders.TmdbCollection.ToString(); /// - public ExternalIdMediaType Type => ExternalIdMediaType.BoxSet; + public ExternalIdMediaType? Type => ExternalIdMediaType.BoxSet; /// public string UrlFormatString => TmdbUtils.BaseTmdbUrl + "collection/{0}"; diff --git a/MediaBrowser.Providers/Tmdb/Movies/TmdbMovieExternalId.cs b/MediaBrowser.Providers/Tmdb/Movies/TmdbMovieExternalId.cs index 75e71dda4..5b0cd7509 100644 --- a/MediaBrowser.Providers/Tmdb/Movies/TmdbMovieExternalId.cs +++ b/MediaBrowser.Providers/Tmdb/Movies/TmdbMovieExternalId.cs @@ -16,7 +16,7 @@ namespace MediaBrowser.Providers.Tmdb.Movies public string Key => MetadataProviders.Tmdb.ToString(); /// - public ExternalIdMediaType Type => ExternalIdMediaType.Movie; + public ExternalIdMediaType? Type => ExternalIdMediaType.Movie; /// public string UrlFormatString => TmdbUtils.BaseTmdbUrl + "movie/{0}"; diff --git a/MediaBrowser.Providers/Tmdb/People/TmdbPersonExternalId.cs b/MediaBrowser.Providers/Tmdb/People/TmdbPersonExternalId.cs index a8685d669..fa12a4581 100644 --- a/MediaBrowser.Providers/Tmdb/People/TmdbPersonExternalId.cs +++ b/MediaBrowser.Providers/Tmdb/People/TmdbPersonExternalId.cs @@ -14,7 +14,7 @@ namespace MediaBrowser.Providers.Tmdb.People public string Key => MetadataProviders.Tmdb.ToString(); /// - public ExternalIdMediaType Type => ExternalIdMediaType.Person; + public ExternalIdMediaType? Type => ExternalIdMediaType.Person; /// public string UrlFormatString => TmdbUtils.BaseTmdbUrl + "person/{0}"; diff --git a/MediaBrowser.Providers/Tmdb/TV/TmdbSeriesExternalId.cs b/MediaBrowser.Providers/Tmdb/TV/TmdbSeriesExternalId.cs index fd6dd9b41..8513dadd2 100644 --- a/MediaBrowser.Providers/Tmdb/TV/TmdbSeriesExternalId.cs +++ b/MediaBrowser.Providers/Tmdb/TV/TmdbSeriesExternalId.cs @@ -14,7 +14,7 @@ namespace MediaBrowser.Providers.Tmdb.TV public string Key => MetadataProviders.Tmdb.ToString(); /// - public ExternalIdMediaType Type => ExternalIdMediaType.Series; + public ExternalIdMediaType? Type => ExternalIdMediaType.Series; /// public string UrlFormatString => TmdbUtils.BaseTmdbUrl + "tv/{0}"; -- cgit v1.2.3 From 29443e36817e4866cc58e8397c1233b05624284a Mon Sep 17 00:00:00 2001 From: Vasily Date: Tue, 26 May 2020 00:50:29 +0300 Subject: Apply suggestions from code review Co-authored-by: dkanada --- .vscode/tasks.json | 1 - Emby.Server.Implementations/Library/LibraryManager.cs | 1 - MediaBrowser.Controller/Drawing/IImageEncoder.cs | 2 +- MediaBrowser.Model/Dto/BaseItemDto.cs | 2 +- 4 files changed, 2 insertions(+), 4 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 7475617c9..2289fd991 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -21,6 +21,5 @@ ], "problemMatcher": "$msCompile" } - ] } diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index 579fb7edd..e63776bff 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -71,7 +71,6 @@ namespace Emby.Server.Implementations.Library private readonly ConcurrentDictionary _libraryItemsCache; private readonly IImageProcessor _imageProcessor; - private NamingOptions _namingOptions; private string[] _videoFileExtensions; diff --git a/MediaBrowser.Controller/Drawing/IImageEncoder.cs b/MediaBrowser.Controller/Drawing/IImageEncoder.cs index 1d3f0d3b4..4baec6204 100644 --- a/MediaBrowser.Controller/Drawing/IImageEncoder.cs +++ b/MediaBrowser.Controller/Drawing/IImageEncoder.cs @@ -44,7 +44,7 @@ namespace MediaBrowser.Controller.Drawing ImageDimensions GetImageSize(string path); /// - /// Get the blurhash of an image. + /// Gets the blurhash of an image. /// /// The filepath of the image. /// The blurhash. diff --git a/MediaBrowser.Model/Dto/BaseItemDto.cs b/MediaBrowser.Model/Dto/BaseItemDto.cs index df84dcf12..6213206ff 100644 --- a/MediaBrowser.Model/Dto/BaseItemDto.cs +++ b/MediaBrowser.Model/Dto/BaseItemDto.cs @@ -511,7 +511,7 @@ namespace MediaBrowser.Model.Dto public string SeriesThumbImageTag { get; set; } /// - /// Gets or sets the blurhash for the image tags. + /// Gets or sets the blurhashes for the image tags. /// /// The blurhashes. public Dictionary ImageBlurHashes { get; set; } -- cgit v1.2.3 From 10e381f66f957ffa2e8339a02b0c970086673739 Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Mon, 25 May 2020 23:52:51 +0200 Subject: Fix some 'bugs' flagged by sonarcloud --- DvdLib/Ifo/Program.cs | 2 +- Emby.Dlna/ContentDirectory/ContentDirectory.cs | 8 +--- Emby.Dlna/Main/DlnaEntryPoint.cs | 10 ++--- Emby.Dlna/PlayTo/Device.cs | 20 ++++----- Emby.Dlna/PlayTo/PlayToController.cs | 19 +++++---- Emby.Dlna/Ssdp/Extensions.cs | 14 ++----- .../EntryPoints/LibraryChangedNotifier.cs | 4 +- .../EntryPoints/RecordingNotifier.cs | 18 ++++---- .../EntryPoints/ServerEventNotifier.cs | 48 +++++++++++----------- .../HttpServer/HttpResultFactory.cs | 12 ++++-- .../LiveTv/EmbyTV/EmbyTV.cs | 13 ++---- .../LiveTv/EmbyTV/EncodedRecorder.cs | 4 +- .../LiveTv/LiveTvManager.cs | 20 +++------ .../SocketSharp/WebSocketSharpRequest.cs | 5 ++- MediaBrowser.Api/Images/ImageService.cs | 3 +- .../Sessions/SessionInfoWebSocketListener.cs | 28 ++++++------- .../Net/BasePeriodicWebSocketListener.cs | 25 +++++++---- MediaBrowser.MediaEncoding/Subtitles/AssParser.cs | 6 ++- 18 files changed, 126 insertions(+), 133 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/DvdLib/Ifo/Program.cs b/DvdLib/Ifo/Program.cs index 9f6251270..3d94fa7dc 100644 --- a/DvdLib/Ifo/Program.cs +++ b/DvdLib/Ifo/Program.cs @@ -6,7 +6,7 @@ namespace DvdLib.Ifo { public class Program { - public readonly List Cells; + public IReadOnlyList Cells { get; } public Program(List cells) { diff --git a/Emby.Dlna/ContentDirectory/ContentDirectory.cs b/Emby.Dlna/ContentDirectory/ContentDirectory.cs index 64cd308a2..66805b7c8 100644 --- a/Emby.Dlna/ContentDirectory/ContentDirectory.cs +++ b/Emby.Dlna/ContentDirectory/ContentDirectory.cs @@ -1,6 +1,7 @@ #pragma warning disable CS1591 using System; +using System.Linq; using System.Threading.Tasks; using Emby.Dlna.Service; using MediaBrowser.Common.Net; @@ -136,12 +137,7 @@ namespace Emby.Dlna.ContentDirectory } } - foreach (var user in _userManager.Users) - { - return user; - } - - return null; + return _userManager.Users.FirstOrDefault(); } } } diff --git a/Emby.Dlna/Main/DlnaEntryPoint.cs b/Emby.Dlna/Main/DlnaEntryPoint.cs index c5d60b2a0..bcab4adba 100644 --- a/Emby.Dlna/Main/DlnaEntryPoint.cs +++ b/Emby.Dlna/Main/DlnaEntryPoint.cs @@ -133,20 +133,20 @@ namespace Emby.Dlna.Main { await ((DlnaManager)_dlnaManager).InitProfilesAsync().ConfigureAwait(false); - ReloadComponents(); + await ReloadComponents().ConfigureAwait(false); - _config.NamedConfigurationUpdated += _config_NamedConfigurationUpdated; + _config.NamedConfigurationUpdated += OnNamedConfigurationUpdated; } - void _config_NamedConfigurationUpdated(object sender, ConfigurationUpdateEventArgs e) + private async void OnNamedConfigurationUpdated(object sender, ConfigurationUpdateEventArgs e) { if (string.Equals(e.Key, "dlna", StringComparison.OrdinalIgnoreCase)) { - ReloadComponents(); + await ReloadComponents().ConfigureAwait(false); } } - private async void ReloadComponents() + private async Task ReloadComponents() { var options = _config.GetDlnaConfiguration(); diff --git a/Emby.Dlna/PlayTo/Device.cs b/Emby.Dlna/PlayTo/Device.cs index 6abc3a82c..c7431d143 100644 --- a/Emby.Dlna/PlayTo/Device.cs +++ b/Emby.Dlna/PlayTo/Device.cs @@ -34,7 +34,7 @@ namespace Emby.Dlna.PlayTo { get { - RefreshVolumeIfNeeded(); + RefreshVolumeIfNeeded().GetAwaiter().GetResult(); return _volume; } set => _volume = value; @@ -76,24 +76,24 @@ namespace Emby.Dlna.PlayTo private DateTime _lastVolumeRefresh; private bool _volumeRefreshActive; - private void RefreshVolumeIfNeeded() + private Task RefreshVolumeIfNeeded() { - if (!_volumeRefreshActive) - { - return; - } - - if (DateTime.UtcNow >= _lastVolumeRefresh.AddSeconds(5)) + if (_volumeRefreshActive + && DateTime.UtcNow >= _lastVolumeRefresh.AddSeconds(5)) { _lastVolumeRefresh = DateTime.UtcNow; - RefreshVolume(CancellationToken.None); + return RefreshVolume(); } + + return Task.CompletedTask; } - private async void RefreshVolume(CancellationToken cancellationToken) + private async Task RefreshVolume(CancellationToken cancellationToken = default) { if (_disposed) + { return; + } try { diff --git a/Emby.Dlna/PlayTo/PlayToController.cs b/Emby.Dlna/PlayTo/PlayToController.cs index 9d7c0d365..7403a2a16 100644 --- a/Emby.Dlna/PlayTo/PlayToController.cs +++ b/Emby.Dlna/PlayTo/PlayToController.cs @@ -146,11 +146,14 @@ namespace Emby.Dlna.PlayTo { var positionTicks = GetProgressPositionTicks(streamInfo); - ReportPlaybackStopped(streamInfo, positionTicks); + await ReportPlaybackStopped(streamInfo, positionTicks).ConfigureAwait(false); } streamInfo = StreamParams.ParseFromUrl(e.NewMediaInfo.Url, _libraryManager, _mediaSourceManager); - if (streamInfo.Item == null) return; + if (streamInfo.Item == null) + { + return; + } var newItemProgress = GetProgressInfo(streamInfo); @@ -173,11 +176,14 @@ namespace Emby.Dlna.PlayTo { var streamInfo = StreamParams.ParseFromUrl(e.MediaInfo.Url, _libraryManager, _mediaSourceManager); - if (streamInfo.Item == null) return; + if (streamInfo.Item == null) + { + return; + } var positionTicks = GetProgressPositionTicks(streamInfo); - ReportPlaybackStopped(streamInfo, positionTicks); + await ReportPlaybackStopped(streamInfo, positionTicks).ConfigureAwait(false); var mediaSource = await streamInfo.GetMediaSource(CancellationToken.None).ConfigureAwait(false); @@ -185,7 +191,7 @@ namespace Emby.Dlna.PlayTo (_device.Duration == null ? (long?)null : _device.Duration.Value.Ticks) : mediaSource.RunTimeTicks; - var playedToCompletion = (positionTicks.HasValue && positionTicks.Value == 0); + var playedToCompletion = positionTicks.HasValue && positionTicks.Value == 0; if (!playedToCompletion && duration.HasValue && positionTicks.HasValue) { @@ -210,7 +216,7 @@ namespace Emby.Dlna.PlayTo } } - private async void ReportPlaybackStopped(StreamParams streamInfo, long? positionTicks) + private async Task ReportPlaybackStopped(StreamParams streamInfo, long? positionTicks) { try { @@ -220,7 +226,6 @@ namespace Emby.Dlna.PlayTo SessionId = _session.Id, PositionTicks = positionTicks, MediaSourceId = streamInfo.MediaSourceId - }).ConfigureAwait(false); } catch (Exception ex) diff --git a/Emby.Dlna/Ssdp/Extensions.cs b/Emby.Dlna/Ssdp/Extensions.cs index 10c1f321b..613d332b2 100644 --- a/Emby.Dlna/Ssdp/Extensions.cs +++ b/Emby.Dlna/Ssdp/Extensions.cs @@ -1,5 +1,6 @@ #pragma warning disable CS1591 +using System.Linq; using System.Xml.Linq; namespace Emby.Dlna.Ssdp @@ -10,24 +11,17 @@ namespace Emby.Dlna.Ssdp { var node = container.Element(name); - return node == null ? null : node.Value; + return node?.Value; } public static string GetAttributeValue(this XElement container, XName name) { var node = container.Attribute(name); - return node == null ? null : node.Value; + return node?.Value; } public static string GetDescendantValue(this XElement container, XName name) - { - foreach (var node in container.Descendants(name)) - { - return node.Value; - } - - return null; - } + => container.Descendants(name).FirstOrDefault()?.Value; } } diff --git a/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs b/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs index 8e3236407..9bc2b62ec 100644 --- a/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs +++ b/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs @@ -302,7 +302,7 @@ namespace Emby.Server.Implementations.EntryPoints .Select(x => x.First()) .ToList(); - SendChangeNotifications(_itemsAdded.ToList(), itemsUpdated, _itemsRemoved.ToList(), foldersAddedTo, foldersRemovedFrom, CancellationToken.None); + SendChangeNotifications(_itemsAdded.ToList(), itemsUpdated, _itemsRemoved.ToList(), foldersAddedTo, foldersRemovedFrom, CancellationToken.None).GetAwaiter().GetResult(); if (LibraryUpdateTimer != null) { @@ -327,7 +327,7 @@ namespace Emby.Server.Implementations.EntryPoints /// The folders added to. /// The folders removed from. /// The cancellation token. - private async void SendChangeNotifications(List itemsAdded, List itemsUpdated, List itemsRemoved, List foldersAddedTo, List foldersRemovedFrom, CancellationToken cancellationToken) + private async Task SendChangeNotifications(List itemsAdded, List itemsUpdated, List itemsRemoved, List foldersAddedTo, List foldersRemovedFrom, CancellationToken cancellationToken) { var userIds = _sessionManager.Sessions .Select(i => i.UserId) diff --git a/Emby.Server.Implementations/EntryPoints/RecordingNotifier.cs b/Emby.Server.Implementations/EntryPoints/RecordingNotifier.cs index 41c0c5115..997571a91 100644 --- a/Emby.Server.Implementations/EntryPoints/RecordingNotifier.cs +++ b/Emby.Server.Implementations/EntryPoints/RecordingNotifier.cs @@ -42,27 +42,27 @@ namespace Emby.Server.Implementations.EntryPoints return Task.CompletedTask; } - private void OnLiveTvManagerSeriesTimerCreated(object sender, MediaBrowser.Model.Events.GenericEventArgs e) + private async void OnLiveTvManagerSeriesTimerCreated(object sender, MediaBrowser.Model.Events.GenericEventArgs e) { - SendMessage("SeriesTimerCreated", e.Argument); + await SendMessage("SeriesTimerCreated", e.Argument).ConfigureAwait(false); } - private void OnLiveTvManagerTimerCreated(object sender, MediaBrowser.Model.Events.GenericEventArgs e) + private async void OnLiveTvManagerTimerCreated(object sender, MediaBrowser.Model.Events.GenericEventArgs e) { - SendMessage("TimerCreated", e.Argument); + await SendMessage("TimerCreated", e.Argument).ConfigureAwait(false); } - private void OnLiveTvManagerSeriesTimerCancelled(object sender, MediaBrowser.Model.Events.GenericEventArgs e) + private async void OnLiveTvManagerSeriesTimerCancelled(object sender, MediaBrowser.Model.Events.GenericEventArgs e) { - SendMessage("SeriesTimerCancelled", e.Argument); + await SendMessage("SeriesTimerCancelled", e.Argument).ConfigureAwait(false); } - private void OnLiveTvManagerTimerCancelled(object sender, MediaBrowser.Model.Events.GenericEventArgs e) + private async void OnLiveTvManagerTimerCancelled(object sender, MediaBrowser.Model.Events.GenericEventArgs e) { - SendMessage("TimerCancelled", e.Argument); + await SendMessage("TimerCancelled", e.Argument).ConfigureAwait(false); } - private async void SendMessage(string name, TimerEventInfo info) + private async Task SendMessage(string name, TimerEventInfo info) { var users = _userManager.Users.Where(i => i.Policy.EnableLiveTvAccess).Select(i => i.Id).ToList(); diff --git a/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs b/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs index e1dbb663b..dea85d299 100644 --- a/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs +++ b/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs @@ -85,29 +85,29 @@ namespace Emby.Server.Implementations.EntryPoints return Task.CompletedTask; } - private void OnPackageInstalling(object sender, InstallationEventArgs e) + private async void OnPackageInstalling(object sender, InstallationEventArgs e) { - SendMessageToAdminSessions("PackageInstalling", e.InstallationInfo); + await SendMessageToAdminSessions("PackageInstalling", e.InstallationInfo).ConfigureAwait(false); } - private void OnPackageInstallationCancelled(object sender, InstallationEventArgs e) + private async void OnPackageInstallationCancelled(object sender, InstallationEventArgs e) { - SendMessageToAdminSessions("PackageInstallationCancelled", e.InstallationInfo); + await SendMessageToAdminSessions("PackageInstallationCancelled", e.InstallationInfo).ConfigureAwait(false); } - private void OnPackageInstallationCompleted(object sender, InstallationEventArgs e) + private async void OnPackageInstallationCompleted(object sender, InstallationEventArgs e) { - SendMessageToAdminSessions("PackageInstallationCompleted", e.InstallationInfo); + await SendMessageToAdminSessions("PackageInstallationCompleted", e.InstallationInfo).ConfigureAwait(false); } - private void OnPackageInstallationFailed(object sender, InstallationFailedEventArgs e) + private async void OnPackageInstallationFailed(object sender, InstallationFailedEventArgs e) { - SendMessageToAdminSessions("PackageInstallationFailed", e.InstallationInfo); + await SendMessageToAdminSessions("PackageInstallationFailed", e.InstallationInfo).ConfigureAwait(false); } - private void OnTaskCompleted(object sender, TaskCompletionEventArgs e) + private async void OnTaskCompleted(object sender, TaskCompletionEventArgs e) { - SendMessageToAdminSessions("ScheduledTaskEnded", e.Result); + await SendMessageToAdminSessions("ScheduledTaskEnded", e.Result).ConfigureAwait(false); } /// @@ -115,9 +115,9 @@ namespace Emby.Server.Implementations.EntryPoints /// /// The sender. /// The e. - private void OnPluginUninstalled(object sender, GenericEventArgs e) + private async void OnPluginUninstalled(object sender, GenericEventArgs e) { - SendMessageToAdminSessions("PluginUninstalled", e.Argument.GetPluginInfo()); + await SendMessageToAdminSessions("PluginUninstalled", e.Argument.GetPluginInfo()).ConfigureAwait(false); } /// @@ -125,9 +125,9 @@ namespace Emby.Server.Implementations.EntryPoints /// /// The source of the event. /// The instance containing the event data. - private void OnHasPendingRestartChanged(object sender, EventArgs e) + private async void OnHasPendingRestartChanged(object sender, EventArgs e) { - _sessionManager.SendRestartRequiredNotification(CancellationToken.None); + await _sessionManager.SendRestartRequiredNotification(CancellationToken.None).ConfigureAwait(false); } /// @@ -135,11 +135,11 @@ namespace Emby.Server.Implementations.EntryPoints /// /// The sender. /// The e. - private void OnUserUpdated(object sender, GenericEventArgs e) + private async void OnUserUpdated(object sender, GenericEventArgs e) { var dto = _userManager.GetUserDto(e.Argument); - SendMessageToUserSession(e.Argument, "UserUpdated", dto); + await SendMessageToUserSession(e.Argument, "UserUpdated", dto).ConfigureAwait(false); } /// @@ -147,26 +147,26 @@ namespace Emby.Server.Implementations.EntryPoints /// /// The sender. /// The e. - private void OnUserDeleted(object sender, GenericEventArgs e) + private async void OnUserDeleted(object sender, GenericEventArgs e) { - SendMessageToUserSession(e.Argument, "UserDeleted", e.Argument.Id.ToString("N", CultureInfo.InvariantCulture)); + await SendMessageToUserSession(e.Argument, "UserDeleted", e.Argument.Id.ToString("N", CultureInfo.InvariantCulture)).ConfigureAwait(false); } - private void OnUserPolicyUpdated(object sender, GenericEventArgs e) + private async void OnUserPolicyUpdated(object sender, GenericEventArgs e) { var dto = _userManager.GetUserDto(e.Argument); - SendMessageToUserSession(e.Argument, "UserPolicyUpdated", dto); + await SendMessageToUserSession(e.Argument, "UserPolicyUpdated", dto).ConfigureAwait(false); } - private void OnUserConfigurationUpdated(object sender, GenericEventArgs e) + private async void OnUserConfigurationUpdated(object sender, GenericEventArgs e) { var dto = _userManager.GetUserDto(e.Argument); - SendMessageToUserSession(e.Argument, "UserConfigurationUpdated", dto); + await SendMessageToUserSession(e.Argument, "UserConfigurationUpdated", dto).ConfigureAwait(false); } - private async void SendMessageToAdminSessions(string name, T data) + private async Task SendMessageToAdminSessions(string name, T data) { try { @@ -178,7 +178,7 @@ namespace Emby.Server.Implementations.EntryPoints } } - private async void SendMessageToUserSession(User user, string name, T data) + private async Task SendMessageToUserSession(User user, string name, T data) { try { diff --git a/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs b/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs index 2e9ecc4ae..cffae7b1c 100644 --- a/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs +++ b/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs @@ -255,16 +255,20 @@ namespace Emby.Server.Implementations.HttpServer { var acceptEncoding = request.Headers[HeaderNames.AcceptEncoding].ToString(); - if (string.IsNullOrEmpty(acceptEncoding)) + if (!string.IsNullOrEmpty(acceptEncoding)) { - //if (_brotliCompressor != null && acceptEncoding.IndexOf("br", StringComparison.OrdinalIgnoreCase) != -1) + // if (_brotliCompressor != null && acceptEncoding.IndexOf("br", StringComparison.OrdinalIgnoreCase) != -1) // return "br"; - if (acceptEncoding.IndexOf("deflate", StringComparison.OrdinalIgnoreCase) != -1) + if (acceptEncoding.Contains("deflate", StringComparison.OrdinalIgnoreCase)) + { return "deflate"; + } - if (acceptEncoding.IndexOf("gzip", StringComparison.OrdinalIgnoreCase) != -1) + if (acceptEncoding.Contains("gzip", StringComparison.OrdinalIgnoreCase)) + { return "gzip"; + } } return null; diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index 3efe1ee25..5a5dc3329 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -140,11 +140,11 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV } } - private void OnNamedConfigurationUpdated(object sender, ConfigurationUpdateEventArgs e) + private async void OnNamedConfigurationUpdated(object sender, ConfigurationUpdateEventArgs e) { if (string.Equals(e.Key, "livetv", StringComparison.OrdinalIgnoreCase)) { - OnRecordingFoldersChanged(); + await CreateRecordingFolders().ConfigureAwait(false); } } @@ -155,11 +155,6 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV return CreateRecordingFolders(); } - private async void OnRecordingFoldersChanged() - { - await CreateRecordingFolders().ConfigureAwait(false); - } - internal async Task CreateRecordingFolders() { try @@ -1334,7 +1329,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV await CreateRecordingFolders().ConfigureAwait(false); TriggerRefresh(recordPath); - EnforceKeepUpTo(timer, seriesPath); + await EnforceKeepUpTo(timer, seriesPath).ConfigureAwait(false); }; await recorder.Record(directStreamProvider, mediaStreamInfo, recordPath, duration, onStarted, activeRecordingInfo.CancellationTokenSource.Token).ConfigureAwait(false); @@ -1494,7 +1489,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV return item; } - private async void EnforceKeepUpTo(TimerInfo timer, string seriesPath) + private async Task EnforceKeepUpTo(TimerInfo timer, string seriesPath) { if (string.IsNullOrWhiteSpace(timer.SeriesTimerId)) { diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs index bc86cc59a..70dd8f321 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs @@ -117,7 +117,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV onStarted(); // Important - don't await the log task or we won't be able to kill ffmpeg when the user stops playback - StartStreamingLog(_process.StandardError.BaseStream, _logFileStream); + _ = StartStreamingLog(_process.StandardError.BaseStream, _logFileStream); _logger.LogInformation("ffmpeg recording process started for {0}", _targetPath); @@ -321,7 +321,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV } } - private async void StartStreamingLog(Stream source, Stream target) + private async Task StartStreamingLog(Stream source, Stream target) { try { diff --git a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs index 1b10f2d27..a3dd45a53 100644 --- a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs @@ -788,22 +788,12 @@ namespace Emby.Server.Implementations.LiveTv if (query.OrderBy.Count == 0) { - if (query.IsAiring ?? false) - { - // Unless something else was specified, order by start date to take advantage of a specialized index - query.OrderBy = new[] - { - (ItemSortBy.StartDate, SortOrder.Ascending) - }; - } - else + + // Unless something else was specified, order by start date to take advantage of a specialized index + query.OrderBy = new[] { - // Unless something else was specified, order by start date to take advantage of a specialized index - query.OrderBy = new[] - { - (ItemSortBy.StartDate, SortOrder.Ascending) - }; - } + (ItemSortBy.StartDate, SortOrder.Ascending) + }; } RemoveFields(options); diff --git a/Emby.Server.Implementations/SocketSharp/WebSocketSharpRequest.cs b/Emby.Server.Implementations/SocketSharp/WebSocketSharpRequest.cs index ee5131c1f..5554aa97f 100644 --- a/Emby.Server.Implementations/SocketSharp/WebSocketSharpRequest.cs +++ b/Emby.Server.Implementations/SocketSharp/WebSocketSharpRequest.cs @@ -208,8 +208,9 @@ namespace Emby.Server.Implementations.SocketSharp private static string GetQueryStringContentType(HttpRequest httpReq) { - ReadOnlySpan format = httpReq.Query["format"].ToString(); - if (format == null) + string formatStr = httpReq.Query["format"].ToString(); + ReadOnlySpan format = formatStr; + if (formatStr == null) { const int FormatMaxLength = 4; ReadOnlySpan pi = httpReq.Path.ToString(); diff --git a/MediaBrowser.Api/Images/ImageService.cs b/MediaBrowser.Api/Images/ImageService.cs index 2e9b3e6cb..eaff22fff 100644 --- a/MediaBrowser.Api/Images/ImageService.cs +++ b/MediaBrowser.Api/Images/ImageService.cs @@ -555,8 +555,7 @@ namespace MediaBrowser.Api.Images var imageInfo = GetImageInfo(request, item); if (imageInfo == null) { - var displayText = item == null ? itemId.ToString() : item.Name; - throw new ResourceNotFoundException(string.Format("{0} does not have an image of type {1}", displayText, request.Type)); + throw new ResourceNotFoundException(string.Format("{0} does not have an image of type {1}", item.Name, request.Type)); } bool cropwhitespace; diff --git a/MediaBrowser.Api/Sessions/SessionInfoWebSocketListener.cs b/MediaBrowser.Api/Sessions/SessionInfoWebSocketListener.cs index 0e74c9267..175984575 100644 --- a/MediaBrowser.Api/Sessions/SessionInfoWebSocketListener.cs +++ b/MediaBrowser.Api/Sessions/SessionInfoWebSocketListener.cs @@ -40,39 +40,39 @@ namespace MediaBrowser.Api.Sessions _sessionManager.SessionActivity += OnSessionManagerSessionActivity; } - private void OnSessionManagerSessionActivity(object sender, SessionEventArgs e) + private async void OnSessionManagerSessionActivity(object sender, SessionEventArgs e) { - SendData(false); + await SendData(false).ConfigureAwait(false); } - private void OnSessionManagerCapabilitiesChanged(object sender, SessionEventArgs e) + private async void OnSessionManagerCapabilitiesChanged(object sender, SessionEventArgs e) { - SendData(true); + await SendData(true).ConfigureAwait(false); } - private void OnSessionManagerPlaybackProgress(object sender, PlaybackProgressEventArgs e) + private async void OnSessionManagerPlaybackProgress(object sender, PlaybackProgressEventArgs e) { - SendData(!e.IsAutomated); + await SendData(!e.IsAutomated).ConfigureAwait(false); } - private void OnSessionManagerPlaybackStopped(object sender, PlaybackStopEventArgs e) + private async void OnSessionManagerPlaybackStopped(object sender, PlaybackStopEventArgs e) { - SendData(true); + await SendData(true).ConfigureAwait(false); } - private void OnSessionManagerPlaybackStart(object sender, PlaybackProgressEventArgs e) + private async void OnSessionManagerPlaybackStart(object sender, PlaybackProgressEventArgs e) { - SendData(true); + await SendData(true).ConfigureAwait(false); } - private void OnSessionManagerSessionEnded(object sender, SessionEventArgs e) + private async void OnSessionManagerSessionEnded(object sender, SessionEventArgs e) { - SendData(true); + await SendData(true).ConfigureAwait(false); } - private void OnSessionManagerSessionStarted(object sender, SessionEventArgs e) + private async void OnSessionManagerSessionStarted(object sender, SessionEventArgs e) { - SendData(true); + await SendData(true).ConfigureAwait(false); } /// diff --git a/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs b/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs index 1162bff13..5be656bdb 100644 --- a/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs +++ b/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs @@ -104,7 +104,7 @@ namespace MediaBrowser.Controller.Net } } - protected void SendData(bool force) + protected async Task SendData(bool force) { Tuple[] tuples; @@ -128,13 +128,18 @@ namespace MediaBrowser.Controller.Net .ToArray(); } - foreach (var tuple in tuples) + IEnumerable GetTasks() { - SendData(tuple); + foreach (var tuple in tuples) + { + yield return SendData(tuple); + } } + + await Task.WhenAll(GetTasks()).ConfigureAwait(false); } - private async void SendData(Tuple tuple) + private async Task SendData(Tuple tuple) { var connection = tuple.Item1; @@ -148,11 +153,13 @@ namespace MediaBrowser.Controller.Net if (data != null) { - await connection.SendAsync(new WebSocketMessage - { - MessageType = Name, - Data = data - }, cancellationToken).ConfigureAwait(false); + await connection.SendAsync( + new WebSocketMessage + { + MessageType = Name, + Data = data + }, + cancellationToken).ConfigureAwait(false); state.DateLastSendUtc = DateTime.UtcNow; } diff --git a/MediaBrowser.MediaEncoding/Subtitles/AssParser.cs b/MediaBrowser.MediaEncoding/Subtitles/AssParser.cs index 293cf5ea5..f44cf1452 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/AssParser.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/AssParser.cs @@ -33,10 +33,12 @@ namespace MediaBrowser.MediaEncoding.Subtitles { continue; } + if (line.StartsWith("[")) + { break; - if (string.IsNullOrEmpty(line)) - continue; + } + var subEvent = new SubtitleTrackEvent { Id = eventIndex.ToString(_usCulture) }; eventIndex++; var sections = line.Substring(10).Split(','); -- cgit v1.2.3 From 46420dfd68945fd7c7045b8492c401e3d8cd302d Mon Sep 17 00:00:00 2001 From: xumix Date: Tue, 26 May 2020 00:58:19 +0300 Subject: Refactor copy codec checks --- MediaBrowser.Api/ApiEntryPoint.cs | 4 +-- MediaBrowser.Api/Playback/BaseStreamingService.cs | 10 ++++---- MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs | 14 +++++----- MediaBrowser.Api/Playback/Hls/VideoHlsService.cs | 2 +- MediaBrowser.Api/Playback/StreamState.cs | 2 +- .../MediaEncoding/EncodingHelper.cs | 20 ++++++++++----- .../MediaEncoding/EncodingJobInfo.cs | 30 +++++++++++----------- .../Configuration/EncodingOptions.cs | 12 +++++++++ 8 files changed, 56 insertions(+), 38 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Api/ApiEntryPoint.cs b/MediaBrowser.Api/ApiEntryPoint.cs index 6691080bc..c7485a2e9 100644 --- a/MediaBrowser.Api/ApiEntryPoint.cs +++ b/MediaBrowser.Api/ApiEntryPoint.cs @@ -284,8 +284,8 @@ namespace MediaBrowser.Api Width = state.OutputWidth, Height = state.OutputHeight, AudioChannels = state.OutputAudioChannels, - IsAudioDirect = string.Equals(state.OutputAudioCodec, "copy", StringComparison.OrdinalIgnoreCase), - IsVideoDirect = string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase), + IsAudioDirect = EncodingHelper.IsCopyCodec(state.OutputAudioCodec), + IsVideoDirect = EncodingHelper.IsCopyCodec(state.OutputVideoCodec), TranscodeReasons = state.TranscodeReasons }); } diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index f796aa486..24297d500 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -193,7 +193,7 @@ namespace MediaBrowser.Api.Playback await AcquireResources(state, cancellationTokenSource).ConfigureAwait(false); - if (state.VideoRequest != null && !string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase)) + if (state.VideoRequest != null && !EncodingHelper.IsCopyCodec(state.OutputVideoCodec)) { var auth = AuthorizationContext.GetAuthorizationInfo(Request); if (auth.User != null && !auth.User.Policy.EnableVideoPlaybackTranscoding) @@ -243,9 +243,9 @@ namespace MediaBrowser.Api.Playback var logFilePrefix = "ffmpeg-transcode"; if (state.VideoRequest != null - && string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase)) + && EncodingHelper.IsCopyCodec(state.OutputVideoCodec)) { - logFilePrefix = string.Equals(state.OutputAudioCodec, "copy", StringComparison.OrdinalIgnoreCase) + logFilePrefix = EncodingHelper.IsCopyCodec(state.OutputAudioCodec) ? "ffmpeg-remux" : "ffmpeg-directstream"; } @@ -328,7 +328,7 @@ namespace MediaBrowser.Api.Playback state.RunTimeTicks.Value >= TimeSpan.FromMinutes(5).Ticks && state.IsInputVideo && state.VideoType == VideoType.VideoFile && - !string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase); + !EncodingHelper.IsCopyCodec(state.OutputVideoCodec); } return false; @@ -791,7 +791,7 @@ namespace MediaBrowser.Api.Playback EncodingHelper.TryStreamCopy(state); } - if (state.OutputVideoBitrate.HasValue && !string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase)) + if (state.OutputVideoBitrate.HasValue && !EncodingHelper.IsCopyCodec(state.OutputVideoCodec)) { var resolution = ResolutionNormalizer.Normalize( state.VideoStream?.BitRate, diff --git a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs index 061316cb8..50d34cca9 100644 --- a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs +++ b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs @@ -700,12 +700,12 @@ namespace MediaBrowser.Api.Playback.Hls return false; } - if (string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase)) + if (EncodingHelper.IsCopyCodec(state.OutputVideoCodec)) { return false; } - if (string.Equals(state.OutputAudioCodec, "copy", StringComparison.OrdinalIgnoreCase)) + if (EncodingHelper.IsCopyCodec(state.OutputAudioCodec)) { return false; } @@ -728,7 +728,7 @@ namespace MediaBrowser.Api.Playback.Hls private int? GetOutputVideoCodecLevel(StreamState state) { string levelString; - if (string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase) + if (EncodingHelper.IsCopyCodec(state.OutputVideoCodec) && state.VideoStream.Level.HasValue) { levelString = state.VideoStream?.Level.ToString(); @@ -1008,7 +1008,7 @@ namespace MediaBrowser.Api.Playback.Hls if (!state.IsOutputVideo) { - if (string.Equals(audioCodec, "copy", StringComparison.OrdinalIgnoreCase)) + if (EncodingHelper.IsCopyCodec(audioCodec)) { return "-acodec copy"; } @@ -1036,11 +1036,11 @@ namespace MediaBrowser.Api.Playback.Hls return string.Join(" ", audioTranscodeParams.ToArray()); } - if (string.Equals(audioCodec, "copy", StringComparison.OrdinalIgnoreCase)) + if (EncodingHelper.IsCopyCodec(audioCodec)) { var videoCodec = EncodingHelper.GetVideoEncoder(state, encodingOptions); - if (string.Equals(videoCodec, "copy", StringComparison.OrdinalIgnoreCase) && state.EnableBreakOnNonKeyFrames(videoCodec)) + if (EncodingHelper.IsCopyCodec(videoCodec) && state.EnableBreakOnNonKeyFrames(videoCodec)) { return "-codec:a:0 copy -copypriorss:a:0 0"; } @@ -1091,7 +1091,7 @@ namespace MediaBrowser.Api.Playback.Hls // } // See if we can save come cpu cycles by avoiding encoding - if (string.Equals(codec, "copy", StringComparison.OrdinalIgnoreCase)) + if (EncodingHelper.IsCopyCodec(codec)) { if (state.VideoStream != null && !string.Equals(state.VideoStream.NalLengthSize, "0", StringComparison.OrdinalIgnoreCase)) { diff --git a/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs b/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs index d1c53c1c1..aefb3f019 100644 --- a/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs +++ b/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs @@ -72,7 +72,7 @@ namespace MediaBrowser.Api.Playback.Hls { var codec = EncodingHelper.GetAudioEncoder(state); - if (string.Equals(codec, "copy", StringComparison.OrdinalIgnoreCase)) + if (EncodingHelper.IsCopyCodec(codec)) { return "-codec:a:0 copy"; } diff --git a/MediaBrowser.Api/Playback/StreamState.cs b/MediaBrowser.Api/Playback/StreamState.cs index d5d2f58c0..c244b0033 100644 --- a/MediaBrowser.Api/Playback/StreamState.cs +++ b/MediaBrowser.Api/Playback/StreamState.cs @@ -42,7 +42,7 @@ namespace MediaBrowser.Api.Playback return Request.SegmentLength.Value; } - if (string.Equals(OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase)) + if (EncodingHelper.IsCopyCodec(OutputVideoCodec)) { var userAgent = UserAgent ?? string.Empty; diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 61a330675..2d2f73148 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -1338,7 +1338,7 @@ namespace MediaBrowser.Controller.MediaEncoding transcoderChannelLimit = 6; } - var isTranscodingAudio = !string.Equals(codec, "copy", StringComparison.OrdinalIgnoreCase); + var isTranscodingAudio = !EncodingHelper.IsCopyCodec(codec); int? resultChannels = state.GetRequestedAudioChannels(codec); if (isTranscodingAudio) @@ -1734,7 +1734,8 @@ namespace MediaBrowser.Controller.MediaEncoding var hasTextSubs = state.SubtitleStream != null && state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode; - if (string.Equals(videoEncoder, "h264_vaapi", StringComparison.OrdinalIgnoreCase) || (string.Equals(videoEncoder, "h264_qsv", StringComparison.OrdinalIgnoreCase) && !hasTextSubs) + if ((string.Equals(videoEncoder, "h264_vaapi", StringComparison.OrdinalIgnoreCase) + || (string.Equals(videoEncoder, "h264_qsv", StringComparison.OrdinalIgnoreCase) && !hasTextSubs)) && width.HasValue && height.HasValue) { @@ -1991,7 +1992,7 @@ namespace MediaBrowser.Controller.MediaEncoding filters.Add("hwupload"); } - // When the input may or may not be hardware QSV decodable + // When the input may or may not be hardware QSV decodable else if (string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase)) { if (!hasTextSubs) @@ -2248,7 +2249,7 @@ namespace MediaBrowser.Controller.MediaEncoding flags.Add("+ignidx"); } - if (state.GenPtsInput || string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase)) + if (state.GenPtsInput || EncodingHelper.IsCopyCodec(state.OutputVideoCodec)) { flags.Add("+genpts"); } @@ -2511,7 +2512,7 @@ namespace MediaBrowser.Controller.MediaEncoding /// protected string GetHardwareAcceleratedVideoDecoder(EncodingJobInfo state, EncodingOptions encodingOptions) { - if (string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase)) + if (EncodingHelper.IsCopyCodec(state.OutputVideoCodec)) { return null; } @@ -2799,7 +2800,7 @@ namespace MediaBrowser.Controller.MediaEncoding args += " -mpegts_m2ts_mode 1"; } - if (string.Equals(videoCodec, "copy", StringComparison.OrdinalIgnoreCase)) + if (EncodingHelper.IsCopyCodec(videoCodec)) { if (state.VideoStream != null && string.Equals(state.OutputContainer, "ts", StringComparison.OrdinalIgnoreCase) @@ -2901,7 +2902,7 @@ namespace MediaBrowser.Controller.MediaEncoding var args = "-codec:a:0 " + codec; - if (string.Equals(codec, "copy", StringComparison.OrdinalIgnoreCase)) + if (EncodingHelper.IsCopyCodec(codec)) { return args; } @@ -2973,5 +2974,10 @@ namespace MediaBrowser.Controller.MediaEncoding string.Empty, string.Empty).Trim(); } + + public static bool IsCopyCodec(string codec) + { + return string.Equals(codec, "copy", StringComparison.OrdinalIgnoreCase); + } } } diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs b/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs index 1127a08de..7cd783595 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs @@ -302,7 +302,7 @@ namespace MediaBrowser.Controller.MediaEncoding return false; } - return BaseRequest.BreakOnNonKeyFrames && string.Equals(videoCodec, "copy", StringComparison.OrdinalIgnoreCase); + return BaseRequest.BreakOnNonKeyFrames && EncodingHelper.IsCopyCodec(videoCodec); } return false; @@ -367,7 +367,7 @@ namespace MediaBrowser.Controller.MediaEncoding get { if (BaseRequest.Static - || string.Equals(OutputAudioCodec, "copy", StringComparison.OrdinalIgnoreCase)) + || EncodingHelper.IsCopyCodec(OutputAudioCodec)) { if (AudioStream != null) { @@ -390,7 +390,7 @@ namespace MediaBrowser.Controller.MediaEncoding get { if (BaseRequest.Static - || string.Equals(OutputAudioCodec, "copy", StringComparison.OrdinalIgnoreCase)) + || EncodingHelper.IsCopyCodec(OutputAudioCodec)) { if (AudioStream != null) { @@ -409,7 +409,7 @@ namespace MediaBrowser.Controller.MediaEncoding { get { - if (BaseRequest.Static || string.Equals(OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase)) + if (BaseRequest.Static || EncodingHelper.IsCopyCodec(OutputVideoCodec)) { return VideoStream?.Level; } @@ -433,7 +433,7 @@ namespace MediaBrowser.Controller.MediaEncoding get { if (BaseRequest.Static - || string.Equals(OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase)) + || EncodingHelper.IsCopyCodec(OutputVideoCodec)) { return VideoStream?.BitDepth; } @@ -451,7 +451,7 @@ namespace MediaBrowser.Controller.MediaEncoding get { if (BaseRequest.Static - || string.Equals(OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase)) + || EncodingHelper.IsCopyCodec(OutputVideoCodec)) { return VideoStream?.RefFrames; } @@ -468,7 +468,7 @@ namespace MediaBrowser.Controller.MediaEncoding get { if (BaseRequest.Static - || string.Equals(OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase)) + || EncodingHelper.IsCopyCodec(OutputVideoCodec)) { return VideoStream == null ? null : (VideoStream.AverageFrameRate ?? VideoStream.RealFrameRate); } @@ -499,7 +499,7 @@ namespace MediaBrowser.Controller.MediaEncoding { get { - if (BaseRequest.Static || string.Equals(OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase)) + if (BaseRequest.Static || EncodingHelper.IsCopyCodec(OutputVideoCodec)) { return VideoStream?.PacketLength; } @@ -515,7 +515,7 @@ namespace MediaBrowser.Controller.MediaEncoding { get { - if (BaseRequest.Static || string.Equals(OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase)) + if (BaseRequest.Static || EncodingHelper.IsCopyCodec(OutputVideoCodec)) { return VideoStream?.Profile; } @@ -535,7 +535,7 @@ namespace MediaBrowser.Controller.MediaEncoding get { if (BaseRequest.Static - || string.Equals(OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase)) + || EncodingHelper.IsCopyCodec(OutputVideoCodec)) { return VideoStream?.CodecTag; } @@ -549,7 +549,7 @@ namespace MediaBrowser.Controller.MediaEncoding get { if (BaseRequest.Static - || string.Equals(OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase)) + || EncodingHelper.IsCopyCodec(OutputVideoCodec)) { return VideoStream?.IsAnamorphic; } @@ -562,7 +562,7 @@ namespace MediaBrowser.Controller.MediaEncoding { get { - if (string.Equals(OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase)) + if (EncodingHelper.IsCopyCodec(OutputVideoCodec)) { return VideoStream?.Codec; } @@ -575,7 +575,7 @@ namespace MediaBrowser.Controller.MediaEncoding { get { - if (string.Equals(OutputAudioCodec, "copy", StringComparison.OrdinalIgnoreCase)) + if (EncodingHelper.IsCopyCodec(OutputAudioCodec)) { return AudioStream?.Codec; } @@ -589,7 +589,7 @@ namespace MediaBrowser.Controller.MediaEncoding get { if (BaseRequest.Static - || string.Equals(OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase)) + || EncodingHelper.IsCopyCodec(OutputVideoCodec)) { return VideoStream?.IsInterlaced; } @@ -607,7 +607,7 @@ namespace MediaBrowser.Controller.MediaEncoding { get { - if (BaseRequest.Static || string.Equals(OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase)) + if (BaseRequest.Static || EncodingHelper.IsCopyCodec(OutputVideoCodec)) { return VideoStream?.IsAVC; } diff --git a/MediaBrowser.Model/Configuration/EncodingOptions.cs b/MediaBrowser.Model/Configuration/EncodingOptions.cs index 648568fd7..5880730fd 100644 --- a/MediaBrowser.Model/Configuration/EncodingOptions.cs +++ b/MediaBrowser.Model/Configuration/EncodingOptions.cs @@ -5,10 +5,15 @@ namespace MediaBrowser.Model.Configuration public class EncodingOptions { public int EncodingThreadCount { get; set; } + public string TranscodingTempPath { get; set; } + public double DownMixAudioBoost { get; set; } + public bool EnableThrottling { get; set; } + public int ThrottleDelaySeconds { get; set; } + public string HardwareAccelerationType { get; set; } /// @@ -20,12 +25,19 @@ namespace MediaBrowser.Model.Configuration /// The current FFmpeg path being used by the system and displayed on the transcode page. /// public string EncoderAppPathDisplay { get; set; } + public string VaapiDevice { get; set; } + public int H264Crf { get; set; } + public int H265Crf { get; set; } + public string EncoderPreset { get; set; } + public string DeinterlaceMethod { get; set; } + public bool EnableHardwareEncoding { get; set; } + public bool EnableSubtitleExtraction { get; set; } public string[] HardwareDecodingCodecs { get; set; } -- cgit v1.2.3 From e42bfc92f3e072a3d51dddce06bc90587e06791c Mon Sep 17 00:00:00 2001 From: gion Date: Tue, 26 May 2020 11:37:52 +0200 Subject: Fix code issues --- .../HttpServer/WebSocketConnection.cs | 6 ++-- .../Session/SessionWebSocketListener.cs | 10 +++--- .../SyncPlay/SyncPlayController.cs | 37 ++-------------------- .../SyncPlay/SyncPlayManager.cs | 1 + MediaBrowser.Api/SyncPlay/SyncPlayService.cs | 4 +-- MediaBrowser.Controller/SyncPlay/GroupInfo.cs | 9 +++--- 6 files changed, 19 insertions(+), 48 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs b/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs index 1f5a7d177..0680c5ffe 100644 --- a/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs +++ b/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs @@ -223,7 +223,7 @@ namespace Emby.Server.Implementations.HttpServer if (info.MessageType.Equals("KeepAlive", StringComparison.Ordinal)) { - SendKeepAliveResponse(); + await SendKeepAliveResponse(); } else { @@ -231,10 +231,10 @@ namespace Emby.Server.Implementations.HttpServer } } - private void SendKeepAliveResponse() + private Task SendKeepAliveResponse() { LastKeepAliveDate = DateTime.UtcNow; - SendAsync(new WebSocketMessage + return SendAsync(new WebSocketMessage { MessageType = "KeepAlive" }, CancellationToken.None); diff --git a/Emby.Server.Implementations/Session/SessionWebSocketListener.cs b/Emby.Server.Implementations/Session/SessionWebSocketListener.cs index 3af18f681..e7b4b0ec3 100644 --- a/Emby.Server.Implementations/Session/SessionWebSocketListener.cs +++ b/Emby.Server.Implementations/Session/SessionWebSocketListener.cs @@ -87,13 +87,13 @@ namespace Emby.Server.Implementations.Session httpServer.WebSocketConnected += OnServerManagerWebSocketConnected; } - private void OnServerManagerWebSocketConnected(object sender, GenericEventArgs e) + private async void OnServerManagerWebSocketConnected(object sender, GenericEventArgs e) { var session = GetSession(e.Argument.QueryString, e.Argument.RemoteEndPoint.ToString()); if (session != null) { EnsureController(session, e.Argument); - KeepAliveWebSocket(e.Argument); + await KeepAliveWebSocket(e.Argument); } else { @@ -149,7 +149,7 @@ namespace Emby.Server.Implementations.Session /// The event arguments. private void OnWebSocketClosed(object sender, EventArgs e) { - var webSocket = (IWebSocketConnection) sender; + var webSocket = (IWebSocketConnection)sender; _logger.LogDebug("WebSocket {0} is closed.", webSocket); RemoveWebSocket(webSocket); } @@ -158,7 +158,7 @@ namespace Emby.Server.Implementations.Session /// Adds a WebSocket to the KeepAlive watchlist. /// /// The WebSocket to monitor. - private void KeepAliveWebSocket(IWebSocketConnection webSocket) + private async Task KeepAliveWebSocket(IWebSocketConnection webSocket) { lock (_webSocketsLock) { @@ -176,7 +176,7 @@ namespace Emby.Server.Implementations.Session // Notify WebSocket about timeout try { - SendForceKeepAlive(webSocket).Wait(); + await SendForceKeepAlive(webSocket); } catch (WebSocketException exception) { diff --git a/Emby.Server.Implementations/SyncPlay/SyncPlayController.cs b/Emby.Server.Implementations/SyncPlay/SyncPlayController.cs index c7bd242a7..d430d4d16 100644 --- a/Emby.Server.Implementations/SyncPlay/SyncPlayController.cs +++ b/Emby.Server.Implementations/SyncPlay/SyncPlayController.cs @@ -16,7 +16,7 @@ namespace Emby.Server.Implementations.SyncPlay /// /// Class is not thread-safe, external locking is required when accessing methods. /// - public class SyncPlayController : ISyncPlayController, IDisposable + public class SyncPlayController : ISyncPlayController { /// /// Used to filter the sessions of a group. @@ -65,8 +65,6 @@ namespace Emby.Server.Implementations.SyncPlay /// public bool IsGroupEmpty() => _group.IsEmpty(); - private bool _disposed = false; - public SyncPlayController( ISessionManager sessionManager, ISyncPlayManager syncPlayManager) @@ -75,36 +73,6 @@ namespace Emby.Server.Implementations.SyncPlay _syncPlayManager = syncPlayManager; } - /// - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - /// - /// Releases unmanaged and optionally managed resources. - /// - /// true to release both managed and unmanaged resources; false to release only unmanaged resources. - protected virtual void Dispose(bool disposing) - { - if (_disposed) - { - return; - } - - _disposed = true; - } - - // TODO: use this somewhere - private void CheckDisposed() - { - if (_disposed) - { - throw new ObjectDisposedException(GetType().Name); - } - } - /// /// Converts DateTime to UTC string. /// @@ -518,6 +486,7 @@ namespace Emby.Server.Implementations.SyncPlay var runTimeTicks = _group.PlayingItem.RunTimeTicks ?? 0; ticks = ticks > runTimeTicks ? runTimeTicks : ticks; } + return ticks; } @@ -541,7 +510,7 @@ namespace Emby.Server.Implementations.SyncPlay PlayingItemName = _group.PlayingItem.Name, PlayingItemId = _group.PlayingItem.Id.ToString(), PositionTicks = _group.PositionTicks, - Participants = _group.Participants.Values.Select(session => session.Session.UserName).Distinct().ToList().AsReadOnly() + Participants = _group.Participants.Values.Select(session => session.Session.UserName).Distinct().ToList() }; } } diff --git a/Emby.Server.Implementations/SyncPlay/SyncPlayManager.cs b/Emby.Server.Implementations/SyncPlay/SyncPlayManager.cs index 93cec1304..1f76dd4e3 100644 --- a/Emby.Server.Implementations/SyncPlay/SyncPlayManager.cs +++ b/Emby.Server.Implementations/SyncPlay/SyncPlayManager.cs @@ -374,6 +374,7 @@ namespace Emby.Server.Implementations.SyncPlay { throw new InvalidOperationException("Session in other group already!"); } + _sessionToGroupMap[session.Id] = group; } diff --git a/MediaBrowser.Api/SyncPlay/SyncPlayService.cs b/MediaBrowser.Api/SyncPlay/SyncPlayService.cs index 8064ea7dc..1e14ea552 100644 --- a/MediaBrowser.Api/SyncPlay/SyncPlayService.cs +++ b/MediaBrowser.Api/SyncPlay/SyncPlayService.cs @@ -182,7 +182,7 @@ namespace MediaBrowser.Api.SyncPlay } // Both null and empty strings mean that client isn't playing anything - if (!String.IsNullOrEmpty(request.PlayingItemId) && !Guid.TryParse(request.PlayingItemId, out playingItemId)) + if (!string.IsNullOrEmpty(request.PlayingItemId) && !Guid.TryParse(request.PlayingItemId, out playingItemId)) { Logger.LogError("JoinGroup: {0} is not a valid format for PlayingItemId. Ignoring request.", request.PlayingItemId); return; @@ -217,7 +217,7 @@ namespace MediaBrowser.Api.SyncPlay var currentSession = GetSession(_sessionContext); var filterItemId = Guid.Empty; - if (!String.IsNullOrEmpty(request.FilterItemId) && !Guid.TryParse(request.FilterItemId, out filterItemId)) + if (!string.IsNullOrEmpty(request.FilterItemId) && !Guid.TryParse(request.FilterItemId, out filterItemId)) { Logger.LogWarning("ListGroups: {0} is not a valid format for FilterItemId. Ignoring filter.", request.FilterItemId); } diff --git a/MediaBrowser.Controller/SyncPlay/GroupInfo.cs b/MediaBrowser.Controller/SyncPlay/GroupInfo.cs index bda49bd1b..28a3ac505 100644 --- a/MediaBrowser.Controller/SyncPlay/GroupInfo.cs +++ b/MediaBrowser.Controller/SyncPlay/GroupInfo.cs @@ -16,12 +16,13 @@ namespace MediaBrowser.Controller.SyncPlay /// /// Default ping value used for sessions. /// - public readonly long DefaulPing = 500; + public long DefaulPing { get; } = 500; + /// /// Gets or sets the group identifier. /// /// The group identifier. - public readonly Guid GroupId = Guid.NewGuid(); + public Guid GroupId { get; } = Guid.NewGuid(); /// /// Gets or sets the playing item. @@ -51,7 +52,7 @@ namespace MediaBrowser.Controller.SyncPlay /// Gets the participants. /// /// The participants, or members of the group. - public readonly Dictionary Participants = + public Dictionary Participants { get; } = new Dictionary(StringComparer.OrdinalIgnoreCase); /// @@ -85,7 +86,6 @@ namespace MediaBrowser.Controller.SyncPlay /// Removes the session from the group. /// /// The session. - public void RemoveSession(SessionInfo session) { if (!ContainsSession(session.Id.ToString())) @@ -153,6 +153,7 @@ namespace MediaBrowser.Controller.SyncPlay return true; } } + return false; } -- cgit v1.2.3 From b4b93995f7f05971bd8532cadc9b80db07de9ab3 Mon Sep 17 00:00:00 2001 From: nyanmisaka Date: Thu, 9 Apr 2020 00:15:01 +0800 Subject: add more separate hw decoding toggles --- .../MediaEncoding/EncodingHelper.cs | 267 ++++++++++++++++++--- .../MediaEncoding/IMediaEncoder.cs | 15 +- .../Encoder/EncoderValidator.cs | 77 ++++-- MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 13 + .../Subtitles/SubtitleEncoder.cs | 2 +- .../Configuration/EncodingOptions.cs | 2 + 6 files changed, 330 insertions(+), 46 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 61a330675..807ba4e93 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -103,6 +103,11 @@ namespace MediaBrowser.Controller.MediaEncoding return false; } + if (!_mediaEncoder.SupportsHwaccel("vaapi")) + { + return false; + } + return true; } @@ -444,18 +449,30 @@ namespace MediaBrowser.Controller.MediaEncoding public string GetInputArgument(EncodingJobInfo state, EncodingOptions encodingOptions) { var arg = new StringBuilder(); + var videoDecoder = GetHardwareAcceleratedVideoDecoder(state, encodingOptions); + var outputVideoCodec = GetVideoEncoder(state, encodingOptions); - if (state.IsVideoRequest - && string.Equals(encodingOptions.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase)) + if (state.IsVideoRequest && string.Equals(encodingOptions.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase)) { - arg.Append("-hwaccel vaapi -hwaccel_output_format vaapi") - .Append(" -vaapi_device ") - .Append(encodingOptions.VaapiDevice) - .Append(' '); + // While using VAAPI decoder + if ((videoDecoder ?? string.Empty).IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1) + { + arg.Append("-hwaccel_output_format vaapi") + .Append(" -vaapi_device ") + .Append(encodingOptions.VaapiDevice) + .Append(" "); + } + // While using SW decoder and VAAPI encoder + else if ((videoDecoder ?? string.Empty).IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) == -1 + && (outputVideoCodec ?? string.Empty).IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1) + { + arg.Append("-vaapi_device ") + .Append(encodingOptions.VaapiDevice) + .Append(" "); + } } - if (state.IsVideoRequest - && string.Equals(encodingOptions.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase)) + if (state.IsVideoRequest && string.Equals(encodingOptions.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase)) { var videoDecoder = GetHardwareAcceleratedVideoDecoder(state, encodingOptions); var outputVideoCodec = GetVideoEncoder(state, encodingOptions); @@ -1655,7 +1672,7 @@ namespace MediaBrowser.Controller.MediaEncoding For software decoding and hardware encoding option, frames must be hwuploaded into hardware with fixed frame size. */ - if (!string.IsNullOrEmpty(videoDecoder) && videoDecoder.Contains("qsv", StringComparison.OrdinalIgnoreCase)) + if ((videoDecoder ?? string.Empty).IndexOf("qsv", StringComparison.OrdinalIgnoreCase) != -1) { retStr = " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}][sub]overlay_qsv=x=(W-w)/2:y=(H-h)/2{3}\""; } @@ -2511,16 +2528,15 @@ namespace MediaBrowser.Controller.MediaEncoding /// protected string GetHardwareAcceleratedVideoDecoder(EncodingJobInfo state, EncodingOptions encodingOptions) { + var videoType = state.MediaSource.VideoType ?? VideoType.VideoFile; + var videoStream = state.VideoStream; + var IsColorDepth10 = (videoStream.Profile ?? string.Empty).IndexOf("10", StringComparison.OrdinalIgnoreCase) != -1; + if (string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase)) { return null; } - return GetHardwareAcceleratedVideoDecoder(state.MediaSource.VideoType ?? VideoType.VideoFile, state.VideoStream, encodingOptions); - } - - public string GetHardwareAcceleratedVideoDecoder(VideoType videoType, MediaStream videoStream, EncodingOptions encodingOptions) - { // Only use alternative encoders for video files. // When using concat with folder rips, if the mfx session fails to initialize, ffmpeg will be stuck retrying and will not exit gracefully // Since transcoding of folder rips is expiremental anyway, it's not worth adding additional variables such as this. @@ -2533,6 +2549,14 @@ namespace MediaBrowser.Controller.MediaEncoding && !string.IsNullOrEmpty(videoStream.Codec) && !string.IsNullOrEmpty(encodingOptions.HardwareAccelerationType)) { + // Only hevc and vp9 formats have 10-bit hardware decoder support now. + if (IsColorDepth10 && !(string.Equals(videoStream.Codec, "hevc", StringComparison.OrdinalIgnoreCase) + || string.Equals(videoStream.Codec, "h265", StringComparison.OrdinalIgnoreCase) + || string.Equals(videoStream.Codec, "vp9", StringComparison.OrdinalIgnoreCase))) + { + return null; + } + if (string.Equals(encodingOptions.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase)) { switch (videoStream.Codec.ToLowerInvariant()) @@ -2554,8 +2578,17 @@ namespace MediaBrowser.Controller.MediaEncoding case "h265": if (_mediaEncoder.SupportsDecoder("hevc_qsv") && encodingOptions.HardwareDecodingCodecs.Contains("hevc", StringComparer.OrdinalIgnoreCase)) { - //return "-c:v hevc_qsv -load_plugin hevc_hw "; - return "-c:v hevc_qsv"; + if (IsColorDepth10) + { + if (encodingOptions.EnableDecodingColorDepth10) + { + return "-c:v hevc_qsv "; + } + + return null; + } + + return "-c:v hevc_qsv "; } break; case "mpeg2video": @@ -2570,6 +2603,28 @@ namespace MediaBrowser.Controller.MediaEncoding return "-c:v vc1_qsv"; } break; + case "vp8": + if (_mediaEncoder.SupportsDecoder("vp8_qsv") && encodingOptions.HardwareDecodingCodecs.Contains("vp8", StringComparer.OrdinalIgnoreCase)) + { + return "-c:v vp8_qsv "; + } + break; + case "vp9": + if (_mediaEncoder.SupportsDecoder("vp9_qsv") && encodingOptions.HardwareDecodingCodecs.Contains("vp9", StringComparer.OrdinalIgnoreCase)) + { + if (IsColorDepth10) + { + if (encodingOptions.EnableDecodingColorDepth10) + { + return "-c:v vp9_qsv "; + } + + return null; + } + + return "-c:v vp9_qsv "; + } + break; } } @@ -2594,7 +2649,17 @@ namespace MediaBrowser.Controller.MediaEncoding case "h265": if (_mediaEncoder.SupportsDecoder("hevc_cuvid") && encodingOptions.HardwareDecodingCodecs.Contains("hevc", StringComparer.OrdinalIgnoreCase)) { - return "-c:v hevc_cuvid"; + if (IsColorDepth10) + { + if (encodingOptions.EnableDecodingColorDepth10) + { + return "-c:v hevc_cuvid "; + } + + return null; + } + + return "-c:v hevc_cuvid "; } break; case "mpeg2video": @@ -2615,6 +2680,28 @@ namespace MediaBrowser.Controller.MediaEncoding return "-c:v mpeg4_cuvid"; } break; + case "vp8": + if (_mediaEncoder.SupportsDecoder("vp8_cuvid") && encodingOptions.HardwareDecodingCodecs.Contains("vp8", StringComparer.OrdinalIgnoreCase)) + { + return "-c:v vp8_cuvid "; + } + break; + case "vp9": + if (_mediaEncoder.SupportsDecoder("vp9_cuvid") && encodingOptions.HardwareDecodingCodecs.Contains("vp9", StringComparer.OrdinalIgnoreCase)) + { + if (IsColorDepth10) + { + if (encodingOptions.EnableDecodingColorDepth10) + { + return "-c:v vp9_cuvid "; + } + + return null; + } + + return "-c:v vp9_cuvid "; + } + break; } } @@ -2633,7 +2720,17 @@ namespace MediaBrowser.Controller.MediaEncoding case "h265": if (_mediaEncoder.SupportsDecoder("hevc_mediacodec") && encodingOptions.HardwareDecodingCodecs.Contains("hevc", StringComparer.OrdinalIgnoreCase)) { - return "-c:v hevc_mediacodec"; + if (IsColorDepth10) + { + if (encodingOptions.EnableDecodingColorDepth10) + { + return "-c:v hevc_mediacodec "; + } + + return null; + } + + return "-c:v hevc_mediacodec "; } break; case "mpeg2video": @@ -2657,7 +2754,17 @@ namespace MediaBrowser.Controller.MediaEncoding case "vp9": if (_mediaEncoder.SupportsDecoder("vp9_mediacodec") && encodingOptions.HardwareDecodingCodecs.Contains("vp9", StringComparer.OrdinalIgnoreCase)) { - return "-c:v vp9_mediacodec"; + if (IsColorDepth10) + { + if (encodingOptions.EnableDecodingColorDepth10) + { + return "-c:v vp9_mediacodec "; + } + + return null; + } + + return "-c:v vp9_mediacodec "; } break; } @@ -2697,27 +2804,133 @@ namespace MediaBrowser.Controller.MediaEncoding else if (string.Equals(encodingOptions.HardwareAccelerationType, "amf", StringComparison.OrdinalIgnoreCase)) { - if (Environment.OSVersion.Platform == PlatformID.Win32NT) + switch (videoStream.Codec.ToLowerInvariant()) { - if (Environment.OSVersion.Version.Major > 6 || (Environment.OSVersion.Version.Major == 6 && Environment.OSVersion.Version.Minor > 1)) - return "-hwaccel d3d11va"; - else - return "-hwaccel dxva2"; + case "avc": + case "h264": + return GetHwaccelType(state, encodingOptions, "h264"); + case "hevc": + case "h265": + if (IsColorDepth10) + { + if (encodingOptions.EnableDecodingColorDepth10) + { + return GetHwaccelType(state, encodingOptions, "hevc"); + } + + return null; + } + + return GetHwaccelType(state, encodingOptions, "hevc"); + case "mpeg2video": + return GetHwaccelType(state, encodingOptions, "mpeg2video"); + case "vc1": + return GetHwaccelType(state, encodingOptions, "vc1"); + case "mpeg4": + return GetHwaccelType(state, encodingOptions, "mpeg4"); + case "vp9": + if (IsColorDepth10) + { + if (encodingOptions.EnableDecodingColorDepth10) + { + return GetHwaccelType(state, encodingOptions, "vp9"); + } + + return null; + } + + return GetHwaccelType(state, encodingOptions, "vp9"); } - else + } + + else if (string.Equals(encodingOptions.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase)) + { + switch (videoStream.Codec.ToLowerInvariant()) { - return "-hwaccel vaapi"; + case "avc": + case "h264": + return GetHwaccelType(state, encodingOptions, "h264"); + case "hevc": + case "h265": + if (IsColorDepth10) + { + if (encodingOptions.EnableDecodingColorDepth10) + { + return GetHwaccelType(state, encodingOptions, "hevc"); + } + + return null; + } + + return GetHwaccelType(state, encodingOptions, "hevc"); + case "mpeg2video": + return GetHwaccelType(state, encodingOptions, "mpeg2video"); + case "vc1": + return GetHwaccelType(state, encodingOptions, "vc1"); + case "vp8": + return GetHwaccelType(state, encodingOptions, "vp8"); + case "vp9": + if (IsColorDepth10) + { + if (encodingOptions.EnableDecodingColorDepth10) + { + return GetHwaccelType(state, encodingOptions, "vp9"); + } + + return null; + } + + return GetHwaccelType(state, encodingOptions, "vp9"); } } } + var whichCodec = videoStream.Codec.ToLowerInvariant(); + switch (whichCodec) + { + case "avc": + whichCodec = "h264"; + break; + case "h265": + whichCodec = "hevc"; + break; + } + // Avoid a second attempt if no hardware acceleration is being used - encodingOptions.HardwareDecodingCodecs = Array.Empty(); + encodingOptions.HardwareDecodingCodecs = encodingOptions.HardwareDecodingCodecs.Where(val => val != whichCodec).ToArray(); // leave blank so ffmpeg will decide return null; } + /// + /// Gets a hwaccel type to use as a hardware decoder(dxva/vaapi) depending on the system + /// + public string GetHwaccelType(EncodingJobInfo state, EncodingOptions options, string videoCodec) + { + var IsWindows = Environment.OSVersion.Platform == PlatformID.Win32NT; + var IsNewWindows = Environment.OSVersion.Version.Major > 6 || (Environment.OSVersion.Version.Major == 6 && Environment.OSVersion.Version.Minor > 1); + var IsDxvaSupported = _mediaEncoder.SupportsHwaccel("dxva2") || _mediaEncoder.SupportsHwaccel("d3d11va"); + + if ((IsDxvaSupported || IsVaapiSupported(state)) && options.HardwareDecodingCodecs.Contains(videoCodec, StringComparer.OrdinalIgnoreCase)) + { + if (!IsWindows) + { + return "-hwaccel vaapi "; + } + else if (IsWindows && IsNewWindows) + { + return "-hwaccel d3d11va "; + } + else if (IsWindows && !IsNewWindows) + { + return "-hwaccel dxva2 "; + } + } + + return null; + } + public string GetSubtitleEmbedArguments(EncodingJobInfo state) { if (state.SubtitleStream == null || state.SubtitleDeliveryMethod != SubtitleDeliveryMethod.Embed) diff --git a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs index 37f0b11a7..6fa3bed48 100644 --- a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs +++ b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs @@ -26,6 +26,13 @@ namespace MediaBrowser.Controller.MediaEncoding /// The encoder path. string EncoderPath { get; } + /// + /// Supportses the encoder. + /// + /// The encoder. + /// true if XXXX, false otherwise. + bool SupportsEncoder(string encoder); + /// /// Supportses the decoder. /// @@ -33,6 +40,13 @@ namespace MediaBrowser.Controller.MediaEncoding /// true if XXXX, false otherwise. bool SupportsDecoder(string decoder); + /// + /// Supportses the hwaccel. + /// + /// The hwaccel. + /// true if XXXX, false otherwise. + bool SupportsHwaccel(string hwaccel); + /// /// Extracts the audio image. /// @@ -98,7 +112,6 @@ namespace MediaBrowser.Controller.MediaEncoding void SetFFmpegPath(); void UpdateEncoderPath(string path, string pathType); - bool SupportsEncoder(string encoder); IEnumerable GetPrimaryPlaylistVobFiles(string path, IIsoMount isoMount, uint? titleNumber); } diff --git a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs index 6e036d24c..e329f605d 100644 --- a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs +++ b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs @@ -14,23 +14,38 @@ namespace MediaBrowser.MediaEncoding.Encoder private static readonly string[] requiredDecoders = new[] { + "h264", + "hevc", "mpeg2video", + "mpeg4", + "msmpeg4", + "dts", + "ac3", + "aac", + "mp3", "h264_qsv", "hevc_qsv", "mpeg2_qsv", - "mpeg2_mmal", - "mpeg4_mmal", "vc1_qsv", - "vc1_mmal", + "vp8_qsv", + "vp9_qsv", "h264_cuvid", "hevc_cuvid", - "dts", - "ac3", - "aac", - "mp3", - "h264", + "mpeg2_cuvid", + "vc1_cuvid", + "mpeg4_cuvid", + "vp8_cuvid", + "vp9_cuvid", "h264_mmal", - "hevc" + "mpeg2_mmal", + "mpeg4_mmal", + "vc1_mmal", + "h264_mediacodec", + "hevc_mediacodec", + "mpeg2_mediacodec", + "mpeg4_mediacodec", + "vp8_mediacodec", + "vp9_mediacodec" }; private static readonly string[] requiredEncoders = new[] @@ -43,22 +58,22 @@ namespace MediaBrowser.MediaEncoding.Encoder "libvpx-vp9", "aac", "libfdk_aac", + "ac3", "libmp3lame", "libopus", "libvorbis", "srt", - "h264_nvenc", - "hevc_nvenc", + "h264_amf", + "hevc_amf", "h264_qsv", "hevc_qsv", - "h264_omx", - "hevc_omx", + "h264_nvenc", + "hevc_nvenc", "h264_vaapi", "hevc_vaapi", - "h264_v4l2m2m", - "ac3", - "h264_amf", - "hevc_amf" + "h264_omx", + "hevc_omx", + "h264_v4l2m2m" }; // Try and use the individual library versions to determine a FFmpeg version @@ -159,6 +174,8 @@ namespace MediaBrowser.MediaEncoding.Encoder public IEnumerable GetEncoders() => GetCodecs(Codec.Encoder); + public IEnumerable GetHwaccels() => GetHwaccelTypes(); + /// /// Using the output from "ffmpeg -version" work out the FFmpeg version. /// For pre-built binaries the first line should contain a string like "ffmpeg version x.y", which is easy @@ -218,6 +235,32 @@ namespace MediaBrowser.MediaEncoding.Encoder Decoder } + private IEnumerable GetHwaccelTypes() + { + string output = null; + try + { + output = GetProcessOutput(_encoderPath, "-hwaccels"); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error detecting available hwaccel types"); + } + + if (string.IsNullOrWhiteSpace(output)) + { + return Enumerable.Empty(); + } + + var found = output.Split(new char[] {'\r','\n'},StringSplitOptions.RemoveEmptyEntries).Distinct().ToList(); + + found.RemoveAt(0); + + _logger.LogInformation("Available hwaccel types: {Types}", found); + + return found; + } + private IEnumerable GetCodecs(Codec codec) { string codecstr = codec == Codec.Encoder ? "encoders" : "decoders"; diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index 1377502dd..4cc971809 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -111,6 +111,7 @@ namespace MediaBrowser.MediaEncoding.Encoder SetAvailableDecoders(validator.GetDecoders()); SetAvailableEncoders(validator.GetEncoders()); + SetAvailableHwaccels(validator.GetHwaccels()); } _logger.LogInformation("FFmpeg: {EncoderLocation}: {FfmpegPath}", EncoderLocation, _ffmpegPath ?? string.Empty); @@ -257,6 +258,13 @@ namespace MediaBrowser.MediaEncoding.Encoder //_logger.Info("Supported decoders: {0}", string.Join(",", list.ToArray())); } + private List _hwaccels = new List(); + public void SetAvailableHwaccels(IEnumerable list) + { + _hwaccels = list.ToList(); + //_logger.Info("Supported hwaccels: {0}", string.Join(",", list.ToArray())); + } + public bool SupportsEncoder(string encoder) { return _encoders.Contains(encoder, StringComparer.OrdinalIgnoreCase); @@ -267,6 +275,11 @@ namespace MediaBrowser.MediaEncoding.Encoder return _decoders.Contains(decoder, StringComparer.OrdinalIgnoreCase); } + public bool SupportsHwaccel(string hwaccel) + { + return _hwaccels.Contains(hwaccel, StringComparer.OrdinalIgnoreCase); + } + public bool CanEncodeToAudioCodec(string codec) { if (string.Equals(codec, "opus", StringComparison.OrdinalIgnoreCase)) diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs index ba171295e..7d85f6ef7 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs @@ -737,7 +737,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles var charset = CharsetDetector.DetectFromStream(stream).Detected?.EncodingName; // UTF16 is automatically converted to UTF8 by FFmpeg, do not specify a character encoding - if ((path.EndsWith(".ass") || path.EndsWith(".ssa")) + if ((path.EndsWith(".ass") || path.EndsWith(".ssa") || path.EndsWith(".srt")) && (string.Equals(charset, "utf-16le", StringComparison.OrdinalIgnoreCase) || string.Equals(charset, "utf-16be", StringComparison.OrdinalIgnoreCase))) { diff --git a/MediaBrowser.Model/Configuration/EncodingOptions.cs b/MediaBrowser.Model/Configuration/EncodingOptions.cs index 648568fd7..dfc0deea9 100644 --- a/MediaBrowser.Model/Configuration/EncodingOptions.cs +++ b/MediaBrowser.Model/Configuration/EncodingOptions.cs @@ -25,6 +25,7 @@ namespace MediaBrowser.Model.Configuration public int H265Crf { get; set; } public string EncoderPreset { get; set; } public string DeinterlaceMethod { get; set; } + public bool EnableDecodingColorDepth10 { get; set; } public bool EnableHardwareEncoding { get; set; } public bool EnableSubtitleExtraction { get; set; } @@ -41,6 +42,7 @@ namespace MediaBrowser.Model.Configuration H264Crf = 23; H265Crf = 28; DeinterlaceMethod = "yadif"; + EnableDecodingColorDepth10 = true; EnableHardwareEncoding = true; EnableSubtitleExtraction = true; HardwareDecodingCodecs = new string[] { "h264", "vc1" }; -- cgit v1.2.3 From c4ba71d96a4f8651a65b901861bf0f2c053f5f50 Mon Sep 17 00:00:00 2001 From: nyanmisaka Date: Thu, 9 Apr 2020 01:38:06 +0800 Subject: resolve conflicts --- MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 807ba4e93..1a12ff721 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -2019,7 +2019,7 @@ namespace MediaBrowser.Controller.MediaEncoding } // If we're hardware VAAPI decoding and software encoding, download frames from the decoder first - else if (IsVaapiSupported(state) && string.Equals(options.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase) + else if ((videoDecoder ?? string.Empty).IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1 && string.Equals(outputVideoCodec, "libx264", StringComparison.OrdinalIgnoreCase)) { var codec = videoStream.Codec.ToLowerInvariant(); -- cgit v1.2.3 From 161b2a2da95b35631d005cae48a651dcad6fe9a5 Mon Sep 17 00:00:00 2001 From: Nyanmisaka Date: Fri, 10 Apr 2020 23:40:56 +0800 Subject: minor changes --- .../MediaEncoding/EncodingHelper.cs | 46 +++++++++++----------- 1 file changed, 24 insertions(+), 22 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 1a12ff721..4a019321d 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -457,8 +457,8 @@ namespace MediaBrowser.Controller.MediaEncoding // While using VAAPI decoder if ((videoDecoder ?? string.Empty).IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1) { - arg.Append("-hwaccel_output_format vaapi") - .Append(" -vaapi_device ") + arg.Append("-hwaccel_output_format vaapi ") + .Append("-vaapi_device ") .Append(encodingOptions.VaapiDevice) .Append(" "); } @@ -1610,8 +1610,10 @@ namespace MediaBrowser.Controller.MediaEncoding // For VAAPI and CUVID decoder // these encoders cannot automatically adjust the size of graphical subtitles to fit the output video, // thus needs to be manually adjusted. - if ((IsVaapiSupported(state) && string.Equals(options.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase)) - || (videoDecoder ?? string.Empty).IndexOf("cuvid", StringComparison.OrdinalIgnoreCase) != -1) + if ((videoDecoder ?? string.Empty).IndexOf("cuvid", StringComparison.OrdinalIgnoreCase) != -1 + || (IsVaapiSupported(state) && string.Equals(options.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase) + && ((videoDecoder ?? string.Empty).IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1 + || (outputVideoCodec ?? string.Empty).IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1))) { var videoStream = state.VideoStream; var inputWidth = videoStream?.Width; @@ -1653,7 +1655,7 @@ namespace MediaBrowser.Controller.MediaEncoding } // If we're hardware VAAPI decoding and software encoding, download frames from the decoder first - else if (IsVaapiSupported(state) && string.Equals(options.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase) + else if (IsVaapiSupported(state) && (videoDecoder ?? string.Empty).IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1 && string.Equals(outputVideoCodec, "libx264", StringComparison.OrdinalIgnoreCase)) { /* @@ -2582,13 +2584,13 @@ namespace MediaBrowser.Controller.MediaEncoding { if (encodingOptions.EnableDecodingColorDepth10) { - return "-c:v hevc_qsv "; + return "-c:v hevc_qsv"; } return null; } - return "-c:v hevc_qsv "; + return "-c:v hevc_qsv"; } break; case "mpeg2video": @@ -2606,7 +2608,7 @@ namespace MediaBrowser.Controller.MediaEncoding case "vp8": if (_mediaEncoder.SupportsDecoder("vp8_qsv") && encodingOptions.HardwareDecodingCodecs.Contains("vp8", StringComparer.OrdinalIgnoreCase)) { - return "-c:v vp8_qsv "; + return "-c:v vp8_qsv"; } break; case "vp9": @@ -2616,13 +2618,13 @@ namespace MediaBrowser.Controller.MediaEncoding { if (encodingOptions.EnableDecodingColorDepth10) { - return "-c:v vp9_qsv "; + return "-c:v vp9_qsv"; } return null; } - return "-c:v vp9_qsv "; + return "-c:v vp9_qsv"; } break; } @@ -2653,13 +2655,13 @@ namespace MediaBrowser.Controller.MediaEncoding { if (encodingOptions.EnableDecodingColorDepth10) { - return "-c:v hevc_cuvid "; + return "-c:v hevc_cuvid"; } return null; } - return "-c:v hevc_cuvid "; + return "-c:v hevc_cuvid"; } break; case "mpeg2video": @@ -2683,7 +2685,7 @@ namespace MediaBrowser.Controller.MediaEncoding case "vp8": if (_mediaEncoder.SupportsDecoder("vp8_cuvid") && encodingOptions.HardwareDecodingCodecs.Contains("vp8", StringComparer.OrdinalIgnoreCase)) { - return "-c:v vp8_cuvid "; + return "-c:v vp8_cuvid"; } break; case "vp9": @@ -2693,13 +2695,13 @@ namespace MediaBrowser.Controller.MediaEncoding { if (encodingOptions.EnableDecodingColorDepth10) { - return "-c:v vp9_cuvid "; + return "-c:v vp9_cuvid"; } return null; } - return "-c:v vp9_cuvid "; + return "-c:v vp9_cuvid"; } break; } @@ -2724,13 +2726,13 @@ namespace MediaBrowser.Controller.MediaEncoding { if (encodingOptions.EnableDecodingColorDepth10) { - return "-c:v hevc_mediacodec "; + return "-c:v hevc_mediacodec"; } return null; } - return "-c:v hevc_mediacodec "; + return "-c:v hevc_mediacodec"; } break; case "mpeg2video": @@ -2758,13 +2760,13 @@ namespace MediaBrowser.Controller.MediaEncoding { if (encodingOptions.EnableDecodingColorDepth10) { - return "-c:v vp9_mediacodec "; + return "-c:v vp9_mediacodec"; } return null; } - return "-c:v vp9_mediacodec "; + return "-c:v vp9_mediacodec"; } break; } @@ -2916,15 +2918,15 @@ namespace MediaBrowser.Controller.MediaEncoding { if (!IsWindows) { - return "-hwaccel vaapi "; + return "-hwaccel vaapi"; } else if (IsWindows && IsNewWindows) { - return "-hwaccel d3d11va "; + return "-hwaccel d3d11va"; } else if (IsWindows && !IsNewWindows) { - return "-hwaccel dxva2 "; + return "-hwaccel dxva2"; } } -- cgit v1.2.3 From 695f20b3035621957e5db994478a2046a405c785 Mon Sep 17 00:00:00 2001 From: Nyanmisaka Date: Sat, 11 Apr 2020 01:21:26 +0800 Subject: probe Main/High 10 more specifically --- MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 4a019321d..fb8b50bf2 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -2532,7 +2532,8 @@ namespace MediaBrowser.Controller.MediaEncoding { var videoType = state.MediaSource.VideoType ?? VideoType.VideoFile; var videoStream = state.VideoStream; - var IsColorDepth10 = (videoStream.Profile ?? string.Empty).IndexOf("10", StringComparison.OrdinalIgnoreCase) != -1; + var IsColorDepth10 = (videoStream.Profile ?? string.Empty).IndexOf("Main 10", StringComparison.OrdinalIgnoreCase) != -1 + || (videoStream.Profile ?? string.Empty).IndexOf("High 10", StringComparison.OrdinalIgnoreCase) != -1; if (string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase)) { -- cgit v1.2.3 From 5fd3ea8b21cc48c4b7d0f4f29933ac8f9f4ad61a Mon Sep 17 00:00:00 2001 From: Nyanmisaka Date: Sun, 12 Apr 2020 17:37:30 +0800 Subject: minor changes --- .../MediaEncoding/EncodingHelper.cs | 26 +++++++++++----------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index fb8b50bf2..e0a2224ed 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -2532,8 +2532,8 @@ namespace MediaBrowser.Controller.MediaEncoding { var videoType = state.MediaSource.VideoType ?? VideoType.VideoFile; var videoStream = state.VideoStream; - var IsColorDepth10 = (videoStream.Profile ?? string.Empty).IndexOf("Main 10", StringComparison.OrdinalIgnoreCase) != -1 - || (videoStream.Profile ?? string.Empty).IndexOf("High 10", StringComparison.OrdinalIgnoreCase) != -1; + var isColorDepth10 = !string.IsNullOrEmpty(videoStream.Profile) && (videoStream.Profile.Contains("Main 10", StringComparison.OrdinalIgnoreCase) + || videoStream.Profile.Contains("High 10", StringComparison.OrdinalIgnoreCase)); if (string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase)) { @@ -2553,7 +2553,7 @@ namespace MediaBrowser.Controller.MediaEncoding && !string.IsNullOrEmpty(encodingOptions.HardwareAccelerationType)) { // Only hevc and vp9 formats have 10-bit hardware decoder support now. - if (IsColorDepth10 && !(string.Equals(videoStream.Codec, "hevc", StringComparison.OrdinalIgnoreCase) + if (isColorDepth10 && !(string.Equals(videoStream.Codec, "hevc", StringComparison.OrdinalIgnoreCase) || string.Equals(videoStream.Codec, "h265", StringComparison.OrdinalIgnoreCase) || string.Equals(videoStream.Codec, "vp9", StringComparison.OrdinalIgnoreCase))) { @@ -2581,7 +2581,7 @@ namespace MediaBrowser.Controller.MediaEncoding case "h265": if (_mediaEncoder.SupportsDecoder("hevc_qsv") && encodingOptions.HardwareDecodingCodecs.Contains("hevc", StringComparer.OrdinalIgnoreCase)) { - if (IsColorDepth10) + if (isColorDepth10) { if (encodingOptions.EnableDecodingColorDepth10) { @@ -2615,7 +2615,7 @@ namespace MediaBrowser.Controller.MediaEncoding case "vp9": if (_mediaEncoder.SupportsDecoder("vp9_qsv") && encodingOptions.HardwareDecodingCodecs.Contains("vp9", StringComparer.OrdinalIgnoreCase)) { - if (IsColorDepth10) + if (isColorDepth10) { if (encodingOptions.EnableDecodingColorDepth10) { @@ -2652,7 +2652,7 @@ namespace MediaBrowser.Controller.MediaEncoding case "h265": if (_mediaEncoder.SupportsDecoder("hevc_cuvid") && encodingOptions.HardwareDecodingCodecs.Contains("hevc", StringComparer.OrdinalIgnoreCase)) { - if (IsColorDepth10) + if (isColorDepth10) { if (encodingOptions.EnableDecodingColorDepth10) { @@ -2692,7 +2692,7 @@ namespace MediaBrowser.Controller.MediaEncoding case "vp9": if (_mediaEncoder.SupportsDecoder("vp9_cuvid") && encodingOptions.HardwareDecodingCodecs.Contains("vp9", StringComparer.OrdinalIgnoreCase)) { - if (IsColorDepth10) + if (isColorDepth10) { if (encodingOptions.EnableDecodingColorDepth10) { @@ -2723,7 +2723,7 @@ namespace MediaBrowser.Controller.MediaEncoding case "h265": if (_mediaEncoder.SupportsDecoder("hevc_mediacodec") && encodingOptions.HardwareDecodingCodecs.Contains("hevc", StringComparer.OrdinalIgnoreCase)) { - if (IsColorDepth10) + if (isColorDepth10) { if (encodingOptions.EnableDecodingColorDepth10) { @@ -2757,7 +2757,7 @@ namespace MediaBrowser.Controller.MediaEncoding case "vp9": if (_mediaEncoder.SupportsDecoder("vp9_mediacodec") && encodingOptions.HardwareDecodingCodecs.Contains("vp9", StringComparer.OrdinalIgnoreCase)) { - if (IsColorDepth10) + if (isColorDepth10) { if (encodingOptions.EnableDecodingColorDepth10) { @@ -2814,7 +2814,7 @@ namespace MediaBrowser.Controller.MediaEncoding return GetHwaccelType(state, encodingOptions, "h264"); case "hevc": case "h265": - if (IsColorDepth10) + if (isColorDepth10) { if (encodingOptions.EnableDecodingColorDepth10) { @@ -2832,7 +2832,7 @@ namespace MediaBrowser.Controller.MediaEncoding case "mpeg4": return GetHwaccelType(state, encodingOptions, "mpeg4"); case "vp9": - if (IsColorDepth10) + if (isColorDepth10) { if (encodingOptions.EnableDecodingColorDepth10) { @@ -2855,7 +2855,7 @@ namespace MediaBrowser.Controller.MediaEncoding return GetHwaccelType(state, encodingOptions, "h264"); case "hevc": case "h265": - if (IsColorDepth10) + if (isColorDepth10) { if (encodingOptions.EnableDecodingColorDepth10) { @@ -2873,7 +2873,7 @@ namespace MediaBrowser.Controller.MediaEncoding case "vp8": return GetHwaccelType(state, encodingOptions, "vp8"); case "vp9": - if (IsColorDepth10) + if (isColorDepth10) { if (encodingOptions.EnableDecodingColorDepth10) { -- cgit v1.2.3 From 22ef0e3574418ed22fe24db149613d71bb8daf9a Mon Sep 17 00:00:00 2001 From: Nyanmisaka Date: Mon, 13 Apr 2020 10:52:21 +0800 Subject: drop 'force_original_aspect_ratio' graphical subtitles can be off-center in some cases --- MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index e0a2224ed..f7aaf8645 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -1593,11 +1593,9 @@ namespace MediaBrowser.Controller.MediaEncoding // Setup subtitle scaling if (state.VideoStream != null && state.VideoStream.Width.HasValue && state.VideoStream.Height.HasValue) { - // force_original_aspect_ratio=decrease - // Enable decreasing output video width or height if necessary to keep the original aspect ratio videoSizeParam = string.Format( CultureInfo.InvariantCulture, - "scale={0}:{1}:force_original_aspect_ratio=decrease", + "scale={0}:{1}", state.VideoStream.Width.Value, state.VideoStream.Height.Value); @@ -1624,7 +1622,7 @@ namespace MediaBrowser.Controller.MediaEncoding { videoSizeParam = string.Format( CultureInfo.InvariantCulture, - "scale={0}:{1}:force_original_aspect_ratio=decrease", + "scale={0}:{1}", width.Value, height.Value); } -- cgit v1.2.3 From 0eb5791c702fb75ad74775ce41158cac8ef55d26 Mon Sep 17 00:00:00 2001 From: artiume Date: Mon, 25 May 2020 17:30:13 -0400 Subject: Comments --- .../MediaEncoding/EncodingHelper.cs | 124 ++++++--------------- 1 file changed, 33 insertions(+), 91 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index f7aaf8645..fe5d9c813 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -73,7 +73,8 @@ namespace MediaBrowser.Controller.MediaEncoding {"omx", hwEncoder + "_omx"}, {hwEncoder + "_v4l2m2m", hwEncoder + "_v4l2m2m"}, {"mediacodec", hwEncoder + "_mediacodec"}, - {"vaapi", hwEncoder + "_vaapi"} + {"vaapi", hwEncoder + "_vaapi"}, + {"videotoolbox", hwEncoder + "_videotoolbox"} }; if (!string.IsNullOrEmpty(hwType) @@ -103,12 +104,8 @@ namespace MediaBrowser.Controller.MediaEncoding return false; } - if (!_mediaEncoder.SupportsHwaccel("vaapi")) - { - return false; - } + if _mediaEncoder.SupportsHwaccel("vaapi"); - return true; } /// @@ -451,11 +448,15 @@ namespace MediaBrowser.Controller.MediaEncoding var arg = new StringBuilder(); var videoDecoder = GetHardwareAcceleratedVideoDecoder(state, encodingOptions); var outputVideoCodec = GetVideoEncoder(state, encodingOptions); + bool isVaapiDecoder = (videoDecoder ?? string.Empty).IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1; + bool isVaapiEncoder = (outputVideoCodec ?? string.Empty).IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1; + bool isQsvDecoder = (videoDecoder ?? string.Empty).IndexOf("qsv", StringComparison.OrdinalIgnoreCase) != -1; + bool isQsvEncoder = (outputVideoCodec ?? string.Empty).IndexOf("qsv", StringComparison.OrdinalIgnoreCase) != -1; - if (state.IsVideoRequest && string.Equals(encodingOptions.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase)) + if (state.IsVideoRequest + && string.Equals(encodingOptions.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase)) { - // While using VAAPI decoder - if ((videoDecoder ?? string.Empty).IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1) + if (isVaapiDecoder) { arg.Append("-hwaccel_output_format vaapi ") .Append("-vaapi_device ") @@ -463,8 +464,7 @@ namespace MediaBrowser.Controller.MediaEncoding .Append(" "); } // While using SW decoder and VAAPI encoder - else if ((videoDecoder ?? string.Empty).IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) == -1 - && (outputVideoCodec ?? string.Empty).IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1) + else if (!isVaapiDecoder && isVaapiEncoder) { arg.Append("-vaapi_device ") .Append(encodingOptions.VaapiDevice) @@ -472,7 +472,8 @@ namespace MediaBrowser.Controller.MediaEncoding } } - if (state.IsVideoRequest && string.Equals(encodingOptions.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase)) + if (state.IsVideoRequest + && string.Equals(encodingOptions.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase)) { var videoDecoder = GetHardwareAcceleratedVideoDecoder(state, encodingOptions); var outputVideoCodec = GetVideoEncoder(state, encodingOptions); @@ -481,11 +482,9 @@ namespace MediaBrowser.Controller.MediaEncoding if (!hasTextSubs) { - // While using QSV encoder - if ((outputVideoCodec ?? string.Empty).IndexOf("qsv", StringComparison.OrdinalIgnoreCase) != -1) + if (isQsvEncoder) { - // While using QSV decoder - if ((videoDecoder ?? string.Empty).IndexOf("qsv", StringComparison.OrdinalIgnoreCase) != -1) + if (isQsvDecoder) { arg.Append("-hwaccel qsv "); } @@ -543,6 +542,8 @@ namespace MediaBrowser.Controller.MediaEncoding || codec.IndexOf("hevc", StringComparison.OrdinalIgnoreCase) != -1; } + // TODO This is auto inserted into the mpegts mux so it might not be needed + // https://www.ffmpeg.org/ffmpeg-bitstream-filters.html#h264_005fmp4toannexb public string GetBitStreamArgs(MediaStream stream) { if (IsH264(stream)) @@ -567,8 +568,8 @@ namespace MediaBrowser.Controller.MediaEncoding { if (string.Equals(videoCodec, "libvpx", StringComparison.OrdinalIgnoreCase)) { - // With vpx when crf is used, b:v becomes a max rate - // https://trac.ffmpeg.org/wiki/vpxEncodingGuide. + // When crf is used with vpx, b:v becomes a max rate + // https://trac.ffmpeg.org/wiki/Encode/VP9 return string.Format( CultureInfo.InvariantCulture, " -maxrate:v {0} -bufsize:v {1} -b:v {0}", @@ -2579,17 +2580,8 @@ namespace MediaBrowser.Controller.MediaEncoding case "h265": if (_mediaEncoder.SupportsDecoder("hevc_qsv") && encodingOptions.HardwareDecodingCodecs.Contains("hevc", StringComparer.OrdinalIgnoreCase)) { - if (isColorDepth10) - { - if (encodingOptions.EnableDecodingColorDepth10) - { - return "-c:v hevc_qsv"; - } - - return null; - } - - return "-c:v hevc_qsv"; + return (isColorDepth10 && + !encodingOptions.EnableDecodingColorDepth10) ? null : "-c:v hevc_qsv"; } break; case "mpeg2video": @@ -2613,17 +2605,8 @@ namespace MediaBrowser.Controller.MediaEncoding case "vp9": if (_mediaEncoder.SupportsDecoder("vp9_qsv") && encodingOptions.HardwareDecodingCodecs.Contains("vp9", StringComparer.OrdinalIgnoreCase)) { - if (isColorDepth10) - { - if (encodingOptions.EnableDecodingColorDepth10) - { - return "-c:v vp9_qsv"; - } - - return null; - } - - return "-c:v vp9_qsv"; + return (isColorDepth10 && + !encodingOptions.EnableDecodingColorDepth10) ? null : "-c:v vp9_qsv"; } break; } @@ -2637,30 +2620,16 @@ namespace MediaBrowser.Controller.MediaEncoding case "h264": if (_mediaEncoder.SupportsDecoder("h264_cuvid") && encodingOptions.HardwareDecodingCodecs.Contains("h264", StringComparer.OrdinalIgnoreCase)) { - // cuvid decoder does not support 10-bit input - if ((videoStream.BitDepth ?? 8) > 8) - { - encodingOptions.HardwareDecodingCodecs = Array.Empty(); - return null; - } - return "-c:v h264_cuvid"; + return (isColorDepth10 && + !encodingOptions.EnableDecodingColorDepth10) ? null : "-c:v h264_cuvid"; } break; case "hevc": case "h265": if (_mediaEncoder.SupportsDecoder("hevc_cuvid") && encodingOptions.HardwareDecodingCodecs.Contains("hevc", StringComparer.OrdinalIgnoreCase)) { - if (isColorDepth10) - { - if (encodingOptions.EnableDecodingColorDepth10) - { - return "-c:v hevc_cuvid"; - } - - return null; - } - - return "-c:v hevc_cuvid"; + return (isColorDepth10 && + !encodingOptions.EnableDecodingColorDepth10) ? null : "-c:v hevc_cuvid"; } break; case "mpeg2video": @@ -2690,17 +2659,8 @@ namespace MediaBrowser.Controller.MediaEncoding case "vp9": if (_mediaEncoder.SupportsDecoder("vp9_cuvid") && encodingOptions.HardwareDecodingCodecs.Contains("vp9", StringComparer.OrdinalIgnoreCase)) { - if (isColorDepth10) - { - if (encodingOptions.EnableDecodingColorDepth10) - { - return "-c:v vp9_cuvid"; - } - - return null; - } - - return "-c:v vp9_cuvid"; + return (isColorDepth10 && + !encodingOptions.EnableDecodingColorDepth10) ? null : "-c:v vp9_cuvid"; } break; } @@ -2721,17 +2681,8 @@ namespace MediaBrowser.Controller.MediaEncoding case "h265": if (_mediaEncoder.SupportsDecoder("hevc_mediacodec") && encodingOptions.HardwareDecodingCodecs.Contains("hevc", StringComparer.OrdinalIgnoreCase)) { - if (isColorDepth10) - { - if (encodingOptions.EnableDecodingColorDepth10) - { - return "-c:v hevc_mediacodec"; - } - - return null; - } - - return "-c:v hevc_mediacodec"; + return (isColorDepth10 && + !encodingOptions.EnableDecodingColorDepth10) ? null : "-c:v hevc_mediacodec"; } break; case "mpeg2video": @@ -2755,17 +2706,8 @@ namespace MediaBrowser.Controller.MediaEncoding case "vp9": if (_mediaEncoder.SupportsDecoder("vp9_mediacodec") && encodingOptions.HardwareDecodingCodecs.Contains("vp9", StringComparer.OrdinalIgnoreCase)) { - if (isColorDepth10) - { - if (encodingOptions.EnableDecodingColorDepth10) - { - return "-c:v vp9_mediacodec"; - } - - return null; - } - - return "-c:v vp9_mediacodec"; + return (isColorDepth10 && + !encodingOptions.EnableDecodingColorDepth10) ? null : "-c:v vp9_mediacodec"; } break; } -- cgit v1.2.3 From 62e47d056d81a6f835050446be130e0a00e55150 Mon Sep 17 00:00:00 2001 From: artiume Date: Mon, 25 May 2020 17:43:26 -0400 Subject: Update IMediaEncoder.cs --- MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs index 6fa3bed48..393a411a1 100644 --- a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs +++ b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs @@ -27,21 +27,21 @@ namespace MediaBrowser.Controller.MediaEncoding string EncoderPath { get; } /// - /// Supportses the encoder. + /// Whether given encoder codec is supported. /// /// The encoder. /// true if XXXX, false otherwise. bool SupportsEncoder(string encoder); /// - /// Supportses the decoder. + /// Whether given decoder codec is supported. /// /// The decoder. /// true if XXXX, false otherwise. bool SupportsDecoder(string decoder); /// - /// Supportses the hwaccel. + /// Whether given hardware acceleration type is supported. /// /// The hwaccel. /// true if XXXX, false otherwise. -- cgit v1.2.3 From f056704c78e700d98d28d3c2688ba0ba1349bbf7 Mon Sep 17 00:00:00 2001 From: artiume Date: Mon, 25 May 2020 18:11:32 -0400 Subject: add videotoolbox --- .../MediaEncoding/EncodingHelper.cs | 32 ++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index fe5d9c813..b3aeac709 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -2826,6 +2826,38 @@ namespace MediaBrowser.Controller.MediaEncoding return GetHwaccelType(state, encodingOptions, "vp9"); } } + else if (string.Equals(encodingOptions.HardwareAccelerationType, "videotoolbox", StringComparison.OrdinalIgnoreCase)) + { + switch (videoStream.Codec.ToLowerInvariant()) + { + case "avc": + case "h264": + if (_mediaEncoder.SupportsDecoder("h264_videotoolbox") && encodingOptions.HardwareDecodingCodecs.Contains("h264", StringComparer.OrdinalIgnoreCase)) + { + return "-c:v h264_videotoolbox"; + } + break; + case "mpeg2video": + if (_mediaEncoder.SupportsDecoder("mpeg2_videotoolbox") && encodingOptions.HardwareDecodingCodecs.Contains("mpeg2video", StringComparer.OrdinalIgnoreCase)) + { + return "-c:v mpeg2_videotoolbox"; + } + break; + case "mpeg4": + if (_mediaEncoder.SupportsDecoder("mpeg4_videotoolbox") && encodingOptions.HardwareDecodingCodecs.Contains("mpeg4", StringComparer.OrdinalIgnoreCase)) + { + return "-c:v mpeg4_videotoolbox"; + } + break; + case "vc1": + if (_mediaEncoder.SupportsDecoder("vc1_videotoolbox") && encodingOptions.HardwareDecodingCodecs.Contains("vc1", StringComparer.OrdinalIgnoreCase)) + { + return "-c:v vc1_videotoolbox"; + } + break; + } + } + } var whichCodec = videoStream.Codec.ToLowerInvariant(); -- cgit v1.2.3 From abc7558f51d4bb21979b8115b4b73ad35fa075b6 Mon Sep 17 00:00:00 2001 From: artiume Date: Mon, 25 May 2020 18:12:54 -0400 Subject: Update EncodingHelper.cs --- MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index b3aeac709..50acc35f2 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -104,7 +104,7 @@ namespace MediaBrowser.Controller.MediaEncoding return false; } - if _mediaEncoder.SupportsHwaccel("vaapi"); + return _mediaEncoder.SupportsHwaccel("vaapi"); } -- cgit v1.2.3 From 628734931ceb87f265320cf83b3fd29710a03c2b Mon Sep 17 00:00:00 2001 From: Vasily Date: Tue, 26 May 2020 18:41:38 +0300 Subject: Fix missing commas and merge defects --- MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs | 3 --- MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs | 6 +++--- MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 2 +- 3 files changed, 4 insertions(+), 7 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 50acc35f2..94fa5c6c0 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -475,9 +475,6 @@ namespace MediaBrowser.Controller.MediaEncoding if (state.IsVideoRequest && string.Equals(encodingOptions.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase)) { - var videoDecoder = GetHardwareAcceleratedVideoDecoder(state, encodingOptions); - var outputVideoCodec = GetVideoEncoder(state, encodingOptions); - var hasTextSubs = state.SubtitleStream != null && state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode; if (!hasTextSubs) diff --git a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs index 89f33b048..f155379a0 100644 --- a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs +++ b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs @@ -45,7 +45,7 @@ namespace MediaBrowser.MediaEncoding.Encoder "mpeg2_mediacodec", "mpeg4_mediacodec", "vp8_mediacodec", - "vp9_mediacodec" + "vp9_mediacodec", "h264_videotoolbox", "hevc_videotoolbox", "mpeg2_videotoolbox", @@ -80,8 +80,8 @@ namespace MediaBrowser.MediaEncoding.Encoder "hevc_vaapi", "h264_omx", "hevc_omx", - "h264_v4l2m2m" - "h264_videotoolbox" + "h264_v4l2m2m", + "h264_videotoolbox", "hevc_videotoolbox" }; diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index c51b8c110..4cc971809 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -258,7 +258,7 @@ namespace MediaBrowser.MediaEncoding.Encoder //_logger.Info("Supported decoders: {0}", string.Join(",", list.ToArray())); } - private List _hwaccels = Array.Empty(); + private List _hwaccels = new List(); public void SetAvailableHwaccels(IEnumerable list) { _hwaccels = list.ToList(); -- cgit v1.2.3 From 3e381cfd5ef5a14d48cc904dc40ad1f6dc7a32e8 Mon Sep 17 00:00:00 2001 From: Vasily Date: Tue, 26 May 2020 19:02:22 +0300 Subject: Clean GetHwaccelType Windows handling a tiny bit --- MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 94fa5c6c0..761ea160e 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -2880,21 +2880,21 @@ namespace MediaBrowser.Controller.MediaEncoding /// public string GetHwaccelType(EncodingJobInfo state, EncodingOptions options, string videoCodec) { - var IsWindows = Environment.OSVersion.Platform == PlatformID.Win32NT; - var IsNewWindows = Environment.OSVersion.Version.Major > 6 || (Environment.OSVersion.Version.Major == 6 && Environment.OSVersion.Version.Minor > 1); - var IsDxvaSupported = _mediaEncoder.SupportsHwaccel("dxva2") || _mediaEncoder.SupportsHwaccel("d3d11va"); + var isWindows = Environment.OSVersion.Platform == PlatformID.Win32NT; + var isWindows8orLater = Environment.OSVersion.Version.Major > 6 || (Environment.OSVersion.Version.Major == 6 && Environment.OSVersion.Version.Minor > 1); + var isDxvaSupported = _mediaEncoder.SupportsHwaccel("dxva2") || _mediaEncoder.SupportsHwaccel("d3d11va"); - if ((IsDxvaSupported || IsVaapiSupported(state)) && options.HardwareDecodingCodecs.Contains(videoCodec, StringComparer.OrdinalIgnoreCase)) + if ((isDxvaSupported || IsVaapiSupported(state)) && options.HardwareDecodingCodecs.Contains(videoCodec, StringComparer.OrdinalIgnoreCase)) { - if (!IsWindows) + if (!isWindows) { return "-hwaccel vaapi"; } - else if (IsWindows && IsNewWindows) + else if (isWindows8orLater) { return "-hwaccel d3d11va"; } - else if (IsWindows && !IsNewWindows) + else { return "-hwaccel dxva2"; } -- cgit v1.2.3 From 92008baf85113897a37c8ca565216d4a1dca2a50 Mon Sep 17 00:00:00 2001 From: Vasily Date: Tue, 26 May 2020 19:12:13 +0300 Subject: Some simple cleanup --- .../MediaEncoding/EncodingHelper.cs | 29 +++++++++++----------- 1 file changed, 14 insertions(+), 15 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 761ea160e..cea9c7c15 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -446,12 +446,12 @@ namespace MediaBrowser.Controller.MediaEncoding public string GetInputArgument(EncodingJobInfo state, EncodingOptions encodingOptions) { var arg = new StringBuilder(); - var videoDecoder = GetHardwareAcceleratedVideoDecoder(state, encodingOptions); - var outputVideoCodec = GetVideoEncoder(state, encodingOptions); - bool isVaapiDecoder = (videoDecoder ?? string.Empty).IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1; - bool isVaapiEncoder = (outputVideoCodec ?? string.Empty).IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1; - bool isQsvDecoder = (videoDecoder ?? string.Empty).IndexOf("qsv", StringComparison.OrdinalIgnoreCase) != -1; - bool isQsvEncoder = (outputVideoCodec ?? string.Empty).IndexOf("qsv", StringComparison.OrdinalIgnoreCase) != -1; + var videoDecoder = GetHardwareAcceleratedVideoDecoder(state, encodingOptions) ?? string.Empty; + var outputVideoCodec = GetVideoEncoder(state, encodingOptions) ?? string.Empty; + bool isVaapiDecoder = videoDecoder.IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1; + bool isVaapiEncoder = outputVideoCodec.IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1; + bool isQsvDecoder = videoDecoder.IndexOf("qsv", StringComparison.OrdinalIgnoreCase) != -1; + bool isQsvEncoder = outputVideoCodec.IndexOf("qsv", StringComparison.OrdinalIgnoreCase) != -1; if (state.IsVideoRequest && string.Equals(encodingOptions.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase)) @@ -463,7 +463,6 @@ namespace MediaBrowser.Controller.MediaEncoding .Append(encodingOptions.VaapiDevice) .Append(" "); } - // While using SW decoder and VAAPI encoder else if (!isVaapiDecoder && isVaapiEncoder) { arg.Append("-vaapi_device ") @@ -1542,8 +1541,9 @@ namespace MediaBrowser.Controller.MediaEncoding EncodingOptions options, string outputVideoCodec) { - var outputSizeParam = string.Empty; + outputVideoCodec ??= string.Empty; + var outputSizeParam = string.Empty; var request = state.BaseRequest; // Add resolution params, if specified @@ -1586,7 +1586,7 @@ namespace MediaBrowser.Controller.MediaEncoding } var videoSizeParam = string.Empty; - var videoDecoder = GetHardwareAcceleratedVideoDecoder(state, options); + var videoDecoder = GetHardwareAcceleratedVideoDecoder(state, options) ?? string.Empty; // Setup subtitle scaling if (state.VideoStream != null && state.VideoStream.Width.HasValue && state.VideoStream.Height.HasValue) @@ -1606,10 +1606,10 @@ namespace MediaBrowser.Controller.MediaEncoding // For VAAPI and CUVID decoder // these encoders cannot automatically adjust the size of graphical subtitles to fit the output video, // thus needs to be manually adjusted. - if ((videoDecoder ?? string.Empty).IndexOf("cuvid", StringComparison.OrdinalIgnoreCase) != -1 + if (videoDecoder.IndexOf("cuvid", StringComparison.OrdinalIgnoreCase) != -1 || (IsVaapiSupported(state) && string.Equals(options.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase) - && ((videoDecoder ?? string.Empty).IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1 - || (outputVideoCodec ?? string.Empty).IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1))) + && (videoDecoder.IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1 + || outputVideoCodec.IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1))) { var videoStream = state.VideoStream; var inputWidth = videoStream?.Width; @@ -1651,7 +1651,7 @@ namespace MediaBrowser.Controller.MediaEncoding } // If we're hardware VAAPI decoding and software encoding, download frames from the decoder first - else if (IsVaapiSupported(state) && (videoDecoder ?? string.Empty).IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1 + else if (IsVaapiSupported(state) && videoDecoder.IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1 && string.Equals(outputVideoCodec, "libx264", StringComparison.OrdinalIgnoreCase)) { /* @@ -1662,7 +1662,6 @@ namespace MediaBrowser.Controller.MediaEncoding outputSizeParam = outputSizeParam.TrimStart(','); retStr = " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}]{3}[base];[base][sub]overlay\""; } - else if (string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase)) { /* @@ -1670,7 +1669,7 @@ namespace MediaBrowser.Controller.MediaEncoding For software decoding and hardware encoding option, frames must be hwuploaded into hardware with fixed frame size. */ - if ((videoDecoder ?? string.Empty).IndexOf("qsv", StringComparison.OrdinalIgnoreCase) != -1) + if (videoDecoder.IndexOf("qsv", StringComparison.OrdinalIgnoreCase) != -1) { retStr = " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}][sub]overlay_qsv=x=(W-w)/2:y=(H-h)/2{3}\""; } -- cgit v1.2.3 From 0be3dfe7c53d8c3bb43c28ea02c8a594bcb903b2 Mon Sep 17 00:00:00 2001 From: "Joshua M. Boniface" Date: Tue, 26 May 2020 12:14:40 -0400 Subject: Revert "Fix emby/user/public API leaking sensitive data" --- Emby.Server.Implementations/Library/UserManager.cs | 25 ----------- MediaBrowser.Api/UserService.cs | 38 +++++------------ MediaBrowser.Controller/Library/IUserManager.cs | 8 ---- MediaBrowser.Model/Dto/PublicUserDto.cs | 48 ---------------------- 4 files changed, 11 insertions(+), 108 deletions(-) delete mode 100644 MediaBrowser.Model/Dto/PublicUserDto.cs (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/Library/UserManager.cs b/Emby.Server.Implementations/Library/UserManager.cs index b8feb5535..d63bc6bda 100644 --- a/Emby.Server.Implementations/Library/UserManager.cs +++ b/Emby.Server.Implementations/Library/UserManager.cs @@ -608,31 +608,6 @@ namespace Emby.Server.Implementations.Library return dto; } - public PublicUserDto GetPublicUserDto(User user, string remoteEndPoint = null) - { - if (user == null) - { - throw new ArgumentNullException(nameof(user)); - } - - IAuthenticationProvider authenticationProvider = GetAuthenticationProvider(user); - bool hasConfiguredPassword = authenticationProvider.HasPassword(user); - bool hasConfiguredEasyPassword = !string.IsNullOrEmpty(authenticationProvider.GetEasyPasswordHash(user)); - - bool hasPassword = user.Configuration.EnableLocalPassword && - !string.IsNullOrEmpty(remoteEndPoint) && - _networkManager.IsInLocalNetwork(remoteEndPoint) ? hasConfiguredEasyPassword : hasConfiguredPassword; - - PublicUserDto dto = new PublicUserDto - { - Name = user.Name, - HasPassword = hasPassword, - HasConfiguredPassword = hasConfiguredPassword, - }; - - return dto; - } - public UserDto GetOfflineUserDto(User user) { var dto = GetUserDto(user); diff --git a/MediaBrowser.Api/UserService.cs b/MediaBrowser.Api/UserService.cs index 7d4d5fcf9..78fc6c694 100644 --- a/MediaBrowser.Api/UserService.cs +++ b/MediaBrowser.Api/UserService.cs @@ -35,7 +35,7 @@ namespace MediaBrowser.Api } [Route("/Users/Public", "GET", Summary = "Gets a list of publicly visible users for display on a login screen.")] - public class GetPublicUsers : IReturn + public class GetPublicUsers : IReturn { } @@ -266,38 +266,22 @@ namespace MediaBrowser.Api _authContext = authContext; } - /// - /// Gets the public available Users information - /// - /// The request. - /// System.Object. public object Get(GetPublicUsers request) { - var result = _userManager - .Users - .Where(item => !item.Policy.IsDisabled); - - if (ServerConfigurationManager.Configuration.IsStartupWizardCompleted) + // If the startup wizard hasn't been completed then just return all users + if (!ServerConfigurationManager.Configuration.IsStartupWizardCompleted) { - var deviceId = _authContext.GetAuthorizationInfo(Request).DeviceId; - result = result.Where(item => !item.Policy.IsHidden); - - if (!string.IsNullOrWhiteSpace(deviceId)) + return Get(new GetUsers { - result = result.Where(i => _deviceManager.CanAccessDevice(i, deviceId)); - } - - if (!_networkManager.IsInLocalNetwork(Request.RemoteIp)) - { - result = result.Where(i => i.Policy.EnableRemoteAccess); - } + IsDisabled = false + }); } - return ToOptimizedResult(result - .OrderBy(u => u.Name) - .Select(i => _userManager.GetPublicUserDto(i, Request.RemoteIp)) - .ToArray() - ); + return Get(new GetUsers + { + IsHidden = false, + IsDisabled = false + }, true, true); } /// diff --git a/MediaBrowser.Controller/Library/IUserManager.cs b/MediaBrowser.Controller/Library/IUserManager.cs index ec6cb35eb..be7b4ce59 100644 --- a/MediaBrowser.Controller/Library/IUserManager.cs +++ b/MediaBrowser.Controller/Library/IUserManager.cs @@ -143,14 +143,6 @@ namespace MediaBrowser.Controller.Library /// UserDto. UserDto GetUserDto(User user, string remoteEndPoint = null); - /// - /// Gets the user public dto. - /// - /// Ther user.\ - /// The remote end point. - /// A public UserDto, aka a UserDto stripped of personal data. - PublicUserDto GetPublicUserDto(User user, string remoteEndPoint = null); - /// /// Authenticates the user. /// diff --git a/MediaBrowser.Model/Dto/PublicUserDto.cs b/MediaBrowser.Model/Dto/PublicUserDto.cs deleted file mode 100644 index b6bfaf2e9..000000000 --- a/MediaBrowser.Model/Dto/PublicUserDto.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System; - -namespace MediaBrowser.Model.Dto -{ - /// - /// Class PublicUserDto. Its goal is to show only public information about a user - /// - public class PublicUserDto : IItemDto - { - /// - /// Gets or sets the name. - /// - /// The name. - public string Name { get; set; } - - /// - /// Gets or sets the primary image tag. - /// - /// The primary image tag. - public string PrimaryImageTag { get; set; } - - /// - /// Gets or sets a value indicating whether this instance has password. - /// - /// true if this instance has password; otherwise, false. - public bool HasPassword { get; set; } - - /// - /// Gets or sets a value indicating whether this instance has configured password. - /// Note that in this case this method should not be here, but it is necessary when changing password at the - /// first login. - /// - /// true if this instance has configured password; otherwise, false. - public bool HasConfiguredPassword { get; set; } - - /// - /// Gets or sets the primary image aspect ratio. - /// - /// The primary image aspect ratio. - public double? PrimaryImageAspectRatio { get; set; } - - /// - public override string ToString() - { - return Name ?? base.ToString(); - } - } -} -- cgit v1.2.3 From 8be13b63d494e6541bed075538f84e77202f6c7b Mon Sep 17 00:00:00 2001 From: Vasily Date: Tue, 26 May 2020 19:19:49 +0300 Subject: More cleanup --- .../MediaEncoding/EncodingHelper.cs | 62 ++++------------------ 1 file changed, 10 insertions(+), 52 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index cea9c7c15..fe2130610 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -1991,7 +1991,7 @@ namespace MediaBrowser.Controller.MediaEncoding var videoStream = state.VideoStream; var filters = new List(); - var videoDecoder = GetHardwareAcceleratedVideoDecoder(state, options); + var videoDecoder = GetHardwareAcceleratedVideoDecoder(state, options) ?? string.Empty; var inputWidth = videoStream?.Width; var inputHeight = videoStream?.Height; var threeDFormat = state.MediaSource.Video3DFormat; @@ -2016,7 +2016,7 @@ namespace MediaBrowser.Controller.MediaEncoding } // If we're hardware VAAPI decoding and software encoding, download frames from the decoder first - else if ((videoDecoder ?? string.Empty).IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1 + else if (videoDecoder.IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1 && string.Equals(outputVideoCodec, "libx264", StringComparison.OrdinalIgnoreCase)) { var codec = videoStream.Codec.ToLowerInvariant(); @@ -2607,7 +2607,6 @@ namespace MediaBrowser.Controller.MediaEncoding break; } } - else if (string.Equals(encodingOptions.HardwareAccelerationType, "nvenc", StringComparison.OrdinalIgnoreCase)) { switch (videoStream.Codec.ToLowerInvariant()) @@ -2661,7 +2660,6 @@ namespace MediaBrowser.Controller.MediaEncoding break; } } - else if (string.Equals(encodingOptions.HardwareAccelerationType, "mediacodec", StringComparison.OrdinalIgnoreCase)) { switch (videoStream.Codec.ToLowerInvariant()) @@ -2708,7 +2706,6 @@ namespace MediaBrowser.Controller.MediaEncoding break; } } - else if (string.Equals(encodingOptions.HardwareAccelerationType, "omx", StringComparison.OrdinalIgnoreCase)) { switch (videoStream.Codec.ToLowerInvariant()) @@ -2740,7 +2737,6 @@ namespace MediaBrowser.Controller.MediaEncoding break; } } - else if (string.Equals(encodingOptions.HardwareAccelerationType, "amf", StringComparison.OrdinalIgnoreCase)) { switch (videoStream.Codec.ToLowerInvariant()) @@ -2750,17 +2746,8 @@ namespace MediaBrowser.Controller.MediaEncoding return GetHwaccelType(state, encodingOptions, "h264"); case "hevc": case "h265": - if (isColorDepth10) - { - if (encodingOptions.EnableDecodingColorDepth10) - { - return GetHwaccelType(state, encodingOptions, "hevc"); - } - - return null; - } - - return GetHwaccelType(state, encodingOptions, "hevc"); + return (isColorDepth10 && + !encodingOptions.EnableDecodingColorDepth10) ? null : GetHwaccelType(state, encodingOptions, "hevc"); case "mpeg2video": return GetHwaccelType(state, encodingOptions, "mpeg2video"); case "vc1": @@ -2768,20 +2755,10 @@ namespace MediaBrowser.Controller.MediaEncoding case "mpeg4": return GetHwaccelType(state, encodingOptions, "mpeg4"); case "vp9": - if (isColorDepth10) - { - if (encodingOptions.EnableDecodingColorDepth10) - { - return GetHwaccelType(state, encodingOptions, "vp9"); - } - - return null; - } - - return GetHwaccelType(state, encodingOptions, "vp9"); + return (isColorDepth10 && + !encodingOptions.EnableDecodingColorDepth10) ? null : GetHwaccelType(state, encodingOptions, "vp9"); } } - else if (string.Equals(encodingOptions.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase)) { switch (videoStream.Codec.ToLowerInvariant()) @@ -2791,17 +2768,8 @@ namespace MediaBrowser.Controller.MediaEncoding return GetHwaccelType(state, encodingOptions, "h264"); case "hevc": case "h265": - if (isColorDepth10) - { - if (encodingOptions.EnableDecodingColorDepth10) - { - return GetHwaccelType(state, encodingOptions, "hevc"); - } - - return null; - } - - return GetHwaccelType(state, encodingOptions, "hevc"); + return (isColorDepth10 && + !encodingOptions.EnableDecodingColorDepth10) ? null : GetHwaccelType(state, encodingOptions, "hevc"); case "mpeg2video": return GetHwaccelType(state, encodingOptions, "mpeg2video"); case "vc1": @@ -2809,17 +2777,8 @@ namespace MediaBrowser.Controller.MediaEncoding case "vp8": return GetHwaccelType(state, encodingOptions, "vp8"); case "vp9": - if (isColorDepth10) - { - if (encodingOptions.EnableDecodingColorDepth10) - { - return GetHwaccelType(state, encodingOptions, "vp9"); - } - - return null; - } - - return GetHwaccelType(state, encodingOptions, "vp9"); + return (isColorDepth10 && + !encodingOptions.EnableDecodingColorDepth10) ? null : GetHwaccelType(state, encodingOptions, "vp9"); } } else if (string.Equals(encodingOptions.HardwareAccelerationType, "videotoolbox", StringComparison.OrdinalIgnoreCase)) @@ -2853,7 +2812,6 @@ namespace MediaBrowser.Controller.MediaEncoding break; } } - } var whichCodec = videoStream.Codec.ToLowerInvariant(); -- cgit v1.2.3 From eef7cfd91251ee14717dbccfae7505e444048548 Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Tue, 26 May 2020 22:43:03 -0400 Subject: Make SonarCloud less angry --- Emby.Server.Implementations/HttpServer/ResponseFilter.cs | 1 - Emby.Server.Implementations/HttpServer/Security/AuthService.cs | 1 - Emby.Server.Implementations/Library/MediaStreamSelector.cs | 1 - Emby.Server.Implementations/LiveTv/LiveTvManager.cs | 2 -- Emby.Server.Implementations/SyncPlay/SyncPlayManager.cs | 1 - Emby.Server.Implementations/Updates/InstallationManager.cs | 2 -- MediaBrowser.Api/Images/ImageService.cs | 7 +------ MediaBrowser.Controller/Entities/Audio/Audio.cs | 1 - MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs | 3 --- MediaBrowser.Controller/Entities/AudioBook.cs | 1 - MediaBrowser.Controller/Entities/BaseItem.cs | 1 - MediaBrowser.Controller/Entities/Book.cs | 1 - MediaBrowser.Controller/Entities/InternalItemsQuery.cs | 1 - MediaBrowser.Controller/Entities/Movies/Movie.cs | 1 - MediaBrowser.Controller/Entities/MusicVideo.cs | 1 - MediaBrowser.Controller/Entities/TV/Episode.cs | 1 - MediaBrowser.Controller/Entities/TV/Season.cs | 4 +--- MediaBrowser.Controller/Entities/Trailer.cs | 1 - MediaBrowser.Controller/LiveTv/LiveTvChannel.cs | 1 - MediaBrowser.Controller/LiveTv/LiveTvProgram.cs | 1 - MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs | 1 - MediaBrowser.Controller/Session/ISessionManager.cs | 1 - MediaBrowser.Controller/Sorting/IUserBaseItemComparer.cs | 1 - 23 files changed, 2 insertions(+), 34 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/HttpServer/ResponseFilter.cs b/Emby.Server.Implementations/HttpServer/ResponseFilter.cs index 85c3db9b2..3ab5dbc16 100644 --- a/Emby.Server.Implementations/HttpServer/ResponseFilter.cs +++ b/Emby.Server.Implementations/HttpServer/ResponseFilter.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.Globalization; using System.Text; using MediaBrowser.Controller.Net; diff --git a/Emby.Server.Implementations/HttpServer/Security/AuthService.cs b/Emby.Server.Implementations/HttpServer/Security/AuthService.cs index eace86d51..9441f1a4c 100644 --- a/Emby.Server.Implementations/HttpServer/Security/AuthService.cs +++ b/Emby.Server.Implementations/HttpServer/Security/AuthService.cs @@ -8,7 +8,6 @@ using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; using MediaBrowser.Common.Net; using MediaBrowser.Controller.Configuration; -using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Net; using MediaBrowser.Controller.Security; using MediaBrowser.Controller.Session; diff --git a/Emby.Server.Implementations/Library/MediaStreamSelector.cs b/Emby.Server.Implementations/Library/MediaStreamSelector.cs index a177138b7..ca904c4ec 100644 --- a/Emby.Server.Implementations/Library/MediaStreamSelector.cs +++ b/Emby.Server.Implementations/Library/MediaStreamSelector.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; using System.Linq; using Jellyfin.Data.Enums; -using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Entities; namespace Emby.Server.Implementations.Library diff --git a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs index 64901f9fa..09906c9f1 100644 --- a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs @@ -12,10 +12,8 @@ using Jellyfin.Data.Enums; using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Progress; -using MediaBrowser.Controller; using MediaBrowser.Controller.Channels; using MediaBrowser.Controller.Configuration; -using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; diff --git a/Emby.Server.Implementations/SyncPlay/SyncPlayManager.cs b/Emby.Server.Implementations/SyncPlay/SyncPlayManager.cs index 6a3e684ca..f44b32c36 100644 --- a/Emby.Server.Implementations/SyncPlay/SyncPlayManager.cs +++ b/Emby.Server.Implementations/SyncPlay/SyncPlayManager.cs @@ -8,7 +8,6 @@ using Jellyfin.Data.Enums; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Session; using MediaBrowser.Controller.SyncPlay; -using MediaBrowser.Model.Configuration; using MediaBrowser.Model.SyncPlay; using Microsoft.Extensions.Logging; diff --git a/Emby.Server.Implementations/Updates/InstallationManager.cs b/Emby.Server.Implementations/Updates/InstallationManager.cs index 0b2309889..980572cc2 100644 --- a/Emby.Server.Implementations/Updates/InstallationManager.cs +++ b/Emby.Server.Implementations/Updates/InstallationManager.cs @@ -3,9 +3,7 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; using System.Linq; -using System.Net; using System.Net.Http; -using System.Runtime.CompilerServices; using System.Runtime.Serialization; using System.Security.Cryptography; using System.Threading; diff --git a/MediaBrowser.Api/Images/ImageService.cs b/MediaBrowser.Api/Images/ImageService.cs index 149c4cb9b..d3b739524 100644 --- a/MediaBrowser.Api/Images/ImageService.cs +++ b/MediaBrowser.Api/Images/ImageService.cs @@ -625,12 +625,9 @@ namespace MediaBrowser.Api.Images var outputFormats = GetOutputFormats(request); - return GetImageResult( - user, - user.Id, + return GetImageResult(user.Id, request, imageInfo, - false, outputFormats, cacheDuration, responseHeaders, @@ -638,11 +635,9 @@ namespace MediaBrowser.Api.Images } private async Task GetImageResult( - User user, Guid itemId, ImageRequest request, ItemImageInfo info, - bool cropWhitespace, IReadOnlyCollection supportedFormats, TimeSpan? cacheDuration, IDictionary headers, diff --git a/MediaBrowser.Controller/Entities/Audio/Audio.cs b/MediaBrowser.Controller/Entities/Audio/Audio.cs index 9065cb27f..a8ea2157d 100644 --- a/MediaBrowser.Controller/Entities/Audio/Audio.cs +++ b/MediaBrowser.Controller/Entities/Audio/Audio.cs @@ -5,7 +5,6 @@ using System.Text.Json.Serialization; using Jellyfin.Data.Enums; using MediaBrowser.Controller.Persistence; using MediaBrowser.Controller.Providers; -using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; diff --git a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs index 15b580896..e4a24bb9c 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Globalization; using System.Linq; using System.Text.Json.Serialization; using System.Threading; @@ -10,9 +9,7 @@ using Jellyfin.Data.Enums; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Providers; -using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Entities; -using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.Entities.Audio { diff --git a/MediaBrowser.Controller/Entities/AudioBook.cs b/MediaBrowser.Controller/Entities/AudioBook.cs index ffe7aa8b3..4adaf4c6e 100644 --- a/MediaBrowser.Controller/Entities/AudioBook.cs +++ b/MediaBrowser.Controller/Entities/AudioBook.cs @@ -2,7 +2,6 @@ using System; using System.Text.Json.Serialization; using Jellyfin.Data.Enums; using MediaBrowser.Controller.Providers; -using MediaBrowser.Model.Configuration; namespace MediaBrowser.Controller.Entities { diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index ee12ba73b..672d4fd0c 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -26,7 +26,6 @@ using MediaBrowser.Model.Library; using MediaBrowser.Model.LiveTv; using MediaBrowser.Model.MediaInfo; using MediaBrowser.Model.Providers; -using MediaBrowser.Model.Users; using Microsoft.Extensions.Logging; namespace MediaBrowser.Controller.Entities diff --git a/MediaBrowser.Controller/Entities/Book.cs b/MediaBrowser.Controller/Entities/Book.cs index c4a2929dc..f16554538 100644 --- a/MediaBrowser.Controller/Entities/Book.cs +++ b/MediaBrowser.Controller/Entities/Book.cs @@ -3,7 +3,6 @@ using System.Linq; using System.Text.Json.Serialization; using Jellyfin.Data.Enums; using MediaBrowser.Controller.Providers; -using MediaBrowser.Model.Configuration; namespace MediaBrowser.Controller.Entities { diff --git a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs index a2dff53ad..496bee857 100644 --- a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs +++ b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs @@ -4,7 +4,6 @@ using System.Linq; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; using MediaBrowser.Controller.Dto; -using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Entities; namespace MediaBrowser.Controller.Entities diff --git a/MediaBrowser.Controller/Entities/Movies/Movie.cs b/MediaBrowser.Controller/Entities/Movies/Movie.cs index 38359afcc..68ba71920 100644 --- a/MediaBrowser.Controller/Entities/Movies/Movie.cs +++ b/MediaBrowser.Controller/Entities/Movies/Movie.cs @@ -6,7 +6,6 @@ using System.Threading; using System.Threading.Tasks; using Jellyfin.Data.Enums; using MediaBrowser.Controller.Providers; -using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Entities; using MediaBrowser.Model.IO; using MediaBrowser.Model.Providers; diff --git a/MediaBrowser.Controller/Entities/MusicVideo.cs b/MediaBrowser.Controller/Entities/MusicVideo.cs index 1b9d4614e..6e7f2812d 100644 --- a/MediaBrowser.Controller/Entities/MusicVideo.cs +++ b/MediaBrowser.Controller/Entities/MusicVideo.cs @@ -4,7 +4,6 @@ using System.Text.Json.Serialization; using Jellyfin.Data.Enums; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Providers; -using MediaBrowser.Model.Configuration; namespace MediaBrowser.Controller.Entities { diff --git a/MediaBrowser.Controller/Entities/TV/Episode.cs b/MediaBrowser.Controller/Entities/TV/Episode.cs index 0a89da46d..4ec60e7cd 100644 --- a/MediaBrowser.Controller/Entities/TV/Episode.cs +++ b/MediaBrowser.Controller/Entities/TV/Episode.cs @@ -5,7 +5,6 @@ using System.Linq; using System.Text.Json.Serialization; using Jellyfin.Data.Enums; using MediaBrowser.Controller.Providers; -using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Entities; using MediaBrowser.Model.IO; using Microsoft.Extensions.Logging; diff --git a/MediaBrowser.Controller/Entities/TV/Season.cs b/MediaBrowser.Controller/Entities/TV/Season.cs index 839350fd7..7dfd1a759 100644 --- a/MediaBrowser.Controller/Entities/TV/Season.cs +++ b/MediaBrowser.Controller/Entities/TV/Season.cs @@ -6,9 +6,7 @@ using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Providers; -using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Querying; -using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.Entities.TV { @@ -170,7 +168,7 @@ namespace MediaBrowser.Controller.Entities.TV return GetEpisodes(user, new DtoOptions(true)); } - protected override bool GetBlockUnratedValue(User config) + protected override bool GetBlockUnratedValue(User user) { // Don't block. Let either the entire series rating or episode rating determine it return false; diff --git a/MediaBrowser.Controller/Entities/Trailer.cs b/MediaBrowser.Controller/Entities/Trailer.cs index c646e8ae6..7e29c15fd 100644 --- a/MediaBrowser.Controller/Entities/Trailer.cs +++ b/MediaBrowser.Controller/Entities/Trailer.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.Text.Json.Serialization; using Jellyfin.Data.Enums; using MediaBrowser.Controller.Providers; -using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Providers; diff --git a/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs b/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs index f3ff8bd04..10af98121 100644 --- a/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs +++ b/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs @@ -5,7 +5,6 @@ using System.Linq; using System.Text.Json.Serialization; using Jellyfin.Data.Enums; using MediaBrowser.Controller.Entities; -using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; using MediaBrowser.Model.LiveTv; diff --git a/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs b/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs index e6dc4bdda..b748b089a 100644 --- a/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs +++ b/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs @@ -7,7 +7,6 @@ using Jellyfin.Data.Enums; using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Providers; -using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Entities; using MediaBrowser.Model.LiveTv; using MediaBrowser.Model.Providers; diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs b/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs index 67241c35b..c4ebdac8b 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; using Jellyfin.Data.Entities; -using MediaBrowser.Controller.Entities; using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Drawing; using MediaBrowser.Model.Dto; diff --git a/MediaBrowser.Controller/Session/ISessionManager.cs b/MediaBrowser.Controller/Session/ISessionManager.cs index 70ae19980..1fdb588eb 100644 --- a/MediaBrowser.Controller/Session/ISessionManager.cs +++ b/MediaBrowser.Controller/Session/ISessionManager.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Controller.Authentication; -using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Security; using MediaBrowser.Model.Dto; diff --git a/MediaBrowser.Controller/Sorting/IUserBaseItemComparer.cs b/MediaBrowser.Controller/Sorting/IUserBaseItemComparer.cs index f079bc7ea..6f75d16de 100644 --- a/MediaBrowser.Controller/Sorting/IUserBaseItemComparer.cs +++ b/MediaBrowser.Controller/Sorting/IUserBaseItemComparer.cs @@ -1,4 +1,3 @@ -using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; namespace MediaBrowser.Controller.Sorting -- cgit v1.2.3 From 31f725fdbf9f4a5d91c60cde4dfe8997022f8257 Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Tue, 26 May 2020 23:08:27 -0400 Subject: Fix a bug in Emby.Notifications and clean up --- Emby.Notifications/Api/NotificationsService.cs | 8 +++----- MediaBrowser.Api/Images/ImageService.cs | 25 +++++++++++-------------- MediaBrowser.Controller/Entities/BaseItem.cs | 9 +-------- 3 files changed, 15 insertions(+), 27 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Notifications/Api/NotificationsService.cs b/Emby.Notifications/Api/NotificationsService.cs index 221db5423..1ff8a5026 100644 --- a/Emby.Notifications/Api/NotificationsService.cs +++ b/Emby.Notifications/Api/NotificationsService.cs @@ -150,9 +150,7 @@ namespace Emby.Notifications.Api [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "request", Justification = "Required for ServiceStack")] public object Get(GetNotificationsSummary request) { - return new NotificationsSummary - { - }; + return new NotificationsSummary(); } public Task Post(AddAdminNotification request) @@ -166,8 +164,8 @@ namespace Emby.Notifications.Api Name = request.Name, Url = request.Url, UserIds = _userManager.Users - .Where(p => p.Permissions.Select(x => x.Kind).Contains(PermissionKind.IsAdministrator)) - .Select(p => p.Id) + .Where(user => user.HasPermission(PermissionKind.IsAdministrator)) + .Select(user => user.Id) .ToArray() }; diff --git a/MediaBrowser.Api/Images/ImageService.cs b/MediaBrowser.Api/Images/ImageService.cs index d3b739524..f52c48cc6 100644 --- a/MediaBrowser.Api/Images/ImageService.cs +++ b/MediaBrowser.Api/Images/ImageService.cs @@ -477,7 +477,7 @@ namespace MediaBrowser.Api.Images } catch (IOException e) { - // TODO: Log this + Logger.LogError(e, "Error deleting user profile image:"); } user.ProfileImage = null; @@ -820,14 +820,14 @@ namespace MediaBrowser.Api.Images /// The request. /// The item. /// System.String. - private ItemImageInfo GetImageInfo(ImageRequest request, BaseItem item) + private static ItemImageInfo GetImageInfo(ImageRequest request, BaseItem item) { var index = request.Index ?? 0; return item.GetImageInfo(request.Type, index); } - private ItemImageInfo GetImageInfo(ImageRequest request, User user) + private static ItemImageInfo GetImageInfo(ImageRequest request, User user) { var info = new ItemImageInfo { @@ -859,15 +859,7 @@ namespace MediaBrowser.Api.Images /// Task. public async Task PostImage(BaseItem entity, Stream inputStream, ImageType imageType, string mimeType) { - using var reader = new StreamReader(inputStream); - var text = await reader.ReadToEndAsync().ConfigureAwait(false); - - var bytes = Convert.FromBase64String(text); - - var memoryStream = new MemoryStream(bytes) - { - Position = 0 - }; + var memoryStream = await GetMemoryStream(inputStream); // Handle image/png; charset=utf-8 mimeType = mimeType.Split(';').FirstOrDefault(); @@ -877,16 +869,21 @@ namespace MediaBrowser.Api.Images entity.UpdateToRepository(ItemUpdateType.ImageUpdate, CancellationToken.None); } - public async Task PostImage(User user, Stream inputStream, string mimeType) + private static async Task GetMemoryStream(Stream inputStream) { using var reader = new StreamReader(inputStream); var text = await reader.ReadToEndAsync().ConfigureAwait(false); var bytes = Convert.FromBase64String(text); - var memoryStream = new MemoryStream(bytes) + return new MemoryStream(bytes) { Position = 0 }; + } + + private async Task PostImage(User user, Stream inputStream, string mimeType) + { + var memoryStream = await GetMemoryStream(inputStream); // Handle image/png; charset=utf-8 mimeType = mimeType.Split(';').FirstOrDefault(); diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 672d4fd0c..3feef1d32 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -2760,14 +2760,7 @@ namespace MediaBrowser.Controller.Entities return this; } - foreach (var parent in GetParents()) - { - if (parent.IsTopParent) - { - return parent; - } - } - return null; + return GetParents().FirstOrDefault(parent => parent.IsTopParent); } [JsonIgnore] -- cgit v1.2.3 From edcfcadcd327affb308b0c0eb5cfbb1416e27cae Mon Sep 17 00:00:00 2001 From: Vasily Date: Wed, 27 May 2020 17:00:59 +0300 Subject: Make sure blurhash is recomputed if image changed or metadata refresh toggled --- .../Library/LibraryManager.cs | 47 +++++++++++++++++----- MediaBrowser.Controller/Library/ILibraryManager.cs | 2 +- 2 files changed, 39 insertions(+), 10 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index 903c0b3cf..84bcd1bc1 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -1820,23 +1820,44 @@ namespace Emby.Server.Implementations.Library } } - public void UpdateImages(BaseItem item) + private bool ImageNeedsRefresh(ItemImageInfo image) + { + if (image.Path != null && image.IsLocalFile) + { + if (image.Width == 0 || image.Height == 0 || string.IsNullOrEmpty(image.BlurHash)) + { + return true; + } + + try + { + return _fileSystem.GetLastWriteTimeUtc(image.Path) != image.DateModified; + } + catch (Exception ex) + { + _logger.LogError(ex, "Cannot get file info for {0}", image.Path); + return false; + } + } + + return false; + } + + public void UpdateImages(BaseItem item, bool forceUpdate = false) { if (item == null) { throw new ArgumentNullException(nameof(item)); } - var outdated = item.ImageInfos - .Where(i => (i.IsLocalFile && (i.Width == 0 || i.Height == 0 || string.IsNullOrEmpty(i.BlurHash)))) - .ToList(); - if (outdated.Count == 0) + var outdated = forceUpdate ? item.ImageInfos : item.ImageInfos.Where(ImageNeedsRefresh).ToArray(); + if (outdated.Length == 0) { RegisterItem(item); return; } - outdated.ForEach(img => + foreach (var img in outdated) { ImageDimensions size = _imageProcessor.GetImageDimensions(item, img); img.Width = size.Width; @@ -1850,10 +1871,18 @@ namespace Emby.Server.Implementations.Library _logger.LogError(ex, "Cannot compute blurhash for {0}", img.Path); img.BlurHash = string.Empty; } - }); - _itemRepository.SaveImages(item); + try + { + img.DateModified = _fileSystem.GetLastWriteTimeUtc(img.Path); + } + catch (Exception ex) + { + _logger.LogError(ex, "Cannot update DateModified for {0}", img.Path); + } + } + _itemRepository.SaveImages(item); RegisterItem(item); } @@ -1874,7 +1903,7 @@ namespace Emby.Server.Implementations.Library item.DateLastSaved = DateTime.UtcNow; - UpdateImages(item); + UpdateImages(item, updateReason >= ItemUpdateType.ImageUpdate); } _itemRepository.SaveItems(itemsList, cancellationToken); diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs index 81160efec..916e4fda7 100644 --- a/MediaBrowser.Controller/Library/ILibraryManager.cs +++ b/MediaBrowser.Controller/Library/ILibraryManager.cs @@ -118,7 +118,7 @@ namespace MediaBrowser.Controller.Library /// void QueueLibraryScan(); - void UpdateImages(BaseItem item); + void UpdateImages(BaseItem item, bool forceUpdate = false); /// /// Gets the default view. -- cgit v1.2.3 From 9208acd5ae26d41af6791d7dd7322d682a8b80b6 Mon Sep 17 00:00:00 2001 From: Vasily Date: Thu, 28 May 2020 17:55:29 +0300 Subject: Convert non-local image to local before computing blurhash --- .../Library/LibraryManager.cs | 40 ++++++++++++++++------ MediaBrowser.Controller/Entities/BaseItem.cs | 40 ++++++++++++++++++++++ 2 files changed, 70 insertions(+), 10 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index 6cbca7d02..bb3e3dd11 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -1840,7 +1840,7 @@ namespace Emby.Server.Implementations.Library } } - return false; + return image.Path != null && !image.IsLocalFile; } public void UpdateImages(BaseItem item, bool forceUpdate = false) @@ -1850,7 +1850,7 @@ namespace Emby.Server.Implementations.Library throw new ArgumentNullException(nameof(item)); } - var outdated = forceUpdate ? item.ImageInfos.Where(i => i.IsLocalFile).ToArray() : item.ImageInfos.Where(ImageNeedsRefresh).ToArray(); + var outdated = forceUpdate ? item.ImageInfos.Where(i => i.Path != null).ToArray() : item.ImageInfos.Where(ImageNeedsRefresh).ToArray(); if (outdated.Length == 0) { RegisterItem(item); @@ -1859,26 +1859,46 @@ namespace Emby.Server.Implementations.Library foreach (var img in outdated) { - ImageDimensions size = _imageProcessor.GetImageDimensions(item, img); - img.Width = size.Width; - img.Height = size.Height; + var image = img; + if (!img.IsLocalFile) + { + try + { + var index = item.GetImageIndex(img); + image = ConvertImageToLocal(item, img, index).ConfigureAwait(false).GetAwaiter().GetResult(); + } + catch (ArgumentException) + { + _logger.LogWarning("Cannot get image index for {0}", img.Path); + continue; + } + catch (InvalidOperationException) + { + _logger.LogWarning("Cannot fetch image from {0}", img.Path); + continue; + } + } + + ImageDimensions size = _imageProcessor.GetImageDimensions(item, image); + image.Width = size.Width; + image.Height = size.Height; try { - img.BlurHash = _imageProcessor.GetImageBlurHash(img.Path); + image.BlurHash = _imageProcessor.GetImageBlurHash(image.Path); } catch (Exception ex) { - _logger.LogError(ex, "Cannot compute blurhash for {0}", img.Path); - img.BlurHash = string.Empty; + _logger.LogError(ex, "Cannot compute blurhash for {0}", image.Path); + image.BlurHash = string.Empty; } try { - img.DateModified = _fileSystem.GetLastWriteTimeUtc(img.Path); + image.DateModified = _fileSystem.GetLastWriteTimeUtc(image.Path); } catch (Exception ex) { - _logger.LogError(ex, "Cannot update DateModified for {0}", img.Path); + _logger.LogError(ex, "Cannot update DateModified for {0}", image.Path); } } diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 07aeb69db..f4b71d8bf 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -2375,6 +2375,46 @@ namespace MediaBrowser.Controller.Entities .ElementAtOrDefault(imageIndex); } + /// + /// Computes image index for given image or raises if no matching image found. + /// + /// Image to compute index for. + /// Image index cannot be computed as no matching image found. + /// + /// Image index. + public int GetImageIndex(ItemImageInfo image) + { + if (image == null) + { + throw new ArgumentNullException(nameof(image)); + } + + if (image.Type == ImageType.Chapter) + { + var chapters = ItemRepository.GetChapters(this); + for (var i = 0; i < chapters.Count; i++) + { + if (chapters[i].ImagePath == image.Path) + { + return i; + } + } + + throw new ArgumentException("No chapter index found for image path", image.Path); + } + + var images = GetImages(image.Type).ToArray(); + for (var i = 0; i < images.Length; i++) + { + if (images[i].Path == image.Path) + { + return i; + } + } + + throw new ArgumentException("No image index found for image path", image.Path); + } + public IEnumerable GetImages(ImageType imageType) { if (imageType == ImageType.Chapter) -- cgit v1.2.3 From 26eef1bbf823e6f9fc22b11d95a17b1370b21842 Mon Sep 17 00:00:00 2001 From: Vasily Date: Mon, 1 Jun 2020 18:12:49 +0300 Subject: Move logic of computing Blurhash components to ImageProcessor Also rename last few instances of GetImageHash to GetImageBlurHash for clarity --- Emby.Drawing/ImageProcessor.cs | 19 ++++++++++++++++++- Emby.Drawing/NullImageEncoder.cs | 2 +- Emby.Server.Implementations/Library/LibraryManager.cs | 1 + Jellyfin.Drawing.Skia/SkiaEncoder.cs | 18 +----------------- MediaBrowser.Controller/Drawing/IImageEncoder.cs | 4 +++- 5 files changed, 24 insertions(+), 20 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Drawing/ImageProcessor.cs b/Emby.Drawing/ImageProcessor.cs index 35da6f635..89bb3068b 100644 --- a/Emby.Drawing/ImageProcessor.cs +++ b/Emby.Drawing/ImageProcessor.cs @@ -315,7 +315,24 @@ namespace Emby.Drawing /// public string GetImageBlurHash(string path) - => _imageEncoder.GetImageHash(path); + { + var size = GetImageDimensions(path); + if (size.Width <= 0 || size.Height <= 0) + { + return string.Empty; + } + + // We want tiles to be as close to square as possible, and to *mostly* keep under 16 tiles for performance. + // One tile is (width / xComp) x (height / yComp) pixels, which means that ideally yComp = xComp * height / width. + // See more at https://github.com/woltapp/blurhash/#how-do-i-pick-the-number-of-x-and-y-components + float xCompF = MathF.Sqrt(16.0f * size.Width / size.Height); + float yCompF = xCompF * size.Height / size.Width; + + int xComp = Math.Min((int)xCompF + 1, 9); + int yComp = Math.Min((int)yCompF + 1, 9); + + return _imageEncoder.GetImageBlurHash(xComp, yComp, path); + } /// public string GetImageCacheTag(BaseItem item, ItemImageInfo image) diff --git a/Emby.Drawing/NullImageEncoder.cs b/Emby.Drawing/NullImageEncoder.cs index 54de7212a..bbb5c1716 100644 --- a/Emby.Drawing/NullImageEncoder.cs +++ b/Emby.Drawing/NullImageEncoder.cs @@ -44,7 +44,7 @@ namespace Emby.Drawing } /// - public string GetImageHash(string path) + public string GetImageBlurHash(int xComp, int yComp, string path) { throw new NotImplementedException(); } diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index bb3e3dd11..15362182c 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -1882,6 +1882,7 @@ namespace Emby.Server.Implementations.Library ImageDimensions size = _imageProcessor.GetImageDimensions(item, image); image.Width = size.Width; image.Height = size.Height; + try { image.BlurHash = _imageProcessor.GetImageBlurHash(image.Path); diff --git a/Jellyfin.Drawing.Skia/SkiaEncoder.cs b/Jellyfin.Drawing.Skia/SkiaEncoder.cs index 7f0da2c9e..dae0e94d4 100644 --- a/Jellyfin.Drawing.Skia/SkiaEncoder.cs +++ b/Jellyfin.Drawing.Skia/SkiaEncoder.cs @@ -234,29 +234,13 @@ namespace Jellyfin.Drawing.Skia /// The path is null. /// The path is not valid. /// The file at the specified path could not be used to generate a codec. - public string GetImageHash(string path) + public string GetImageBlurHash(int xComp, int yComp, string path) { if (path == null) { throw new ArgumentNullException(nameof(path)); } - var dims = GetImageSize(path); - if (dims.Width <= 0 || dims.Height <= 0) - { - // empty image does not have any blurhash - return string.Empty; - } - - // We want tiles to be as close to square as possible, and to *mostly* keep under 16 tiles for performance. - // One tile is (width / xComp) x (height / yComp) pixels, which means that ideally yComp = xComp * height / width. - // See more at https://github.com/woltapp/blurhash/#how-do-i-pick-the-number-of-x-and-y-components - float xCompF = MathF.Sqrt(16.0f * dims.Width / dims.Height); - float yCompF = xCompF * dims.Height / dims.Width; - - int xComp = Math.Min((int)xCompF + 1, 9); - int yComp = Math.Min((int)yCompF + 1, 9); - return BlurHashEncoder.Encode(xComp, yComp, path); } diff --git a/MediaBrowser.Controller/Drawing/IImageEncoder.cs b/MediaBrowser.Controller/Drawing/IImageEncoder.cs index 4baec6204..e09ccd204 100644 --- a/MediaBrowser.Controller/Drawing/IImageEncoder.cs +++ b/MediaBrowser.Controller/Drawing/IImageEncoder.cs @@ -46,9 +46,11 @@ namespace MediaBrowser.Controller.Drawing /// /// Gets the blurhash of an image. /// + /// Amount of X components of DCT to take. + /// Amount of Y components of DCT to take. /// The filepath of the image. /// The blurhash. - string GetImageHash(string path); + string GetImageBlurHash(int xComp, int yComp, string path); /// /// Encode an image. -- cgit v1.2.3 From e30a85025f3d0f8b936827613239da7c2c2387c2 Mon Sep 17 00:00:00 2001 From: crobibero Date: Mon, 1 Jun 2020 12:42:59 -0600 Subject: Remove log spam when using legacy api --- .../HttpServer/Security/AuthService.cs | 6 ++++++ Jellyfin.Api/Auth/CustomAuthenticationHandler.cs | 11 +++++++++-- MediaBrowser.Controller/Net/AuthenticatedAttribute.cs | 4 ++++ 3 files changed, 19 insertions(+), 2 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/HttpServer/Security/AuthService.cs b/Emby.Server.Implementations/HttpServer/Security/AuthService.cs index 58421aaf1..18bea59ad 100644 --- a/Emby.Server.Implementations/HttpServer/Security/AuthService.cs +++ b/Emby.Server.Implementations/HttpServer/Security/AuthService.cs @@ -146,11 +146,17 @@ namespace Emby.Server.Implementations.HttpServer.Security { return true; } + if (authAttribtues.AllowLocalOnly && request.IsLocal) { return true; } + if (authAttribtues.IgnoreLegacyAuth) + { + return true; + } + return false; } diff --git a/Jellyfin.Api/Auth/CustomAuthenticationHandler.cs b/Jellyfin.Api/Auth/CustomAuthenticationHandler.cs index 26f7d9d2d..a0c9c3f5a 100644 --- a/Jellyfin.Api/Auth/CustomAuthenticationHandler.cs +++ b/Jellyfin.Api/Auth/CustomAuthenticationHandler.cs @@ -37,13 +37,20 @@ namespace Jellyfin.Api.Auth /// protected override Task HandleAuthenticateAsync() { - var authenticatedAttribute = new AuthenticatedAttribute(); + var authenticatedAttribute = new AuthenticatedAttribute + { + IgnoreLegacyAuth = true + }; + try { var user = _authService.Authenticate(Request, authenticatedAttribute); if (user == null) { - return Task.FromResult(AuthenticateResult.Fail("Invalid user")); + return Task.FromResult(AuthenticateResult.NoResult()); + // TODO return when legacy API is removed. + // Don't spam the log with "Invalid User" + // return Task.FromResult(AuthenticateResult.Fail("Invalid user")); } var claims = new[] diff --git a/MediaBrowser.Controller/Net/AuthenticatedAttribute.cs b/MediaBrowser.Controller/Net/AuthenticatedAttribute.cs index 29fb81e32..9f2743ea1 100644 --- a/MediaBrowser.Controller/Net/AuthenticatedAttribute.cs +++ b/MediaBrowser.Controller/Net/AuthenticatedAttribute.cs @@ -52,6 +52,8 @@ namespace MediaBrowser.Controller.Net return (Roles ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); } + public bool IgnoreLegacyAuth { get; set; } + public bool AllowLocalOnly { get; set; } } @@ -63,5 +65,7 @@ namespace MediaBrowser.Controller.Net bool AllowLocalOnly { get; } string[] GetRoles(); + + bool IgnoreLegacyAuth { get; } } } -- cgit v1.2.3 From 2dbb9d4895e5fd2bf802d6acd47f35e35b1a0e19 Mon Sep 17 00:00:00 2001 From: Bond-009 Date: Wed, 3 Jun 2020 11:54:01 +0200 Subject: Fix build --- .../Library/LibraryManager.cs | 1 + MediaBrowser.Api/Devices/DeviceService.cs | 28 ---------------------- .../Devices/CameraImageUploadInfo.cs | 10 -------- MediaBrowser.Model/Devices/ContentUploadHistory.cs | 19 --------------- MediaBrowser.Model/Devices/DeviceOptions.cs | 2 +- MediaBrowser.Model/Devices/LocalFileInfo.cs | 16 ------------- MediaBrowser.Model/SyncPlay/GroupInfoView.cs | 2 ++ MediaBrowser.Model/SyncPlay/GroupUpdate.cs | 2 ++ MediaBrowser.Model/SyncPlay/SendCommand.cs | 2 ++ MediaBrowser.Model/SyncPlay/UtcTimeResponse.cs | 2 ++ MediaBrowser.Model/Updates/VersionInfo.cs | 2 ++ 11 files changed, 12 insertions(+), 74 deletions(-) delete mode 100644 MediaBrowser.Controller/Devices/CameraImageUploadInfo.cs delete mode 100644 MediaBrowser.Model/Devices/ContentUploadHistory.cs delete mode 100644 MediaBrowser.Model/Devices/LocalFileInfo.cs (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index 932ddd861..677030b82 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -144,6 +144,7 @@ namespace Emby.Server.Implementations.Library /// The userview manager. /// The media encoder. /// The item repository. + /// The image processor. public LibraryManager( IServerApplicationHost appHost, ILogger logger, diff --git a/MediaBrowser.Api/Devices/DeviceService.cs b/MediaBrowser.Api/Devices/DeviceService.cs index 53eb9667d..dd3f3e738 100644 --- a/MediaBrowser.Api/Devices/DeviceService.cs +++ b/MediaBrowser.Api/Devices/DeviceService.cs @@ -1,4 +1,3 @@ -using System.IO; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Devices; using MediaBrowser.Controller.Net; @@ -40,33 +39,6 @@ namespace MediaBrowser.Api.Devices public string Id { get; set; } } - [Route("/Devices/CameraUploads", "GET", Summary = "Gets camera upload history for a device")] - [Authenticated] - public class GetCameraUploads : IReturn - { - [ApiMember(Name = "Id", Description = "Device Id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")] - public string DeviceId { get; set; } - } - - [Route("/Devices/CameraUploads", "POST", Summary = "Uploads content")] - [Authenticated] - public class PostCameraUpload : IRequiresRequestStream, IReturnVoid - { - [ApiMember(Name = "DeviceId", Description = "Device Id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")] - public string DeviceId { get; set; } - - [ApiMember(Name = "Album", Description = "Album", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")] - public string Album { get; set; } - - [ApiMember(Name = "Name", Description = "Name", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")] - public string Name { get; set; } - - [ApiMember(Name = "Id", Description = "Id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")] - public string Id { get; set; } - - public Stream RequestStream { get; set; } - } - [Route("/Devices/Options", "POST", Summary = "Updates device options")] [Authenticated(Roles = "Admin")] public class PostDeviceOptions : DeviceOptions, IReturnVoid diff --git a/MediaBrowser.Controller/Devices/CameraImageUploadInfo.cs b/MediaBrowser.Controller/Devices/CameraImageUploadInfo.cs deleted file mode 100644 index 89d0be58f..000000000 --- a/MediaBrowser.Controller/Devices/CameraImageUploadInfo.cs +++ /dev/null @@ -1,10 +0,0 @@ -using MediaBrowser.Model.Devices; - -namespace MediaBrowser.Controller.Devices -{ - public class CameraImageUploadInfo - { - public LocalFileInfo FileInfo { get; set; } - public DeviceInfo Device { get; set; } - } -} diff --git a/MediaBrowser.Model/Devices/ContentUploadHistory.cs b/MediaBrowser.Model/Devices/ContentUploadHistory.cs deleted file mode 100644 index 868956df2..000000000 --- a/MediaBrowser.Model/Devices/ContentUploadHistory.cs +++ /dev/null @@ -1,19 +0,0 @@ -#nullable disable -#pragma warning disable CS1591 - -using System; - -namespace MediaBrowser.Model.Devices -{ - public class ContentUploadHistory - { - public string DeviceId { get; set; } - - public LocalFileInfo[] FilesUploaded { get; set; } - - public ContentUploadHistory() - { - FilesUploaded = Array.Empty(); - } - } -} diff --git a/MediaBrowser.Model/Devices/DeviceOptions.cs b/MediaBrowser.Model/Devices/DeviceOptions.cs index 8b77fd7fc..037ffeb5e 100644 --- a/MediaBrowser.Model/Devices/DeviceOptions.cs +++ b/MediaBrowser.Model/Devices/DeviceOptions.cs @@ -4,6 +4,6 @@ namespace MediaBrowser.Model.Devices { public class DeviceOptions { - public string CustomName { get; set; } + public string? CustomName { get; set; } } } diff --git a/MediaBrowser.Model/Devices/LocalFileInfo.cs b/MediaBrowser.Model/Devices/LocalFileInfo.cs deleted file mode 100644 index c3158b2f2..000000000 --- a/MediaBrowser.Model/Devices/LocalFileInfo.cs +++ /dev/null @@ -1,16 +0,0 @@ -#nullable disable -#pragma warning disable CS1591 - -namespace MediaBrowser.Model.Devices -{ - public class LocalFileInfo - { - public string Name { get; set; } - - public string Id { get; set; } - - public string Album { get; set; } - - public string MimeType { get; set; } - } -} diff --git a/MediaBrowser.Model/SyncPlay/GroupInfoView.cs b/MediaBrowser.Model/SyncPlay/GroupInfoView.cs index f28ecf16d..f4c685998 100644 --- a/MediaBrowser.Model/SyncPlay/GroupInfoView.cs +++ b/MediaBrowser.Model/SyncPlay/GroupInfoView.cs @@ -1,3 +1,5 @@ +#nullable disable + using System.Collections.Generic; namespace MediaBrowser.Model.SyncPlay diff --git a/MediaBrowser.Model/SyncPlay/GroupUpdate.cs b/MediaBrowser.Model/SyncPlay/GroupUpdate.cs index 895702f3d..8c7208211 100644 --- a/MediaBrowser.Model/SyncPlay/GroupUpdate.cs +++ b/MediaBrowser.Model/SyncPlay/GroupUpdate.cs @@ -1,3 +1,5 @@ +#nullable disable + namespace MediaBrowser.Model.SyncPlay { /// diff --git a/MediaBrowser.Model/SyncPlay/SendCommand.cs b/MediaBrowser.Model/SyncPlay/SendCommand.cs index 0f06e381f..0f0be0152 100644 --- a/MediaBrowser.Model/SyncPlay/SendCommand.cs +++ b/MediaBrowser.Model/SyncPlay/SendCommand.cs @@ -1,3 +1,5 @@ +#nullable disable + namespace MediaBrowser.Model.SyncPlay { /// diff --git a/MediaBrowser.Model/SyncPlay/UtcTimeResponse.cs b/MediaBrowser.Model/SyncPlay/UtcTimeResponse.cs index 0a6036154..8ec5eaab3 100644 --- a/MediaBrowser.Model/SyncPlay/UtcTimeResponse.cs +++ b/MediaBrowser.Model/SyncPlay/UtcTimeResponse.cs @@ -1,3 +1,5 @@ +#nullable disable + namespace MediaBrowser.Model.SyncPlay { /// diff --git a/MediaBrowser.Model/Updates/VersionInfo.cs b/MediaBrowser.Model/Updates/VersionInfo.cs index fe5826ad2..5ab276b89 100644 --- a/MediaBrowser.Model/Updates/VersionInfo.cs +++ b/MediaBrowser.Model/Updates/VersionInfo.cs @@ -1,3 +1,5 @@ +#nullable disable + using System; namespace MediaBrowser.Model.Updates -- cgit v1.2.3 From 44957c5a9a11fcd6e4567c7d31bc39d79c709068 Mon Sep 17 00:00:00 2001 From: crobibero Date: Fri, 5 Jun 2020 18:15:56 -0600 Subject: Use typed logger where possible --- Emby.Dlna/ConnectionManager/ConnectionManager.cs | 2 +- Emby.Dlna/DlnaManager.cs | 4 ++-- Emby.Dlna/Main/DlnaEntryPoint.cs | 10 ++++++---- Emby.Dlna/PlayTo/PlayToManager.cs | 3 ++- Emby.Dlna/Service/BaseService.cs | 4 ++-- Emby.Drawing/ImageProcessor.cs | 2 +- Emby.Notifications/NotificationEntryPoint.cs | 2 +- Emby.Notifications/NotificationManager.cs | 2 +- Emby.Photos/PhotoProvider.cs | 2 +- .../AppBase/BaseConfigurationManager.cs | 4 ++-- Emby.Server.Implementations/ApplicationHost.cs | 2 +- Emby.Server.Implementations/Browser/BrowserLauncher.cs | 2 +- Emby.Server.Implementations/Channels/ChannelManager.cs | 2 +- .../Channels/RefreshChannelsScheduledTask.cs | 2 +- Emby.Server.Implementations/Collections/CollectionManager.cs | 6 +++--- Emby.Server.Implementations/Data/BaseSqliteRepository.cs | 4 ++-- Emby.Server.Implementations/Data/CleanDatabaseScheduledTask.cs | 2 +- Emby.Server.Implementations/Devices/DeviceId.cs | 4 ++-- Emby.Server.Implementations/Dto/DtoService.cs | 2 +- .../EntryPoints/ExternalPortForwarding.cs | 2 +- .../EntryPoints/LibraryChangedNotifier.cs | 2 +- Emby.Server.Implementations/EntryPoints/RecordingNotifier.cs | 2 +- Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs | 2 +- .../HttpClientManager/HttpClientManager.cs | 2 +- Emby.Server.Implementations/HttpServer/HttpListenerHost.cs | 4 ++-- Emby.Server.Implementations/HttpServer/HttpResultFactory.cs | 4 ++-- Emby.Server.Implementations/HttpServer/Security/AuthService.cs | 2 +- Emby.Server.Implementations/HttpServer/WebSocketConnection.cs | 2 +- Emby.Server.Implementations/IO/LibraryMonitor.cs | 2 +- Emby.Server.Implementations/IO/ManagedFileSystem.cs | 2 +- Emby.Server.Implementations/Library/LibraryManager.cs | 2 +- Emby.Server.Implementations/Library/MediaSourceManager.cs | 2 +- .../Library/Resolvers/Audio/MusicAlbumResolver.cs | 2 +- .../Library/Resolvers/TV/SeasonResolver.cs | 2 +- .../Library/Resolvers/TV/SeriesResolver.cs | 4 ++-- Emby.Server.Implementations/Library/SearchEngine.cs | 2 +- Emby.Server.Implementations/Library/UserDataManager.cs | 2 +- Emby.Server.Implementations/Library/UserManager.cs | 2 +- .../Library/Validators/ArtistsPostScanTask.cs | 4 ++-- .../Library/Validators/ArtistsValidator.cs | 4 ++-- .../Library/Validators/GenresPostScanTask.cs | 4 ++-- .../Library/Validators/GenresValidator.cs | 4 ++-- .../Library/Validators/MusicGenresPostScanTask.cs | 4 ++-- .../Library/Validators/MusicGenresValidator.cs | 4 ++-- .../Library/Validators/StudiosPostScanTask.cs | 4 ++-- .../Library/Validators/StudiosValidator.cs | 4 ++-- Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs | 2 +- Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs | 2 +- .../LiveTv/Listings/XmlTvListingsProvider.cs | 2 +- Emby.Server.Implementations/LiveTv/LiveTvDtoService.cs | 2 +- Emby.Server.Implementations/LiveTv/LiveTvManager.cs | 2 +- .../LiveTv/LiveTvMediaSourceProvider.cs | 2 +- Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs | 4 ++-- Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs | 1 + .../Localization/LocalizationManager.cs | 2 +- Emby.Server.Implementations/MediaEncoder/EncodingManager.cs | 2 +- Emby.Server.Implementations/Networking/NetworkManager.cs | 2 +- Emby.Server.Implementations/Playlists/PlaylistManager.cs | 2 +- Emby.Server.Implementations/ResourceFileManager.cs | 2 +- Emby.Server.Implementations/ScheduledTasks/TaskManager.cs | 2 +- .../ScheduledTasks/Tasks/ChapterImagesTask.cs | 4 ++-- .../ScheduledTasks/Tasks/DeleteCacheFileTask.cs | 2 +- .../ScheduledTasks/Tasks/DeleteTranscodeFileTask.cs | 2 +- .../ScheduledTasks/Tasks/PluginUpdateTask.cs | 2 +- Emby.Server.Implementations/Services/ServiceController.cs | 2 +- Emby.Server.Implementations/Session/SessionManager.cs | 2 +- .../Session/SessionWebSocketListener.cs | 2 +- Emby.Server.Implementations/Session/WebSocketController.cs | 2 +- .../SocketSharp/WebSocketSharpRequest.cs | 2 +- Emby.Server.Implementations/SyncPlay/SyncPlayManager.cs | 2 +- Emby.Server.Implementations/Updates/InstallationManager.cs | 2 +- Jellyfin.Drawing.Skia/SkiaEncoder.cs | 2 +- .../Migrations/Routines/DisableTranscodingThrottling.cs | 2 +- Jellyfin.Server/Migrations/Routines/RemoveDuplicateExtras.cs | 2 +- MediaBrowser.Api/ApiEntryPoint.cs | 2 +- MediaBrowser.Api/Music/AlbumsService.cs | 10 ++++++---- MediaBrowser.Api/SimilarItemsHelper.cs | 2 +- MediaBrowser.Controller/Entities/BaseItem.cs | 3 ++- MediaBrowser.Controller/Entities/UserView.cs | 3 ++- MediaBrowser.Controller/Entities/UserViewBuilder.cs | 4 ++-- MediaBrowser.Controller/IO/FileData.cs | 3 ++- MediaBrowser.Controller/Library/Profiler.cs | 2 +- MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs | 4 ++-- MediaBrowser.Controller/Session/SessionInfo.cs | 1 + .../Images/InternalMetadataFolderImageProvider.cs | 2 +- MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs | 4 ++-- MediaBrowser.LocalMetadata/Parsers/BoxSetXmlParser.cs | 2 +- MediaBrowser.LocalMetadata/Parsers/PlaylistXmlParser.cs | 2 +- MediaBrowser.LocalMetadata/Providers/BoxSetXmlProvider.cs | 4 ++-- MediaBrowser.LocalMetadata/Providers/PlaylistXmlProvider.cs | 4 ++-- MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs | 4 ++-- MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs | 2 +- MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 2 +- MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs | 2 +- MediaBrowser.Providers/Manager/ImageSaver.cs | 1 + MediaBrowser.Providers/Manager/MetadataService.cs | 4 ++-- MediaBrowser.Providers/Manager/ProviderManager.cs | 2 +- MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs | 2 +- MediaBrowser.Providers/MediaInfo/SubtitleDownloader.cs | 3 ++- MediaBrowser.Providers/MediaInfo/SubtitleScheduledTask.cs | 2 +- MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs | 2 +- MediaBrowser.Providers/Playlists/PlaylistItemsProvider.cs | 2 +- MediaBrowser.Providers/Plugins/MusicBrainz/AlbumProvider.cs | 2 +- .../Plugins/TheTvdb/TvdbEpisodeImageProvider.cs | 2 +- MediaBrowser.Providers/Plugins/TheTvdb/TvdbEpisodeProvider.cs | 2 +- .../Plugins/TheTvdb/TvdbPersonImageProvider.cs | 2 +- .../Plugins/TheTvdb/TvdbSeasonImageProvider.cs | 2 +- .../Plugins/TheTvdb/TvdbSeriesImageProvider.cs | 2 +- MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeriesProvider.cs | 2 +- MediaBrowser.Providers/Subtitles/SubtitleManager.cs | 2 +- MediaBrowser.Providers/TV/SeriesMetadataService.cs | 3 ++- MediaBrowser.Providers/Tmdb/BoxSets/TmdbBoxSetProvider.cs | 2 +- MediaBrowser.Providers/Tmdb/Movies/TmdbMovieProvider.cs | 2 +- MediaBrowser.Providers/Tmdb/People/TmdbPersonProvider.cs | 2 +- MediaBrowser.Providers/Tmdb/TV/TmdbEpisodeImageProvider.cs | 4 ++-- MediaBrowser.Providers/Tmdb/TV/TmdbEpisodeProvider.cs | 4 ++-- MediaBrowser.Providers/Tmdb/TV/TmdbEpisodeProviderBase.cs | 4 ++-- MediaBrowser.Providers/Tmdb/TV/TmdbSeasonProvider.cs | 6 +++--- MediaBrowser.Providers/Tmdb/TV/TmdbSeriesProvider.cs | 2 +- MediaBrowser.WebDashboard/Api/DashboardService.cs | 2 +- MediaBrowser.XbmcMetadata/EntryPoint.cs | 2 +- MediaBrowser.XbmcMetadata/Providers/AlbumNfoProvider.cs | 2 +- MediaBrowser.XbmcMetadata/Providers/ArtistNfoProvider.cs | 2 +- MediaBrowser.XbmcMetadata/Providers/BaseVideoNfoProvider.cs | 4 ++-- MediaBrowser.XbmcMetadata/Providers/EpisodeNfoProvider.cs | 2 +- MediaBrowser.XbmcMetadata/Providers/SeasonNfoProvider.cs | 2 +- MediaBrowser.XbmcMetadata/Providers/SeriesNfoProvider.cs | 2 +- MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs | 6 +++--- 128 files changed, 179 insertions(+), 166 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Dlna/ConnectionManager/ConnectionManager.cs b/Emby.Dlna/ConnectionManager/ConnectionManager.cs index e32cc11bf..480dd3a79 100644 --- a/Emby.Dlna/ConnectionManager/ConnectionManager.cs +++ b/Emby.Dlna/ConnectionManager/ConnectionManager.cs @@ -18,7 +18,7 @@ namespace Emby.Dlna.ConnectionManager public ConnectionManager( IDlnaManager dlna, IServerConfigurationManager config, - ILogger logger, + ILogger logger, IHttpClient httpClient) : base(logger, httpClient) { diff --git a/Emby.Dlna/DlnaManager.cs b/Emby.Dlna/DlnaManager.cs index 10f881fe7..a85e5c35e 100644 --- a/Emby.Dlna/DlnaManager.cs +++ b/Emby.Dlna/DlnaManager.cs @@ -31,7 +31,7 @@ namespace Emby.Dlna private readonly IApplicationPaths _appPaths; private readonly IXmlSerializer _xmlSerializer; private readonly IFileSystem _fileSystem; - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IJsonSerializer _jsonSerializer; private readonly IServerApplicationHost _appHost; private static readonly Assembly _assembly = typeof(DlnaManager).Assembly; @@ -49,7 +49,7 @@ namespace Emby.Dlna _xmlSerializer = xmlSerializer; _fileSystem = fileSystem; _appPaths = appPaths; - _logger = loggerFactory.CreateLogger("Dlna"); + _logger = loggerFactory.CreateLogger(); _jsonSerializer = jsonSerializer; _appHost = appHost; } diff --git a/Emby.Dlna/Main/DlnaEntryPoint.cs b/Emby.Dlna/Main/DlnaEntryPoint.cs index bcab4adba..47b235e59 100644 --- a/Emby.Dlna/Main/DlnaEntryPoint.cs +++ b/Emby.Dlna/Main/DlnaEntryPoint.cs @@ -33,7 +33,7 @@ namespace Emby.Dlna.Main public class DlnaEntryPoint : IServerEntryPoint, IRunBeforeStartup { private readonly IServerConfigurationManager _config; - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IServerApplicationHost _appHost; private PlayToManager _manager; @@ -65,7 +65,8 @@ namespace Emby.Dlna.Main public static DlnaEntryPoint Current; - public DlnaEntryPoint(IServerConfigurationManager config, + public DlnaEntryPoint( + IServerConfigurationManager config, ILoggerFactory loggerFactory, IServerApplicationHost appHost, ISessionManager sessionManager, @@ -99,7 +100,7 @@ namespace Emby.Dlna.Main _mediaEncoder = mediaEncoder; _socketFactory = socketFactory; _networkManager = networkManager; - _logger = loggerFactory.CreateLogger("Dlna"); + _logger = loggerFactory.CreateLogger(); ContentDirectory = new ContentDirectory.ContentDirectory( dlnaManager, @@ -347,7 +348,8 @@ namespace Emby.Dlna.Main try { - _manager = new PlayToManager(_logger, + _manager = new PlayToManager( + _logger, _sessionManager, _libraryManager, _userManager, diff --git a/Emby.Dlna/PlayTo/PlayToManager.cs b/Emby.Dlna/PlayTo/PlayToManager.cs index bbedd1485..9b0339e5d 100644 --- a/Emby.Dlna/PlayTo/PlayToManager.cs +++ b/Emby.Dlna/PlayTo/PlayToManager.cs @@ -184,7 +184,8 @@ namespace Emby.Dlna.PlayTo serverAddress = _appHost.GetLocalApiUrl(info.LocalIpAddress); } - controller = new PlayToController(sessionInfo, + controller = new PlayToController( + sessionInfo, _sessionManager, _libraryManager, _logger, diff --git a/Emby.Dlna/Service/BaseService.cs b/Emby.Dlna/Service/BaseService.cs index 3704bedcd..4ecffa293 100644 --- a/Emby.Dlna/Service/BaseService.cs +++ b/Emby.Dlna/Service/BaseService.cs @@ -12,12 +12,12 @@ namespace Emby.Dlna.Service protected IHttpClient HttpClient; protected ILogger Logger; - protected BaseService(ILogger logger, IHttpClient httpClient) + protected BaseService(ILogger logger, IHttpClient httpClient) { Logger = logger; HttpClient = httpClient; - EventManager = new EventManager(Logger, HttpClient); + EventManager = new EventManager(logger, HttpClient); } public EventSubscriptionResponse CancelEventSubscription(string subscriptionId) diff --git a/Emby.Drawing/ImageProcessor.cs b/Emby.Drawing/ImageProcessor.cs index 47778acac..c9fc8d55a 100644 --- a/Emby.Drawing/ImageProcessor.cs +++ b/Emby.Drawing/ImageProcessor.cs @@ -28,7 +28,7 @@ namespace Emby.Drawing private static readonly HashSet _transparentImageTypes = new HashSet(StringComparer.OrdinalIgnoreCase) { ".png", ".webp", ".gif" }; - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IFileSystem _fileSystem; private readonly IServerApplicationPaths _appPaths; private readonly IImageEncoder _imageEncoder; diff --git a/Emby.Notifications/NotificationEntryPoint.cs b/Emby.Notifications/NotificationEntryPoint.cs index 869b7407e..b923fd26c 100644 --- a/Emby.Notifications/NotificationEntryPoint.cs +++ b/Emby.Notifications/NotificationEntryPoint.cs @@ -25,7 +25,7 @@ namespace Emby.Notifications /// public class NotificationEntryPoint : IServerEntryPoint { - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IActivityManager _activityManager; private readonly ILocalizationManager _localization; private readonly INotificationManager _notificationManager; diff --git a/Emby.Notifications/NotificationManager.cs b/Emby.Notifications/NotificationManager.cs index 639a5e1aa..2792a8f0b 100644 --- a/Emby.Notifications/NotificationManager.cs +++ b/Emby.Notifications/NotificationManager.cs @@ -21,7 +21,7 @@ namespace Emby.Notifications /// public class NotificationManager : INotificationManager { - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IUserManager _userManager; private readonly IServerConfigurationManager _config; diff --git a/Emby.Photos/PhotoProvider.cs b/Emby.Photos/PhotoProvider.cs index 987cb7fb2..58baa1e50 100644 --- a/Emby.Photos/PhotoProvider.cs +++ b/Emby.Photos/PhotoProvider.cs @@ -22,7 +22,7 @@ namespace Emby.Photos /// public class PhotoProvider : ICustomMetadataProvider, IForcedProvider, IHasItemChangeMonitor { - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IImageProcessor _imageProcessor; // These are causing taglib to hang diff --git a/Emby.Server.Implementations/AppBase/BaseConfigurationManager.cs b/Emby.Server.Implementations/AppBase/BaseConfigurationManager.cs index 080cfbbd1..d4a8268b9 100644 --- a/Emby.Server.Implementations/AppBase/BaseConfigurationManager.cs +++ b/Emby.Server.Implementations/AppBase/BaseConfigurationManager.cs @@ -53,7 +53,7 @@ namespace Emby.Server.Implementations.AppBase CommonApplicationPaths = applicationPaths; XmlSerializer = xmlSerializer; _fileSystem = fileSystem; - Logger = loggerFactory.CreateLogger(GetType().Name); + Logger = loggerFactory.CreateLogger(); UpdateCachePath(); } @@ -83,7 +83,7 @@ namespace Emby.Server.Implementations.AppBase /// Gets the logger. /// /// The logger. - protected ILogger Logger { get; private set; } + protected ILogger Logger { get; private set; } /// /// Gets the XML serializer. diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index be4e05a64..184c6f399 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -173,7 +173,7 @@ namespace Emby.Server.Implementations /// /// Gets the logger. /// - protected ILogger Logger { get; } + protected ILogger Logger { get; } private IPlugin[] _plugins; diff --git a/Emby.Server.Implementations/Browser/BrowserLauncher.cs b/Emby.Server.Implementations/Browser/BrowserLauncher.cs index 7f7c6a0be..7a0294e07 100644 --- a/Emby.Server.Implementations/Browser/BrowserLauncher.cs +++ b/Emby.Server.Implementations/Browser/BrowserLauncher.cs @@ -41,7 +41,7 @@ namespace Emby.Server.Implementations.Browser } catch (Exception ex) { - var logger = appHost.Resolve(); + var logger = appHost.Resolve>(); logger?.LogError(ex, "Failed to open browser window with URL {URL}", relativeUrl); } } diff --git a/Emby.Server.Implementations/Channels/ChannelManager.cs b/Emby.Server.Implementations/Channels/ChannelManager.cs index 04fe0bacb..f9eea66b4 100644 --- a/Emby.Server.Implementations/Channels/ChannelManager.cs +++ b/Emby.Server.Implementations/Channels/ChannelManager.cs @@ -36,7 +36,7 @@ namespace Emby.Server.Implementations.Channels private readonly IUserDataManager _userDataManager; private readonly IDtoService _dtoService; private readonly ILibraryManager _libraryManager; - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IServerConfigurationManager _config; private readonly IFileSystem _fileSystem; private readonly IJsonSerializer _jsonSerializer; diff --git a/Emby.Server.Implementations/Channels/RefreshChannelsScheduledTask.cs b/Emby.Server.Implementations/Channels/RefreshChannelsScheduledTask.cs index 54b621e25..e5dde48d8 100644 --- a/Emby.Server.Implementations/Channels/RefreshChannelsScheduledTask.cs +++ b/Emby.Server.Implementations/Channels/RefreshChannelsScheduledTask.cs @@ -17,7 +17,7 @@ namespace Emby.Server.Implementations.Channels public class RefreshChannelsScheduledTask : IScheduledTask, IConfigurableScheduledTask { private readonly IChannelManager _channelManager; - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly ILibraryManager _libraryManager; private readonly ILocalizationManager _localization; diff --git a/Emby.Server.Implementations/Collections/CollectionManager.cs b/Emby.Server.Implementations/Collections/CollectionManager.cs index 7c518d483..cba3975cf 100644 --- a/Emby.Server.Implementations/Collections/CollectionManager.cs +++ b/Emby.Server.Implementations/Collections/CollectionManager.cs @@ -29,7 +29,7 @@ namespace Emby.Server.Implementations.Collections private readonly ILibraryManager _libraryManager; private readonly IFileSystem _fileSystem; private readonly ILibraryMonitor _iLibraryMonitor; - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IProviderManager _providerManager; private readonly ILocalizationManager _localizationManager; private readonly IApplicationPaths _appPaths; @@ -56,7 +56,7 @@ namespace Emby.Server.Implementations.Collections _libraryManager = libraryManager; _fileSystem = fileSystem; _iLibraryMonitor = iLibraryMonitor; - _logger = loggerFactory.CreateLogger(nameof(CollectionManager)); + _logger = loggerFactory.CreateLogger(); _providerManager = providerManager; _localizationManager = localizationManager; _appPaths = appPaths; @@ -370,7 +370,7 @@ namespace Emby.Server.Implementations.Collections { private readonly CollectionManager _collectionManager; private readonly IServerConfigurationManager _config; - private readonly ILogger _logger; + private readonly ILogger _logger; /// /// Initializes a new instance of the class. diff --git a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs index 0654132f4..f816fd54f 100644 --- a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs +++ b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs @@ -17,7 +17,7 @@ namespace Emby.Server.Implementations.Data /// Initializes a new instance of the class. /// /// The logger. - protected BaseSqliteRepository(ILogger logger) + protected BaseSqliteRepository(ILogger logger) { Logger = logger; } @@ -32,7 +32,7 @@ namespace Emby.Server.Implementations.Data /// Gets the logger. /// /// The logger. - protected ILogger Logger { get; } + protected ILogger Logger { get; } /// /// Gets the default connection flags. diff --git a/Emby.Server.Implementations/Data/CleanDatabaseScheduledTask.cs b/Emby.Server.Implementations/Data/CleanDatabaseScheduledTask.cs index 37c678a5d..6c9bcff0f 100644 --- a/Emby.Server.Implementations/Data/CleanDatabaseScheduledTask.cs +++ b/Emby.Server.Implementations/Data/CleanDatabaseScheduledTask.cs @@ -12,7 +12,7 @@ namespace Emby.Server.Implementations.Data public class CleanDatabaseScheduledTask : ILibraryPostScanTask { private readonly ILibraryManager _libraryManager; - private readonly ILogger _logger; + private readonly ILogger _logger; public CleanDatabaseScheduledTask(ILibraryManager libraryManager, ILogger logger) { diff --git a/Emby.Server.Implementations/Devices/DeviceId.cs b/Emby.Server.Implementations/Devices/DeviceId.cs index f0d43e665..fa6ac95fd 100644 --- a/Emby.Server.Implementations/Devices/DeviceId.cs +++ b/Emby.Server.Implementations/Devices/DeviceId.cs @@ -12,7 +12,7 @@ namespace Emby.Server.Implementations.Devices public class DeviceId { private readonly IApplicationPaths _appPaths; - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly object _syncLock = new object(); @@ -90,7 +90,7 @@ namespace Emby.Server.Implementations.Devices public DeviceId(IApplicationPaths appPaths, ILoggerFactory loggerFactory) { _appPaths = appPaths; - _logger = loggerFactory.CreateLogger("SystemId"); + _logger = loggerFactory.CreateLogger(); } public string Value => _id ?? (_id = GetDeviceId()); diff --git a/Emby.Server.Implementations/Dto/DtoService.cs b/Emby.Server.Implementations/Dto/DtoService.cs index 38c4f940d..f9841082c 100644 --- a/Emby.Server.Implementations/Dto/DtoService.cs +++ b/Emby.Server.Implementations/Dto/DtoService.cs @@ -29,7 +29,7 @@ namespace Emby.Server.Implementations.Dto { public class DtoService : IDtoService { - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly ILibraryManager _libraryManager; private readonly IUserDataManager _userDataRepository; private readonly IItemRepository _itemRepo; diff --git a/Emby.Server.Implementations/EntryPoints/ExternalPortForwarding.cs b/Emby.Server.Implementations/EntryPoints/ExternalPortForwarding.cs index 878cee23c..9fce49425 100644 --- a/Emby.Server.Implementations/EntryPoints/ExternalPortForwarding.cs +++ b/Emby.Server.Implementations/EntryPoints/ExternalPortForwarding.cs @@ -23,7 +23,7 @@ namespace Emby.Server.Implementations.EntryPoints public class ExternalPortForwarding : IServerEntryPoint { private readonly IServerApplicationHost _appHost; - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IServerConfigurationManager _config; private readonly IDeviceDiscovery _deviceDiscovery; diff --git a/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs b/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs index 9bc2b62ec..b9992ae73 100644 --- a/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs +++ b/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs @@ -28,7 +28,7 @@ namespace Emby.Server.Implementations.EntryPoints private readonly ISessionManager _sessionManager; private readonly IUserManager _userManager; - private readonly ILogger _logger; + private readonly ILogger _logger; /// /// The library changed sync lock. diff --git a/Emby.Server.Implementations/EntryPoints/RecordingNotifier.cs b/Emby.Server.Implementations/EntryPoints/RecordingNotifier.cs index 997571a91..b64439802 100644 --- a/Emby.Server.Implementations/EntryPoints/RecordingNotifier.cs +++ b/Emby.Server.Implementations/EntryPoints/RecordingNotifier.cs @@ -17,7 +17,7 @@ namespace Emby.Server.Implementations.EntryPoints private readonly ILiveTvManager _liveTvManager; private readonly ISessionManager _sessionManager; private readonly IUserManager _userManager; - private readonly ILogger _logger; + private readonly ILogger _logger; public RecordingNotifier( ISessionManager sessionManager, diff --git a/Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs b/Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs index 5bc1a81aa..ecdce89ce 100644 --- a/Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs +++ b/Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs @@ -21,7 +21,7 @@ namespace Emby.Server.Implementations.EntryPoints /// /// The logger. /// - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IServerApplicationHost _appHost; private readonly IConfiguration _config; diff --git a/Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs b/Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs index d66bb7638..87977494a 100644 --- a/Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs +++ b/Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs @@ -22,7 +22,7 @@ namespace Emby.Server.Implementations.HttpClientManager /// public class HttpClientManager : IHttpClient { - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IApplicationPaths _appPaths; private readonly IFileSystem _fileSystem; private readonly IApplicationHost _appHost; diff --git a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs index 7de4f168c..17994d199 100644 --- a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs +++ b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs @@ -41,7 +41,7 @@ namespace Emby.Server.Implementations.HttpServer /// public const string DefaultRedirectKey = "HttpListenerHost:DefaultRedirectPath"; - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly ILoggerFactory _loggerFactory; private readonly IServerConfigurationManager _config; private readonly INetworkManager _networkManager; @@ -397,7 +397,7 @@ namespace Emby.Server.Implementations.HttpServer var response = context.Response; var localPath = context.Request.Path.ToString(); - var req = new WebSocketSharpRequest(request, response, request.Path, _logger); + var req = new WebSocketSharpRequest(request, response, request.Path); return RequestHandler(req, request.GetDisplayUrl(), request.Host.ToString(), localPath, context.RequestAborted); } diff --git a/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs b/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs index 9d5969583..cc4797790 100644 --- a/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs +++ b/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs @@ -37,7 +37,7 @@ namespace Emby.Server.Implementations.HttpServer /// /// The logger. /// - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IFileSystem _fileSystem; private readonly IJsonSerializer _jsonSerializer; private readonly IStreamHelper _streamHelper; @@ -50,7 +50,7 @@ namespace Emby.Server.Implementations.HttpServer _fileSystem = fileSystem; _jsonSerializer = jsonSerializer; _streamHelper = streamHelper; - _logger = loggerfactory.CreateLogger("HttpResultFactory"); + _logger = loggerfactory.CreateLogger(); } /// diff --git a/Emby.Server.Implementations/HttpServer/Security/AuthService.cs b/Emby.Server.Implementations/HttpServer/Security/AuthService.cs index 256b24924..9bb29586e 100644 --- a/Emby.Server.Implementations/HttpServer/Security/AuthService.cs +++ b/Emby.Server.Implementations/HttpServer/Security/AuthService.cs @@ -45,7 +45,7 @@ namespace Emby.Server.Implementations.HttpServer.Security public User Authenticate(HttpRequest request, IAuthenticationAttributes authAttributes) { - var req = new WebSocketSharpRequest(request, null, request.Path, _logger); + var req = new WebSocketSharpRequest(request, null, request.Path); var user = ValidateUser(req, authAttributes); return user; } diff --git a/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs b/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs index 0680c5ffe..c64d57339 100644 --- a/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs +++ b/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs @@ -24,7 +24,7 @@ namespace Emby.Server.Implementations.HttpServer /// /// The logger. /// - private readonly ILogger _logger; + private readonly ILogger _logger; /// /// The json serializer options. diff --git a/Emby.Server.Implementations/IO/LibraryMonitor.cs b/Emby.Server.Implementations/IO/LibraryMonitor.cs index eb5e190aa..49bca7dac 100644 --- a/Emby.Server.Implementations/IO/LibraryMonitor.cs +++ b/Emby.Server.Implementations/IO/LibraryMonitor.cs @@ -18,7 +18,7 @@ namespace Emby.Server.Implementations.IO { public class LibraryMonitor : ILibraryMonitor { - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly ILibraryManager _libraryManager; private readonly IServerConfigurationManager _configurationManager; private readonly IFileSystem _fileSystem; diff --git a/Emby.Server.Implementations/IO/ManagedFileSystem.cs b/Emby.Server.Implementations/IO/ManagedFileSystem.cs index 7461ec4f1..2bcfc82b6 100644 --- a/Emby.Server.Implementations/IO/ManagedFileSystem.cs +++ b/Emby.Server.Implementations/IO/ManagedFileSystem.cs @@ -20,7 +20,7 @@ namespace Emby.Server.Implementations.IO /// public class ManagedFileSystem : IFileSystem { - protected ILogger Logger; + protected ILogger Logger; private readonly List _shortcutHandlers = new List(); private readonly string _tempPath; diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index 677030b82..8c6be8e04 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -56,7 +56,7 @@ namespace Emby.Server.Implementations.Library /// public class LibraryManager : ILibraryManager { - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly ITaskManager _taskManager; private readonly IUserManager _userManager; private readonly IUserDataManager _userDataRepository; diff --git a/Emby.Server.Implementations/Library/MediaSourceManager.cs b/Emby.Server.Implementations/Library/MediaSourceManager.cs index a5e5981b8..00826c7cb 100644 --- a/Emby.Server.Implementations/Library/MediaSourceManager.cs +++ b/Emby.Server.Implementations/Library/MediaSourceManager.cs @@ -33,7 +33,7 @@ namespace Emby.Server.Implementations.Library private readonly ILibraryManager _libraryManager; private readonly IJsonSerializer _jsonSerializer; private readonly IFileSystem _fileSystem; - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IUserDataManager _userDataManager; private readonly IMediaEncoder _mediaEncoder; private readonly ILocalizationManager _localizationManager; diff --git a/Emby.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs index 6c9ba7c27..ebfe95d0a 100644 --- a/Emby.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs @@ -109,7 +109,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio IEnumerable list, bool allowSubfolders, IDirectoryService directoryService, - ILogger logger, + ILogger logger, IFileSystem fileSystem, ILibraryManager libraryManager) { diff --git a/Emby.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs b/Emby.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs index 18145b7f1..7f8800a64 100644 --- a/Emby.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs @@ -16,7 +16,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV private readonly IServerConfigurationManager _config; private readonly ILibraryManager _libraryManager; private readonly ILocalizationManager _localization; - private readonly ILogger _logger; + private readonly ILogger _logger; /// /// Initializes a new instance of the class. diff --git a/Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs b/Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs index dd6bd8ee8..4180dad36 100644 --- a/Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs @@ -20,7 +20,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV public class SeriesResolver : FolderResolver { private readonly IFileSystem _fileSystem; - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly ILibraryManager _libraryManager; /// @@ -119,7 +119,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV IEnumerable fileSystemChildren, IDirectoryService directoryService, IFileSystem fileSystem, - ILogger logger, + ILogger logger, ILibraryManager libraryManager, bool isTvContentType) { diff --git a/Emby.Server.Implementations/Library/SearchEngine.cs b/Emby.Server.Implementations/Library/SearchEngine.cs index 59a77607d..bde77ee8e 100644 --- a/Emby.Server.Implementations/Library/SearchEngine.cs +++ b/Emby.Server.Implementations/Library/SearchEngine.cs @@ -17,7 +17,7 @@ namespace Emby.Server.Implementations.Library { public class SearchEngine : ISearchEngine { - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly ILibraryManager _libraryManager; private readonly IUserManager _userManager; diff --git a/Emby.Server.Implementations/Library/UserDataManager.cs b/Emby.Server.Implementations/Library/UserDataManager.cs index a9772a078..d8694b07d 100644 --- a/Emby.Server.Implementations/Library/UserDataManager.cs +++ b/Emby.Server.Implementations/Library/UserDataManager.cs @@ -26,7 +26,7 @@ namespace Emby.Server.Implementations.Library private readonly ConcurrentDictionary _userData = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IServerConfigurationManager _config; private readonly IUserManager _userManager; private readonly IUserDataRepository _repository; diff --git a/Emby.Server.Implementations/Library/UserManager.cs b/Emby.Server.Implementations/Library/UserManager.cs index 140155d0e..531e00666 100644 --- a/Emby.Server.Implementations/Library/UserManager.cs +++ b/Emby.Server.Implementations/Library/UserManager.cs @@ -46,7 +46,7 @@ namespace Emby.Server.Implementations.Library private readonly object _policySyncLock = new object(); private readonly object _configSyncLock = new object(); - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IUserRepository _userRepository; private readonly IXmlSerializer _xmlSerializer; private readonly IJsonSerializer _jsonSerializer; diff --git a/Emby.Server.Implementations/Library/Validators/ArtistsPostScanTask.cs b/Emby.Server.Implementations/Library/Validators/ArtistsPostScanTask.cs index 2af8ff5cb..d51f9aaa7 100644 --- a/Emby.Server.Implementations/Library/Validators/ArtistsPostScanTask.cs +++ b/Emby.Server.Implementations/Library/Validators/ArtistsPostScanTask.cs @@ -16,7 +16,7 @@ namespace Emby.Server.Implementations.Library.Validators /// The _library manager. /// private readonly ILibraryManager _libraryManager; - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IItemRepository _itemRepo; /// @@ -27,7 +27,7 @@ namespace Emby.Server.Implementations.Library.Validators /// The item repository. public ArtistsPostScanTask( ILibraryManager libraryManager, - ILogger logger, + ILogger logger, IItemRepository itemRepo) { _libraryManager = libraryManager; diff --git a/Emby.Server.Implementations/Library/Validators/ArtistsValidator.cs b/Emby.Server.Implementations/Library/Validators/ArtistsValidator.cs index 1497f4a3a..8a6bd5e78 100644 --- a/Emby.Server.Implementations/Library/Validators/ArtistsValidator.cs +++ b/Emby.Server.Implementations/Library/Validators/ArtistsValidator.cs @@ -24,7 +24,7 @@ namespace Emby.Server.Implementations.Library.Validators /// /// The logger. /// - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IItemRepository _itemRepo; /// @@ -33,7 +33,7 @@ namespace Emby.Server.Implementations.Library.Validators /// The library manager. /// The logger. /// The item repository. - public ArtistsValidator(ILibraryManager libraryManager, ILogger logger, IItemRepository itemRepo) + public ArtistsValidator(ILibraryManager libraryManager, ILogger logger, IItemRepository itemRepo) { _libraryManager = libraryManager; _logger = logger; diff --git a/Emby.Server.Implementations/Library/Validators/GenresPostScanTask.cs b/Emby.Server.Implementations/Library/Validators/GenresPostScanTask.cs index 251785dfd..d21d2887b 100644 --- a/Emby.Server.Implementations/Library/Validators/GenresPostScanTask.cs +++ b/Emby.Server.Implementations/Library/Validators/GenresPostScanTask.cs @@ -16,7 +16,7 @@ namespace Emby.Server.Implementations.Library.Validators /// The _library manager. /// private readonly ILibraryManager _libraryManager; - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IItemRepository _itemRepo; /// @@ -27,7 +27,7 @@ namespace Emby.Server.Implementations.Library.Validators /// The item repository. public GenresPostScanTask( ILibraryManager libraryManager, - ILogger logger, + ILogger logger, IItemRepository itemRepo) { _libraryManager = libraryManager; diff --git a/Emby.Server.Implementations/Library/Validators/GenresValidator.cs b/Emby.Server.Implementations/Library/Validators/GenresValidator.cs index b0cd5f87a..e59c62e23 100644 --- a/Emby.Server.Implementations/Library/Validators/GenresValidator.cs +++ b/Emby.Server.Implementations/Library/Validators/GenresValidator.cs @@ -21,7 +21,7 @@ namespace Emby.Server.Implementations.Library.Validators /// /// The logger. /// - private readonly ILogger _logger; + private readonly ILogger _logger; /// /// Initializes a new instance of the class. @@ -29,7 +29,7 @@ namespace Emby.Server.Implementations.Library.Validators /// The library manager. /// The logger. /// The item repository. - public GenresValidator(ILibraryManager libraryManager, ILogger logger, IItemRepository itemRepo) + public GenresValidator(ILibraryManager libraryManager, ILogger logger, IItemRepository itemRepo) { _libraryManager = libraryManager; _logger = logger; diff --git a/Emby.Server.Implementations/Library/Validators/MusicGenresPostScanTask.cs b/Emby.Server.Implementations/Library/Validators/MusicGenresPostScanTask.cs index 9d8690116..be119866b 100644 --- a/Emby.Server.Implementations/Library/Validators/MusicGenresPostScanTask.cs +++ b/Emby.Server.Implementations/Library/Validators/MusicGenresPostScanTask.cs @@ -16,7 +16,7 @@ namespace Emby.Server.Implementations.Library.Validators /// The library manager. /// private readonly ILibraryManager _libraryManager; - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IItemRepository _itemRepo; /// @@ -27,7 +27,7 @@ namespace Emby.Server.Implementations.Library.Validators /// The item repository. public MusicGenresPostScanTask( ILibraryManager libraryManager, - ILogger logger, + ILogger logger, IItemRepository itemRepo) { _libraryManager = libraryManager; diff --git a/Emby.Server.Implementations/Library/Validators/MusicGenresValidator.cs b/Emby.Server.Implementations/Library/Validators/MusicGenresValidator.cs index 5ee4ca72e..1ecf4c87c 100644 --- a/Emby.Server.Implementations/Library/Validators/MusicGenresValidator.cs +++ b/Emby.Server.Implementations/Library/Validators/MusicGenresValidator.cs @@ -20,7 +20,7 @@ namespace Emby.Server.Implementations.Library.Validators /// /// The logger. /// - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IItemRepository _itemRepo; /// @@ -29,7 +29,7 @@ namespace Emby.Server.Implementations.Library.Validators /// The library manager. /// The logger. /// The item repository. - public MusicGenresValidator(ILibraryManager libraryManager, ILogger logger, IItemRepository itemRepo) + public MusicGenresValidator(ILibraryManager libraryManager, ILogger logger, IItemRepository itemRepo) { _libraryManager = libraryManager; _logger = logger; diff --git a/Emby.Server.Implementations/Library/Validators/StudiosPostScanTask.cs b/Emby.Server.Implementations/Library/Validators/StudiosPostScanTask.cs index 2f8f906b9..c682b156b 100644 --- a/Emby.Server.Implementations/Library/Validators/StudiosPostScanTask.cs +++ b/Emby.Server.Implementations/Library/Validators/StudiosPostScanTask.cs @@ -17,7 +17,7 @@ namespace Emby.Server.Implementations.Library.Validators /// private readonly ILibraryManager _libraryManager; - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IItemRepository _itemRepo; /// @@ -28,7 +28,7 @@ namespace Emby.Server.Implementations.Library.Validators /// The item repository. public StudiosPostScanTask( ILibraryManager libraryManager, - ILogger logger, + ILogger logger, IItemRepository itemRepo) { _libraryManager = libraryManager; diff --git a/Emby.Server.Implementations/Library/Validators/StudiosValidator.cs b/Emby.Server.Implementations/Library/Validators/StudiosValidator.cs index 15e7a0dbb..7a6cd11df 100644 --- a/Emby.Server.Implementations/Library/Validators/StudiosValidator.cs +++ b/Emby.Server.Implementations/Library/Validators/StudiosValidator.cs @@ -24,7 +24,7 @@ namespace Emby.Server.Implementations.Library.Validators /// /// The logger. /// - private readonly ILogger _logger; + private readonly ILogger _logger; /// /// Initializes a new instance of the class. @@ -32,7 +32,7 @@ namespace Emby.Server.Implementations.Library.Validators /// The library manager. /// The logger. /// The item repository. - public StudiosValidator(ILibraryManager libraryManager, ILogger logger, IItemRepository itemRepo) + public StudiosValidator(ILibraryManager libraryManager, ILogger logger, IItemRepository itemRepo) { _libraryManager = libraryManager; _logger = logger; diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index 5a5dc3329..f9b71939b 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -46,7 +46,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV private const int TunerDiscoveryDurationMs = 3000; private readonly IServerApplicationHost _appHost; - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IHttpClient _httpClient; private readonly IServerConfigurationManager _config; private readonly IJsonSerializer _jsonSerializer; diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs index 89b81fd96..02f18060d 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs @@ -24,7 +24,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings { public class SchedulesDirect : IListingsProvider { - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IJsonSerializer _jsonSerializer; private readonly IHttpClient _httpClient; private readonly SemaphoreSlim _tokenSemaphore = new SemaphoreSlim(1, 1); diff --git a/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs b/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs index 07f8539c5..077b5c7e5 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs @@ -26,7 +26,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings { private readonly IServerConfigurationManager _config; private readonly IHttpClient _httpClient; - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IFileSystem _fileSystem; private readonly IZipClient _zipClient; diff --git a/Emby.Server.Implementations/LiveTv/LiveTvDtoService.cs b/Emby.Server.Implementations/LiveTv/LiveTvDtoService.cs index a59c1090e..49ad73af3 100644 --- a/Emby.Server.Implementations/LiveTv/LiveTvDtoService.cs +++ b/Emby.Server.Implementations/LiveTv/LiveTvDtoService.cs @@ -26,7 +26,7 @@ namespace Emby.Server.Implementations.LiveTv private const string ServiceName = "Emby"; - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IImageProcessor _imageProcessor; private readonly IDtoService _dtoService; private readonly IApplicationHost _appHost; diff --git a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs index dbd0e6f2e..a88e0f31f 100644 --- a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs @@ -44,7 +44,7 @@ namespace Emby.Server.Implementations.LiveTv private const string EtagKey = "ProgramEtag"; private readonly IServerConfigurationManager _config; - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IItemRepository _itemRepo; private readonly IUserManager _userManager; private readonly IDtoService _dtoService; diff --git a/Emby.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs b/Emby.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs index 7f63991d0..f3fc41352 100644 --- a/Emby.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs +++ b/Emby.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs @@ -23,7 +23,7 @@ namespace Emby.Server.Implementations.LiveTv private const string StreamIdDelimeterString = "_"; private readonly ILiveTvManager _liveTvManager; - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IMediaSourceManager _mediaSourceManager; private readonly IServerApplicationHost _appHost; diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs index 80ee1ee33..ba3594efd 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs @@ -22,14 +22,14 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts public abstract class BaseTunerHost { protected readonly IServerConfigurationManager Config; - protected readonly ILogger Logger; + protected readonly ILogger Logger; protected IJsonSerializer JsonSerializer; protected readonly IFileSystem FileSystem; private readonly ConcurrentDictionary _channelCache = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); - protected BaseTunerHost(IServerConfigurationManager config, ILogger logger, IJsonSerializer jsonSerializer, IFileSystem fileSystem) + protected BaseTunerHost(IServerConfigurationManager config, ILogger logger, IJsonSerializer jsonSerializer, IFileSystem fileSystem) { Config = config; Logger = logger; diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs index 4e4f1d7f6..c3336ca92 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs @@ -7,6 +7,7 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; +using Emby.Server.Implementations.Library; using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Library; using MediaBrowser.Model.Dto; diff --git a/Emby.Server.Implementations/Localization/LocalizationManager.cs b/Emby.Server.Implementations/Localization/LocalizationManager.cs index e2a634e1a..62a23118f 100644 --- a/Emby.Server.Implementations/Localization/LocalizationManager.cs +++ b/Emby.Server.Implementations/Localization/LocalizationManager.cs @@ -25,7 +25,7 @@ namespace Emby.Server.Implementations.Localization private readonly IServerConfigurationManager _configurationManager; private readonly IJsonSerializer _jsonSerializer; - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly Dictionary> _allParentalRatings = new Dictionary>(StringComparer.OrdinalIgnoreCase); diff --git a/Emby.Server.Implementations/MediaEncoder/EncodingManager.cs b/Emby.Server.Implementations/MediaEncoder/EncodingManager.cs index 7b7575707..438bbe24a 100644 --- a/Emby.Server.Implementations/MediaEncoder/EncodingManager.cs +++ b/Emby.Server.Implementations/MediaEncoder/EncodingManager.cs @@ -23,7 +23,7 @@ namespace Emby.Server.Implementations.MediaEncoder { private readonly CultureInfo _usCulture = new CultureInfo("en-US"); private readonly IFileSystem _fileSystem; - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IMediaEncoder _encoder; private readonly IChapterManager _chapterManager; private readonly ILibraryManager _libraryManager; diff --git a/Emby.Server.Implementations/Networking/NetworkManager.cs b/Emby.Server.Implementations/Networking/NetworkManager.cs index d1a28e7a1..45864bb42 100644 --- a/Emby.Server.Implementations/Networking/NetworkManager.cs +++ b/Emby.Server.Implementations/Networking/NetworkManager.cs @@ -15,7 +15,7 @@ namespace Emby.Server.Implementations.Networking { public class NetworkManager : INetworkManager { - private readonly ILogger _logger; + private readonly ILogger _logger; private IPAddress[] _localIpAddresses; private readonly object _localIpAddressSyncLock = new object(); diff --git a/Emby.Server.Implementations/Playlists/PlaylistManager.cs b/Emby.Server.Implementations/Playlists/PlaylistManager.cs index c51eb0586..8d022d6c4 100644 --- a/Emby.Server.Implementations/Playlists/PlaylistManager.cs +++ b/Emby.Server.Implementations/Playlists/PlaylistManager.cs @@ -29,7 +29,7 @@ namespace Emby.Server.Implementations.Playlists private readonly ILibraryManager _libraryManager; private readonly IFileSystem _fileSystem; private readonly ILibraryMonitor _iLibraryMonitor; - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IUserManager _userManager; private readonly IProviderManager _providerManager; private readonly IConfiguration _appConfig; diff --git a/Emby.Server.Implementations/ResourceFileManager.cs b/Emby.Server.Implementations/ResourceFileManager.cs index d192be921..22fc62293 100644 --- a/Emby.Server.Implementations/ResourceFileManager.cs +++ b/Emby.Server.Implementations/ResourceFileManager.cs @@ -12,7 +12,7 @@ namespace Emby.Server.Implementations public class ResourceFileManager : IResourceFileManager { private readonly IFileSystem _fileSystem; - private readonly ILogger _logger; + private readonly ILogger _logger; public ResourceFileManager(ILogger logger, IFileSystem fileSystem) { diff --git a/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs b/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs index efefa5506..94220ac5d 100644 --- a/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs +++ b/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs @@ -36,7 +36,7 @@ namespace Emby.Server.Implementations.ScheduledTasks private readonly IJsonSerializer _jsonSerializer; private readonly IApplicationPaths _applicationPaths; - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IFileSystem _fileSystem; /// diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/ChapterImagesTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/ChapterImagesTask.cs index fae049914..9028222dd 100644 --- a/Emby.Server.Implementations/ScheduledTasks/Tasks/ChapterImagesTask.cs +++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/ChapterImagesTask.cs @@ -27,7 +27,7 @@ namespace Emby.Server.Implementations.ScheduledTasks /// /// The _logger. /// - private readonly ILogger _logger; + private readonly ILogger _logger; /// /// The _library manager. @@ -54,7 +54,7 @@ namespace Emby.Server.Implementations.ScheduledTasks IFileSystem fileSystem, ILocalizationManager localization) { - _logger = loggerFactory.CreateLogger(GetType().Name); + _logger = loggerFactory.CreateLogger(); _libraryManager = libraryManager; _itemRepo = itemRepo; _appPaths = appPaths; diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs index a6c13eaef..966b549b2 100644 --- a/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs +++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs @@ -23,7 +23,7 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks /// The application paths. private IApplicationPaths ApplicationPaths { get; set; } - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IFileSystem _fileSystem; private readonly ILocalizationManager _localization; diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteTranscodeFileTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteTranscodeFileTask.cs index 0d36b82c0..53cf9a0a5 100644 --- a/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteTranscodeFileTask.cs +++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteTranscodeFileTask.cs @@ -17,7 +17,7 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks /// public class DeleteTranscodeFileTask : IScheduledTask, IConfigurableScheduledTask { - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IConfigurationManager _configurationManager; private readonly IFileSystem _fileSystem; private readonly ILocalizationManager _localization; diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/PluginUpdateTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/PluginUpdateTask.cs index acab3aeea..7388086fb 100644 --- a/Emby.Server.Implementations/ScheduledTasks/Tasks/PluginUpdateTask.cs +++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/PluginUpdateTask.cs @@ -22,7 +22,7 @@ namespace Emby.Server.Implementations.ScheduledTasks /// /// The _logger. /// - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IInstallationManager _installationManager; private readonly ILocalizationManager _localization; diff --git a/Emby.Server.Implementations/Services/ServiceController.cs b/Emby.Server.Implementations/Services/ServiceController.cs index ad6015c1c..e688278b5 100644 --- a/Emby.Server.Implementations/Services/ServiceController.cs +++ b/Emby.Server.Implementations/Services/ServiceController.cs @@ -15,7 +15,7 @@ namespace Emby.Server.Implementations.Services public class ServiceController { - private readonly ILogger _logger; + private readonly ILogger _logger; /// /// Initializes a new instance of the class. diff --git a/Emby.Server.Implementations/Session/SessionManager.cs b/Emby.Server.Implementations/Session/SessionManager.cs index 5c480e842..506e6739f 100644 --- a/Emby.Server.Implementations/Session/SessionManager.cs +++ b/Emby.Server.Implementations/Session/SessionManager.cs @@ -45,7 +45,7 @@ namespace Emby.Server.Implementations.Session /// /// The logger. /// - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly ILibraryManager _libraryManager; private readonly IUserManager _userManager; diff --git a/Emby.Server.Implementations/Session/SessionWebSocketListener.cs b/Emby.Server.Implementations/Session/SessionWebSocketListener.cs index e7b4b0ec3..ef32c692c 100644 --- a/Emby.Server.Implementations/Session/SessionWebSocketListener.cs +++ b/Emby.Server.Implementations/Session/SessionWebSocketListener.cs @@ -41,7 +41,7 @@ namespace Emby.Server.Implementations.Session /// /// The _logger /// - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly ILoggerFactory _loggerFactory; private readonly IHttpServer _httpServer; diff --git a/Emby.Server.Implementations/Session/WebSocketController.cs b/Emby.Server.Implementations/Session/WebSocketController.cs index a0274acd2..94604ca1e 100644 --- a/Emby.Server.Implementations/Session/WebSocketController.cs +++ b/Emby.Server.Implementations/Session/WebSocketController.cs @@ -17,7 +17,7 @@ namespace Emby.Server.Implementations.Session { public sealed class WebSocketController : ISessionController, IDisposable { - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly ISessionManager _sessionManager; private readonly SessionInfo _session; diff --git a/Emby.Server.Implementations/SocketSharp/WebSocketSharpRequest.cs b/Emby.Server.Implementations/SocketSharp/WebSocketSharpRequest.cs index aa76901a4..ae1a8d0b7 100644 --- a/Emby.Server.Implementations/SocketSharp/WebSocketSharpRequest.cs +++ b/Emby.Server.Implementations/SocketSharp/WebSocketSharpRequest.cs @@ -26,7 +26,7 @@ namespace Emby.Server.Implementations.SocketSharp private Dictionary _items; private string _responseContentType; - public WebSocketSharpRequest(HttpRequest httpRequest, HttpResponse httpResponse, string operationName, ILogger logger) + public WebSocketSharpRequest(HttpRequest httpRequest, HttpResponse httpResponse, string operationName) { this.OperationName = operationName; this.Request = httpRequest; diff --git a/Emby.Server.Implementations/SyncPlay/SyncPlayManager.cs b/Emby.Server.Implementations/SyncPlay/SyncPlayManager.cs index 129262e53..1bfc9a9a5 100644 --- a/Emby.Server.Implementations/SyncPlay/SyncPlayManager.cs +++ b/Emby.Server.Implementations/SyncPlay/SyncPlayManager.cs @@ -21,7 +21,7 @@ namespace Emby.Server.Implementations.SyncPlay /// /// The logger. /// - private readonly ILogger _logger; + private readonly ILogger _logger; /// /// The user manager. diff --git a/Emby.Server.Implementations/Updates/InstallationManager.cs b/Emby.Server.Implementations/Updates/InstallationManager.cs index 178f32c31..80326fddf 100644 --- a/Emby.Server.Implementations/Updates/InstallationManager.cs +++ b/Emby.Server.Implementations/Updates/InstallationManager.cs @@ -39,7 +39,7 @@ namespace Emby.Server.Implementations.Updates /// /// The logger. /// - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IApplicationPaths _appPaths; private readonly IHttpClient _httpClient; private readonly IJsonSerializer _jsonSerializer; diff --git a/Jellyfin.Drawing.Skia/SkiaEncoder.cs b/Jellyfin.Drawing.Skia/SkiaEncoder.cs index ccee5c5b9..ba9a5809f 100644 --- a/Jellyfin.Drawing.Skia/SkiaEncoder.cs +++ b/Jellyfin.Drawing.Skia/SkiaEncoder.cs @@ -21,7 +21,7 @@ namespace Jellyfin.Drawing.Skia private static readonly HashSet _transparentImageTypes = new HashSet(StringComparer.OrdinalIgnoreCase) { ".png", ".gif", ".webp" }; - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IApplicationPaths _appPaths; /// diff --git a/Jellyfin.Server/Migrations/Routines/DisableTranscodingThrottling.cs b/Jellyfin.Server/Migrations/Routines/DisableTranscodingThrottling.cs index b2e957d5b..c18aa1629 100644 --- a/Jellyfin.Server/Migrations/Routines/DisableTranscodingThrottling.cs +++ b/Jellyfin.Server/Migrations/Routines/DisableTranscodingThrottling.cs @@ -10,7 +10,7 @@ namespace Jellyfin.Server.Migrations.Routines /// internal class DisableTranscodingThrottling : IMigrationRoutine { - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IConfigurationManager _configManager; public DisableTranscodingThrottling(ILogger logger, IConfigurationManager configManager) diff --git a/Jellyfin.Server/Migrations/Routines/RemoveDuplicateExtras.cs b/Jellyfin.Server/Migrations/Routines/RemoveDuplicateExtras.cs index e95536388..2ebef0241 100644 --- a/Jellyfin.Server/Migrations/Routines/RemoveDuplicateExtras.cs +++ b/Jellyfin.Server/Migrations/Routines/RemoveDuplicateExtras.cs @@ -14,7 +14,7 @@ namespace Jellyfin.Server.Migrations.Routines internal class RemoveDuplicateExtras : IMigrationRoutine { private const string DbFilename = "library.db"; - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IServerApplicationPaths _paths; public RemoveDuplicateExtras(ILogger logger, IServerApplicationPaths paths) diff --git a/MediaBrowser.Api/ApiEntryPoint.cs b/MediaBrowser.Api/ApiEntryPoint.cs index c7485a2e9..9e651fb19 100644 --- a/MediaBrowser.Api/ApiEntryPoint.cs +++ b/MediaBrowser.Api/ApiEntryPoint.cs @@ -31,7 +31,7 @@ namespace MediaBrowser.Api /// /// The logger. /// - private ILogger _logger; + private ILogger _logger; /// /// The configuration manager. diff --git a/MediaBrowser.Api/Music/AlbumsService.cs b/MediaBrowser.Api/Music/AlbumsService.cs index 58c95d053..f257d1014 100644 --- a/MediaBrowser.Api/Music/AlbumsService.cs +++ b/MediaBrowser.Api/Music/AlbumsService.cs @@ -67,12 +67,13 @@ namespace MediaBrowser.Api.Music { var dtoOptions = GetDtoOptions(_authContext, request); - var result = SimilarItemsHelper.GetSimilarItemsResult(dtoOptions, _userManager, + var result = SimilarItemsHelper.GetSimilarItemsResult( + dtoOptions, + _userManager, _itemRepo, _libraryManager, _userDataRepository, _dtoService, - Logger, request, new[] { typeof(MusicArtist) }, SimilarItemsHelper.GetSimiliarityScore); @@ -88,12 +89,13 @@ namespace MediaBrowser.Api.Music { var dtoOptions = GetDtoOptions(_authContext, request); - var result = SimilarItemsHelper.GetSimilarItemsResult(dtoOptions, _userManager, + var result = SimilarItemsHelper.GetSimilarItemsResult( + dtoOptions, + _userManager, _itemRepo, _libraryManager, _userDataRepository, _dtoService, - Logger, request, new[] { typeof(MusicAlbum) }, GetAlbumSimilarityScore); diff --git a/MediaBrowser.Api/SimilarItemsHelper.cs b/MediaBrowser.Api/SimilarItemsHelper.cs index 44bb24ef2..dcd22280a 100644 --- a/MediaBrowser.Api/SimilarItemsHelper.cs +++ b/MediaBrowser.Api/SimilarItemsHelper.cs @@ -69,7 +69,7 @@ namespace MediaBrowser.Api /// public static class SimilarItemsHelper { - internal static QueryResult GetSimilarItemsResult(DtoOptions dtoOptions, IUserManager userManager, IItemRepository itemRepository, ILibraryManager libraryManager, IUserDataManager userDataRepository, IDtoService dtoService, ILogger logger, BaseGetSimilarItemsFromItem request, Type[] includeTypes, Func, List, BaseItem, int> getSimilarityScore) + internal static QueryResult GetSimilarItemsResult(DtoOptions dtoOptions, IUserManager userManager, IItemRepository itemRepository, ILibraryManager libraryManager, IUserDataManager userDataRepository, IDtoService dtoService, BaseGetSimilarItemsFromItem request, Type[] includeTypes, Func, List, BaseItem, int> getSimilarityScore) { var user = !request.UserId.Equals(Guid.Empty) ? userManager.GetUserById(request.UserId) : null; diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index f4b71d8bf..2c789e386 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -557,7 +557,8 @@ namespace MediaBrowser.Controller.Entities /// /// The logger /// - public static ILogger Logger { get; set; } + public static ILoggerFactory LoggerFactory { get; set; } + public static ILogger Logger { get; set; } public static ILibraryManager LibraryManager { get; set; } public static IServerConfigurationManager ConfigurationManager { get; set; } public static IProviderManager ProviderManager { get; set; } diff --git a/MediaBrowser.Controller/Entities/UserView.cs b/MediaBrowser.Controller/Entities/UserView.cs index 4ce9ec6f8..86cff632c 100644 --- a/MediaBrowser.Controller/Entities/UserView.cs +++ b/MediaBrowser.Controller/Entities/UserView.cs @@ -5,6 +5,7 @@ using System.Text.Json.Serialization; using System.Threading.Tasks; using MediaBrowser.Controller.TV; using MediaBrowser.Model.Querying; +using Microsoft.Extensions.Logging; namespace MediaBrowser.Controller.Entities { @@ -66,7 +67,7 @@ namespace MediaBrowser.Controller.Entities parent = LibraryManager.GetItemById(ParentId) as Folder ?? parent; } - return new UserViewBuilder(UserViewManager, LibraryManager, Logger, UserDataManager, TVSeriesManager, ConfigurationManager) + return new UserViewBuilder(UserViewManager, LibraryManager, LoggerFactory.CreateLogger(), UserDataManager, TVSeriesManager, ConfigurationManager) .GetUserItems(parent, this, CollectionType, query); } diff --git a/MediaBrowser.Controller/Entities/UserViewBuilder.cs b/MediaBrowser.Controller/Entities/UserViewBuilder.cs index 435a1e8da..3d91a0d0e 100644 --- a/MediaBrowser.Controller/Entities/UserViewBuilder.cs +++ b/MediaBrowser.Controller/Entities/UserViewBuilder.cs @@ -17,7 +17,7 @@ namespace MediaBrowser.Controller.Entities { private readonly IUserViewManager _userViewManager; private readonly ILibraryManager _libraryManager; - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IUserDataManager _userDataManager; private readonly ITVSeriesManager _tvSeriesManager; private readonly IServerConfigurationManager _config; @@ -25,7 +25,7 @@ namespace MediaBrowser.Controller.Entities public UserViewBuilder( IUserViewManager userViewManager, ILibraryManager libraryManager, - ILogger logger, + ILogger logger, IUserDataManager userDataManager, ITVSeriesManager tvSeriesManager, IServerConfigurationManager config) diff --git a/MediaBrowser.Controller/IO/FileData.cs b/MediaBrowser.Controller/IO/FileData.cs index 4bbb60283..666a3f76b 100644 --- a/MediaBrowser.Controller/IO/FileData.cs +++ b/MediaBrowser.Controller/IO/FileData.cs @@ -35,7 +35,8 @@ namespace MediaBrowser.Controller.IO /// if set to true [resolve shortcuts]. /// Dictionary{System.StringFileSystemInfo}. /// path - public static FileSystemMetadata[] GetFilteredFileSystemEntries(IDirectoryService directoryService, + public static FileSystemMetadata[] GetFilteredFileSystemEntries( + IDirectoryService directoryService, string path, IFileSystem fileSystem, IServerApplicationHost appHost, diff --git a/MediaBrowser.Controller/Library/Profiler.cs b/MediaBrowser.Controller/Library/Profiler.cs index 46a97d181..0febef3d3 100644 --- a/MediaBrowser.Controller/Library/Profiler.cs +++ b/MediaBrowser.Controller/Library/Profiler.cs @@ -21,7 +21,7 @@ namespace MediaBrowser.Controller.Library /// /// The _logger /// - private readonly ILogger _logger; + private readonly ILogger _logger; /// /// Initializes a new instance of the class. diff --git a/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs b/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs index 5be656bdb..7dca793c6 100644 --- a/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs +++ b/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs @@ -40,9 +40,9 @@ namespace MediaBrowser.Controller.Net /// /// The logger /// - protected ILogger Logger; + protected ILogger> Logger; - protected BasePeriodicWebSocketListener(ILogger logger) + protected BasePeriodicWebSocketListener(ILogger> logger) { if (logger == null) { diff --git a/MediaBrowser.Controller/Session/SessionInfo.cs b/MediaBrowser.Controller/Session/SessionInfo.cs index 2ba7c9fec..ecc910872 100644 --- a/MediaBrowser.Controller/Session/SessionInfo.cs +++ b/MediaBrowser.Controller/Session/SessionInfo.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Text.Json.Serialization; using System.Threading; using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Session; using Microsoft.Extensions.Logging; diff --git a/MediaBrowser.LocalMetadata/Images/InternalMetadataFolderImageProvider.cs b/MediaBrowser.LocalMetadata/Images/InternalMetadataFolderImageProvider.cs index 795933ce9..5137e4c68 100644 --- a/MediaBrowser.LocalMetadata/Images/InternalMetadataFolderImageProvider.cs +++ b/MediaBrowser.LocalMetadata/Images/InternalMetadataFolderImageProvider.cs @@ -13,7 +13,7 @@ namespace MediaBrowser.LocalMetadata.Images { private readonly IServerConfigurationManager _config; private readonly IFileSystem _fileSystem; - private readonly ILogger _logger; + private readonly ILogger _logger; public InternalMetadataFolderImageProvider( IServerConfigurationManager config, diff --git a/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs b/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs index d4b98182f..9621cfa4e 100644 --- a/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs +++ b/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs @@ -23,7 +23,7 @@ namespace MediaBrowser.LocalMetadata.Parsers /// /// The logger /// - protected ILogger Logger { get; private set; } + protected ILogger> Logger { get; private set; } protected IProviderManager ProviderManager { get; private set; } private Dictionary _validProviderIds; @@ -32,7 +32,7 @@ namespace MediaBrowser.LocalMetadata.Parsers /// Initializes a new instance of the class. /// /// The logger. - public BaseItemXmlParser(ILogger logger, IProviderManager providerManager) + public BaseItemXmlParser(ILogger> logger, IProviderManager providerManager) { Logger = logger; ProviderManager = providerManager; diff --git a/MediaBrowser.LocalMetadata/Parsers/BoxSetXmlParser.cs b/MediaBrowser.LocalMetadata/Parsers/BoxSetXmlParser.cs index 127334625..ca11a079d 100644 --- a/MediaBrowser.LocalMetadata/Parsers/BoxSetXmlParser.cs +++ b/MediaBrowser.LocalMetadata/Parsers/BoxSetXmlParser.cs @@ -85,7 +85,7 @@ namespace MediaBrowser.LocalMetadata.Parsers item.Item.LinkedChildren = list.ToArray(); } - public BoxSetXmlParser(ILogger logger, IProviderManager providerManager) + public BoxSetXmlParser(ILogger logger, IProviderManager providerManager) : base(logger, providerManager) { } diff --git a/MediaBrowser.LocalMetadata/Parsers/PlaylistXmlParser.cs b/MediaBrowser.LocalMetadata/Parsers/PlaylistXmlParser.cs index 5608a0be9..54710cd82 100644 --- a/MediaBrowser.LocalMetadata/Parsers/PlaylistXmlParser.cs +++ b/MediaBrowser.LocalMetadata/Parsers/PlaylistXmlParser.cs @@ -93,7 +93,7 @@ namespace MediaBrowser.LocalMetadata.Parsers item.LinkedChildren = list.ToArray(); } - public PlaylistXmlParser(ILogger logger, IProviderManager providerManager) + public PlaylistXmlParser(ILogger logger, IProviderManager providerManager) : base(logger, providerManager) { } diff --git a/MediaBrowser.LocalMetadata/Providers/BoxSetXmlProvider.cs b/MediaBrowser.LocalMetadata/Providers/BoxSetXmlProvider.cs index b2e3bc9e2..2d115a591 100644 --- a/MediaBrowser.LocalMetadata/Providers/BoxSetXmlProvider.cs +++ b/MediaBrowser.LocalMetadata/Providers/BoxSetXmlProvider.cs @@ -13,10 +13,10 @@ namespace MediaBrowser.LocalMetadata.Providers /// public class BoxSetXmlProvider : BaseXmlProvider { - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IProviderManager _providerManager; - public BoxSetXmlProvider(IFileSystem fileSystem, ILogger logger, IProviderManager providerManager) + public BoxSetXmlProvider(IFileSystem fileSystem, ILogger logger, IProviderManager providerManager) : base(fileSystem) { _logger = logger; diff --git a/MediaBrowser.LocalMetadata/Providers/PlaylistXmlProvider.cs b/MediaBrowser.LocalMetadata/Providers/PlaylistXmlProvider.cs index df8107bad..d4e2bc8e5 100644 --- a/MediaBrowser.LocalMetadata/Providers/PlaylistXmlProvider.cs +++ b/MediaBrowser.LocalMetadata/Providers/PlaylistXmlProvider.cs @@ -10,12 +10,12 @@ namespace MediaBrowser.LocalMetadata.Providers { public class PlaylistXmlProvider : BaseXmlProvider { - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IProviderManager _providerManager; public PlaylistXmlProvider( IFileSystem fileSystem, - ILogger logger, + ILogger logger, IProviderManager providerManager) : base(fileSystem) { diff --git a/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs index ba1d850e3..071902393 100644 --- a/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs +++ b/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs @@ -21,7 +21,7 @@ namespace MediaBrowser.LocalMetadata.Savers { private static readonly CultureInfo UsCulture = new CultureInfo("en-US"); - public BaseXmlSaver(IFileSystem fileSystem, IServerConfigurationManager configurationManager, ILibraryManager libraryManager, IUserManager userManager, IUserDataManager userDataManager, ILogger logger) + public BaseXmlSaver(IFileSystem fileSystem, IServerConfigurationManager configurationManager, ILibraryManager libraryManager, IUserManager userManager, IUserDataManager userDataManager, ILogger logger) { FileSystem = fileSystem; ConfigurationManager = configurationManager; @@ -36,7 +36,7 @@ namespace MediaBrowser.LocalMetadata.Savers protected ILibraryManager LibraryManager { get; private set; } protected IUserManager UserManager { get; private set; } protected IUserDataManager UserDataManager { get; private set; } - protected ILogger Logger { get; private set; } + protected ILogger Logger { get; private set; } public string Name => XmlProviderUtils.Name; diff --git a/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs b/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs index 3f177a9fa..a82f2108f 100644 --- a/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs +++ b/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs @@ -21,7 +21,7 @@ namespace MediaBrowser.MediaEncoding.Attachments { public class AttachmentExtractor : IAttachmentExtractor, IDisposable { - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IApplicationPaths _appPaths; private readonly IFileSystem _fileSystem; private readonly IMediaEncoder _mediaEncoder; diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index 1377502dd..26bd202ba 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -34,7 +34,7 @@ namespace MediaBrowser.MediaEncoding.Encoder /// internal const int DefaultImageExtractionTimeout = 5000; - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IServerConfigurationManager _configurationManager; private readonly IFileSystem _fileSystem; private readonly ILocalizationManager _localization; diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs index ba171295e..f08af6045 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs @@ -25,7 +25,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles public class SubtitleEncoder : ISubtitleEncoder { private readonly ILibraryManager _libraryManager; - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IApplicationPaths _appPaths; private readonly IFileSystem _fileSystem; private readonly IMediaEncoder _mediaEncoder; diff --git a/MediaBrowser.Providers/Manager/ImageSaver.cs b/MediaBrowser.Providers/Manager/ImageSaver.cs index 3ab621ba4..f21ac2d65 100644 --- a/MediaBrowser.Providers/Manager/ImageSaver.cs +++ b/MediaBrowser.Providers/Manager/ImageSaver.cs @@ -15,6 +15,7 @@ using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Entities; using MediaBrowser.Model.IO; using MediaBrowser.Model.Net; +using MediaBrowser.Providers.Tmdb.Models.General; using Microsoft.Extensions.Logging; namespace MediaBrowser.Providers.Manager diff --git a/MediaBrowser.Providers/Manager/MetadataService.cs b/MediaBrowser.Providers/Manager/MetadataService.cs index c49aa407a..2997ba064 100644 --- a/MediaBrowser.Providers/Manager/MetadataService.cs +++ b/MediaBrowser.Providers/Manager/MetadataService.cs @@ -20,12 +20,12 @@ namespace MediaBrowser.Providers.Manager where TIdType : ItemLookupInfo, new() { protected readonly IServerConfigurationManager ServerConfigurationManager; - protected readonly ILogger Logger; + protected readonly ILogger> Logger; protected readonly IProviderManager ProviderManager; protected readonly IFileSystem FileSystem; protected readonly ILibraryManager LibraryManager; - protected MetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IFileSystem fileSystem, ILibraryManager libraryManager) + protected MetadataService(IServerConfigurationManager serverConfigurationManager, ILogger> logger, IProviderManager providerManager, IFileSystem fileSystem, ILibraryManager libraryManager) { ServerConfigurationManager = serverConfigurationManager; Logger = logger; diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs index 400ec8d29..13a4436e1 100644 --- a/MediaBrowser.Providers/Manager/ProviderManager.cs +++ b/MediaBrowser.Providers/Manager/ProviderManager.cs @@ -36,7 +36,7 @@ namespace MediaBrowser.Providers.Manager /// public class ProviderManager : IProviderManager, IDisposable { - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IHttpClient _httpClient; private readonly ILibraryMonitor _libraryMonitor; private readonly IFileSystem _fileSystem; diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs b/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs index 6982568eb..81103575d 100644 --- a/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs +++ b/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs @@ -37,7 +37,7 @@ namespace MediaBrowser.Providers.MediaInfo IPreRefreshProvider, IHasItemChangeMonitor { - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IIsoManager _isoManager; private readonly IMediaEncoder _mediaEncoder; private readonly IItemRepository _itemRepo; diff --git a/MediaBrowser.Providers/MediaInfo/SubtitleDownloader.cs b/MediaBrowser.Providers/MediaInfo/SubtitleDownloader.cs index 77c0e9b4e..f35e82bb5 100644 --- a/MediaBrowser.Providers/MediaInfo/SubtitleDownloader.cs +++ b/MediaBrowser.Providers/MediaInfo/SubtitleDownloader.cs @@ -25,7 +25,8 @@ namespace MediaBrowser.Providers.MediaInfo _subtitleManager = subtitleManager; } - public async Task> DownloadSubtitles(Video video, + public async Task> DownloadSubtitles( + Video video, List mediaStreams, bool skipIfEmbeddedSubtitlesPresent, bool skipIfAudioTrackMatches, diff --git a/MediaBrowser.Providers/MediaInfo/SubtitleScheduledTask.cs b/MediaBrowser.Providers/MediaInfo/SubtitleScheduledTask.cs index 2615f2dbb..fb87030ff 100644 --- a/MediaBrowser.Providers/MediaInfo/SubtitleScheduledTask.cs +++ b/MediaBrowser.Providers/MediaInfo/SubtitleScheduledTask.cs @@ -24,7 +24,7 @@ namespace MediaBrowser.Providers.MediaInfo private readonly IServerConfigurationManager _config; private readonly ISubtitleManager _subtitleManager; private readonly IMediaSourceManager _mediaSourceManager; - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IJsonSerializer _json; private readonly ILocalizationManager _localization; diff --git a/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs b/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs index f40570040..08e503a71 100644 --- a/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs +++ b/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs @@ -17,7 +17,7 @@ namespace MediaBrowser.Providers.MediaInfo public class VideoImageProvider : IDynamicImageProvider, IHasOrder { private readonly IMediaEncoder _mediaEncoder; - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IFileSystem _fileSystem; public VideoImageProvider(IMediaEncoder mediaEncoder, ILogger logger, IFileSystem fileSystem) diff --git a/MediaBrowser.Providers/Playlists/PlaylistItemsProvider.cs b/MediaBrowser.Providers/Playlists/PlaylistItemsProvider.cs index ae837c591..9fc86b213 100644 --- a/MediaBrowser.Providers/Playlists/PlaylistItemsProvider.cs +++ b/MediaBrowser.Providers/Playlists/PlaylistItemsProvider.cs @@ -20,7 +20,7 @@ namespace MediaBrowser.Providers.Playlists IPreRefreshProvider, IHasItemChangeMonitor { - private ILogger _logger; + private readonly ILogger _logger; private IFileSystem _fileSystem; public PlaylistItemsProvider(IFileSystem fileSystem, ILogger logger) diff --git a/MediaBrowser.Providers/Plugins/MusicBrainz/AlbumProvider.cs b/MediaBrowser.Providers/Plugins/MusicBrainz/AlbumProvider.cs index 31cdaf616..9d0d14969 100644 --- a/MediaBrowser.Providers/Plugins/MusicBrainz/AlbumProvider.cs +++ b/MediaBrowser.Providers/Plugins/MusicBrainz/AlbumProvider.cs @@ -42,7 +42,7 @@ namespace MediaBrowser.Providers.Music private readonly IHttpClient _httpClient; private readonly IApplicationHost _appHost; - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly string _musicBrainzBaseUrl; diff --git a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbEpisodeImageProvider.cs b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbEpisodeImageProvider.cs index 6118a9c53..7a6fdc5f4 100644 --- a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbEpisodeImageProvider.cs +++ b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbEpisodeImageProvider.cs @@ -17,7 +17,7 @@ namespace MediaBrowser.Providers.Plugins.TheTvdb public class TvdbEpisodeImageProvider : IRemoteImageProvider { private readonly IHttpClient _httpClient; - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly TvdbClientManager _tvdbClientManager; public TvdbEpisodeImageProvider(IHttpClient httpClient, ILogger logger, TvdbClientManager tvdbClientManager) diff --git a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbEpisodeProvider.cs b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbEpisodeProvider.cs index 08c2a74d2..1f8b82ecd 100644 --- a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbEpisodeProvider.cs +++ b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbEpisodeProvider.cs @@ -21,7 +21,7 @@ namespace MediaBrowser.Providers.Plugins.TheTvdb public class TvdbEpisodeProvider : IRemoteMetadataProvider, IHasOrder { private readonly IHttpClient _httpClient; - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly TvdbClientManager _tvdbClientManager; public TvdbEpisodeProvider(IHttpClient httpClient, ILogger logger, TvdbClientManager tvdbClientManager) diff --git a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbPersonImageProvider.cs b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbPersonImageProvider.cs index c1cdc90e9..961cb5970 100644 --- a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbPersonImageProvider.cs +++ b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbPersonImageProvider.cs @@ -19,7 +19,7 @@ namespace MediaBrowser.Providers.Plugins.TheTvdb public class TvdbPersonImageProvider : IRemoteImageProvider, IHasOrder { private readonly IHttpClient _httpClient; - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly ILibraryManager _libraryManager; private readonly TvdbClientManager _tvdbClientManager; diff --git a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeasonImageProvider.cs b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeasonImageProvider.cs index a5d183df7..cd22514b4 100644 --- a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeasonImageProvider.cs +++ b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeasonImageProvider.cs @@ -19,7 +19,7 @@ namespace MediaBrowser.Providers.Plugins.TheTvdb public class TvdbSeasonImageProvider : IRemoteImageProvider, IHasOrder { private readonly IHttpClient _httpClient; - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly TvdbClientManager _tvdbClientManager; public TvdbSeasonImageProvider(IHttpClient httpClient, ILogger logger, TvdbClientManager tvdbClientManager) diff --git a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeriesImageProvider.cs b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeriesImageProvider.cs index 1bad60756..3fd98b828 100644 --- a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeriesImageProvider.cs +++ b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeriesImageProvider.cs @@ -19,7 +19,7 @@ namespace MediaBrowser.Providers.Plugins.TheTvdb public class TvdbSeriesImageProvider : IRemoteImageProvider, IHasOrder { private readonly IHttpClient _httpClient; - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly TvdbClientManager _tvdbClientManager; public TvdbSeriesImageProvider(IHttpClient httpClient, ILogger logger, TvdbClientManager tvdbClientManager) diff --git a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeriesProvider.cs b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeriesProvider.cs index f6cd249f5..35152610a 100644 --- a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeriesProvider.cs +++ b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeriesProvider.cs @@ -23,7 +23,7 @@ namespace MediaBrowser.Providers.Plugins.TheTvdb { internal static TvdbSeriesProvider Current { get; private set; } private readonly IHttpClient _httpClient; - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly ILibraryManager _libraryManager; private readonly ILocalizationManager _localizationManager; private readonly TvdbClientManager _tvdbClientManager; diff --git a/MediaBrowser.Providers/Subtitles/SubtitleManager.cs b/MediaBrowser.Providers/Subtitles/SubtitleManager.cs index 127d29c04..c6ffc460c 100644 --- a/MediaBrowser.Providers/Subtitles/SubtitleManager.cs +++ b/MediaBrowser.Providers/Subtitles/SubtitleManager.cs @@ -25,7 +25,7 @@ namespace MediaBrowser.Providers.Subtitles { public class SubtitleManager : ISubtitleManager { - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IFileSystem _fileSystem; private readonly ILibraryMonitor _monitor; private readonly IMediaSourceManager _mediaSourceManager; diff --git a/MediaBrowser.Providers/TV/SeriesMetadataService.cs b/MediaBrowser.Providers/TV/SeriesMetadataService.cs index 5e75a8125..a91d5d707 100644 --- a/MediaBrowser.Providers/TV/SeriesMetadataService.cs +++ b/MediaBrowser.Providers/TV/SeriesMetadataService.cs @@ -42,7 +42,8 @@ namespace MediaBrowser.Providers.TV await seasonProvider.Run(item, cancellationToken).ConfigureAwait(false); // TODO why does it not register this itself omg - var provider = new MissingEpisodeProvider(Logger, + var provider = new MissingEpisodeProvider( + Logger, ServerConfigurationManager, LibraryManager, _localization, diff --git a/MediaBrowser.Providers/Tmdb/BoxSets/TmdbBoxSetProvider.cs b/MediaBrowser.Providers/Tmdb/BoxSets/TmdbBoxSetProvider.cs index dd3783ffb..e17f5efdf 100644 --- a/MediaBrowser.Providers/Tmdb/BoxSets/TmdbBoxSetProvider.cs +++ b/MediaBrowser.Providers/Tmdb/BoxSets/TmdbBoxSetProvider.cs @@ -29,7 +29,7 @@ namespace MediaBrowser.Providers.Tmdb.BoxSets internal static TmdbBoxSetProvider Current; - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IJsonSerializer _json; private readonly IServerConfigurationManager _config; private readonly IFileSystem _fileSystem; diff --git a/MediaBrowser.Providers/Tmdb/Movies/TmdbMovieProvider.cs b/MediaBrowser.Providers/Tmdb/Movies/TmdbMovieProvider.cs index e2fd5b9e3..3787d4003 100644 --- a/MediaBrowser.Providers/Tmdb/Movies/TmdbMovieProvider.cs +++ b/MediaBrowser.Providers/Tmdb/Movies/TmdbMovieProvider.cs @@ -36,7 +36,7 @@ namespace MediaBrowser.Providers.Tmdb.Movies private readonly IHttpClient _httpClient; private readonly IFileSystem _fileSystem; private readonly IServerConfigurationManager _configurationManager; - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly ILibraryManager _libraryManager; private readonly IApplicationHost _appHost; diff --git a/MediaBrowser.Providers/Tmdb/People/TmdbPersonProvider.cs b/MediaBrowser.Providers/Tmdb/People/TmdbPersonProvider.cs index 588001169..1f09badbc 100644 --- a/MediaBrowser.Providers/Tmdb/People/TmdbPersonProvider.cs +++ b/MediaBrowser.Providers/Tmdb/People/TmdbPersonProvider.cs @@ -35,7 +35,7 @@ namespace MediaBrowser.Providers.Tmdb.People private readonly IFileSystem _fileSystem; private readonly IServerConfigurationManager _configurationManager; private readonly IHttpClient _httpClient; - private readonly ILogger _logger; + private readonly ILogger _logger; public TmdbPersonProvider( IFileSystem fileSystem, diff --git a/MediaBrowser.Providers/Tmdb/TV/TmdbEpisodeImageProvider.cs b/MediaBrowser.Providers/Tmdb/TV/TmdbEpisodeImageProvider.cs index 558c8149e..b0174a587 100644 --- a/MediaBrowser.Providers/Tmdb/TV/TmdbEpisodeImageProvider.cs +++ b/MediaBrowser.Providers/Tmdb/TV/TmdbEpisodeImageProvider.cs @@ -24,8 +24,8 @@ namespace MediaBrowser.Providers.Tmdb.TV IRemoteImageProvider, IHasOrder { - public TmdbEpisodeImageProvider(IHttpClient httpClient, IServerConfigurationManager configurationManager, IJsonSerializer jsonSerializer, IFileSystem fileSystem, ILocalizationManager localization, ILoggerFactory loggerFactory) - : base(httpClient, configurationManager, jsonSerializer, fileSystem, localization, loggerFactory) + public TmdbEpisodeImageProvider(IHttpClient httpClient, IServerConfigurationManager configurationManager, IJsonSerializer jsonSerializer, IFileSystem fileSystem, ILocalizationManager localization, ILogger logger) + : base(httpClient, configurationManager, jsonSerializer, fileSystem, localization, logger) { } public IEnumerable GetSupportedImages(BaseItem item) diff --git a/MediaBrowser.Providers/Tmdb/TV/TmdbEpisodeProvider.cs b/MediaBrowser.Providers/Tmdb/TV/TmdbEpisodeProvider.cs index a17f5d17a..330b9f42b 100644 --- a/MediaBrowser.Providers/Tmdb/TV/TmdbEpisodeProvider.cs +++ b/MediaBrowser.Providers/Tmdb/TV/TmdbEpisodeProvider.cs @@ -25,8 +25,8 @@ namespace MediaBrowser.Providers.Tmdb.TV IRemoteMetadataProvider, IHasOrder { - public TmdbEpisodeProvider(IHttpClient httpClient, IServerConfigurationManager configurationManager, IJsonSerializer jsonSerializer, IFileSystem fileSystem, ILocalizationManager localization, ILoggerFactory loggerFactory) - : base(httpClient, configurationManager, jsonSerializer, fileSystem, localization, loggerFactory) + public TmdbEpisodeProvider(IHttpClient httpClient, IServerConfigurationManager configurationManager, IJsonSerializer jsonSerializer, IFileSystem fileSystem, ILocalizationManager localization, ILogger logger) + : base(httpClient, configurationManager, jsonSerializer, fileSystem, localization, logger) { } public async Task> GetSearchResults(EpisodeInfo searchInfo, CancellationToken cancellationToken) diff --git a/MediaBrowser.Providers/Tmdb/TV/TmdbEpisodeProviderBase.cs b/MediaBrowser.Providers/Tmdb/TV/TmdbEpisodeProviderBase.cs index e87fe9332..3937ebc95 100644 --- a/MediaBrowser.Providers/Tmdb/TV/TmdbEpisodeProviderBase.cs +++ b/MediaBrowser.Providers/Tmdb/TV/TmdbEpisodeProviderBase.cs @@ -24,14 +24,14 @@ namespace MediaBrowser.Providers.Tmdb.TV private readonly ILocalizationManager _localization; private readonly ILogger _logger; - protected TmdbEpisodeProviderBase(IHttpClient httpClient, IServerConfigurationManager configurationManager, IJsonSerializer jsonSerializer, IFileSystem fileSystem, ILocalizationManager localization, ILoggerFactory loggerFactory) + protected TmdbEpisodeProviderBase(IHttpClient httpClient, IServerConfigurationManager configurationManager, IJsonSerializer jsonSerializer, IFileSystem fileSystem, ILocalizationManager localization, ILogger logger) { _httpClient = httpClient; _configurationManager = configurationManager; _jsonSerializer = jsonSerializer; _fileSystem = fileSystem; _localization = localization; - _logger = loggerFactory.CreateLogger(GetType().Name); + _logger = logger; } protected ILogger Logger => _logger; diff --git a/MediaBrowser.Providers/Tmdb/TV/TmdbSeasonProvider.cs b/MediaBrowser.Providers/Tmdb/TV/TmdbSeasonProvider.cs index 5ad331971..832b64941 100644 --- a/MediaBrowser.Providers/Tmdb/TV/TmdbSeasonProvider.cs +++ b/MediaBrowser.Providers/Tmdb/TV/TmdbSeasonProvider.cs @@ -29,18 +29,18 @@ namespace MediaBrowser.Providers.Tmdb.TV private readonly IJsonSerializer _jsonSerializer; private readonly IFileSystem _fileSystem; private readonly ILocalizationManager _localization; - private readonly ILogger _logger; + private readonly ILogger _logger; internal static TmdbSeasonProvider Current { get; private set; } - public TmdbSeasonProvider(IHttpClient httpClient, IServerConfigurationManager configurationManager, IFileSystem fileSystem, ILocalizationManager localization, IJsonSerializer jsonSerializer, ILoggerFactory loggerFactory) + public TmdbSeasonProvider(IHttpClient httpClient, IServerConfigurationManager configurationManager, IFileSystem fileSystem, ILocalizationManager localization, IJsonSerializer jsonSerializer, ILogger logger) { _httpClient = httpClient; _configurationManager = configurationManager; _fileSystem = fileSystem; _localization = localization; _jsonSerializer = jsonSerializer; - _logger = loggerFactory.CreateLogger(GetType().Name); + _logger = logger; Current = this; } diff --git a/MediaBrowser.Providers/Tmdb/TV/TmdbSeriesProvider.cs b/MediaBrowser.Providers/Tmdb/TV/TmdbSeriesProvider.cs index 6e3c26c26..649c5474b 100644 --- a/MediaBrowser.Providers/Tmdb/TV/TmdbSeriesProvider.cs +++ b/MediaBrowser.Providers/Tmdb/TV/TmdbSeriesProvider.cs @@ -31,7 +31,7 @@ namespace MediaBrowser.Providers.Tmdb.TV private readonly IJsonSerializer _jsonSerializer; private readonly IFileSystem _fileSystem; private readonly IServerConfigurationManager _configurationManager; - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly ILocalizationManager _localization; private readonly IHttpClient _httpClient; private readonly ILibraryManager _libraryManager; diff --git a/MediaBrowser.WebDashboard/Api/DashboardService.cs b/MediaBrowser.WebDashboard/Api/DashboardService.cs index 55fc463d0..63cbfd9e4 100644 --- a/MediaBrowser.WebDashboard/Api/DashboardService.cs +++ b/MediaBrowser.WebDashboard/Api/DashboardService.cs @@ -90,7 +90,7 @@ namespace MediaBrowser.WebDashboard.Api /// Gets or sets the logger. /// /// The logger. - private readonly ILogger _logger; + private readonly ILogger _logger; /// /// Gets or sets the HTTP result factory. diff --git a/MediaBrowser.XbmcMetadata/EntryPoint.cs b/MediaBrowser.XbmcMetadata/EntryPoint.cs index 571953b47..11b36285c 100644 --- a/MediaBrowser.XbmcMetadata/EntryPoint.cs +++ b/MediaBrowser.XbmcMetadata/EntryPoint.cs @@ -17,7 +17,7 @@ namespace MediaBrowser.XbmcMetadata public sealed class EntryPoint : IServerEntryPoint { private readonly IUserDataManager _userDataManager; - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IProviderManager _providerManager; private readonly IConfigurationManager _config; diff --git a/MediaBrowser.XbmcMetadata/Providers/AlbumNfoProvider.cs b/MediaBrowser.XbmcMetadata/Providers/AlbumNfoProvider.cs index 4b1ee4c9c..433a936d9 100644 --- a/MediaBrowser.XbmcMetadata/Providers/AlbumNfoProvider.cs +++ b/MediaBrowser.XbmcMetadata/Providers/AlbumNfoProvider.cs @@ -14,7 +14,7 @@ namespace MediaBrowser.XbmcMetadata.Providers /// public class AlbumNfoProvider : BaseNfoProvider { - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IConfigurationManager _config; private readonly IProviderManager _providerManager; diff --git a/MediaBrowser.XbmcMetadata/Providers/ArtistNfoProvider.cs b/MediaBrowser.XbmcMetadata/Providers/ArtistNfoProvider.cs index 3bbfa6e83..d69cdc90a 100644 --- a/MediaBrowser.XbmcMetadata/Providers/ArtistNfoProvider.cs +++ b/MediaBrowser.XbmcMetadata/Providers/ArtistNfoProvider.cs @@ -14,7 +14,7 @@ namespace MediaBrowser.XbmcMetadata.Providers /// public class ArtistNfoProvider : BaseNfoProvider { - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IConfigurationManager _config; private readonly IProviderManager _providerManager; diff --git a/MediaBrowser.XbmcMetadata/Providers/BaseVideoNfoProvider.cs b/MediaBrowser.XbmcMetadata/Providers/BaseVideoNfoProvider.cs index 84c99664a..2b1589d47 100644 --- a/MediaBrowser.XbmcMetadata/Providers/BaseVideoNfoProvider.cs +++ b/MediaBrowser.XbmcMetadata/Providers/BaseVideoNfoProvider.cs @@ -15,12 +15,12 @@ namespace MediaBrowser.XbmcMetadata.Providers public abstract class BaseVideoNfoProvider : BaseNfoProvider where T : Video, new() { - private readonly ILogger _logger; + private readonly ILogger> _logger; private readonly IConfigurationManager _config; private readonly IProviderManager _providerManager; public BaseVideoNfoProvider( - ILogger logger, + ILogger> logger, IFileSystem fileSystem, IConfigurationManager config, IProviderManager providerManager) diff --git a/MediaBrowser.XbmcMetadata/Providers/EpisodeNfoProvider.cs b/MediaBrowser.XbmcMetadata/Providers/EpisodeNfoProvider.cs index b2dc2e38e..26983b1a6 100644 --- a/MediaBrowser.XbmcMetadata/Providers/EpisodeNfoProvider.cs +++ b/MediaBrowser.XbmcMetadata/Providers/EpisodeNfoProvider.cs @@ -14,7 +14,7 @@ namespace MediaBrowser.XbmcMetadata.Providers /// public class EpisodeNfoProvider : BaseNfoProvider { - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IConfigurationManager _config; private readonly IProviderManager _providerManager; diff --git a/MediaBrowser.XbmcMetadata/Providers/SeasonNfoProvider.cs b/MediaBrowser.XbmcMetadata/Providers/SeasonNfoProvider.cs index 63ddd6025..0603fd0d1 100644 --- a/MediaBrowser.XbmcMetadata/Providers/SeasonNfoProvider.cs +++ b/MediaBrowser.XbmcMetadata/Providers/SeasonNfoProvider.cs @@ -14,7 +14,7 @@ namespace MediaBrowser.XbmcMetadata.Providers /// public class SeasonNfoProvider : BaseNfoProvider { - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IConfigurationManager _config; private readonly IProviderManager _providerManager; diff --git a/MediaBrowser.XbmcMetadata/Providers/SeriesNfoProvider.cs b/MediaBrowser.XbmcMetadata/Providers/SeriesNfoProvider.cs index d65914542..7e059e0aa 100644 --- a/MediaBrowser.XbmcMetadata/Providers/SeriesNfoProvider.cs +++ b/MediaBrowser.XbmcMetadata/Providers/SeriesNfoProvider.cs @@ -14,7 +14,7 @@ namespace MediaBrowser.XbmcMetadata.Providers /// public class SeriesNfoProvider : BaseNfoProvider { - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IConfigurationManager _config; private readonly IProviderManager _providerManager; diff --git a/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs b/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs index 90e8b4b99..3602ec14c 100644 --- a/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs +++ b/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs @@ -105,7 +105,7 @@ namespace MediaBrowser.XbmcMetadata.Savers ILibraryManager libraryManager, IUserManager userManager, IUserDataManager userDataManager, - ILogger logger) + ILogger logger) { Logger = logger; UserDataManager = userDataManager; @@ -125,7 +125,7 @@ namespace MediaBrowser.XbmcMetadata.Savers protected IUserDataManager UserDataManager { get; } - protected ILogger Logger { get; } + protected ILogger Logger { get; } protected ItemUpdateType MinimumUpdateType { @@ -974,7 +974,7 @@ namespace MediaBrowser.XbmcMetadata.Savers => string.Equals(person.Type, type, StringComparison.OrdinalIgnoreCase) || string.Equals(person.Role, type, StringComparison.OrdinalIgnoreCase); - private void AddCustomTags(string path, List xmlTagsUsed, XmlWriter writer, ILogger logger) + private void AddCustomTags(string path, List xmlTagsUsed, XmlWriter writer, ILogger logger) { var settings = new XmlReaderSettings() { -- cgit v1.2.3 From 57d1dbfe7b3bc4ad8cc4cc1c89313ad394db4f50 Mon Sep 17 00:00:00 2001 From: crobibero Date: Fri, 5 Jun 2020 18:29:58 -0600 Subject: undo erroneous changes --- Emby.Dlna/ConnectionManager/ConnectionManager.cs | 2 +- Emby.Dlna/Service/BaseService.cs | 2 +- Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs | 1 - MediaBrowser.Controller/Session/SessionInfo.cs | 1 - MediaBrowser.Providers/Manager/ImageSaver.cs | 1 - MediaBrowser.Providers/Tmdb/TV/TmdbEpisodeImageProvider.cs | 4 ++-- MediaBrowser.Providers/Tmdb/TV/TmdbEpisodeProvider.cs | 4 ++-- MediaBrowser.Providers/Tmdb/TV/TmdbEpisodeProviderBase.cs | 6 +++--- 8 files changed, 9 insertions(+), 12 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Dlna/ConnectionManager/ConnectionManager.cs b/Emby.Dlna/ConnectionManager/ConnectionManager.cs index 480dd3a79..e32cc11bf 100644 --- a/Emby.Dlna/ConnectionManager/ConnectionManager.cs +++ b/Emby.Dlna/ConnectionManager/ConnectionManager.cs @@ -18,7 +18,7 @@ namespace Emby.Dlna.ConnectionManager public ConnectionManager( IDlnaManager dlna, IServerConfigurationManager config, - ILogger logger, + ILogger logger, IHttpClient httpClient) : base(logger, httpClient) { diff --git a/Emby.Dlna/Service/BaseService.cs b/Emby.Dlna/Service/BaseService.cs index 4ecffa293..8794ec26a 100644 --- a/Emby.Dlna/Service/BaseService.cs +++ b/Emby.Dlna/Service/BaseService.cs @@ -12,7 +12,7 @@ namespace Emby.Dlna.Service protected IHttpClient HttpClient; protected ILogger Logger; - protected BaseService(ILogger logger, IHttpClient httpClient) + protected BaseService(ILogger logger, IHttpClient httpClient) { Logger = logger; HttpClient = httpClient; diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs index c3336ca92..4e4f1d7f6 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs @@ -7,7 +7,6 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; -using Emby.Server.Implementations.Library; using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Library; using MediaBrowser.Model.Dto; diff --git a/MediaBrowser.Controller/Session/SessionInfo.cs b/MediaBrowser.Controller/Session/SessionInfo.cs index ecc910872..2ba7c9fec 100644 --- a/MediaBrowser.Controller/Session/SessionInfo.cs +++ b/MediaBrowser.Controller/Session/SessionInfo.cs @@ -3,7 +3,6 @@ using System.Linq; using System.Text.Json.Serialization; using System.Threading; using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Session; using Microsoft.Extensions.Logging; diff --git a/MediaBrowser.Providers/Manager/ImageSaver.cs b/MediaBrowser.Providers/Manager/ImageSaver.cs index f21ac2d65..3ab621ba4 100644 --- a/MediaBrowser.Providers/Manager/ImageSaver.cs +++ b/MediaBrowser.Providers/Manager/ImageSaver.cs @@ -15,7 +15,6 @@ using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Entities; using MediaBrowser.Model.IO; using MediaBrowser.Model.Net; -using MediaBrowser.Providers.Tmdb.Models.General; using Microsoft.Extensions.Logging; namespace MediaBrowser.Providers.Manager diff --git a/MediaBrowser.Providers/Tmdb/TV/TmdbEpisodeImageProvider.cs b/MediaBrowser.Providers/Tmdb/TV/TmdbEpisodeImageProvider.cs index b0174a587..558c8149e 100644 --- a/MediaBrowser.Providers/Tmdb/TV/TmdbEpisodeImageProvider.cs +++ b/MediaBrowser.Providers/Tmdb/TV/TmdbEpisodeImageProvider.cs @@ -24,8 +24,8 @@ namespace MediaBrowser.Providers.Tmdb.TV IRemoteImageProvider, IHasOrder { - public TmdbEpisodeImageProvider(IHttpClient httpClient, IServerConfigurationManager configurationManager, IJsonSerializer jsonSerializer, IFileSystem fileSystem, ILocalizationManager localization, ILogger logger) - : base(httpClient, configurationManager, jsonSerializer, fileSystem, localization, logger) + public TmdbEpisodeImageProvider(IHttpClient httpClient, IServerConfigurationManager configurationManager, IJsonSerializer jsonSerializer, IFileSystem fileSystem, ILocalizationManager localization, ILoggerFactory loggerFactory) + : base(httpClient, configurationManager, jsonSerializer, fileSystem, localization, loggerFactory) { } public IEnumerable GetSupportedImages(BaseItem item) diff --git a/MediaBrowser.Providers/Tmdb/TV/TmdbEpisodeProvider.cs b/MediaBrowser.Providers/Tmdb/TV/TmdbEpisodeProvider.cs index 330b9f42b..a17f5d17a 100644 --- a/MediaBrowser.Providers/Tmdb/TV/TmdbEpisodeProvider.cs +++ b/MediaBrowser.Providers/Tmdb/TV/TmdbEpisodeProvider.cs @@ -25,8 +25,8 @@ namespace MediaBrowser.Providers.Tmdb.TV IRemoteMetadataProvider, IHasOrder { - public TmdbEpisodeProvider(IHttpClient httpClient, IServerConfigurationManager configurationManager, IJsonSerializer jsonSerializer, IFileSystem fileSystem, ILocalizationManager localization, ILogger logger) - : base(httpClient, configurationManager, jsonSerializer, fileSystem, localization, logger) + public TmdbEpisodeProvider(IHttpClient httpClient, IServerConfigurationManager configurationManager, IJsonSerializer jsonSerializer, IFileSystem fileSystem, ILocalizationManager localization, ILoggerFactory loggerFactory) + : base(httpClient, configurationManager, jsonSerializer, fileSystem, localization, loggerFactory) { } public async Task> GetSearchResults(EpisodeInfo searchInfo, CancellationToken cancellationToken) diff --git a/MediaBrowser.Providers/Tmdb/TV/TmdbEpisodeProviderBase.cs b/MediaBrowser.Providers/Tmdb/TV/TmdbEpisodeProviderBase.cs index 3937ebc95..f6f607a1e 100644 --- a/MediaBrowser.Providers/Tmdb/TV/TmdbEpisodeProviderBase.cs +++ b/MediaBrowser.Providers/Tmdb/TV/TmdbEpisodeProviderBase.cs @@ -22,16 +22,16 @@ namespace MediaBrowser.Providers.Tmdb.TV private readonly IJsonSerializer _jsonSerializer; private readonly IFileSystem _fileSystem; private readonly ILocalizationManager _localization; - private readonly ILogger _logger; + private readonly ILogger _logger; - protected TmdbEpisodeProviderBase(IHttpClient httpClient, IServerConfigurationManager configurationManager, IJsonSerializer jsonSerializer, IFileSystem fileSystem, ILocalizationManager localization, ILogger logger) + protected TmdbEpisodeProviderBase(IHttpClient httpClient, IServerConfigurationManager configurationManager, IJsonSerializer jsonSerializer, IFileSystem fileSystem, ILocalizationManager localization, ILoggerFactory loggerFactory) { _httpClient = httpClient; _configurationManager = configurationManager; _jsonSerializer = jsonSerializer; _fileSystem = fileSystem; _localization = localization; - _logger = logger; + _logger = loggerFactory.CreateLogger(); } protected ILogger Logger => _logger; -- cgit v1.2.3 From 613748b45da34e829b206b3437b50459a15207e4 Mon Sep 17 00:00:00 2001 From: Daniyar Itegulov Date: Sat, 6 Jun 2020 18:49:12 +1000 Subject: Make books resumable and have duration of 1 second --- Emby.Server.Implementations/Library/UserDataManager.cs | 2 +- MediaBrowser.Controller/Entities/Book.cs | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/Library/UserDataManager.cs b/Emby.Server.Implementations/Library/UserDataManager.cs index a9772a078..e996f3f78 100644 --- a/Emby.Server.Implementations/Library/UserDataManager.cs +++ b/Emby.Server.Implementations/Library/UserDataManager.cs @@ -240,7 +240,7 @@ namespace Emby.Server.Implementations.Library { // Enforce MinResumeDuration var durationSeconds = TimeSpan.FromTicks(runtimeTicks).TotalSeconds; - if (durationSeconds < _config.Configuration.MinResumeDurationSeconds) + if (durationSeconds < _config.Configuration.MinResumeDurationSeconds && !(item is Book)) { positionTicks = 0; data.Played = playedToCompletion = true; diff --git a/MediaBrowser.Controller/Entities/Book.cs b/MediaBrowser.Controller/Entities/Book.cs index dcad2554b..c5ce001c0 100644 --- a/MediaBrowser.Controller/Entities/Book.cs +++ b/MediaBrowser.Controller/Entities/Book.cs @@ -11,6 +11,10 @@ namespace MediaBrowser.Controller.Entities [JsonIgnore] public override string MediaType => Model.Entities.MediaType.Book; + public override bool SupportsPlayedStatus => true; + + public override bool SupportsPositionTicksResume => true; + [JsonIgnore] public string SeriesPresentationUniqueKey { get; set; } @@ -20,6 +24,11 @@ namespace MediaBrowser.Controller.Entities [JsonIgnore] public Guid SeriesId { get; set; } + public Book() + { + this.RunTimeTicks = TimeSpan.TicksPerSecond; + } + public string FindSeriesSortName() { return SeriesName; -- cgit v1.2.3 From 22a860a8068f502c3b5324c71573af2525a84fca Mon Sep 17 00:00:00 2001 From: aled Date: Sat, 6 Jun 2020 20:17:49 +0100 Subject: Fix a small number of compile warnings --- .../Data/SqliteItemRepository.cs | 6 +-- .../Library/Resolvers/Movies/BoxSetResolver.cs | 2 +- .../Library/Resolvers/Movies/MovieResolver.cs | 4 +- .../Library/Resolvers/TV/SeriesResolver.cs | 2 +- .../LiveTv/EmbyTV/EmbyTV.cs | 16 ++++---- .../LiveTv/Listings/SchedulesDirect.cs | 2 +- MediaBrowser.Api/Library/LibraryService.cs | 6 +-- MediaBrowser.Api/Movies/MoviesService.cs | 4 +- .../Entities/Audio/MusicAlbum.cs | 4 +- .../Entities/Audio/MusicArtist.cs | 2 +- MediaBrowser.Controller/Entities/Movies/Movie.cs | 2 +- MediaBrowser.Controller/Entities/TV/Series.cs | 6 +-- MediaBrowser.Controller/Entities/Trailer.cs | 2 +- .../Entities/UserViewBuilder.cs | 6 +-- MediaBrowser.Controller/Entities/Video.cs | 8 ++-- MediaBrowser.Controller/LiveTv/LiveTvProgram.cs | 6 +-- .../Parsers/BaseItemXmlParser.cs | 2 +- .../Probing/ProbeResultNormalizer.cs | 10 ++--- MediaBrowser.Model/Entities/MetadataProvider.cs | 41 ++++++++++++++++++ MediaBrowser.Model/Entities/MetadataProviders.cs | 41 ------------------ .../Entities/ProviderIdsExtensions.cs | 6 +-- .../MediaInfo/FFProbeAudioInfo.cs | 10 ++--- MediaBrowser.Providers/Movies/MovieExternalIds.cs | 4 +- MediaBrowser.Providers/Music/Extensions.cs | 18 ++++---- .../Plugins/AudioDb/AlbumImageProvider.cs | 2 +- .../Plugins/AudioDb/AlbumProvider.cs | 8 ++-- .../Plugins/AudioDb/ArtistImageProvider.cs | 2 +- .../Plugins/AudioDb/ArtistProvider.cs | 4 +- .../Plugins/AudioDb/ExternalIds.cs | 8 ++-- .../Plugins/MusicBrainz/AlbumProvider.cs | 10 ++--- .../Plugins/MusicBrainz/ArtistProvider.cs | 6 +-- .../Plugins/MusicBrainz/ExternalIds.cs | 12 +++--- .../Plugins/Omdb/OmdbEpisodeProvider.cs | 4 +- .../Plugins/Omdb/OmdbImageProvider.cs | 2 +- .../Plugins/Omdb/OmdbItemProvider.cs | 18 ++++---- .../Plugins/Omdb/OmdbProvider.cs | 6 +-- .../Plugins/TheTvdb/TvdbClientManager.cs | 2 +- .../Plugins/TheTvdb/TvdbEpisodeImageProvider.cs | 4 +- .../Plugins/TheTvdb/TvdbEpisodeProvider.cs | 6 +-- .../Plugins/TheTvdb/TvdbPersonImageProvider.cs | 2 +- .../Plugins/TheTvdb/TvdbSeasonImageProvider.cs | 2 +- .../Plugins/TheTvdb/TvdbSeriesImageProvider.cs | 2 +- .../Plugins/TheTvdb/TvdbSeriesProvider.cs | 42 +++++++++---------- .../Plugins/Tmdb/BoxSets/TmdbBoxSetExternalId.cs | 2 +- .../Tmdb/BoxSets/TmdbBoxSetImageProvider.cs | 2 +- .../Plugins/Tmdb/BoxSets/TmdbBoxSetProvider.cs | 10 ++--- .../Plugins/Tmdb/Movies/GenericTmdbMovieInfo.cs | 16 ++++---- .../Plugins/Tmdb/Movies/TmdbImageProvider.cs | 4 +- .../Plugins/Tmdb/Movies/TmdbMovieExternalId.cs | 2 +- .../Plugins/Tmdb/Movies/TmdbMovieProvider.cs | 6 +-- .../Plugins/Tmdb/Movies/TmdbSearch.cs | 4 +- .../Plugins/Tmdb/People/TmdbPersonExternalId.cs | 2 +- .../Plugins/Tmdb/People/TmdbPersonImageProvider.cs | 2 +- .../Plugins/Tmdb/People/TmdbPersonProvider.cs | 16 ++++---- .../Plugins/Tmdb/TV/TmdbEpisodeImageProvider.cs | 2 +- .../Plugins/Tmdb/TV/TmdbEpisodeProvider.cs | 4 +- .../Plugins/Tmdb/TV/TmdbSeasonImageProvider.cs | 2 +- .../Plugins/Tmdb/TV/TmdbSeasonProvider.cs | 4 +- .../Plugins/Tmdb/TV/TmdbSeriesExternalId.cs | 2 +- .../Plugins/Tmdb/TV/TmdbSeriesImageProvider.cs | 2 +- .../Plugins/Tmdb/TV/TmdbSeriesProvider.cs | 36 ++++++++-------- .../TV/MissingEpisodeProvider.cs | 2 +- MediaBrowser.Providers/TV/TvExternalIds.cs | 8 ++-- MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs | 6 +-- .../Parsers/MovieNfoParser.cs | 6 +-- .../Parsers/SeriesNfoParser.cs | 6 +-- MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs | 48 +++++++++++----------- MediaBrowser.XbmcMetadata/Savers/MovieNfoSaver.cs | 2 +- MediaBrowser.XbmcMetadata/Savers/SeriesNfoSaver.cs | 2 +- 69 files changed, 275 insertions(+), 275 deletions(-) create mode 100644 MediaBrowser.Model/Entities/MetadataProvider.cs delete mode 100644 MediaBrowser.Model/Entities/MetadataProviders.cs (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index 18d235c87..03581dae2 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -2734,7 +2734,7 @@ namespace Emby.Server.Implementations.Data foreach (var providerId in newItem.ProviderIds) { - if (providerId.Key == MetadataProviders.TmdbCollection.ToString()) + if (providerId.Key == MetadataProvider.TmdbCollection.ToString()) { continue; } @@ -4324,7 +4324,7 @@ namespace Emby.Server.Implementations.Data var index = 0; foreach (var pair in query.ExcludeProviderIds) { - if (string.Equals(pair.Key, MetadataProviders.TmdbCollection.ToString(), StringComparison.OrdinalIgnoreCase)) + if (string.Equals(pair.Key, MetadataProvider.TmdbCollection.ToString(), StringComparison.OrdinalIgnoreCase)) { continue; } @@ -4353,7 +4353,7 @@ namespace Emby.Server.Implementations.Data var index = 0; foreach (var pair in query.HasAnyProviderId) { - if (string.Equals(pair.Key, MetadataProviders.TmdbCollection.ToString(), StringComparison.OrdinalIgnoreCase)) + if (string.Equals(pair.Key, MetadataProvider.TmdbCollection.ToString(), StringComparison.OrdinalIgnoreCase)) { continue; } diff --git a/Emby.Server.Implementations/Library/Resolvers/Movies/BoxSetResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Movies/BoxSetResolver.cs index e4bc4a469..295e9e120 100644 --- a/Emby.Server.Implementations/Library/Resolvers/Movies/BoxSetResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/Movies/BoxSetResolver.cs @@ -69,7 +69,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies if (!string.IsNullOrEmpty(id)) { - item.SetProviderId(MetadataProviders.Tmdb, id); + item.SetProviderId(MetadataProvider.Tmdb, id); } } } diff --git a/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs index cb67c8aa7..baf0e3cf9 100644 --- a/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs @@ -350,7 +350,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies if (!string.IsNullOrWhiteSpace(tmdbid)) { - item.SetProviderId(MetadataProviders.Tmdb, tmdbid); + item.SetProviderId(MetadataProvider.Tmdb, tmdbid); } } @@ -361,7 +361,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies if (!string.IsNullOrWhiteSpace(imdbid)) { - item.SetProviderId(MetadataProviders.Imdb, imdbid); + item.SetProviderId(MetadataProvider.Imdb, imdbid); } } } diff --git a/Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs b/Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs index dd6bd8ee8..b2627f044 100644 --- a/Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs @@ -217,7 +217,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV if (!string.IsNullOrEmpty(id)) { - item.SetProviderId(MetadataProviders.Tvdb, id); + item.SetProviderId(MetadataProvider.Tvdb, id); } } } diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index 5a5dc3329..0ee2872c4 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -1893,22 +1893,22 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV writer.WriteStartDocument(true); writer.WriteStartElement("tvshow"); string id; - if (timer.SeriesProviderIds.TryGetValue(MetadataProviders.Tvdb.ToString(), out id)) + if (timer.SeriesProviderIds.TryGetValue(MetadataProvider.Tvdb.ToString(), out id)) { writer.WriteElementString("id", id); } - if (timer.SeriesProviderIds.TryGetValue(MetadataProviders.Imdb.ToString(), out id)) + if (timer.SeriesProviderIds.TryGetValue(MetadataProvider.Imdb.ToString(), out id)) { writer.WriteElementString("imdb_id", id); } - if (timer.SeriesProviderIds.TryGetValue(MetadataProviders.Tmdb.ToString(), out id)) + if (timer.SeriesProviderIds.TryGetValue(MetadataProvider.Tmdb.ToString(), out id)) { writer.WriteElementString("tmdbid", id); } - if (timer.SeriesProviderIds.TryGetValue(MetadataProviders.Zap2It.ToString(), out id)) + if (timer.SeriesProviderIds.TryGetValue(MetadataProvider.Zap2It.ToString(), out id)) { writer.WriteElementString("zap2itid", id); } @@ -2075,14 +2075,14 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV writer.WriteElementString("credits", person); } - var tmdbCollection = item.GetProviderId(MetadataProviders.TmdbCollection); + var tmdbCollection = item.GetProviderId(MetadataProvider.TmdbCollection); if (!string.IsNullOrEmpty(tmdbCollection)) { writer.WriteElementString("collectionnumber", tmdbCollection); } - var imdb = item.GetProviderId(MetadataProviders.Imdb); + var imdb = item.GetProviderId(MetadataProvider.Imdb); if (!string.IsNullOrEmpty(imdb)) { if (!isSeriesEpisode) @@ -2096,7 +2096,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV lockData = false; } - var tvdb = item.GetProviderId(MetadataProviders.Tvdb); + var tvdb = item.GetProviderId(MetadataProvider.Tvdb); if (!string.IsNullOrEmpty(tvdb)) { writer.WriteElementString("tvdbid", tvdb); @@ -2105,7 +2105,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV lockData = false; } - var tmdb = item.GetProviderId(MetadataProviders.Tmdb); + var tmdb = item.GetProviderId(MetadataProvider.Tmdb); if (!string.IsNullOrEmpty(tmdb)) { writer.WriteElementString("tmdbid", tmdb); diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs index 89b81fd96..d82d554eb 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs @@ -342,7 +342,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings { info.SeriesId = programId.Substring(0, 10); - info.SeriesProviderIds[MetadataProviders.Zap2It.ToString()] = info.SeriesId; + info.SeriesProviderIds[MetadataProvider.Zap2It.ToString()] = info.SeriesId; if (details.metadata != null) { diff --git a/MediaBrowser.Api/Library/LibraryService.cs b/MediaBrowser.Api/Library/LibraryService.cs index c0146dfee..9d53a2610 100644 --- a/MediaBrowser.Api/Library/LibraryService.cs +++ b/MediaBrowser.Api/Library/LibraryService.cs @@ -655,7 +655,7 @@ namespace MediaBrowser.Api.Library EnableImages = false } - }).Where(i => string.Equals(request.TvdbId, i.GetProviderId(MetadataProviders.Tvdb), StringComparison.OrdinalIgnoreCase)).ToArray(); + }).Where(i => string.Equals(request.TvdbId, i.GetProviderId(MetadataProvider.Tvdb), StringComparison.OrdinalIgnoreCase)).ToArray(); foreach (var item in series) { @@ -688,11 +688,11 @@ namespace MediaBrowser.Api.Library if (!string.IsNullOrWhiteSpace(request.ImdbId)) { - movies = movies.Where(i => string.Equals(request.ImdbId, i.GetProviderId(MetadataProviders.Imdb), StringComparison.OrdinalIgnoreCase)).ToList(); + movies = movies.Where(i => string.Equals(request.ImdbId, i.GetProviderId(MetadataProvider.Imdb), StringComparison.OrdinalIgnoreCase)).ToList(); } else if (!string.IsNullOrWhiteSpace(request.TmdbId)) { - movies = movies.Where(i => string.Equals(request.TmdbId, i.GetProviderId(MetadataProviders.Tmdb), StringComparison.OrdinalIgnoreCase)).ToList(); + movies = movies.Where(i => string.Equals(request.TmdbId, i.GetProviderId(MetadataProvider.Tmdb), StringComparison.OrdinalIgnoreCase)).ToList(); } else { diff --git a/MediaBrowser.Api/Movies/MoviesService.cs b/MediaBrowser.Api/Movies/MoviesService.cs index cdd027634..a9c7f5d6f 100644 --- a/MediaBrowser.Api/Movies/MoviesService.cs +++ b/MediaBrowser.Api/Movies/MoviesService.cs @@ -273,7 +273,7 @@ namespace MediaBrowser.Api.Movies EnableGroupByMetadataKey = true, DtoOptions = dtoOptions - }).GroupBy(i => i.GetProviderId(MetadataProviders.Imdb) ?? Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture)) + }).GroupBy(i => i.GetProviderId(MetadataProvider.Imdb) ?? Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture)) .Select(x => x.First()) .Take(itemLimit) .ToList(); @@ -314,7 +314,7 @@ namespace MediaBrowser.Api.Movies EnableGroupByMetadataKey = true, DtoOptions = dtoOptions - }).GroupBy(i => i.GetProviderId(MetadataProviders.Imdb) ?? Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture)) + }).GroupBy(i => i.GetProviderId(MetadataProvider.Imdb) ?? Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture)) .Select(x => x.First()) .Take(itemLimit) .ToList(); diff --git a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs index c216176e7..b702bdb71 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs @@ -97,14 +97,14 @@ namespace MediaBrowser.Controller.Entities.Audio list.Insert(0, albumArtist + "-" + Name); } - var id = this.GetProviderId(MetadataProviders.MusicBrainzAlbum); + var id = this.GetProviderId(MetadataProvider.MusicBrainzAlbum); if (!string.IsNullOrEmpty(id)) { list.Insert(0, "MusicAlbum-Musicbrainz-" + id); } - id = this.GetProviderId(MetadataProviders.MusicBrainzReleaseGroup); + id = this.GetProviderId(MetadataProvider.MusicBrainzReleaseGroup); if (!string.IsNullOrEmpty(id)) { diff --git a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs index 5e3056ccb..31136e004 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs @@ -128,7 +128,7 @@ namespace MediaBrowser.Controller.Entities.Audio private static List GetUserDataKeys(MusicArtist item) { var list = new List(); - var id = item.GetProviderId(MetadataProviders.MusicBrainzArtist); + var id = item.GetProviderId(MetadataProvider.MusicBrainzArtist); if (!string.IsNullOrEmpty(id)) { diff --git a/MediaBrowser.Controller/Entities/Movies/Movie.cs b/MediaBrowser.Controller/Entities/Movies/Movie.cs index 11dc472b6..d5c9ff025 100644 --- a/MediaBrowser.Controller/Entities/Movies/Movie.cs +++ b/MediaBrowser.Controller/Entities/Movies/Movie.cs @@ -173,7 +173,7 @@ namespace MediaBrowser.Controller.Entities.Movies { var list = base.GetRelatedUrls(); - var imdbId = this.GetProviderId(MetadataProviders.Imdb); + var imdbId = this.GetProviderId(MetadataProvider.Imdb); if (!string.IsNullOrEmpty(imdbId)) { list.Add(new ExternalUrl diff --git a/MediaBrowser.Controller/Entities/TV/Series.cs b/MediaBrowser.Controller/Entities/TV/Series.cs index 2475b2b7e..6f1c2501f 100644 --- a/MediaBrowser.Controller/Entities/TV/Series.cs +++ b/MediaBrowser.Controller/Entities/TV/Series.cs @@ -164,13 +164,13 @@ namespace MediaBrowser.Controller.Entities.TV { var list = base.GetUserDataKeys(); - var key = this.GetProviderId(MetadataProviders.Imdb); + var key = this.GetProviderId(MetadataProvider.Imdb); if (!string.IsNullOrEmpty(key)) { list.Insert(0, key); } - key = this.GetProviderId(MetadataProviders.Tvdb); + key = this.GetProviderId(MetadataProvider.Tvdb); if (!string.IsNullOrEmpty(key)) { list.Insert(0, key); @@ -493,7 +493,7 @@ namespace MediaBrowser.Controller.Entities.TV { var list = base.GetRelatedUrls(); - var imdbId = this.GetProviderId(MetadataProviders.Imdb); + var imdbId = this.GetProviderId(MetadataProvider.Imdb); if (!string.IsNullOrEmpty(imdbId)) { list.Add(new ExternalUrl diff --git a/MediaBrowser.Controller/Entities/Trailer.cs b/MediaBrowser.Controller/Entities/Trailer.cs index 0b8be90cd..7159b5b1a 100644 --- a/MediaBrowser.Controller/Entities/Trailer.cs +++ b/MediaBrowser.Controller/Entities/Trailer.cs @@ -80,7 +80,7 @@ namespace MediaBrowser.Controller.Entities { var list = base.GetRelatedUrls(); - var imdbId = this.GetProviderId(MetadataProviders.Imdb); + var imdbId = this.GetProviderId(MetadataProvider.Imdb); if (!string.IsNullOrEmpty(imdbId)) { list.Add(new ExternalUrl diff --git a/MediaBrowser.Controller/Entities/UserViewBuilder.cs b/MediaBrowser.Controller/Entities/UserViewBuilder.cs index 435a1e8da..029602196 100644 --- a/MediaBrowser.Controller/Entities/UserViewBuilder.cs +++ b/MediaBrowser.Controller/Entities/UserViewBuilder.cs @@ -611,7 +611,7 @@ namespace MediaBrowser.Controller.Entities { var filterValue = query.HasImdbId.Value; - var hasValue = !string.IsNullOrEmpty(item.GetProviderId(MetadataProviders.Imdb)); + var hasValue = !string.IsNullOrEmpty(item.GetProviderId(MetadataProvider.Imdb)); if (hasValue != filterValue) { @@ -623,7 +623,7 @@ namespace MediaBrowser.Controller.Entities { var filterValue = query.HasTmdbId.Value; - var hasValue = !string.IsNullOrEmpty(item.GetProviderId(MetadataProviders.Tmdb)); + var hasValue = !string.IsNullOrEmpty(item.GetProviderId(MetadataProvider.Tmdb)); if (hasValue != filterValue) { @@ -635,7 +635,7 @@ namespace MediaBrowser.Controller.Entities { var filterValue = query.HasTvdbId.Value; - var hasValue = !string.IsNullOrEmpty(item.GetProviderId(MetadataProviders.Tvdb)); + var hasValue = !string.IsNullOrEmpty(item.GetProviderId(MetadataProvider.Tvdb)); if (hasValue != filterValue) { diff --git a/MediaBrowser.Controller/Entities/Video.cs b/MediaBrowser.Controller/Entities/Video.cs index c3ea7f347..72eb67a06 100644 --- a/MediaBrowser.Controller/Entities/Video.cs +++ b/MediaBrowser.Controller/Entities/Video.cs @@ -272,13 +272,13 @@ namespace MediaBrowser.Controller.Entities { if (ExtraType.HasValue) { - var key = this.GetProviderId(MetadataProviders.Tmdb); + var key = this.GetProviderId(MetadataProvider.Tmdb); if (!string.IsNullOrEmpty(key)) { list.Insert(0, GetUserDataKey(key)); } - key = this.GetProviderId(MetadataProviders.Imdb); + key = this.GetProviderId(MetadataProvider.Imdb); if (!string.IsNullOrEmpty(key)) { list.Insert(0, GetUserDataKey(key)); @@ -286,13 +286,13 @@ namespace MediaBrowser.Controller.Entities } else { - var key = this.GetProviderId(MetadataProviders.Imdb); + var key = this.GetProviderId(MetadataProvider.Imdb); if (!string.IsNullOrEmpty(key)) { list.Insert(0, key); } - key = this.GetProviderId(MetadataProviders.Tmdb); + key = this.GetProviderId(MetadataProvider.Tmdb); if (!string.IsNullOrEmpty(key)) { list.Insert(0, key); diff --git a/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs b/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs index 13df85aed..e89bc05aa 100644 --- a/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs +++ b/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs @@ -26,13 +26,13 @@ namespace MediaBrowser.Controller.LiveTv if (!IsSeries) { - var key = this.GetProviderId(MetadataProviders.Imdb); + var key = this.GetProviderId(MetadataProvider.Imdb); if (!string.IsNullOrEmpty(key)) { list.Insert(0, key); } - key = this.GetProviderId(MetadataProviders.Tmdb); + key = this.GetProviderId(MetadataProvider.Tmdb); if (!string.IsNullOrEmpty(key)) { list.Insert(0, key); @@ -253,7 +253,7 @@ namespace MediaBrowser.Controller.LiveTv { var list = base.GetRelatedUrls(); - var imdbId = this.GetProviderId(MetadataProviders.Imdb); + var imdbId = this.GetProviderId(MetadataProvider.Imdb); if (!string.IsNullOrEmpty(imdbId)) { if (IsMovie) diff --git a/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs b/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs index d4b98182f..2e0dade07 100644 --- a/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs +++ b/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs @@ -543,7 +543,7 @@ namespace MediaBrowser.LocalMetadata.Parsers var tmdbCollection = reader.ReadElementContentAsString(); if (!string.IsNullOrWhiteSpace(tmdbCollection)) { - item.SetProviderId(MetadataProviders.TmdbCollection, tmdbCollection); + item.SetProviderId(MetadataProvider.TmdbCollection, tmdbCollection); } break; diff --git a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs index d3f8094b9..9386d6524 100644 --- a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs +++ b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs @@ -1057,23 +1057,23 @@ namespace MediaBrowser.MediaEncoding.Probing // These support mulitple values, but for now we only store the first. var mb = GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MusicBrainz Album Artist Id")); if (mb == null) mb = GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MUSICBRAINZ_ALBUMARTISTID")); - audio.SetProviderId(MetadataProviders.MusicBrainzAlbumArtist, mb); + audio.SetProviderId(MetadataProvider.MusicBrainzAlbumArtist, mb); mb = GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MusicBrainz Artist Id")); if (mb == null) mb = GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MUSICBRAINZ_ARTISTID")); - audio.SetProviderId(MetadataProviders.MusicBrainzArtist, mb); + audio.SetProviderId(MetadataProvider.MusicBrainzArtist, mb); mb = GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MusicBrainz Album Id")); if (mb == null) mb = GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MUSICBRAINZ_ALBUMID")); - audio.SetProviderId(MetadataProviders.MusicBrainzAlbum, mb); + audio.SetProviderId(MetadataProvider.MusicBrainzAlbum, mb); mb = GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MusicBrainz Release Group Id")); if (mb == null) mb = GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MUSICBRAINZ_RELEASEGROUPID")); - audio.SetProviderId(MetadataProviders.MusicBrainzReleaseGroup, mb); + audio.SetProviderId(MetadataProvider.MusicBrainzReleaseGroup, mb); mb = GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MusicBrainz Release Track Id")); if (mb == null) mb = GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MUSICBRAINZ_RELEASETRACKID")); - audio.SetProviderId(MetadataProviders.MusicBrainzTrack, mb); + audio.SetProviderId(MetadataProvider.MusicBrainzTrack, mb); } private string GetMultipleMusicBrainzId(string value) diff --git a/MediaBrowser.Model/Entities/MetadataProvider.cs b/MediaBrowser.Model/Entities/MetadataProvider.cs new file mode 100644 index 000000000..bcc2b48e7 --- /dev/null +++ b/MediaBrowser.Model/Entities/MetadataProvider.cs @@ -0,0 +1,41 @@ +#pragma warning disable CS1591 + +namespace MediaBrowser.Model.Entities +{ + /// + /// Enum MetadataProviders + /// + public enum MetadataProvider + { + /// + /// The imdb + /// + Imdb = 2, + /// + /// The TMDB + /// + Tmdb = 3, + /// + /// The TVDB + /// + Tvdb = 4, + /// + /// The tvcom + /// + Tvcom = 5, + /// + /// Tmdb Collection Id + /// + TmdbCollection = 7, + MusicBrainzAlbum = 8, + MusicBrainzAlbumArtist = 9, + MusicBrainzArtist = 10, + MusicBrainzReleaseGroup = 11, + Zap2It = 12, + TvRage = 15, + AudioDbArtist = 16, + AudioDbAlbum = 17, + MusicBrainzTrack = 18, + TvMaze = 19 + } +} diff --git a/MediaBrowser.Model/Entities/MetadataProviders.cs b/MediaBrowser.Model/Entities/MetadataProviders.cs deleted file mode 100644 index 1a44a1661..000000000 --- a/MediaBrowser.Model/Entities/MetadataProviders.cs +++ /dev/null @@ -1,41 +0,0 @@ -#pragma warning disable CS1591 - -namespace MediaBrowser.Model.Entities -{ - /// - /// Enum MetadataProviders - /// - public enum MetadataProviders - { - /// - /// The imdb - /// - Imdb = 2, - /// - /// The TMDB - /// - Tmdb = 3, - /// - /// The TVDB - /// - Tvdb = 4, - /// - /// The tvcom - /// - Tvcom = 5, - /// - /// Tmdb Collection Id - /// - TmdbCollection = 7, - MusicBrainzAlbum = 8, - MusicBrainzAlbumArtist = 9, - MusicBrainzArtist = 10, - MusicBrainzReleaseGroup = 11, - Zap2It = 12, - TvRage = 15, - AudioDbArtist = 16, - AudioDbAlbum = 17, - MusicBrainzTrack = 18, - TvMaze = 19 - } -} diff --git a/MediaBrowser.Model/Entities/ProviderIdsExtensions.cs b/MediaBrowser.Model/Entities/ProviderIdsExtensions.cs index e089dd1e5..9c11fe0ad 100644 --- a/MediaBrowser.Model/Entities/ProviderIdsExtensions.cs +++ b/MediaBrowser.Model/Entities/ProviderIdsExtensions.cs @@ -14,7 +14,7 @@ namespace MediaBrowser.Model.Entities /// The instance. /// The provider. /// true if [has provider identifier] [the specified instance]; otherwise, false. - public static bool HasProviderId(this IHasProviderIds instance, MetadataProviders provider) + public static bool HasProviderId(this IHasProviderIds instance, MetadataProvider provider) { return !string.IsNullOrEmpty(instance.GetProviderId(provider.ToString())); } @@ -25,7 +25,7 @@ namespace MediaBrowser.Model.Entities /// The instance. /// The provider. /// System.String. - public static string? GetProviderId(this IHasProviderIds instance, MetadataProviders provider) + public static string? GetProviderId(this IHasProviderIds instance, MetadataProvider provider) { return instance.GetProviderId(provider.ToString()); } @@ -94,7 +94,7 @@ namespace MediaBrowser.Model.Entities /// The instance. /// The provider. /// The value. - public static void SetProviderId(this IHasProviderIds instance, MetadataProviders provider, string value) + public static void SetProviderId(this IHasProviderIds instance, MetadataProvider provider, string value) { instance.SetProviderId(provider.ToString(), value); } diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs b/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs index 207d75524..16d914e2d 100644 --- a/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs +++ b/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs @@ -158,11 +158,11 @@ namespace MediaBrowser.Providers.MediaInfo audio.SetStudios(data.Studios); } - audio.SetProviderId(MetadataProviders.MusicBrainzAlbumArtist, data.GetProviderId(MetadataProviders.MusicBrainzAlbumArtist)); - audio.SetProviderId(MetadataProviders.MusicBrainzArtist, data.GetProviderId(MetadataProviders.MusicBrainzArtist)); - audio.SetProviderId(MetadataProviders.MusicBrainzAlbum, data.GetProviderId(MetadataProviders.MusicBrainzAlbum)); - audio.SetProviderId(MetadataProviders.MusicBrainzReleaseGroup, data.GetProviderId(MetadataProviders.MusicBrainzReleaseGroup)); - audio.SetProviderId(MetadataProviders.MusicBrainzTrack, data.GetProviderId(MetadataProviders.MusicBrainzTrack)); + audio.SetProviderId(MetadataProvider.MusicBrainzAlbumArtist, data.GetProviderId(MetadataProvider.MusicBrainzAlbumArtist)); + audio.SetProviderId(MetadataProvider.MusicBrainzArtist, data.GetProviderId(MetadataProvider.MusicBrainzArtist)); + audio.SetProviderId(MetadataProvider.MusicBrainzAlbum, data.GetProviderId(MetadataProvider.MusicBrainzAlbum)); + audio.SetProviderId(MetadataProvider.MusicBrainzReleaseGroup, data.GetProviderId(MetadataProvider.MusicBrainzReleaseGroup)); + audio.SetProviderId(MetadataProvider.MusicBrainzTrack, data.GetProviderId(MetadataProvider.MusicBrainzTrack)); } } } diff --git a/MediaBrowser.Providers/Movies/MovieExternalIds.cs b/MediaBrowser.Providers/Movies/MovieExternalIds.cs index 55810b1ed..1f07deacf 100644 --- a/MediaBrowser.Providers/Movies/MovieExternalIds.cs +++ b/MediaBrowser.Providers/Movies/MovieExternalIds.cs @@ -13,7 +13,7 @@ namespace MediaBrowser.Providers.Movies public string Name => "IMDb"; /// - public string Key => MetadataProviders.Imdb.ToString(); + public string Key => MetadataProvider.Imdb.ToString(); /// public string UrlFormatString => "https://www.imdb.com/title/{0}"; @@ -37,7 +37,7 @@ namespace MediaBrowser.Providers.Movies public string Name => "IMDb"; /// - public string Key => MetadataProviders.Imdb.ToString(); + public string Key => MetadataProvider.Imdb.ToString(); /// public string UrlFormatString => "https://www.imdb.com/name/{0}"; diff --git a/MediaBrowser.Providers/Music/Extensions.cs b/MediaBrowser.Providers/Music/Extensions.cs index ea1efe266..a1d5aa826 100644 --- a/MediaBrowser.Providers/Music/Extensions.cs +++ b/MediaBrowser.Providers/Music/Extensions.cs @@ -21,11 +21,11 @@ namespace MediaBrowser.Providers.Music public static string GetReleaseGroupId(this AlbumInfo info) { - var id = info.GetProviderId(MetadataProviders.MusicBrainzReleaseGroup); + var id = info.GetProviderId(MetadataProvider.MusicBrainzReleaseGroup); if (string.IsNullOrEmpty(id)) { - return info.SongInfos.Select(i => i.GetProviderId(MetadataProviders.MusicBrainzReleaseGroup)) + return info.SongInfos.Select(i => i.GetProviderId(MetadataProvider.MusicBrainzReleaseGroup)) .FirstOrDefault(i => !string.IsNullOrEmpty(i)); } @@ -34,11 +34,11 @@ namespace MediaBrowser.Providers.Music public static string GetReleaseId(this AlbumInfo info) { - var id = info.GetProviderId(MetadataProviders.MusicBrainzAlbum); + var id = info.GetProviderId(MetadataProvider.MusicBrainzAlbum); if (string.IsNullOrEmpty(id)) { - return info.SongInfos.Select(i => i.GetProviderId(MetadataProviders.MusicBrainzAlbum)) + return info.SongInfos.Select(i => i.GetProviderId(MetadataProvider.MusicBrainzAlbum)) .FirstOrDefault(i => !string.IsNullOrEmpty(i)); } @@ -47,16 +47,16 @@ namespace MediaBrowser.Providers.Music public static string GetMusicBrainzArtistId(this AlbumInfo info) { - info.ProviderIds.TryGetValue(MetadataProviders.MusicBrainzAlbumArtist.ToString(), out string id); + info.ProviderIds.TryGetValue(MetadataProvider.MusicBrainzAlbumArtist.ToString(), out string id); if (string.IsNullOrEmpty(id)) { - info.ArtistProviderIds.TryGetValue(MetadataProviders.MusicBrainzArtist.ToString(), out id); + info.ArtistProviderIds.TryGetValue(MetadataProvider.MusicBrainzArtist.ToString(), out id); } if (string.IsNullOrEmpty(id)) { - return info.SongInfos.Select(i => i.GetProviderId(MetadataProviders.MusicBrainzAlbumArtist)) + return info.SongInfos.Select(i => i.GetProviderId(MetadataProvider.MusicBrainzAlbumArtist)) .FirstOrDefault(i => !string.IsNullOrEmpty(i)); } @@ -65,11 +65,11 @@ namespace MediaBrowser.Providers.Music public static string GetMusicBrainzArtistId(this ArtistInfo info) { - info.ProviderIds.TryGetValue(MetadataProviders.MusicBrainzArtist.ToString(), out var id); + info.ProviderIds.TryGetValue(MetadataProvider.MusicBrainzArtist.ToString(), out var id); if (string.IsNullOrEmpty(id)) { - return info.SongInfos.Select(i => i.GetProviderId(MetadataProviders.MusicBrainzAlbumArtist)) + return info.SongInfos.Select(i => i.GetProviderId(MetadataProvider.MusicBrainzAlbumArtist)) .FirstOrDefault(i => !string.IsNullOrEmpty(i)); } diff --git a/MediaBrowser.Providers/Plugins/AudioDb/AlbumImageProvider.cs b/MediaBrowser.Providers/Plugins/AudioDb/AlbumImageProvider.cs index dee2d59f0..3c314acb3 100644 --- a/MediaBrowser.Providers/Plugins/AudioDb/AlbumImageProvider.cs +++ b/MediaBrowser.Providers/Plugins/AudioDb/AlbumImageProvider.cs @@ -45,7 +45,7 @@ namespace MediaBrowser.Providers.Plugins.AudioDb /// public async Task> GetImages(BaseItem item, CancellationToken cancellationToken) { - var id = item.GetProviderId(MetadataProviders.MusicBrainzReleaseGroup); + var id = item.GetProviderId(MetadataProvider.MusicBrainzReleaseGroup); if (!string.IsNullOrWhiteSpace(id)) { diff --git a/MediaBrowser.Providers/Plugins/AudioDb/AlbumProvider.cs b/MediaBrowser.Providers/Plugins/AudioDb/AlbumProvider.cs index 1a0e87871..b1a54f22f 100644 --- a/MediaBrowser.Providers/Plugins/AudioDb/AlbumProvider.cs +++ b/MediaBrowser.Providers/Plugins/AudioDb/AlbumProvider.cs @@ -104,11 +104,11 @@ namespace MediaBrowser.Providers.Plugins.AudioDb item.Genres = new[] { result.strGenre }; } - item.SetProviderId(MetadataProviders.AudioDbArtist, result.idArtist); - item.SetProviderId(MetadataProviders.AudioDbAlbum, result.idAlbum); + item.SetProviderId(MetadataProvider.AudioDbArtist, result.idArtist); + item.SetProviderId(MetadataProvider.AudioDbAlbum, result.idAlbum); - item.SetProviderId(MetadataProviders.MusicBrainzAlbumArtist, result.strMusicBrainzArtistID); - item.SetProviderId(MetadataProviders.MusicBrainzReleaseGroup, result.strMusicBrainzID); + item.SetProviderId(MetadataProvider.MusicBrainzAlbumArtist, result.strMusicBrainzArtistID); + item.SetProviderId(MetadataProvider.MusicBrainzReleaseGroup, result.strMusicBrainzID); string overview = null; diff --git a/MediaBrowser.Providers/Plugins/AudioDb/ArtistImageProvider.cs b/MediaBrowser.Providers/Plugins/AudioDb/ArtistImageProvider.cs index 18afd5dd5..04cdab66a 100644 --- a/MediaBrowser.Providers/Plugins/AudioDb/ArtistImageProvider.cs +++ b/MediaBrowser.Providers/Plugins/AudioDb/ArtistImageProvider.cs @@ -47,7 +47,7 @@ namespace MediaBrowser.Providers.Plugins.AudioDb /// public async Task> GetImages(BaseItem item, CancellationToken cancellationToken) { - var id = item.GetProviderId(MetadataProviders.MusicBrainzArtist); + var id = item.GetProviderId(MetadataProvider.MusicBrainzArtist); if (!string.IsNullOrWhiteSpace(id)) { diff --git a/MediaBrowser.Providers/Plugins/AudioDb/ArtistProvider.cs b/MediaBrowser.Providers/Plugins/AudioDb/ArtistProvider.cs index df0f3df8f..d8a18a6bc 100644 --- a/MediaBrowser.Providers/Plugins/AudioDb/ArtistProvider.cs +++ b/MediaBrowser.Providers/Plugins/AudioDb/ArtistProvider.cs @@ -92,8 +92,8 @@ namespace MediaBrowser.Providers.Plugins.AudioDb item.Genres = new[] { result.strGenre }; } - item.SetProviderId(MetadataProviders.AudioDbArtist, result.idArtist); - item.SetProviderId(MetadataProviders.MusicBrainzArtist, result.strMusicBrainzID); + item.SetProviderId(MetadataProvider.AudioDbArtist, result.idArtist); + item.SetProviderId(MetadataProvider.MusicBrainzArtist, result.strMusicBrainzID); string overview = null; diff --git a/MediaBrowser.Providers/Plugins/AudioDb/ExternalIds.cs b/MediaBrowser.Providers/Plugins/AudioDb/ExternalIds.cs index 2d8cb431c..478ea5190 100644 --- a/MediaBrowser.Providers/Plugins/AudioDb/ExternalIds.cs +++ b/MediaBrowser.Providers/Plugins/AudioDb/ExternalIds.cs @@ -10,7 +10,7 @@ namespace MediaBrowser.Providers.Plugins.AudioDb public string Name => "TheAudioDb"; /// - public string Key => MetadataProviders.AudioDbAlbum.ToString(); + public string Key => MetadataProvider.AudioDbAlbum.ToString(); /// public string UrlFormatString => "https://www.theaudiodb.com/album/{0}"; @@ -25,7 +25,7 @@ namespace MediaBrowser.Providers.Plugins.AudioDb public string Name => "TheAudioDb Album"; /// - public string Key => MetadataProviders.AudioDbAlbum.ToString(); + public string Key => MetadataProvider.AudioDbAlbum.ToString(); /// public string UrlFormatString => "https://www.theaudiodb.com/album/{0}"; @@ -40,7 +40,7 @@ namespace MediaBrowser.Providers.Plugins.AudioDb public string Name => "TheAudioDb"; /// - public string Key => MetadataProviders.AudioDbArtist.ToString(); + public string Key => MetadataProvider.AudioDbArtist.ToString(); /// public string UrlFormatString => "https://www.theaudiodb.com/artist/{0}"; @@ -55,7 +55,7 @@ namespace MediaBrowser.Providers.Plugins.AudioDb public string Name => "TheAudioDb Artist"; /// - public string Key => MetadataProviders.AudioDbArtist.ToString(); + public string Key => MetadataProvider.AudioDbArtist.ToString(); /// public string UrlFormatString => "https://www.theaudiodb.com/artist/{0}"; diff --git a/MediaBrowser.Providers/Plugins/MusicBrainz/AlbumProvider.cs b/MediaBrowser.Providers/Plugins/MusicBrainz/AlbumProvider.cs index 31cdaf616..10dc73924 100644 --- a/MediaBrowser.Providers/Plugins/MusicBrainz/AlbumProvider.cs +++ b/MediaBrowser.Providers/Plugins/MusicBrainz/AlbumProvider.cs @@ -163,17 +163,17 @@ namespace MediaBrowser.Providers.Music Name = i.Artists[0].Item1 }; - result.AlbumArtist.SetProviderId(MetadataProviders.MusicBrainzArtist, i.Artists[0].Item2); + result.AlbumArtist.SetProviderId(MetadataProvider.MusicBrainzArtist, i.Artists[0].Item2); } if (!string.IsNullOrWhiteSpace(i.ReleaseId)) { - result.SetProviderId(MetadataProviders.MusicBrainzAlbum, i.ReleaseId); + result.SetProviderId(MetadataProvider.MusicBrainzAlbum, i.ReleaseId); } if (!string.IsNullOrWhiteSpace(i.ReleaseGroupId)) { - result.SetProviderId(MetadataProviders.MusicBrainzReleaseGroup, i.ReleaseGroupId); + result.SetProviderId(MetadataProvider.MusicBrainzReleaseGroup, i.ReleaseGroupId); } return result; @@ -247,12 +247,12 @@ namespace MediaBrowser.Providers.Music { if (!string.IsNullOrEmpty(releaseId)) { - result.Item.SetProviderId(MetadataProviders.MusicBrainzAlbum, releaseId); + result.Item.SetProviderId(MetadataProvider.MusicBrainzAlbum, releaseId); } if (!string.IsNullOrEmpty(releaseGroupId)) { - result.Item.SetProviderId(MetadataProviders.MusicBrainzReleaseGroup, releaseGroupId); + result.Item.SetProviderId(MetadataProvider.MusicBrainzReleaseGroup, releaseGroupId); } } diff --git a/MediaBrowser.Providers/Plugins/MusicBrainz/ArtistProvider.cs b/MediaBrowser.Providers/Plugins/MusicBrainz/ArtistProvider.cs index 260a3b6e7..9d93dbdd1 100644 --- a/MediaBrowser.Providers/Plugins/MusicBrainz/ArtistProvider.cs +++ b/MediaBrowser.Providers/Plugins/MusicBrainz/ArtistProvider.cs @@ -216,7 +216,7 @@ namespace MediaBrowser.Providers.Music } } - result.SetProviderId(MetadataProviders.MusicBrainzArtist, artistId); + result.SetProviderId(MetadataProvider.MusicBrainzArtist, artistId); if (string.IsNullOrWhiteSpace(artistId) || string.IsNullOrWhiteSpace(result.Name)) { @@ -249,7 +249,7 @@ namespace MediaBrowser.Providers.Music if (singleResult != null) { - musicBrainzId = singleResult.GetProviderId(MetadataProviders.MusicBrainzArtist); + musicBrainzId = singleResult.GetProviderId(MetadataProvider.MusicBrainzArtist); result.Item.Overview = singleResult.Overview; if (Plugin.Instance.Configuration.ReplaceArtistName) @@ -262,7 +262,7 @@ namespace MediaBrowser.Providers.Music if (!string.IsNullOrWhiteSpace(musicBrainzId)) { result.HasMetadata = true; - result.Item.SetProviderId(MetadataProviders.MusicBrainzArtist, musicBrainzId); + result.Item.SetProviderId(MetadataProvider.MusicBrainzArtist, musicBrainzId); } return result; diff --git a/MediaBrowser.Providers/Plugins/MusicBrainz/ExternalIds.cs b/MediaBrowser.Providers/Plugins/MusicBrainz/ExternalIds.cs index 03565a34c..3be6f570b 100644 --- a/MediaBrowser.Providers/Plugins/MusicBrainz/ExternalIds.cs +++ b/MediaBrowser.Providers/Plugins/MusicBrainz/ExternalIds.cs @@ -11,7 +11,7 @@ namespace MediaBrowser.Providers.Music public string Name => "MusicBrainz Release Group"; /// - public string Key => MetadataProviders.MusicBrainzReleaseGroup.ToString(); + public string Key => MetadataProvider.MusicBrainzReleaseGroup.ToString(); /// public string UrlFormatString => Plugin.Instance.Configuration.Server + "/release-group/{0}"; @@ -26,7 +26,7 @@ namespace MediaBrowser.Providers.Music public string Name => "MusicBrainz Album Artist"; /// - public string Key => MetadataProviders.MusicBrainzAlbumArtist.ToString(); + public string Key => MetadataProvider.MusicBrainzAlbumArtist.ToString(); /// public string UrlFormatString => Plugin.Instance.Configuration.Server + "/artist/{0}"; @@ -41,7 +41,7 @@ namespace MediaBrowser.Providers.Music public string Name => "MusicBrainz Album"; /// - public string Key => MetadataProviders.MusicBrainzAlbum.ToString(); + public string Key => MetadataProvider.MusicBrainzAlbum.ToString(); /// public string UrlFormatString => Plugin.Instance.Configuration.Server + "/release/{0}"; @@ -56,7 +56,7 @@ namespace MediaBrowser.Providers.Music public string Name => "MusicBrainz"; /// - public string Key => MetadataProviders.MusicBrainzArtist.ToString(); + public string Key => MetadataProvider.MusicBrainzArtist.ToString(); /// public string UrlFormatString => Plugin.Instance.Configuration.Server + "/artist/{0}"; @@ -72,7 +72,7 @@ namespace MediaBrowser.Providers.Music /// - public string Key => MetadataProviders.MusicBrainzArtist.ToString(); + public string Key => MetadataProvider.MusicBrainzArtist.ToString(); /// public string UrlFormatString => Plugin.Instance.Configuration.Server + "/artist/{0}"; @@ -87,7 +87,7 @@ namespace MediaBrowser.Providers.Music public string Name => "MusicBrainz Track"; /// - public string Key => MetadataProviders.MusicBrainzTrack.ToString(); + public string Key => MetadataProvider.MusicBrainzTrack.ToString(); /// public string UrlFormatString => Plugin.Instance.Configuration.Server + "/track/{0}"; diff --git a/MediaBrowser.Providers/Plugins/Omdb/OmdbEpisodeProvider.cs b/MediaBrowser.Providers/Plugins/Omdb/OmdbEpisodeProvider.cs index f0328e8d8..b074a1b0a 100644 --- a/MediaBrowser.Providers/Plugins/Omdb/OmdbEpisodeProvider.cs +++ b/MediaBrowser.Providers/Plugins/Omdb/OmdbEpisodeProvider.cs @@ -63,12 +63,12 @@ namespace MediaBrowser.Providers.Plugins.Omdb return result; } - if (info.SeriesProviderIds.TryGetValue(MetadataProviders.Imdb.ToString(), out string seriesImdbId) && !string.IsNullOrEmpty(seriesImdbId)) + if (info.SeriesProviderIds.TryGetValue(MetadataProvider.Imdb.ToString(), out string seriesImdbId) && !string.IsNullOrEmpty(seriesImdbId)) { if (info.IndexNumber.HasValue && info.ParentIndexNumber.HasValue) { result.HasMetadata = await new OmdbProvider(_jsonSerializer, _httpClient, _fileSystem, _appHost, _configurationManager) - .FetchEpisodeData(result, info.IndexNumber.Value, info.ParentIndexNumber.Value, info.GetProviderId(MetadataProviders.Imdb), seriesImdbId, info.MetadataLanguage, info.MetadataCountryCode, cancellationToken).ConfigureAwait(false); + .FetchEpisodeData(result, info.IndexNumber.Value, info.ParentIndexNumber.Value, info.GetProviderId(MetadataProvider.Imdb), seriesImdbId, info.MetadataLanguage, info.MetadataCountryCode, cancellationToken).ConfigureAwait(false); } } diff --git a/MediaBrowser.Providers/Plugins/Omdb/OmdbImageProvider.cs b/MediaBrowser.Providers/Plugins/Omdb/OmdbImageProvider.cs index 3cf4c3d50..d78a37784 100644 --- a/MediaBrowser.Providers/Plugins/Omdb/OmdbImageProvider.cs +++ b/MediaBrowser.Providers/Plugins/Omdb/OmdbImageProvider.cs @@ -42,7 +42,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb public async Task> GetImages(BaseItem item, CancellationToken cancellationToken) { - var imdbId = item.GetProviderId(MetadataProviders.Imdb); + var imdbId = item.GetProviderId(MetadataProvider.Imdb); var list = new List(); diff --git a/MediaBrowser.Providers/Plugins/Omdb/OmdbItemProvider.cs b/MediaBrowser.Providers/Plugins/Omdb/OmdbItemProvider.cs index 35a840f00..4a29ba4d0 100644 --- a/MediaBrowser.Providers/Plugins/Omdb/OmdbItemProvider.cs +++ b/MediaBrowser.Providers/Plugins/Omdb/OmdbItemProvider.cs @@ -68,12 +68,12 @@ namespace MediaBrowser.Providers.Plugins.Omdb { var episodeSearchInfo = searchInfo as EpisodeInfo; - var imdbId = searchInfo.GetProviderId(MetadataProviders.Imdb); + var imdbId = searchInfo.GetProviderId(MetadataProvider.Imdb); var urlQuery = "plot=full&r=json"; if (type == "episode" && episodeSearchInfo != null) { - episodeSearchInfo.SeriesProviderIds.TryGetValue(MetadataProviders.Imdb.ToString(), out imdbId); + episodeSearchInfo.SeriesProviderIds.TryGetValue(MetadataProvider.Imdb.ToString(), out imdbId); } var name = searchInfo.Name; @@ -165,7 +165,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb item.IndexNumberEnd = episodeSearchInfo.IndexNumberEnd.Value; } - item.SetProviderId(MetadataProviders.Imdb, result.imdbID); + item.SetProviderId(MetadataProvider.Imdb, result.imdbID); if (result.Year.Length > 0 && int.TryParse(result.Year.Substring(0, Math.Min(result.Year.Length, 4)), NumberStyles.Integer, CultureInfo.InvariantCulture, out var parsedYear)) @@ -210,7 +210,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb QueriedById = true }; - var imdbId = info.GetProviderId(MetadataProviders.Imdb); + var imdbId = info.GetProviderId(MetadataProvider.Imdb); if (string.IsNullOrWhiteSpace(imdbId)) { imdbId = await GetSeriesImdbId(info, cancellationToken).ConfigureAwait(false); @@ -219,7 +219,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb if (!string.IsNullOrEmpty(imdbId)) { - result.Item.SetProviderId(MetadataProviders.Imdb, imdbId); + result.Item.SetProviderId(MetadataProvider.Imdb, imdbId); result.HasMetadata = true; await new OmdbProvider(_jsonSerializer, _httpClient, _fileSystem, _appHost, _configurationManager).Fetch(result, imdbId, info.MetadataLanguage, info.MetadataCountryCode, cancellationToken).ConfigureAwait(false); @@ -242,7 +242,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb QueriedById = true }; - var imdbId = info.GetProviderId(MetadataProviders.Imdb); + var imdbId = info.GetProviderId(MetadataProvider.Imdb); if (string.IsNullOrWhiteSpace(imdbId)) { imdbId = await GetMovieImdbId(info, cancellationToken).ConfigureAwait(false); @@ -251,7 +251,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb if (!string.IsNullOrEmpty(imdbId)) { - result.Item.SetProviderId(MetadataProviders.Imdb, imdbId); + result.Item.SetProviderId(MetadataProvider.Imdb, imdbId); result.HasMetadata = true; await new OmdbProvider(_jsonSerializer, _httpClient, _fileSystem, _appHost, _configurationManager).Fetch(result, imdbId, info.MetadataLanguage, info.MetadataCountryCode, cancellationToken).ConfigureAwait(false); @@ -264,14 +264,14 @@ namespace MediaBrowser.Providers.Plugins.Omdb { var results = await GetSearchResultsInternal(info, "movie", false, cancellationToken).ConfigureAwait(false); var first = results.FirstOrDefault(); - return first == null ? null : first.GetProviderId(MetadataProviders.Imdb); + return first == null ? null : first.GetProviderId(MetadataProvider.Imdb); } private async Task GetSeriesImdbId(SeriesInfo info, CancellationToken cancellationToken) { var results = await GetSearchResultsInternal(info, "series", false, cancellationToken).ConfigureAwait(false); var first = results.FirstOrDefault(); - return first == null ? null : first.GetProviderId(MetadataProviders.Imdb); + return first == null ? null : first.GetProviderId(MetadataProvider.Imdb); } public Task GetImageResponse(string url, CancellationToken cancellationToken) diff --git a/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs b/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs index dcc003dca..19b4bd1e3 100644 --- a/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs +++ b/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs @@ -94,7 +94,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb if (!string.IsNullOrWhiteSpace(result.imdbID)) { - item.SetProviderId(MetadataProviders.Imdb, result.imdbID); + item.SetProviderId(MetadataProvider.Imdb, result.imdbID); } ParseAdditionalMetadata(itemResult, result); @@ -195,7 +195,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb if (!string.IsNullOrWhiteSpace(result.imdbID)) { - item.SetProviderId(MetadataProviders.Imdb, result.imdbID); + item.SetProviderId(MetadataProvider.Imdb, result.imdbID); } ParseAdditionalMetadata(itemResult, result); @@ -243,7 +243,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb internal static bool IsValidSeries(Dictionary seriesProviderIds) { - if (seriesProviderIds.TryGetValue(MetadataProviders.Imdb.ToString(), out string id) && !string.IsNullOrEmpty(id)) + if (seriesProviderIds.TryGetValue(MetadataProvider.Imdb.ToString(), out string id) && !string.IsNullOrEmpty(id)) { // This check should ideally never be necessary but we're seeing some cases of this and haven't tracked them down yet. if (!string.IsNullOrWhiteSpace(id)) diff --git a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbClientManager.cs b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbClientManager.cs index 24d60deb9..38e887be1 100644 --- a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbClientManager.cs +++ b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbClientManager.cs @@ -173,7 +173,7 @@ namespace MediaBrowser.Providers.Plugins.TheTvdb string language, CancellationToken cancellationToken) { - searchInfo.SeriesProviderIds.TryGetValue(MetadataProviders.Tvdb.ToString(), + searchInfo.SeriesProviderIds.TryGetValue(MetadataProvider.Tvdb.ToString(), out var seriesTvdbId); var episodeQuery = new EpisodeQuery(); diff --git a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbEpisodeImageProvider.cs b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbEpisodeImageProvider.cs index 6118a9c53..770f6d34b 100644 --- a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbEpisodeImageProvider.cs +++ b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbEpisodeImageProvider.cs @@ -68,7 +68,7 @@ namespace MediaBrowser.Providers.Plugins.TheTvdb "Episode {SeasonNumber}x{EpisodeNumber} not found for series {SeriesTvdbId}", episodeInfo.ParentIndexNumber, episodeInfo.IndexNumber, - series.GetProviderId(MetadataProviders.Tvdb)); + series.GetProviderId(MetadataProvider.Tvdb)); return imageResult; } @@ -85,7 +85,7 @@ namespace MediaBrowser.Providers.Plugins.TheTvdb } catch (TvDbServerException e) { - _logger.LogError(e, "Failed to retrieve episode images for series {TvDbId}", series.GetProviderId(MetadataProviders.Tvdb)); + _logger.LogError(e, "Failed to retrieve episode images for series {TvDbId}", series.GetProviderId(MetadataProvider.Tvdb)); } } diff --git a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbEpisodeProvider.cs b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbEpisodeProvider.cs index 5a4827d2f..451444382 100644 --- a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbEpisodeProvider.cs +++ b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbEpisodeProvider.cs @@ -94,7 +94,7 @@ namespace MediaBrowser.Providers.Plugins.TheTvdb QueriedById = true }; - string seriesTvdbId = searchInfo.GetProviderId(MetadataProviders.Tvdb); + string seriesTvdbId = searchInfo.GetProviderId(MetadataProvider.Tvdb); string episodeTvdbId = null; try { @@ -143,8 +143,8 @@ namespace MediaBrowser.Providers.Plugins.TheTvdb result.ResetPeople(); var item = result.Item; - item.SetProviderId(MetadataProviders.Tvdb, episode.Id.ToString()); - item.SetProviderId(MetadataProviders.Imdb, episode.ImdbId); + item.SetProviderId(MetadataProvider.Tvdb, episode.Id.ToString()); + item.SetProviderId(MetadataProvider.Imdb, episode.ImdbId); if (string.Equals(id.SeriesDisplayOrder, "dvd", StringComparison.OrdinalIgnoreCase)) { diff --git a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbPersonImageProvider.cs b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbPersonImageProvider.cs index 77425f1d2..19ca3dc90 100644 --- a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbPersonImageProvider.cs +++ b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbPersonImageProvider.cs @@ -72,7 +72,7 @@ namespace MediaBrowser.Providers.Plugins.TheTvdb private async Task GetImageFromSeriesData(Series series, string personName, CancellationToken cancellationToken) { - var tvdbId = Convert.ToInt32(series.GetProviderId(MetadataProviders.Tvdb)); + var tvdbId = Convert.ToInt32(series.GetProviderId(MetadataProvider.Tvdb)); try { diff --git a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeasonImageProvider.cs b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeasonImageProvider.cs index 7abcd29ec..c820ea5ea 100644 --- a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeasonImageProvider.cs +++ b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeasonImageProvider.cs @@ -58,7 +58,7 @@ namespace MediaBrowser.Providers.Plugins.TheTvdb return Array.Empty(); } - var tvdbId = Convert.ToInt32(series.GetProviderId(MetadataProviders.Tvdb)); + var tvdbId = Convert.ToInt32(series.GetProviderId(MetadataProvider.Tvdb)); var seasonNumber = season.IndexNumber.Value; var language = item.GetPreferredMetadataLanguage(); var remoteImages = new List(); diff --git a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeriesImageProvider.cs b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeriesImageProvider.cs index f65707291..54aa53173 100644 --- a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeriesImageProvider.cs +++ b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeriesImageProvider.cs @@ -58,7 +58,7 @@ namespace MediaBrowser.Providers.Plugins.TheTvdb var language = item.GetPreferredMetadataLanguage(); var remoteImages = new List(); var keyTypes = new[] { KeyType.Poster, KeyType.Series, KeyType.Fanart }; - var tvdbId = Convert.ToInt32(item.GetProviderId(MetadataProviders.Tvdb)); + var tvdbId = Convert.ToInt32(item.GetProviderId(MetadataProvider.Tvdb)); foreach (KeyType keyType in keyTypes) { var imageQuery = new ImagesQuery diff --git a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeriesProvider.cs b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeriesProvider.cs index d4fcad643..541471561 100644 --- a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeriesProvider.cs +++ b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeriesProvider.cs @@ -95,22 +95,22 @@ namespace MediaBrowser.Providers.Plugins.TheTvdb { var series = result.Item; - if (seriesProviderIds.TryGetValue(MetadataProviders.Tvdb.ToString(), out var tvdbId) && !string.IsNullOrEmpty(tvdbId)) + if (seriesProviderIds.TryGetValue(MetadataProvider.Tvdb.ToString(), out var tvdbId) && !string.IsNullOrEmpty(tvdbId)) { - series.SetProviderId(MetadataProviders.Tvdb, tvdbId); + series.SetProviderId(MetadataProvider.Tvdb, tvdbId); } - if (seriesProviderIds.TryGetValue(MetadataProviders.Imdb.ToString(), out var imdbId) && !string.IsNullOrEmpty(imdbId)) + if (seriesProviderIds.TryGetValue(MetadataProvider.Imdb.ToString(), out var imdbId) && !string.IsNullOrEmpty(imdbId)) { - series.SetProviderId(MetadataProviders.Imdb, imdbId); - tvdbId = await GetSeriesByRemoteId(imdbId, MetadataProviders.Imdb.ToString(), metadataLanguage, + series.SetProviderId(MetadataProvider.Imdb, imdbId); + tvdbId = await GetSeriesByRemoteId(imdbId, MetadataProvider.Imdb.ToString(), metadataLanguage, cancellationToken).ConfigureAwait(false); } - if (seriesProviderIds.TryGetValue(MetadataProviders.Zap2It.ToString(), out var zap2It) && !string.IsNullOrEmpty(zap2It)) + if (seriesProviderIds.TryGetValue(MetadataProvider.Zap2It.ToString(), out var zap2It) && !string.IsNullOrEmpty(zap2It)) { - series.SetProviderId(MetadataProviders.Zap2It, zap2It); - tvdbId = await GetSeriesByRemoteId(zap2It, MetadataProviders.Zap2It.ToString(), metadataLanguage, + series.SetProviderId(MetadataProvider.Zap2It, zap2It); + tvdbId = await GetSeriesByRemoteId(zap2It, MetadataProvider.Zap2It.ToString(), metadataLanguage, cancellationToken).ConfigureAwait(false); } @@ -150,7 +150,7 @@ namespace MediaBrowser.Providers.Plugins.TheTvdb try { - if (string.Equals(idType, MetadataProviders.Zap2It.ToString(), StringComparison.OrdinalIgnoreCase)) + if (string.Equals(idType, MetadataProvider.Zap2It.ToString(), StringComparison.OrdinalIgnoreCase)) { result = await _tvdbClientManager.GetSeriesByZap2ItIdAsync(id, language, cancellationToken) .ConfigureAwait(false); @@ -176,9 +176,9 @@ namespace MediaBrowser.Providers.Plugins.TheTvdb /// True, if the dictionary contains a valid TV provider ID, otherwise false. internal static bool IsValidSeries(Dictionary seriesProviderIds) { - return seriesProviderIds.ContainsKey(MetadataProviders.Tvdb.ToString()) || - seriesProviderIds.ContainsKey(MetadataProviders.Imdb.ToString()) || - seriesProviderIds.ContainsKey(MetadataProviders.Zap2It.ToString()); + return seriesProviderIds.ContainsKey(MetadataProvider.Tvdb.ToString()) || + seriesProviderIds.ContainsKey(MetadataProvider.Imdb.ToString()) || + seriesProviderIds.ContainsKey(MetadataProvider.Zap2It.ToString()); } /// @@ -255,15 +255,15 @@ namespace MediaBrowser.Providers.Plugins.TheTvdb var seriesSesult = await _tvdbClientManager.GetSeriesByIdAsync(seriesSearchResult.Id, language, cancellationToken) .ConfigureAwait(false); - remoteSearchResult.SetProviderId(MetadataProviders.Imdb, seriesSesult.Data.ImdbId); - remoteSearchResult.SetProviderId(MetadataProviders.Zap2It, seriesSesult.Data.Zap2itId); + remoteSearchResult.SetProviderId(MetadataProvider.Imdb, seriesSesult.Data.ImdbId); + remoteSearchResult.SetProviderId(MetadataProvider.Zap2It, seriesSesult.Data.Zap2itId); } catch (TvDbServerException e) { _logger.LogError(e, "Unable to retrieve series with id {TvdbId}", seriesSearchResult.Id); } - remoteSearchResult.SetProviderId(MetadataProviders.Tvdb, seriesSearchResult.Id.ToString()); + remoteSearchResult.SetProviderId(MetadataProvider.Tvdb, seriesSearchResult.Id.ToString()); list.Add(new Tuple, RemoteSearchResult>(tvdbTitles, remoteSearchResult)); } @@ -325,15 +325,15 @@ namespace MediaBrowser.Providers.Plugins.TheTvdb private void MapSeriesToResult(MetadataResult result, TvDbSharper.Dto.Series tvdbSeries, string metadataLanguage) { Series series = result.Item; - series.SetProviderId(MetadataProviders.Tvdb, tvdbSeries.Id.ToString()); + series.SetProviderId(MetadataProvider.Tvdb, tvdbSeries.Id.ToString()); series.Name = tvdbSeries.SeriesName; series.Overview = (tvdbSeries.Overview ?? string.Empty).Trim(); result.ResultLanguage = metadataLanguage; series.AirDays = TVUtils.GetAirDays(tvdbSeries.AirsDayOfWeek); series.AirTime = tvdbSeries.AirsTime; series.CommunityRating = (float?)tvdbSeries.SiteRating; - series.SetProviderId(MetadataProviders.Imdb, tvdbSeries.ImdbId); - series.SetProviderId(MetadataProviders.Zap2It, tvdbSeries.Zap2itId); + series.SetProviderId(MetadataProvider.Imdb, tvdbSeries.ImdbId); + series.SetProviderId(MetadataProvider.Zap2It, tvdbSeries.Zap2itId); if (Enum.TryParse(tvdbSeries.Status, true, out SeriesStatus seriesStatus)) { series.Status = seriesStatus; @@ -411,7 +411,7 @@ namespace MediaBrowser.Providers.Plugins.TheTvdb public async Task Identify(SeriesInfo info) { - if (!string.IsNullOrWhiteSpace(info.GetProviderId(MetadataProviders.Tvdb))) + if (!string.IsNullOrWhiteSpace(info.GetProviderId(MetadataProvider.Tvdb))) { return; } @@ -423,8 +423,8 @@ namespace MediaBrowser.Providers.Plugins.TheTvdb if (entry != null) { - var id = entry.GetProviderId(MetadataProviders.Tvdb); - info.SetProviderId(MetadataProviders.Tvdb, id); + var id = entry.GetProviderId(MetadataProvider.Tvdb); + info.SetProviderId(MetadataProvider.Tvdb, id); } } diff --git a/MediaBrowser.Providers/Plugins/Tmdb/BoxSets/TmdbBoxSetExternalId.cs b/MediaBrowser.Providers/Plugins/Tmdb/BoxSets/TmdbBoxSetExternalId.cs index a260406da..ad0851cef 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/BoxSets/TmdbBoxSetExternalId.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/BoxSets/TmdbBoxSetExternalId.cs @@ -11,7 +11,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.BoxSets public string Name => TmdbUtils.ProviderName; /// - public string Key => MetadataProviders.TmdbCollection.ToString(); + public string Key => MetadataProvider.TmdbCollection.ToString(); /// public string UrlFormatString => TmdbUtils.BaseTmdbUrl + "collection/{0}"; diff --git a/MediaBrowser.Providers/Plugins/Tmdb/BoxSets/TmdbBoxSetImageProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/BoxSets/TmdbBoxSetImageProvider.cs index c47c8d4e9..23eb00b5c 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/BoxSets/TmdbBoxSetImageProvider.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/BoxSets/TmdbBoxSetImageProvider.cs @@ -45,7 +45,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.BoxSets public async Task> GetImages(BaseItem item, CancellationToken cancellationToken) { - var tmdbId = item.GetProviderId(MetadataProviders.Tmdb); + var tmdbId = item.GetProviderId(MetadataProvider.Tmdb); if (!string.IsNullOrEmpty(tmdbId)) { diff --git a/MediaBrowser.Providers/Plugins/Tmdb/BoxSets/TmdbBoxSetProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/BoxSets/TmdbBoxSetProvider.cs index 05c1e3c9d..d3b4bdcff 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/BoxSets/TmdbBoxSetProvider.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/BoxSets/TmdbBoxSetProvider.cs @@ -60,7 +60,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.BoxSets public async Task> GetSearchResults(BoxSetInfo searchInfo, CancellationToken cancellationToken) { - var tmdbId = searchInfo.GetProviderId(MetadataProviders.Tmdb); + var tmdbId = searchInfo.GetProviderId(MetadataProvider.Tmdb); if (!string.IsNullOrEmpty(tmdbId)) { @@ -82,7 +82,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.BoxSets ImageUrl = images.Count == 0 ? null : (tmdbImageUrl + images[0].File_Path) }; - result.SetProviderId(MetadataProviders.Tmdb, info.Id.ToString(_usCulture)); + result.SetProviderId(MetadataProvider.Tmdb, info.Id.ToString(_usCulture)); return new[] { result }; } @@ -92,7 +92,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.BoxSets public async Task> GetMetadata(BoxSetInfo id, CancellationToken cancellationToken) { - var tmdbId = id.GetProviderId(MetadataProviders.Tmdb); + var tmdbId = id.GetProviderId(MetadataProvider.Tmdb); // We don't already have an Id, need to fetch it if (string.IsNullOrEmpty(tmdbId)) @@ -103,7 +103,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.BoxSets if (searchResult != null) { - tmdbId = searchResult.GetProviderId(MetadataProviders.Tmdb); + tmdbId = searchResult.GetProviderId(MetadataProvider.Tmdb); } } @@ -150,7 +150,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.BoxSets Overview = obj.Overview }; - item.SetProviderId(MetadataProviders.Tmdb, obj.Id.ToString(_usCulture)); + item.SetProviderId(MetadataProvider.Tmdb, obj.Id.ToString(_usCulture)); return item; } diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Movies/GenericTmdbMovieInfo.cs b/MediaBrowser.Providers/Plugins/Tmdb/Movies/GenericTmdbMovieInfo.cs index e1edb50e4..60f37dc17 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/Movies/GenericTmdbMovieInfo.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/Movies/GenericTmdbMovieInfo.cs @@ -38,8 +38,8 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Movies public async Task> GetMetadata(ItemLookupInfo itemId, CancellationToken cancellationToken) { - var tmdbId = itemId.GetProviderId(MetadataProviders.Tmdb); - var imdbId = itemId.GetProviderId(MetadataProviders.Imdb); + var tmdbId = itemId.GetProviderId(MetadataProvider.Tmdb); + var imdbId = itemId.GetProviderId(MetadataProvider.Imdb); // Don't search for music video id's because it is very easy to misidentify. if (string.IsNullOrEmpty(tmdbId) && string.IsNullOrEmpty(imdbId) && typeof(T) != typeof(MusicVideo)) @@ -50,7 +50,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Movies if (searchResult != null) { - tmdbId = searchResult.GetProviderId(MetadataProviders.Tmdb); + tmdbId = searchResult.GetProviderId(MetadataProvider.Tmdb); } } @@ -146,12 +146,12 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Movies .ToArray(); } - movie.SetProviderId(MetadataProviders.Tmdb, movieData.Id.ToString(_usCulture)); - movie.SetProviderId(MetadataProviders.Imdb, movieData.Imdb_Id); + movie.SetProviderId(MetadataProvider.Tmdb, movieData.Id.ToString(_usCulture)); + movie.SetProviderId(MetadataProvider.Imdb, movieData.Imdb_Id); if (movieData.Belongs_To_Collection != null) { - movie.SetProviderId(MetadataProviders.TmdbCollection, + movie.SetProviderId(MetadataProvider.TmdbCollection, movieData.Belongs_To_Collection.Id.ToString(CultureInfo.InvariantCulture)); if (movie is Movie movieItem) @@ -240,7 +240,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Movies if (actor.Id > 0) { - personInfo.SetProviderId(MetadataProviders.Tmdb, actor.Id.ToString(CultureInfo.InvariantCulture)); + personInfo.SetProviderId(MetadataProvider.Tmdb, actor.Id.ToString(CultureInfo.InvariantCulture)); } resultItem.AddPerson(personInfo); @@ -282,7 +282,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Movies if (person.Id > 0) { - personInfo.SetProviderId(MetadataProviders.Tmdb, person.Id.ToString(CultureInfo.InvariantCulture)); + personInfo.SetProviderId(MetadataProvider.Tmdb, person.Id.ToString(CultureInfo.InvariantCulture)); } resultItem.AddPerson(personInfo); diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbImageProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbImageProvider.cs index 3f77860f1..a11c89459 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbImageProvider.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbImageProvider.cs @@ -158,11 +158,11 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Movies /// Task{MovieImages}. private async Task FetchImages(BaseItem item, string language, IJsonSerializer jsonSerializer, CancellationToken cancellationToken) { - var tmdbId = item.GetProviderId(MetadataProviders.Tmdb); + var tmdbId = item.GetProviderId(MetadataProvider.Tmdb); if (string.IsNullOrWhiteSpace(tmdbId)) { - var imdbId = item.GetProviderId(MetadataProviders.Imdb); + var imdbId = item.GetProviderId(MetadataProvider.Imdb); if (!string.IsNullOrWhiteSpace(imdbId)) { var movieInfo = await TmdbMovieProvider.Current.FetchMainResult(imdbId, false, language, cancellationToken).ConfigureAwait(false); diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieExternalId.cs b/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieExternalId.cs index a3fac29e5..7aec27e97 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieExternalId.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieExternalId.cs @@ -12,7 +12,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Movies public string Name => TmdbUtils.ProviderName; /// - public string Key => MetadataProviders.Tmdb.ToString(); + public string Key => MetadataProvider.Tmdb.ToString(); /// public string UrlFormatString => TmdbUtils.BaseTmdbUrl + "movie/{0}"; diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieProvider.cs index d2b5967e4..6830968ee 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieProvider.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieProvider.cs @@ -67,7 +67,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Movies public async Task> GetMovieSearchResults(ItemLookupInfo searchInfo, CancellationToken cancellationToken) { - var tmdbId = searchInfo.GetProviderId(MetadataProviders.Tmdb); + var tmdbId = searchInfo.GetProviderId(MetadataProvider.Tmdb); if (!string.IsNullOrEmpty(tmdbId)) { @@ -100,11 +100,11 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Movies } } - remoteResult.SetProviderId(MetadataProviders.Tmdb, obj.Id.ToString(_usCulture)); + remoteResult.SetProviderId(MetadataProvider.Tmdb, obj.Id.ToString(_usCulture)); if (!string.IsNullOrWhiteSpace(obj.Imdb_Id)) { - remoteResult.SetProviderId(MetadataProviders.Imdb, obj.Imdb_Id); + remoteResult.SetProviderId(MetadataProvider.Imdb, obj.Imdb_Id); } return new[] { remoteResult }; diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbSearch.cs b/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbSearch.cs index 1131e0c72..717aa4eef 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbSearch.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbSearch.cs @@ -199,7 +199,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Movies } } - remoteResult.SetProviderId(MetadataProviders.Tmdb, i.Id.ToString(_usCulture)); + remoteResult.SetProviderId(MetadataProvider.Tmdb, i.Id.ToString(_usCulture)); return remoteResult; @@ -252,7 +252,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Movies } } - remoteResult.SetProviderId(MetadataProviders.Tmdb, i.Id.ToString(_usCulture)); + remoteResult.SetProviderId(MetadataProvider.Tmdb, i.Id.ToString(_usCulture)); return remoteResult; diff --git a/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonExternalId.cs b/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonExternalId.cs index c7b04e42b..70cd1cd95 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonExternalId.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonExternalId.cs @@ -10,7 +10,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.People public string Name => TmdbUtils.ProviderName; /// - public string Key => MetadataProviders.Tmdb.ToString(); + public string Key => MetadataProvider.Tmdb.ToString(); /// public string UrlFormatString => TmdbUtils.BaseTmdbUrl + "person/{0}"; diff --git a/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonImageProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonImageProvider.cs index e385207d9..525c0072b 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonImageProvider.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonImageProvider.cs @@ -49,7 +49,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.People public async Task> GetImages(BaseItem item, CancellationToken cancellationToken) { var person = (Person)item; - var id = person.GetProviderId(MetadataProviders.Tmdb); + var id = person.GetProviderId(MetadataProvider.Tmdb); if (!string.IsNullOrEmpty(id)) { diff --git a/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonProvider.cs index bf91406b7..6869788f7 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonProvider.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonProvider.cs @@ -56,7 +56,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.People public async Task> GetSearchResults(PersonLookupInfo searchInfo, CancellationToken cancellationToken) { - var tmdbId = searchInfo.GetProviderId(MetadataProviders.Tmdb); + var tmdbId = searchInfo.GetProviderId(MetadataProvider.Tmdb); var tmdbSettings = await TmdbMovieProvider.Current.GetTmdbSettings(cancellationToken).ConfigureAwait(false); @@ -80,8 +80,8 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.People ImageUrl = images.Count == 0 ? null : (tmdbImageUrl + images[0].File_Path) }; - result.SetProviderId(MetadataProviders.Tmdb, info.Id.ToString(_usCulture)); - result.SetProviderId(MetadataProviders.Imdb, info.Imdb_Id); + result.SetProviderId(MetadataProvider.Tmdb, info.Id.ToString(_usCulture)); + result.SetProviderId(MetadataProvider.Imdb, info.Imdb_Id); return new[] { result }; } @@ -123,14 +123,14 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.People ImageUrl = string.IsNullOrEmpty(i.Profile_Path) ? null : baseImageUrl + i.Profile_Path }; - result.SetProviderId(MetadataProviders.Tmdb, i.Id.ToString(_usCulture)); + result.SetProviderId(MetadataProvider.Tmdb, i.Id.ToString(_usCulture)); return result; } public async Task> GetMetadata(PersonLookupInfo id, CancellationToken cancellationToken) { - var tmdbId = id.GetProviderId(MetadataProviders.Tmdb); + var tmdbId = id.GetProviderId(MetadataProvider.Tmdb); // We don't already have an Id, need to fetch it if (string.IsNullOrEmpty(tmdbId)) @@ -185,11 +185,11 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.People item.EndDate = date.ToUniversalTime(); } - item.SetProviderId(MetadataProviders.Tmdb, info.Id.ToString(_usCulture)); + item.SetProviderId(MetadataProvider.Tmdb, info.Id.ToString(_usCulture)); if (!string.IsNullOrEmpty(info.Imdb_Id)) { - item.SetProviderId(MetadataProviders.Imdb, info.Imdb_Id); + item.SetProviderId(MetadataProvider.Imdb, info.Imdb_Id); } result.HasMetadata = true; @@ -211,7 +211,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.People { var results = await GetSearchResults(info, cancellationToken).ConfigureAwait(false); - return results.Select(i => i.GetProviderId(MetadataProviders.Tmdb)).FirstOrDefault(); + return results.Select(i => i.GetProviderId(MetadataProvider.Tmdb)).FirstOrDefault(); } internal async Task EnsurePersonInfo(string id, CancellationToken cancellationToken) diff --git a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeImageProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeImageProvider.cs index 1d7ad4342..3fa47d54b 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeImageProvider.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeImageProvider.cs @@ -41,7 +41,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV var episode = (Controller.Entities.TV.Episode)item; var series = episode.Series; - var seriesId = series != null ? series.GetProviderId(MetadataProviders.Tmdb) : null; + var seriesId = series != null ? series.GetProviderId(MetadataProvider.Tmdb) : null; var list = new List(); diff --git a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeProvider.cs index d143cbd10..01b295f86 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeProvider.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeProvider.cs @@ -71,7 +71,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV return result; } - info.SeriesProviderIds.TryGetValue(MetadataProviders.Tmdb.ToString(), out string seriesTmdbId); + info.SeriesProviderIds.TryGetValue(MetadataProvider.Tmdb.ToString(), out string seriesTmdbId); if (string.IsNullOrEmpty(seriesTmdbId)) { @@ -109,7 +109,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV if (response.External_Ids.Tvdb_Id > 0) { - item.SetProviderId(MetadataProviders.Tvdb, response.External_Ids.Tvdb_Id.ToString(CultureInfo.InvariantCulture)); + item.SetProviderId(MetadataProvider.Tvdb, response.External_Ids.Tvdb_Id.ToString(CultureInfo.InvariantCulture)); } item.PremiereDate = response.Air_Date; diff --git a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeasonImageProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeasonImageProvider.cs index eb659253e..b5456b45c 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeasonImageProvider.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeasonImageProvider.cs @@ -48,7 +48,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV var season = (Season)item; var series = season.Series; - var seriesId = series?.GetProviderId(MetadataProviders.Tmdb); + var seriesId = series?.GetProviderId(MetadataProvider.Tmdb); if (string.IsNullOrEmpty(seriesId)) { diff --git a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeasonProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeasonProvider.cs index 060ce5503..8eab09c5c 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeasonProvider.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeasonProvider.cs @@ -48,7 +48,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV { var result = new MetadataResult(); - info.SeriesProviderIds.TryGetValue(MetadataProviders.Tmdb.ToString(), out string seriesTmdbId); + info.SeriesProviderIds.TryGetValue(MetadataProvider.Tmdb.ToString(), out string seriesTmdbId); var seasonNumber = info.IndexNumber; @@ -73,7 +73,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV if (seasonInfo.External_Ids.Tvdb_Id > 0) { - result.Item.SetProviderId(MetadataProviders.Tvdb, seasonInfo.External_Ids.Tvdb_Id.ToString(CultureInfo.InvariantCulture)); + result.Item.SetProviderId(MetadataProvider.Tvdb, seasonInfo.External_Ids.Tvdb_Id.ToString(CultureInfo.InvariantCulture)); } var credits = seasonInfo.Credits; diff --git a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesExternalId.cs b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesExternalId.cs index 41fb96882..705f8041b 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesExternalId.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesExternalId.cs @@ -10,7 +10,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV public string Name => TmdbUtils.ProviderName; /// - public string Key => MetadataProviders.Tmdb.ToString(); + public string Key => MetadataProvider.Tmdb.ToString(); /// public string UrlFormatString => TmdbUtils.BaseTmdbUrl + "tv/{0}"; diff --git a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesImageProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesImageProvider.cs index 30a5295f3..40824d88d 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesImageProvider.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesImageProvider.cs @@ -151,7 +151,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV private async Task FetchImages(BaseItem item, string language, IJsonSerializer jsonSerializer, CancellationToken cancellationToken) { - var tmdbId = item.GetProviderId(MetadataProviders.Tmdb); + var tmdbId = item.GetProviderId(MetadataProvider.Tmdb); if (string.IsNullOrEmpty(tmdbId)) { diff --git a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesProvider.cs index bed26cee9..5904347f0 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesProvider.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesProvider.cs @@ -63,7 +63,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV public async Task> GetSearchResults(SeriesInfo searchInfo, CancellationToken cancellationToken) { - var tmdbId = searchInfo.GetProviderId(MetadataProviders.Tmdb); + var tmdbId = searchInfo.GetProviderId(MetadataProvider.Tmdb); if (!string.IsNullOrEmpty(tmdbId)) { @@ -85,18 +85,18 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV ImageUrl = string.IsNullOrWhiteSpace(obj.Poster_Path) ? null : tmdbImageUrl + obj.Poster_Path }; - remoteResult.SetProviderId(MetadataProviders.Tmdb, obj.Id.ToString(_usCulture)); - remoteResult.SetProviderId(MetadataProviders.Imdb, obj.External_Ids.Imdb_Id); + remoteResult.SetProviderId(MetadataProvider.Tmdb, obj.Id.ToString(_usCulture)); + remoteResult.SetProviderId(MetadataProvider.Imdb, obj.External_Ids.Imdb_Id); if (obj.External_Ids.Tvdb_Id > 0) { - remoteResult.SetProviderId(MetadataProviders.Tvdb, obj.External_Ids.Tvdb_Id.ToString(_usCulture)); + remoteResult.SetProviderId(MetadataProvider.Tvdb, obj.External_Ids.Tvdb_Id.ToString(_usCulture)); } return new[] { remoteResult }; } - var imdbId = searchInfo.GetProviderId(MetadataProviders.Imdb); + var imdbId = searchInfo.GetProviderId(MetadataProvider.Imdb); if (!string.IsNullOrEmpty(imdbId)) { @@ -108,7 +108,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV } } - var tvdbId = searchInfo.GetProviderId(MetadataProviders.Tvdb); + var tvdbId = searchInfo.GetProviderId(MetadataProvider.Tvdb); if (!string.IsNullOrEmpty(tvdbId)) { @@ -128,11 +128,11 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV var result = new MetadataResult(); result.QueriedById = true; - var tmdbId = info.GetProviderId(MetadataProviders.Tmdb); + var tmdbId = info.GetProviderId(MetadataProvider.Tmdb); if (string.IsNullOrEmpty(tmdbId)) { - var imdbId = info.GetProviderId(MetadataProviders.Imdb); + var imdbId = info.GetProviderId(MetadataProvider.Imdb); if (!string.IsNullOrEmpty(imdbId)) { @@ -140,14 +140,14 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV if (searchResult != null) { - tmdbId = searchResult.GetProviderId(MetadataProviders.Tmdb); + tmdbId = searchResult.GetProviderId(MetadataProvider.Tmdb); } } } if (string.IsNullOrEmpty(tmdbId)) { - var tvdbId = info.GetProviderId(MetadataProviders.Tvdb); + var tvdbId = info.GetProviderId(MetadataProvider.Tvdb); if (!string.IsNullOrEmpty(tvdbId)) { @@ -155,7 +155,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV if (searchResult != null) { - tmdbId = searchResult.GetProviderId(MetadataProviders.Tmdb); + tmdbId = searchResult.GetProviderId(MetadataProvider.Tmdb); } } } @@ -169,7 +169,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV if (searchResult != null) { - tmdbId = searchResult.GetProviderId(MetadataProviders.Tmdb); + tmdbId = searchResult.GetProviderId(MetadataProvider.Tmdb); } } @@ -219,7 +219,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV series.Name = seriesInfo.Name; series.OriginalTitle = seriesInfo.Original_Name; - series.SetProviderId(MetadataProviders.Tmdb, seriesInfo.Id.ToString(_usCulture)); + series.SetProviderId(MetadataProvider.Tmdb, seriesInfo.Id.ToString(_usCulture)); string voteAvg = seriesInfo.Vote_Average.ToString(CultureInfo.InvariantCulture); @@ -261,17 +261,17 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV { if (!string.IsNullOrWhiteSpace(ids.Imdb_Id)) { - series.SetProviderId(MetadataProviders.Imdb, ids.Imdb_Id); + series.SetProviderId(MetadataProvider.Imdb, ids.Imdb_Id); } if (ids.Tvrage_Id > 0) { - series.SetProviderId(MetadataProviders.TvRage, ids.Tvrage_Id.ToString(_usCulture)); + series.SetProviderId(MetadataProvider.TvRage, ids.Tvrage_Id.ToString(_usCulture)); } if (ids.Tvdb_Id > 0) { - series.SetProviderId(MetadataProviders.Tvdb, ids.Tvdb_Id.ToString(_usCulture)); + series.SetProviderId(MetadataProvider.Tvdb, ids.Tvdb_Id.ToString(_usCulture)); } } @@ -331,7 +331,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV if (actor.Id > 0) { - personInfo.SetProviderId(MetadataProviders.Tmdb, actor.Id.ToString(CultureInfo.InvariantCulture)); + personInfo.SetProviderId(MetadataProvider.Tmdb, actor.Id.ToString(CultureInfo.InvariantCulture)); } seriesResult.AddPerson(personInfo); @@ -540,7 +540,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV ImageUrl = string.IsNullOrWhiteSpace(tv.Poster_Path) ? null : tmdbImageUrl + tv.Poster_Path }; - remoteResult.SetProviderId(MetadataProviders.Tmdb, tv.Id.ToString(_usCulture)); + remoteResult.SetProviderId(MetadataProvider.Tmdb, tv.Id.ToString(_usCulture)); return remoteResult; } diff --git a/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs b/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs index 0721c4bb4..aabad3ada 100644 --- a/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs +++ b/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs @@ -46,7 +46,7 @@ namespace MediaBrowser.Providers.TV public async Task Run(Series series, bool addNewItems, CancellationToken cancellationToken) { - var tvdbId = series.GetProviderId(MetadataProviders.Tvdb); + var tvdbId = series.GetProviderId(MetadataProvider.Tvdb); if (string.IsNullOrEmpty(tvdbId)) { return false; diff --git a/MediaBrowser.Providers/TV/TvExternalIds.cs b/MediaBrowser.Providers/TV/TvExternalIds.cs index baf854285..bd59606e7 100644 --- a/MediaBrowser.Providers/TV/TvExternalIds.cs +++ b/MediaBrowser.Providers/TV/TvExternalIds.cs @@ -11,7 +11,7 @@ namespace MediaBrowser.Providers.TV public string Name => "Zap2It"; /// - public string Key => MetadataProviders.Zap2It.ToString(); + public string Key => MetadataProvider.Zap2It.ToString(); /// public string UrlFormatString => "http://tvlistings.zap2it.com/overview.html?programSeriesId={0}"; @@ -26,7 +26,7 @@ namespace MediaBrowser.Providers.TV public string Name => "TheTVDB"; /// - public string Key => MetadataProviders.Tvdb.ToString(); + public string Key => MetadataProvider.Tvdb.ToString(); /// public string UrlFormatString => TvdbUtils.TvdbBaseUrl + "?tab=series&id={0}"; @@ -42,7 +42,7 @@ namespace MediaBrowser.Providers.TV public string Name => "TheTVDB"; /// - public string Key => MetadataProviders.Tvdb.ToString(); + public string Key => MetadataProvider.Tvdb.ToString(); /// public string UrlFormatString => null; @@ -57,7 +57,7 @@ namespace MediaBrowser.Providers.TV public string Name => "TheTVDB"; /// - public string Key => MetadataProviders.Tvdb.ToString(); + public string Key => MetadataProvider.Tvdb.ToString(); /// public string UrlFormatString => TvdbUtils.TvdbBaseUrl + "?tab=episode&id={0}"; diff --git a/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs b/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs index 5c8de80f1..d54796537 100644 --- a/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs +++ b/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs @@ -212,7 +212,7 @@ namespace MediaBrowser.XbmcMetadata.Parsers var m = Regex.Match(xml, "tt([0-9]{7,8})", RegexOptions.IgnoreCase); if (m.Success) { - item.SetProviderId(MetadataProviders.Imdb, m.Value); + item.SetProviderId(MetadataProvider.Imdb, m.Value); } // Support Tmdb @@ -225,7 +225,7 @@ namespace MediaBrowser.XbmcMetadata.Parsers var tmdbId = xml.Substring(index + srch.Length).TrimEnd('/').Split('-')[0]; if (!string.IsNullOrWhiteSpace(tmdbId) && int.TryParse(tmdbId, NumberStyles.Integer, CultureInfo.InvariantCulture, out var value)) { - item.SetProviderId(MetadataProviders.Tmdb, value.ToString(UsCulture)); + item.SetProviderId(MetadataProvider.Tmdb, value.ToString(UsCulture)); } } @@ -240,7 +240,7 @@ namespace MediaBrowser.XbmcMetadata.Parsers var tvdbId = xml.Substring(index + srch.Length).TrimEnd('/'); if (!string.IsNullOrWhiteSpace(tvdbId) && int.TryParse(tvdbId, NumberStyles.Integer, CultureInfo.InvariantCulture, out var value)) { - item.SetProviderId(MetadataProviders.Tvdb, value.ToString(UsCulture)); + item.SetProviderId(MetadataProvider.Tvdb, value.ToString(UsCulture)); } } } diff --git a/MediaBrowser.XbmcMetadata/Parsers/MovieNfoParser.cs b/MediaBrowser.XbmcMetadata/Parsers/MovieNfoParser.cs index c17212f31..b74a9fd8a 100644 --- a/MediaBrowser.XbmcMetadata/Parsers/MovieNfoParser.cs +++ b/MediaBrowser.XbmcMetadata/Parsers/MovieNfoParser.cs @@ -49,12 +49,12 @@ namespace MediaBrowser.XbmcMetadata.Parsers if (!string.IsNullOrWhiteSpace(imdbId)) { - item.SetProviderId(MetadataProviders.Imdb, imdbId); + item.SetProviderId(MetadataProvider.Imdb, imdbId); } if (!string.IsNullOrWhiteSpace(tmdbId)) { - item.SetProviderId(MetadataProviders.Tmdb, tmdbId); + item.SetProviderId(MetadataProvider.Tmdb, tmdbId); } break; @@ -67,7 +67,7 @@ namespace MediaBrowser.XbmcMetadata.Parsers var tmdbcolid = reader.GetAttribute("tmdbcolid"); if (!string.IsNullOrWhiteSpace(tmdbcolid) && movie != null) { - movie.SetProviderId(MetadataProviders.TmdbCollection, tmdbcolid); + movie.SetProviderId(MetadataProvider.TmdbCollection, tmdbcolid); } var val = reader.ReadInnerXml(); diff --git a/MediaBrowser.XbmcMetadata/Parsers/SeriesNfoParser.cs b/MediaBrowser.XbmcMetadata/Parsers/SeriesNfoParser.cs index 0954ae206..f079d4a7e 100644 --- a/MediaBrowser.XbmcMetadata/Parsers/SeriesNfoParser.cs +++ b/MediaBrowser.XbmcMetadata/Parsers/SeriesNfoParser.cs @@ -51,17 +51,17 @@ namespace MediaBrowser.XbmcMetadata.Parsers if (!string.IsNullOrWhiteSpace(imdbId)) { - item.SetProviderId(MetadataProviders.Imdb, imdbId); + item.SetProviderId(MetadataProvider.Imdb, imdbId); } if (!string.IsNullOrWhiteSpace(tmdbId)) { - item.SetProviderId(MetadataProviders.Tmdb, tmdbId); + item.SetProviderId(MetadataProvider.Tmdb, tmdbId); } if (!string.IsNullOrWhiteSpace(tvdbId)) { - item.SetProviderId(MetadataProviders.Tvdb, tvdbId); + item.SetProviderId(MetadataProvider.Tvdb, tvdbId); } break; diff --git a/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs b/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs index 90e8b4b99..f78034455 100644 --- a/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs +++ b/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs @@ -543,15 +543,15 @@ namespace MediaBrowser.XbmcMetadata.Savers writer.WriteElementString("aspectratio", hasAspectRatio.AspectRatio); } - var tmdbCollection = item.GetProviderId(MetadataProviders.TmdbCollection); + var tmdbCollection = item.GetProviderId(MetadataProvider.TmdbCollection); if (!string.IsNullOrEmpty(tmdbCollection)) { writer.WriteElementString("collectionnumber", tmdbCollection); - writtenProviderIds.Add(MetadataProviders.TmdbCollection.ToString()); + writtenProviderIds.Add(MetadataProvider.TmdbCollection.ToString()); } - var imdb = item.GetProviderId(MetadataProviders.Imdb); + var imdb = item.GetProviderId(MetadataProvider.Imdb); if (!string.IsNullOrEmpty(imdb)) { if (item is Series) @@ -563,25 +563,25 @@ namespace MediaBrowser.XbmcMetadata.Savers writer.WriteElementString("imdbid", imdb); } - writtenProviderIds.Add(MetadataProviders.Imdb.ToString()); + writtenProviderIds.Add(MetadataProvider.Imdb.ToString()); } // Series xml saver already saves this if (!(item is Series)) { - var tvdb = item.GetProviderId(MetadataProviders.Tvdb); + var tvdb = item.GetProviderId(MetadataProvider.Tvdb); if (!string.IsNullOrEmpty(tvdb)) { writer.WriteElementString("tvdbid", tvdb); - writtenProviderIds.Add(MetadataProviders.Tvdb.ToString()); + writtenProviderIds.Add(MetadataProvider.Tvdb.ToString()); } } - var tmdb = item.GetProviderId(MetadataProviders.Tmdb); + var tmdb = item.GetProviderId(MetadataProvider.Tmdb); if (!string.IsNullOrEmpty(tmdb)) { writer.WriteElementString("tmdbid", tmdb); - writtenProviderIds.Add(MetadataProviders.Tmdb.ToString()); + writtenProviderIds.Add(MetadataProvider.Tmdb.ToString()); } if (!string.IsNullOrEmpty(item.PreferredMetadataLanguage)) @@ -686,67 +686,67 @@ namespace MediaBrowser.XbmcMetadata.Savers } } - var externalId = item.GetProviderId(MetadataProviders.AudioDbArtist); + var externalId = item.GetProviderId(MetadataProvider.AudioDbArtist); if (!string.IsNullOrEmpty(externalId)) { writer.WriteElementString("audiodbartistid", externalId); - writtenProviderIds.Add(MetadataProviders.AudioDbArtist.ToString()); + writtenProviderIds.Add(MetadataProvider.AudioDbArtist.ToString()); } - externalId = item.GetProviderId(MetadataProviders.AudioDbAlbum); + externalId = item.GetProviderId(MetadataProvider.AudioDbAlbum); if (!string.IsNullOrEmpty(externalId)) { writer.WriteElementString("audiodbalbumid", externalId); - writtenProviderIds.Add(MetadataProviders.AudioDbAlbum.ToString()); + writtenProviderIds.Add(MetadataProvider.AudioDbAlbum.ToString()); } - externalId = item.GetProviderId(MetadataProviders.Zap2It); + externalId = item.GetProviderId(MetadataProvider.Zap2It); if (!string.IsNullOrEmpty(externalId)) { writer.WriteElementString("zap2itid", externalId); - writtenProviderIds.Add(MetadataProviders.Zap2It.ToString()); + writtenProviderIds.Add(MetadataProvider.Zap2It.ToString()); } - externalId = item.GetProviderId(MetadataProviders.MusicBrainzAlbum); + externalId = item.GetProviderId(MetadataProvider.MusicBrainzAlbum); if (!string.IsNullOrEmpty(externalId)) { writer.WriteElementString("musicbrainzalbumid", externalId); - writtenProviderIds.Add(MetadataProviders.MusicBrainzAlbum.ToString()); + writtenProviderIds.Add(MetadataProvider.MusicBrainzAlbum.ToString()); } - externalId = item.GetProviderId(MetadataProviders.MusicBrainzAlbumArtist); + externalId = item.GetProviderId(MetadataProvider.MusicBrainzAlbumArtist); if (!string.IsNullOrEmpty(externalId)) { writer.WriteElementString("musicbrainzalbumartistid", externalId); - writtenProviderIds.Add(MetadataProviders.MusicBrainzAlbumArtist.ToString()); + writtenProviderIds.Add(MetadataProvider.MusicBrainzAlbumArtist.ToString()); } - externalId = item.GetProviderId(MetadataProviders.MusicBrainzArtist); + externalId = item.GetProviderId(MetadataProvider.MusicBrainzArtist); if (!string.IsNullOrEmpty(externalId)) { writer.WriteElementString("musicbrainzartistid", externalId); - writtenProviderIds.Add(MetadataProviders.MusicBrainzArtist.ToString()); + writtenProviderIds.Add(MetadataProvider.MusicBrainzArtist.ToString()); } - externalId = item.GetProviderId(MetadataProviders.MusicBrainzReleaseGroup); + externalId = item.GetProviderId(MetadataProvider.MusicBrainzReleaseGroup); if (!string.IsNullOrEmpty(externalId)) { writer.WriteElementString("musicbrainzreleasegroupid", externalId); - writtenProviderIds.Add(MetadataProviders.MusicBrainzReleaseGroup.ToString()); + writtenProviderIds.Add(MetadataProvider.MusicBrainzReleaseGroup.ToString()); } - externalId = item.GetProviderId(MetadataProviders.TvRage); + externalId = item.GetProviderId(MetadataProvider.TvRage); if (!string.IsNullOrEmpty(externalId)) { writer.WriteElementString("tvrageid", externalId); - writtenProviderIds.Add(MetadataProviders.TvRage.ToString()); + writtenProviderIds.Add(MetadataProvider.TvRage.ToString()); } if (item.ProviderIds != null) diff --git a/MediaBrowser.XbmcMetadata/Savers/MovieNfoSaver.cs b/MediaBrowser.XbmcMetadata/Savers/MovieNfoSaver.cs index eef989a5b..dca796415 100644 --- a/MediaBrowser.XbmcMetadata/Savers/MovieNfoSaver.cs +++ b/MediaBrowser.XbmcMetadata/Savers/MovieNfoSaver.cs @@ -93,7 +93,7 @@ namespace MediaBrowser.XbmcMetadata.Savers /// protected override void WriteCustomElements(BaseItem item, XmlWriter writer) { - var imdb = item.GetProviderId(MetadataProviders.Imdb); + var imdb = item.GetProviderId(MetadataProvider.Imdb); if (!string.IsNullOrEmpty(imdb)) { diff --git a/MediaBrowser.XbmcMetadata/Savers/SeriesNfoSaver.cs b/MediaBrowser.XbmcMetadata/Savers/SeriesNfoSaver.cs index 2a5d36d40..42285db76 100644 --- a/MediaBrowser.XbmcMetadata/Savers/SeriesNfoSaver.cs +++ b/MediaBrowser.XbmcMetadata/Savers/SeriesNfoSaver.cs @@ -54,7 +54,7 @@ namespace MediaBrowser.XbmcMetadata.Savers { var series = (Series)item; - var tvdb = item.GetProviderId(MetadataProviders.Tvdb); + var tvdb = item.GetProviderId(MetadataProvider.Tvdb); if (!string.IsNullOrEmpty(tvdb)) { -- cgit v1.2.3 From 98142613e8cd8266130847210fb6bfadc1ae11bd Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Sun, 7 Jun 2020 13:36:43 -0400 Subject: Apply review suggestions and fix bug --- Jellyfin.Data/Entities/User.cs | 5 +---- .../Users/UserManager.cs | 26 ++++------------------ MediaBrowser.Controller/Entities/Folder.cs | 7 +++--- 3 files changed, 9 insertions(+), 29 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Jellyfin.Data/Entities/User.cs b/Jellyfin.Data/Entities/User.cs index f09b36bde..cd6cad992 100644 --- a/Jellyfin.Data/Entities/User.cs +++ b/Jellyfin.Data/Entities/User.cs @@ -420,10 +420,7 @@ namespace Jellyfin.Data.Entities /// A string array containing the user's preferences. public string[] GetPreference(PreferenceKind preference) { - var val = Preferences - .Where(p => p.Kind == preference) - .Select(p => p.Value) - .First(); + var val = Preferences.First(p => p.Kind == preference).Value; return Equals(val, string.Empty) ? Array.Empty() : val.Split(Delimiter); } diff --git a/Jellyfin.Server.Implementations/Users/UserManager.cs b/Jellyfin.Server.Implementations/Users/UserManager.cs index 91d0e5b80..01151e65e 100644 --- a/Jellyfin.Server.Implementations/Users/UserManager.cs +++ b/Jellyfin.Server.Implementations/Users/UserManager.cs @@ -84,24 +84,10 @@ namespace Jellyfin.Server.Implementations.Users public event EventHandler> OnUserLockedOut; /// - public IEnumerable Users - { - get - { - var dbContext = _dbProvider.CreateContext(); - return dbContext.Users; - } - } + public IEnumerable Users => _dbProvider.CreateContext().Users; /// - public IEnumerable UsersIds - { - get - { - var dbContext = _dbProvider.CreateContext(); - return dbContext.Users.Select(u => u.Id); - } - } + public IEnumerable UsersIds => _dbProvider.CreateContext().Users.Select(u => u.Id); /// public User GetUserById(Guid id) @@ -111,9 +97,7 @@ namespace Jellyfin.Server.Implementations.Users throw new ArgumentException("Guid can't be empty", nameof(id)); } - var dbContext = _dbProvider.CreateContext(); - - return dbContext.Users.Find(id); + return _dbProvider.CreateContext().Users.Find(id); } /// @@ -124,11 +108,9 @@ namespace Jellyfin.Server.Implementations.Users throw new ArgumentException("Invalid username", nameof(name)); } - var dbContext = _dbProvider.CreateContext(); - // This can't use an overload with StringComparer because that would cause the query to // have to be evaluated client-side. - return dbContext.Users.FirstOrDefault(u => string.Equals(u.Username, name)); + return _dbProvider.CreateContext().Users.FirstOrDefault(u => string.Equals(u.Username, name)); } /// diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index 2f9bc38df..4af74f9cd 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -182,12 +182,13 @@ namespace MediaBrowser.Controller.Entities { if (this is ICollectionFolder && !(this is BasePluginFolder)) { - if (user.GetPreference(PreferenceKind.BlockedMediaFolders) != null) + var blockedMediaFolders = user.GetPreference(PreferenceKind.BlockedMediaFolders); + if (blockedMediaFolders.Length > 0) { - if (user.GetPreference(PreferenceKind.BlockedMediaFolders).Contains(Id.ToString("N", CultureInfo.InvariantCulture), StringComparer.OrdinalIgnoreCase) || + if (blockedMediaFolders.Contains(Id.ToString("N", CultureInfo.InvariantCulture), StringComparer.OrdinalIgnoreCase) || // Backwards compatibility - user.GetPreference(PreferenceKind.BlockedMediaFolders).Contains(Name, StringComparer.OrdinalIgnoreCase)) + blockedMediaFolders.Contains(Name, StringComparer.OrdinalIgnoreCase)) { return false; } -- cgit v1.2.3 From 68e1ecaaf9626c9596c833571bb591a326449dc8 Mon Sep 17 00:00:00 2001 From: crobibero Date: Sun, 7 Jun 2020 14:47:08 -0600 Subject: Remove EasyPassword from Authentication providers --- .../Users/DefaultAuthenticationProvider.cs | 24 ---------------------- .../Users/InvalidAuthProvider.cs | 12 ----------- .../Authentication/IAuthenticationProvider.cs | 2 -- 3 files changed, 38 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Jellyfin.Server.Implementations/Users/DefaultAuthenticationProvider.cs b/Jellyfin.Server.Implementations/Users/DefaultAuthenticationProvider.cs index b0c02030e..9c5056a6b 100644 --- a/Jellyfin.Server.Implementations/Users/DefaultAuthenticationProvider.cs +++ b/Jellyfin.Server.Implementations/Users/DefaultAuthenticationProvider.cs @@ -111,29 +111,5 @@ namespace Jellyfin.Server.Implementations.Users return Task.CompletedTask; } - - /// - public void ChangeEasyPassword(User user, string newPassword, string newPasswordHash) - { - if (newPassword != null) - { - newPasswordHash = _cryptographyProvider.CreatePasswordHash(newPassword).ToString(); - } - - if (string.IsNullOrWhiteSpace(newPasswordHash)) - { - throw new ArgumentNullException(nameof(newPasswordHash)); - } - - user.EasyPassword = newPasswordHash; - } - - /// - public string GetEasyPasswordHash(User user) - { - return string.IsNullOrEmpty(user.EasyPassword) - ? null - : Hex.Encode(PasswordHash.Parse(user.EasyPassword).Hash); - } } } diff --git a/Jellyfin.Server.Implementations/Users/InvalidAuthProvider.cs b/Jellyfin.Server.Implementations/Users/InvalidAuthProvider.cs index b6e65b559..8ad2fecdb 100644 --- a/Jellyfin.Server.Implementations/Users/InvalidAuthProvider.cs +++ b/Jellyfin.Server.Implementations/Users/InvalidAuthProvider.cs @@ -32,17 +32,5 @@ namespace Jellyfin.Server.Implementations.Users { return Task.CompletedTask; } - - /// - public void ChangeEasyPassword(User user, string newPassword, string newPasswordHash) - { - // Nothing here - } - - /// - public string GetEasyPasswordHash(User user) - { - return string.Empty; - } } } diff --git a/MediaBrowser.Controller/Authentication/IAuthenticationProvider.cs b/MediaBrowser.Controller/Authentication/IAuthenticationProvider.cs index c0324a384..da812f551 100644 --- a/MediaBrowser.Controller/Authentication/IAuthenticationProvider.cs +++ b/MediaBrowser.Controller/Authentication/IAuthenticationProvider.cs @@ -11,8 +11,6 @@ namespace MediaBrowser.Controller.Authentication Task Authenticate(string username, string password); bool HasPassword(User user); Task ChangePassword(User user, string newPassword); - void ChangeEasyPassword(User user, string newPassword, string newPasswordHash); - string GetEasyPasswordHash(User user); } public interface IRequiresResolvedUser -- cgit v1.2.3 From 7ed5cf3dcac8d2b63bfbb9c898d7e214e397fc16 Mon Sep 17 00:00:00 2001 From: crobibero Date: Sun, 7 Jun 2020 20:32:06 -0600 Subject: Force configuration paths to not be ignored. --- Emby.Server.Implementations/Library/LibraryManager.cs | 15 +++++++++------ MediaBrowser.Controller/Library/ILibraryManager.cs | 10 +++++++--- 2 files changed, 16 insertions(+), 9 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index 677030b82..7951a7cfb 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -510,8 +510,8 @@ namespace Emby.Server.Implementations.Library return key.GetMD5(); } - public BaseItem ResolvePath(FileSystemMetadata fileInfo, Folder parent = null) - => ResolvePath(fileInfo, new DirectoryService(_fileSystem), null, parent); + public BaseItem ResolvePath(FileSystemMetadata fileInfo, Folder parent = null, bool allowIgnorePath = true) + => ResolvePath(fileInfo, new DirectoryService(_fileSystem), null, parent, allowIgnorePath: allowIgnorePath); private BaseItem ResolvePath( FileSystemMetadata fileInfo, @@ -519,7 +519,8 @@ namespace Emby.Server.Implementations.Library IItemResolver[] resolvers, Folder parent = null, string collectionType = null, - LibraryOptions libraryOptions = null) + LibraryOptions libraryOptions = null, + bool allowIgnorePath = true) { if (fileInfo == null) { @@ -543,7 +544,7 @@ namespace Emby.Server.Implementations.Library }; // Return null if ignore rules deem that we should do so - if (IgnoreFile(args.FileInfo, args.Parent)) + if (allowIgnorePath && IgnoreFile(args.FileInfo, args.Parent)) { return null; } @@ -707,7 +708,9 @@ namespace Emby.Server.Implementations.Library Directory.CreateDirectory(rootFolderPath); - var rootFolder = GetItemById(GetNewItemId(rootFolderPath, typeof(AggregateFolder))) as AggregateFolder ?? ((Folder)ResolvePath(_fileSystem.GetDirectoryInfo(rootFolderPath))).DeepCopy(); + var rootFolder = GetItemById(GetNewItemId(rootFolderPath, typeof(AggregateFolder))) as AggregateFolder ?? + ((Folder) ResolvePath(_fileSystem.GetDirectoryInfo(rootFolderPath), allowIgnorePath: false)) + .DeepCopy(); // In case program data folder was moved if (!string.Equals(rootFolder.Path, rootFolderPath, StringComparison.Ordinal)) @@ -788,7 +791,7 @@ namespace Emby.Server.Implementations.Library if (tmpItem == null) { _logger.LogDebug("Creating new userRootFolder with DeepCopy"); - tmpItem = ((Folder)ResolvePath(_fileSystem.GetDirectoryInfo(userRootPath))).DeepCopy(); + tmpItem = ((Folder)ResolvePath(_fileSystem.GetDirectoryInfo(userRootPath), allowIgnorePath: false)).DeepCopy(); } // In case program data folder was moved diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs index 916e4fda7..5afe356f4 100644 --- a/MediaBrowser.Controller/Library/ILibraryManager.cs +++ b/MediaBrowser.Controller/Library/ILibraryManager.cs @@ -27,14 +27,18 @@ namespace MediaBrowser.Controller.Library /// /// The file information. /// The parent. + /// Allow the path to be ignored. /// BaseItem. - BaseItem ResolvePath(FileSystemMetadata fileInfo, - Folder parent = null); + BaseItem ResolvePath( + FileSystemMetadata fileInfo, + Folder parent = null, + bool allowIgnorePath = true); /// /// Resolves a set of files into a list of BaseItem /// - IEnumerable ResolvePaths(IEnumerable files, + IEnumerable ResolvePaths( + IEnumerable files, IDirectoryService directoryService, Folder parent, LibraryOptions libraryOptions, -- cgit v1.2.3 From 347689e4e23e159ba0c2310cc799dc0a572dcc1d Mon Sep 17 00:00:00 2001 From: artiume Date: Fri, 29 May 2020 09:49:15 -0400 Subject: Split VP9 HEVC 10bit button. MacOS Decoder fixed to opencl --- .../MediaEncoding/EncodingHelper.cs | 51 +++++++++++++--------- 1 file changed, 31 insertions(+), 20 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 4406c17a8..b7a78552d 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -2579,7 +2579,7 @@ namespace MediaBrowser.Controller.MediaEncoding if (_mediaEncoder.SupportsDecoder("hevc_qsv") && encodingOptions.HardwareDecodingCodecs.Contains("hevc", StringComparer.OrdinalIgnoreCase)) { return (isColorDepth10 && - !encodingOptions.EnableDecodingColorDepth10) ? null : "-c:v hevc_qsv"; + !encodingOptions.EnableDecodingColorDepth10Hevc) ? null : "-c:v hevc_qsv"; } break; case "mpeg2video": @@ -2604,7 +2604,7 @@ namespace MediaBrowser.Controller.MediaEncoding if (_mediaEncoder.SupportsDecoder("vp9_qsv") && encodingOptions.HardwareDecodingCodecs.Contains("vp9", StringComparer.OrdinalIgnoreCase)) { return (isColorDepth10 && - !encodingOptions.EnableDecodingColorDepth10) ? null : "-c:v vp9_qsv"; + !encodingOptions.EnableDecodingColorDepth10Vp9) ? null : "-c:v vp9_qsv"; } break; } @@ -2617,8 +2617,7 @@ namespace MediaBrowser.Controller.MediaEncoding case "h264": if (_mediaEncoder.SupportsDecoder("h264_cuvid") && encodingOptions.HardwareDecodingCodecs.Contains("h264", StringComparer.OrdinalIgnoreCase)) { - return (isColorDepth10 && - !encodingOptions.EnableDecodingColorDepth10) ? null : "-c:v h264_cuvid"; + return "-c:v h264_cuvid"; } break; case "hevc": @@ -2626,7 +2625,7 @@ namespace MediaBrowser.Controller.MediaEncoding if (_mediaEncoder.SupportsDecoder("hevc_cuvid") && encodingOptions.HardwareDecodingCodecs.Contains("hevc", StringComparer.OrdinalIgnoreCase)) { return (isColorDepth10 && - !encodingOptions.EnableDecodingColorDepth10) ? null : "-c:v hevc_cuvid"; + !encodingOptions.EnableDecodingColorDepth10Hevc) ? null : "-c:v hevc_cuvid"; } break; case "mpeg2video": @@ -2657,7 +2656,7 @@ namespace MediaBrowser.Controller.MediaEncoding if (_mediaEncoder.SupportsDecoder("vp9_cuvid") && encodingOptions.HardwareDecodingCodecs.Contains("vp9", StringComparer.OrdinalIgnoreCase)) { return (isColorDepth10 && - !encodingOptions.EnableDecodingColorDepth10) ? null : "-c:v vp9_cuvid"; + !encodingOptions.EnableDecodingColorDepth10Vp9) ? null : "-c:v vp9_cuvid"; } break; } @@ -2678,7 +2677,7 @@ namespace MediaBrowser.Controller.MediaEncoding if (_mediaEncoder.SupportsDecoder("hevc_mediacodec") && encodingOptions.HardwareDecodingCodecs.Contains("hevc", StringComparer.OrdinalIgnoreCase)) { return (isColorDepth10 && - !encodingOptions.EnableDecodingColorDepth10) ? null : "-c:v hevc_mediacodec"; + !encodingOptions.EnableDecodingColorDepth10Hevc) ? null : "-c:v hevc_mediacodec"; } break; case "mpeg2video": @@ -2703,7 +2702,7 @@ namespace MediaBrowser.Controller.MediaEncoding if (_mediaEncoder.SupportsDecoder("vp9_mediacodec") && encodingOptions.HardwareDecodingCodecs.Contains("vp9", StringComparer.OrdinalIgnoreCase)) { return (isColorDepth10 && - !encodingOptions.EnableDecodingColorDepth10) ? null : "-c:v vp9_mediacodec"; + !encodingOptions.EnableDecodingColorDepth10Vp9) ? null : "-c:v vp9_mediacodec"; } break; } @@ -2749,7 +2748,7 @@ namespace MediaBrowser.Controller.MediaEncoding case "hevc": case "h265": return (isColorDepth10 && - !encodingOptions.EnableDecodingColorDepth10) ? null : GetHwaccelType(state, encodingOptions, "hevc"); + !encodingOptions.EnableDecodingColorDepth10Hevc) ? null : GetHwaccelType(state, encodingOptions, "hevc"); case "mpeg2video": return GetHwaccelType(state, encodingOptions, "mpeg2video"); case "vc1": @@ -2758,7 +2757,7 @@ namespace MediaBrowser.Controller.MediaEncoding return GetHwaccelType(state, encodingOptions, "mpeg4"); case "vp9": return (isColorDepth10 && - !encodingOptions.EnableDecodingColorDepth10) ? null : GetHwaccelType(state, encodingOptions, "vp9"); + !encodingOptions.EnableDecodingColorDepth10Vp9) ? null : GetHwaccelType(state, encodingOptions, "vp9"); } } else if (string.Equals(encodingOptions.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase)) @@ -2771,7 +2770,7 @@ namespace MediaBrowser.Controller.MediaEncoding case "hevc": case "h265": return (isColorDepth10 && - !encodingOptions.EnableDecodingColorDepth10) ? null : GetHwaccelType(state, encodingOptions, "hevc"); + !encodingOptions.EnableDecodingColorDepth10Hevc) ? null : GetHwaccelType(state, encodingOptions, "hevc"); case "mpeg2video": return GetHwaccelType(state, encodingOptions, "mpeg2video"); case "vc1": @@ -2780,7 +2779,7 @@ namespace MediaBrowser.Controller.MediaEncoding return GetHwaccelType(state, encodingOptions, "vp8"); case "vp9": return (isColorDepth10 && - !encodingOptions.EnableDecodingColorDepth10) ? null : GetHwaccelType(state, encodingOptions, "vp9"); + !encodingOptions.EnableDecodingColorDepth10Vp9) ? null : GetHwaccelType(state, encodingOptions, "vp9"); } } else if (string.Equals(encodingOptions.HardwareAccelerationType, "videotoolbox", StringComparison.OrdinalIgnoreCase)) @@ -2789,27 +2788,39 @@ namespace MediaBrowser.Controller.MediaEncoding { case "avc": case "h264": - if (_mediaEncoder.SupportsDecoder("h264_videotoolbox") && encodingOptions.HardwareDecodingCodecs.Contains("h264", StringComparer.OrdinalIgnoreCase)) + if (_mediaEncoder.SupportsDecoder("h264_opencl") && encodingOptions.HardwareDecodingCodecs.Contains("h264", StringComparer.OrdinalIgnoreCase)) { - return "-c:v h264_videotoolbox"; + return "-c:v h264_opencl"; } break; case "mpeg2video": - if (_mediaEncoder.SupportsDecoder("mpeg2_videotoolbox") && encodingOptions.HardwareDecodingCodecs.Contains("mpeg2video", StringComparer.OrdinalIgnoreCase)) + if (_mediaEncoder.SupportsDecoder("mpeg2_opencl") && encodingOptions.HardwareDecodingCodecs.Contains("mpeg2video", StringComparer.OrdinalIgnoreCase)) { - return "-c:v mpeg2_videotoolbox"; + return "-c:v mpeg2_opencl"; } break; case "mpeg4": - if (_mediaEncoder.SupportsDecoder("mpeg4_videotoolbox") && encodingOptions.HardwareDecodingCodecs.Contains("mpeg4", StringComparer.OrdinalIgnoreCase)) + if (_mediaEncoder.SupportsDecoder("mpeg4_opencl") && encodingOptions.HardwareDecodingCodecs.Contains("mpeg4", StringComparer.OrdinalIgnoreCase)) { - return "-c:v mpeg4_videotoolbox"; + return "-c:v mpeg4_opencl"; } break; case "vc1": - if (_mediaEncoder.SupportsDecoder("vc1_videotoolbox") && encodingOptions.HardwareDecodingCodecs.Contains("vc1", StringComparer.OrdinalIgnoreCase)) + if (_mediaEncoder.SupportsDecoder("vc1_opencl") && encodingOptions.HardwareDecodingCodecs.Contains("vc1", StringComparer.OrdinalIgnoreCase)) + { + return "-c:v vc1_opencl"; + } + break; + case "vp8": + if (_mediaEncoder.SupportsDecoder("vp8_opencl") && encodingOptions.HardwareDecodingCodecs.Contains("vc1", StringComparer.OrdinalIgnoreCase)) + { + return "-c:v vp8_opencl"; + } + break; + case "vp9": + if (_mediaEncoder.SupportsDecoder("vp9_opencl") && encodingOptions.HardwareDecodingCodecs.Contains("vc1", StringComparer.OrdinalIgnoreCase)) { - return "-c:v vc1_videotoolbox"; + return "-c:v vp9_opencl; } break; } -- cgit v1.2.3 From d6504404923c3f46b9a732e684290f5372e5d732 Mon Sep 17 00:00:00 2001 From: artiume Date: Fri, 29 May 2020 09:54:31 -0400 Subject: fix opencl10bit --- MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index b7a78552d..83210c145 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -2793,6 +2793,14 @@ namespace MediaBrowser.Controller.MediaEncoding return "-c:v h264_opencl"; } break; + case "hevc": + case "h265": + if (_mediaEncoder.SupportsDecoder("hevc_opencl") && encodingOptions.HardwareDecodingCodecs.Contains("h264", StringComparer.OrdinalIgnoreCase)) + { + return (isColorDepth10 && + !encodingOptions.EnableDecodingColorDepth10Hevc) ? null : "-c:v hevc_opencl"; + } + break; case "mpeg2video": if (_mediaEncoder.SupportsDecoder("mpeg2_opencl") && encodingOptions.HardwareDecodingCodecs.Contains("mpeg2video", StringComparer.OrdinalIgnoreCase)) { @@ -2820,7 +2828,8 @@ namespace MediaBrowser.Controller.MediaEncoding case "vp9": if (_mediaEncoder.SupportsDecoder("vp9_opencl") && encodingOptions.HardwareDecodingCodecs.Contains("vc1", StringComparer.OrdinalIgnoreCase)) { - return "-c:v vp9_opencl; + return (isColorDepth10 && + !encodingOptions.EnableDecodingColorDepth10Vp9) ? null : "-c:v vp9_opencl"; } break; } -- cgit v1.2.3 From d105bc728d0ca44b601b311eca493c1171fa71fa Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Tue, 9 Jun 2020 14:01:21 -0400 Subject: Fix startup wizard. --- Jellyfin.Api/Controllers/StartupController.cs | 4 ++- .../Users/UserManager.cs | 33 ++++++++++++++++++++++ MediaBrowser.Controller/Library/IUserManager.cs | 5 ++++ 3 files changed, 41 insertions(+), 1 deletion(-) (limited to 'MediaBrowser.Controller') diff --git a/Jellyfin.Api/Controllers/StartupController.cs b/Jellyfin.Api/Controllers/StartupController.cs index f965d83f3..6ec0a4e26 100644 --- a/Jellyfin.Api/Controllers/StartupController.cs +++ b/Jellyfin.Api/Controllers/StartupController.cs @@ -95,6 +95,8 @@ namespace Jellyfin.Api.Controllers [HttpGet("User")] public StartupUserDto GetFirstUser() { + // TODO: Remove this method when startup wizard no longer requires an existing user. + _userManager.Initialize(); var user = _userManager.Users.First(); return new StartupUserDto { @@ -115,7 +117,7 @@ namespace Jellyfin.Api.Controllers user.Username = startupUserDto.Name; - _userManager.UpdateUser(user); + await _userManager.UpdateUserAsync(user).ConfigureAwait(false); if (!string.IsNullOrEmpty(startupUserDto.Password)) { diff --git a/Jellyfin.Server.Implementations/Users/UserManager.cs b/Jellyfin.Server.Implementations/Users/UserManager.cs index e1084627b..0ea13f4e7 100644 --- a/Jellyfin.Server.Implementations/Users/UserManager.cs +++ b/Jellyfin.Server.Implementations/Users/UserManager.cs @@ -520,6 +520,39 @@ namespace Jellyfin.Server.Implementations.Users _defaultPasswordResetProvider = _passwordResetProviders.OfType().First(); } + /// + public void Initialize() + { + // TODO: Refactor the startup wizard so that it doesn't require a user to already exist. + var dbContext = _dbProvider.CreateContext(); + + if (dbContext.Users.Any()) + { + return; + } + + var defaultName = Environment.UserName; + if (string.IsNullOrWhiteSpace(defaultName)) + { + defaultName = "MyJellyfinUser"; + } + + _logger.LogWarning("No users, creating one with username {UserName}", defaultName); + + if (!IsValidUsername(defaultName)) + { + throw new ArgumentException("Provided username is not valid!", defaultName); + } + + var newUser = CreateUser(defaultName); + newUser.SetPermission(PermissionKind.IsAdministrator, true); + newUser.SetPermission(PermissionKind.EnableContentDeletion, true); + newUser.SetPermission(PermissionKind.EnableRemoteControlOfOtherUsers, true); + + dbContext.Users.Add(newUser); + dbContext.SaveChanges(); + } + /// public NameIdPair[] GetAuthenticationProviders() { diff --git a/MediaBrowser.Controller/Library/IUserManager.cs b/MediaBrowser.Controller/Library/IUserManager.cs index 1e385dcb9..74f117f15 100644 --- a/MediaBrowser.Controller/Library/IUserManager.cs +++ b/MediaBrowser.Controller/Library/IUserManager.cs @@ -52,6 +52,11 @@ namespace MediaBrowser.Controller.Library /// The users ids. IEnumerable UsersIds { get; } + /// + /// Initializes the user manager and ensures that a user exists. + /// + void Initialize(); + /// /// Gets a user by Id. /// -- cgit v1.2.3 From 299e49f39d5c3db2542e93364800db7a85ccfd91 Mon Sep 17 00:00:00 2001 From: aled Date: Tue, 9 Jun 2020 23:12:53 +0100 Subject: Fix a small number of compile warnings --- Emby.Photos/PhotoProvider.cs | 2 +- .../Data/SqliteItemRepository.cs | 4 ++-- MediaBrowser.Controller/Entities/BaseItem.cs | 4 ++-- .../Parsers/BaseItemXmlParser.cs | 4 ++-- MediaBrowser.Model/Dto/BaseItemDto.cs | 2 +- MediaBrowser.Model/Entities/MetadataFields.cs | 2 +- .../Books/AudioBookMetadataService.cs | 2 +- MediaBrowser.Providers/Books/BookMetadataService.cs | 2 +- .../BoxSets/BoxSetMetadataService.cs | 2 +- .../Channels/ChannelMetadataService.cs | 2 +- .../Folders/CollectionFolderMetadataService.cs | 2 +- .../Folders/FolderMetadataService.cs | 2 +- .../Folders/UserViewMetadataService.cs | 2 +- .../Genres/GenreMetadataService.cs | 2 +- .../LiveTv/ProgramMetadataService.cs | 2 +- MediaBrowser.Providers/Manager/MetadataService.cs | 14 +++++++------- MediaBrowser.Providers/Manager/ProviderUtils.cs | 20 ++++++++++---------- MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs | 6 +++--- MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs | 12 ++++++------ .../Movies/MovieMetadataService.cs | 2 +- .../Movies/TrailerMetadataService.cs | 2 +- MediaBrowser.Providers/Music/AlbumMetadataService.cs | 4 ++-- .../Music/ArtistMetadataService.cs | 2 +- MediaBrowser.Providers/Music/AudioMetadataService.cs | 2 +- .../Music/MusicVideoMetadataService.cs | 2 +- .../MusicGenres/MusicGenreMetadataService.cs | 2 +- .../People/PersonMetadataService.cs | 2 +- .../Photos/PhotoAlbumMetadataService.cs | 2 +- .../Photos/PhotoMetadataService.cs | 2 +- .../Playlists/PlaylistMetadataService.cs | 2 +- .../Studios/StudioMetadataService.cs | 2 +- MediaBrowser.Providers/TV/EpisodeMetadataService.cs | 2 +- MediaBrowser.Providers/TV/SeasonMetadataService.cs | 2 +- MediaBrowser.Providers/TV/SeriesMetadataService.cs | 2 +- MediaBrowser.Providers/Users/UserMetadataService.cs | 2 +- .../Videos/VideoMetadataService.cs | 2 +- MediaBrowser.Providers/Years/YearMetadataService.cs | 2 +- MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs | 4 ++-- 38 files changed, 65 insertions(+), 65 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Photos/PhotoProvider.cs b/Emby.Photos/PhotoProvider.cs index 987cb7fb2..96f0c1c16 100644 --- a/Emby.Photos/PhotoProvider.cs +++ b/Emby.Photos/PhotoProvider.cs @@ -104,7 +104,7 @@ namespace Emby.Photos item.Overview = image.ImageTag.Comment; if (!string.IsNullOrWhiteSpace(image.ImageTag.Title) - && !item.LockedFields.Contains(MetadataFields.Name)) + && !item.LockedFields.Contains(MetadataField.Name)) { item.Name = image.ImageTag.Title; } diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index 03581dae2..43a593f11 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -1626,11 +1626,11 @@ namespace Emby.Server.Implementations.Data { if (!reader.IsDBNull(index)) { - IEnumerable GetLockedFields(string s) + IEnumerable GetLockedFields(string s) { foreach (var i in s.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries)) { - if (Enum.TryParse(i, true, out MetadataFields parsedValue)) + if (Enum.TryParse(i, true, out MetadataField parsedValue)) { yield return parsedValue; } diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index f4b71d8bf..4402fbd3a 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -63,7 +63,7 @@ namespace MediaBrowser.Controller.Entities Genres = Array.Empty(); Studios = Array.Empty(); ProviderIds = new Dictionary(StringComparer.OrdinalIgnoreCase); - LockedFields = Array.Empty(); + LockedFields = Array.Empty(); ImageInfos = Array.Empty(); ProductionLocations = Array.Empty(); RemoteTrailers = Array.Empty(); @@ -585,7 +585,7 @@ namespace MediaBrowser.Controller.Entities /// /// The locked fields. [JsonIgnore] - public MetadataFields[] LockedFields { get; set; } + public MetadataField[] LockedFields { get; set; } /// /// Gets the type of the media. diff --git a/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs b/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs index 2e0dade07..800cdaf57 100644 --- a/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs +++ b/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs @@ -249,9 +249,9 @@ namespace MediaBrowser.LocalMetadata.Parsers { item.LockedFields = val.Split('|').Select(i => { - if (Enum.TryParse(i, true, out MetadataFields field)) + if (Enum.TryParse(i, true, out MetadataField field)) { - return (MetadataFields?)field; + return (MetadataField?)field; } return null; diff --git a/MediaBrowser.Model/Dto/BaseItemDto.cs b/MediaBrowser.Model/Dto/BaseItemDto.cs index c84c51efb..c7f8f0584 100644 --- a/MediaBrowser.Model/Dto/BaseItemDto.cs +++ b/MediaBrowser.Model/Dto/BaseItemDto.cs @@ -582,7 +582,7 @@ namespace MediaBrowser.Model.Dto /// Gets or sets the locked fields. /// /// The locked fields. - public MetadataFields[] LockedFields { get; set; } + public MetadataField[] LockedFields { get; set; } /// /// Gets or sets the trailer count. diff --git a/MediaBrowser.Model/Entities/MetadataFields.cs b/MediaBrowser.Model/Entities/MetadataFields.cs index d64d4f4da..2cc6c8e33 100644 --- a/MediaBrowser.Model/Entities/MetadataFields.cs +++ b/MediaBrowser.Model/Entities/MetadataFields.cs @@ -3,7 +3,7 @@ namespace MediaBrowser.Model.Entities /// /// Enum MetadataFields. /// - public enum MetadataFields + public enum MetadataField { /// /// The cast. diff --git a/MediaBrowser.Providers/Books/AudioBookMetadataService.cs b/MediaBrowser.Providers/Books/AudioBookMetadataService.cs index 8eaeeea08..4ff42429e 100644 --- a/MediaBrowser.Providers/Books/AudioBookMetadataService.cs +++ b/MediaBrowser.Providers/Books/AudioBookMetadataService.cs @@ -25,7 +25,7 @@ namespace MediaBrowser.Providers.Books protected override void MergeData( MetadataResult source, MetadataResult target, - MetadataFields[] lockedFields, + MetadataField[] lockedFields, bool replaceData, bool mergeMetadataSettings) { diff --git a/MediaBrowser.Providers/Books/BookMetadataService.cs b/MediaBrowser.Providers/Books/BookMetadataService.cs index 340641711..dcdf36f92 100644 --- a/MediaBrowser.Providers/Books/BookMetadataService.cs +++ b/MediaBrowser.Providers/Books/BookMetadataService.cs @@ -22,7 +22,7 @@ namespace MediaBrowser.Providers.Books } /// - protected override void MergeData(MetadataResult source, MetadataResult target, MetadataFields[] lockedFields, bool replaceData, bool mergeMetadataSettings) + protected override void MergeData(MetadataResult source, MetadataResult target, MetadataField[] lockedFields, bool replaceData, bool mergeMetadataSettings) { ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings); diff --git a/MediaBrowser.Providers/BoxSets/BoxSetMetadataService.cs b/MediaBrowser.Providers/BoxSets/BoxSetMetadataService.cs index 3c9760ea7..46c9d6720 100644 --- a/MediaBrowser.Providers/BoxSets/BoxSetMetadataService.cs +++ b/MediaBrowser.Providers/BoxSets/BoxSetMetadataService.cs @@ -43,7 +43,7 @@ namespace MediaBrowser.Providers.BoxSets } /// - protected override void MergeData(MetadataResult source, MetadataResult target, MetadataFields[] lockedFields, bool replaceData, bool mergeMetadataSettings) + protected override void MergeData(MetadataResult source, MetadataResult target, MetadataField[] lockedFields, bool replaceData, bool mergeMetadataSettings) { ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings); diff --git a/MediaBrowser.Providers/Channels/ChannelMetadataService.cs b/MediaBrowser.Providers/Channels/ChannelMetadataService.cs index 9afa82319..b6abadc85 100644 --- a/MediaBrowser.Providers/Channels/ChannelMetadataService.cs +++ b/MediaBrowser.Providers/Channels/ChannelMetadataService.cs @@ -22,7 +22,7 @@ namespace MediaBrowser.Providers.Channels } /// - protected override void MergeData(MetadataResult source, MetadataResult target, MetadataFields[] lockedFields, bool replaceData, bool mergeMetadataSettings) + protected override void MergeData(MetadataResult source, MetadataResult target, MetadataField[] lockedFields, bool replaceData, bool mergeMetadataSettings) { ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings); } diff --git a/MediaBrowser.Providers/Folders/CollectionFolderMetadataService.cs b/MediaBrowser.Providers/Folders/CollectionFolderMetadataService.cs index 921222543..0d00db3eb 100644 --- a/MediaBrowser.Providers/Folders/CollectionFolderMetadataService.cs +++ b/MediaBrowser.Providers/Folders/CollectionFolderMetadataService.cs @@ -23,7 +23,7 @@ namespace MediaBrowser.Providers.Folders } /// - protected override void MergeData(MetadataResult source, MetadataResult target, MetadataFields[] lockedFields, bool replaceData, bool mergeMetadataSettings) + protected override void MergeData(MetadataResult source, MetadataResult target, MetadataField[] lockedFields, bool replaceData, bool mergeMetadataSettings) { ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings); } diff --git a/MediaBrowser.Providers/Folders/FolderMetadataService.cs b/MediaBrowser.Providers/Folders/FolderMetadataService.cs index b6bd2515d..be731e5c2 100644 --- a/MediaBrowser.Providers/Folders/FolderMetadataService.cs +++ b/MediaBrowser.Providers/Folders/FolderMetadataService.cs @@ -26,7 +26,7 @@ namespace MediaBrowser.Providers.Folders public override int Order => 10; /// - protected override void MergeData(MetadataResult source, MetadataResult target, MetadataFields[] lockedFields, bool replaceData, bool mergeMetadataSettings) + protected override void MergeData(MetadataResult source, MetadataResult target, MetadataField[] lockedFields, bool replaceData, bool mergeMetadataSettings) { ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings); } diff --git a/MediaBrowser.Providers/Folders/UserViewMetadataService.cs b/MediaBrowser.Providers/Folders/UserViewMetadataService.cs index 60ee81114..abb78fbc7 100644 --- a/MediaBrowser.Providers/Folders/UserViewMetadataService.cs +++ b/MediaBrowser.Providers/Folders/UserViewMetadataService.cs @@ -22,7 +22,7 @@ namespace MediaBrowser.Providers.Folders } /// - protected override void MergeData(MetadataResult source, MetadataResult target, MetadataFields[] lockedFields, bool replaceData, bool mergeMetadataSettings) + protected override void MergeData(MetadataResult source, MetadataResult target, MetadataField[] lockedFields, bool replaceData, bool mergeMetadataSettings) { ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings); } diff --git a/MediaBrowser.Providers/Genres/GenreMetadataService.cs b/MediaBrowser.Providers/Genres/GenreMetadataService.cs index f3406c1ab..461f3fa2b 100644 --- a/MediaBrowser.Providers/Genres/GenreMetadataService.cs +++ b/MediaBrowser.Providers/Genres/GenreMetadataService.cs @@ -22,7 +22,7 @@ namespace MediaBrowser.Providers.Genres } /// - protected override void MergeData(MetadataResult source, MetadataResult target, MetadataFields[] lockedFields, bool replaceData, bool mergeMetadataSettings) + protected override void MergeData(MetadataResult source, MetadataResult target, MetadataField[] lockedFields, bool replaceData, bool mergeMetadataSettings) { ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings); } diff --git a/MediaBrowser.Providers/LiveTv/ProgramMetadataService.cs b/MediaBrowser.Providers/LiveTv/ProgramMetadataService.cs index 7dd49c71a..ccf90d7ac 100644 --- a/MediaBrowser.Providers/LiveTv/ProgramMetadataService.cs +++ b/MediaBrowser.Providers/LiveTv/ProgramMetadataService.cs @@ -22,7 +22,7 @@ namespace MediaBrowser.Providers.LiveTv } /// - protected override void MergeData(MetadataResult source, MetadataResult target, MetadataFields[] lockedFields, bool replaceData, bool mergeMetadataSettings) + protected override void MergeData(MetadataResult source, MetadataResult target, MetadataField[] lockedFields, bool replaceData, bool mergeMetadataSettings) { ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings); } diff --git a/MediaBrowser.Providers/Manager/MetadataService.cs b/MediaBrowser.Providers/Manager/MetadataService.cs index c49aa407a..04db6ef36 100644 --- a/MediaBrowser.Providers/Manager/MetadataService.cs +++ b/MediaBrowser.Providers/Manager/MetadataService.cs @@ -486,7 +486,7 @@ namespace MediaBrowser.Providers.Manager { var updateType = ItemUpdateType.None; - if (!item.LockedFields.Contains(MetadataFields.Genres)) + if (!item.LockedFields.Contains(MetadataField.Genres)) { var currentList = item.Genres; @@ -507,7 +507,7 @@ namespace MediaBrowser.Providers.Manager { var updateType = ItemUpdateType.None; - if (!item.LockedFields.Contains(MetadataFields.Studios)) + if (!item.LockedFields.Contains(MetadataField.Studios)) { var currentList = item.Studios; @@ -528,7 +528,7 @@ namespace MediaBrowser.Providers.Manager { var updateType = ItemUpdateType.None; - if (!item.LockedFields.Contains(MetadataFields.OfficialRating)) + if (!item.LockedFields.Contains(MetadataField.OfficialRating)) { if (item.UpdateRatingToItems(children)) { @@ -718,7 +718,7 @@ namespace MediaBrowser.Providers.Manager userDataList.AddRange(localItem.UserDataList); } - MergeData(localItem, temp, new MetadataFields[] { }, !options.ReplaceAllMetadata, true); + MergeData(localItem, temp, new MetadataField[] { }, !options.ReplaceAllMetadata, true); refreshResult.UpdateType = refreshResult.UpdateType | ItemUpdateType.MetadataImport; // Only one local provider allowed per item @@ -766,7 +766,7 @@ namespace MediaBrowser.Providers.Manager else { // TODO: If the new metadata from above has some blank data, this can cause old data to get filled into those empty fields - MergeData(metadata, temp, new MetadataFields[] { }, false, false); + MergeData(metadata, temp, new MetadataField[] { }, false, false); MergeData(temp, metadata, item.LockedFields, true, false); } } @@ -843,7 +843,7 @@ namespace MediaBrowser.Providers.Manager { result.Provider = provider.Name; - MergeData(result, temp, new MetadataFields[] { }, false, false); + MergeData(result, temp, new MetadataField[] { }, false, false); MergeNewData(temp.Item, id); refreshResult.UpdateType = refreshResult.UpdateType | ItemUpdateType.MetadataDownload; @@ -894,7 +894,7 @@ namespace MediaBrowser.Providers.Manager protected abstract void MergeData(MetadataResult source, MetadataResult target, - MetadataFields[] lockedFields, + MetadataField[] lockedFields, bool replaceData, bool mergeMetadataSettings); diff --git a/MediaBrowser.Providers/Manager/ProviderUtils.cs b/MediaBrowser.Providers/Manager/ProviderUtils.cs index 8d1588c4e..7f2a1410b 100644 --- a/MediaBrowser.Providers/Manager/ProviderUtils.cs +++ b/MediaBrowser.Providers/Manager/ProviderUtils.cs @@ -14,7 +14,7 @@ namespace MediaBrowser.Providers.Manager public static void MergeBaseItemData( MetadataResult sourceResult, MetadataResult targetResult, - MetadataFields[] lockedFields, + MetadataField[] lockedFields, bool replaceData, bool mergeMetadataSettings) where T : BaseItem @@ -31,7 +31,7 @@ namespace MediaBrowser.Providers.Manager throw new ArgumentNullException(nameof(target)); } - if (!lockedFields.Contains(MetadataFields.Name)) + if (!lockedFields.Contains(MetadataField.Name)) { if (replaceData || string.IsNullOrEmpty(target.Name)) { @@ -62,7 +62,7 @@ namespace MediaBrowser.Providers.Manager target.EndDate = source.EndDate; } - if (!lockedFields.Contains(MetadataFields.Genres)) + if (!lockedFields.Contains(MetadataField.Genres)) { if (replaceData || target.Genres.Length == 0) { @@ -75,7 +75,7 @@ namespace MediaBrowser.Providers.Manager target.IndexNumber = source.IndexNumber; } - if (!lockedFields.Contains(MetadataFields.OfficialRating)) + if (!lockedFields.Contains(MetadataField.OfficialRating)) { if (replaceData || string.IsNullOrEmpty(target.OfficialRating)) { @@ -93,7 +93,7 @@ namespace MediaBrowser.Providers.Manager target.Tagline = source.Tagline; } - if (!lockedFields.Contains(MetadataFields.Overview)) + if (!lockedFields.Contains(MetadataField.Overview)) { if (replaceData || string.IsNullOrEmpty(target.Overview)) { @@ -106,7 +106,7 @@ namespace MediaBrowser.Providers.Manager target.ParentIndexNumber = source.ParentIndexNumber; } - if (!lockedFields.Contains(MetadataFields.Cast)) + if (!lockedFields.Contains(MetadataField.Cast)) { if (replaceData || targetResult.People == null || targetResult.People.Count == 0) { @@ -129,7 +129,7 @@ namespace MediaBrowser.Providers.Manager target.ProductionYear = source.ProductionYear; } - if (!lockedFields.Contains(MetadataFields.Runtime)) + if (!lockedFields.Contains(MetadataField.Runtime)) { if (replaceData || !target.RunTimeTicks.HasValue) { @@ -140,7 +140,7 @@ namespace MediaBrowser.Providers.Manager } } - if (!lockedFields.Contains(MetadataFields.Studios)) + if (!lockedFields.Contains(MetadataField.Studios)) { if (replaceData || target.Studios.Length == 0) { @@ -148,7 +148,7 @@ namespace MediaBrowser.Providers.Manager } } - if (!lockedFields.Contains(MetadataFields.Tags)) + if (!lockedFields.Contains(MetadataField.Tags)) { if (replaceData || target.Tags.Length == 0) { @@ -156,7 +156,7 @@ namespace MediaBrowser.Providers.Manager } } - if (!lockedFields.Contains(MetadataFields.ProductionLocations)) + if (!lockedFields.Contains(MetadataField.ProductionLocations)) { if (replaceData || target.ProductionLocations.Length == 0) { diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs b/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs index 16d914e2d..3b6c8ff72 100644 --- a/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs +++ b/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs @@ -112,7 +112,7 @@ namespace MediaBrowser.Providers.MediaInfo audio.Name = data.Name; } - if (audio.SupportsPeople && !audio.LockedFields.Contains(MetadataFields.Cast)) + if (audio.SupportsPeople && !audio.LockedFields.Contains(MetadataField.Cast)) { var people = new List(); @@ -143,7 +143,7 @@ namespace MediaBrowser.Providers.MediaInfo audio.ProductionYear = audio.PremiereDate.Value.ToLocalTime().Year; } - if (!audio.LockedFields.Contains(MetadataFields.Genres)) + if (!audio.LockedFields.Contains(MetadataField.Genres)) { audio.Genres = Array.Empty(); @@ -153,7 +153,7 @@ namespace MediaBrowser.Providers.MediaInfo } } - if (!audio.LockedFields.Contains(MetadataFields.Studios)) + if (!audio.LockedFields.Contains(MetadataField.Studios)) { audio.SetStudios(data.Studios); } diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs index 89496622f..933cf03d6 100644 --- a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs +++ b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs @@ -368,7 +368,7 @@ namespace MediaBrowser.Providers.MediaInfo { var isFullRefresh = refreshOptions.MetadataRefreshMode == MetadataRefreshMode.FullRefresh; - if (!video.IsLocked && !video.LockedFields.Contains(MetadataFields.OfficialRating)) + if (!video.IsLocked && !video.LockedFields.Contains(MetadataField.OfficialRating)) { if (!string.IsNullOrWhiteSpace(data.OfficialRating) || isFullRefresh) { @@ -376,7 +376,7 @@ namespace MediaBrowser.Providers.MediaInfo } } - if (!video.IsLocked && !video.LockedFields.Contains(MetadataFields.Genres)) + if (!video.IsLocked && !video.LockedFields.Contains(MetadataField.Genres)) { if (video.Genres.Length == 0 || isFullRefresh) { @@ -389,7 +389,7 @@ namespace MediaBrowser.Providers.MediaInfo } } - if (!video.IsLocked && !video.LockedFields.Contains(MetadataFields.Studios)) + if (!video.IsLocked && !video.LockedFields.Contains(MetadataField.Studios)) { if (video.Studios.Length == 0 || isFullRefresh) { @@ -426,7 +426,7 @@ namespace MediaBrowser.Providers.MediaInfo } } - if (!video.IsLocked && !video.LockedFields.Contains(MetadataFields.Name)) + if (!video.IsLocked && !video.LockedFields.Contains(MetadataField.Name)) { if (!string.IsNullOrWhiteSpace(data.Name) && libraryOptions.EnableEmbeddedTitles) { @@ -444,7 +444,7 @@ namespace MediaBrowser.Providers.MediaInfo video.ProductionYear = video.PremiereDate.Value.ToLocalTime().Year; } - if (!video.IsLocked && !video.LockedFields.Contains(MetadataFields.Overview)) + if (!video.IsLocked && !video.LockedFields.Contains(MetadataField.Overview)) { if (string.IsNullOrWhiteSpace(video.Overview) || isFullRefresh) { @@ -457,7 +457,7 @@ namespace MediaBrowser.Providers.MediaInfo { var isFullRefresh = options.MetadataRefreshMode == MetadataRefreshMode.FullRefresh; - if (!video.IsLocked && !video.LockedFields.Contains(MetadataFields.Cast)) + if (!video.IsLocked && !video.LockedFields.Contains(MetadataField.Cast)) { if (isFullRefresh || _libraryManager.GetPeople(video).Count == 0) { diff --git a/MediaBrowser.Providers/Movies/MovieMetadataService.cs b/MediaBrowser.Providers/Movies/MovieMetadataService.cs index 1e2c325d9..9faba4798 100644 --- a/MediaBrowser.Providers/Movies/MovieMetadataService.cs +++ b/MediaBrowser.Providers/Movies/MovieMetadataService.cs @@ -36,7 +36,7 @@ namespace MediaBrowser.Providers.Movies } /// - protected override void MergeData(MetadataResult source, MetadataResult target, MetadataFields[] lockedFields, bool replaceData, bool mergeMetadataSettings) + protected override void MergeData(MetadataResult source, MetadataResult target, MetadataField[] lockedFields, bool replaceData, bool mergeMetadataSettings) { ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings); diff --git a/MediaBrowser.Providers/Movies/TrailerMetadataService.cs b/MediaBrowser.Providers/Movies/TrailerMetadataService.cs index 2e6f762b8..b45d2b745 100644 --- a/MediaBrowser.Providers/Movies/TrailerMetadataService.cs +++ b/MediaBrowser.Providers/Movies/TrailerMetadataService.cs @@ -36,7 +36,7 @@ namespace MediaBrowser.Providers.Movies } /// - protected override void MergeData(MetadataResult source, MetadataResult target, MetadataFields[] lockedFields, bool replaceData, bool mergeMetadataSettings) + protected override void MergeData(MetadataResult source, MetadataResult target, MetadataField[] lockedFields, bool replaceData, bool mergeMetadataSettings) { ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings); diff --git a/MediaBrowser.Providers/Music/AlbumMetadataService.cs b/MediaBrowser.Providers/Music/AlbumMetadataService.cs index ed6c01968..0c6f88c8b 100644 --- a/MediaBrowser.Providers/Music/AlbumMetadataService.cs +++ b/MediaBrowser.Providers/Music/AlbumMetadataService.cs @@ -45,7 +45,7 @@ namespace MediaBrowser.Providers.Music if (isFullRefresh || currentUpdateType > ItemUpdateType.None) { - if (!item.LockedFields.Contains(MetadataFields.Name)) + if (!item.LockedFields.Contains(MetadataField.Name)) { var name = children.Select(i => i.Album).FirstOrDefault(i => !string.IsNullOrEmpty(i)); @@ -108,7 +108,7 @@ namespace MediaBrowser.Providers.Music protected override void MergeData( MetadataResult source, MetadataResult target, - MetadataFields[] lockedFields, + MetadataField[] lockedFields, bool replaceData, bool mergeMetadataSettings) { diff --git a/MediaBrowser.Providers/Music/ArtistMetadataService.cs b/MediaBrowser.Providers/Music/ArtistMetadataService.cs index 5a30260a5..4199c08c6 100644 --- a/MediaBrowser.Providers/Music/ArtistMetadataService.cs +++ b/MediaBrowser.Providers/Music/ArtistMetadataService.cs @@ -39,7 +39,7 @@ namespace MediaBrowser.Providers.Music } /// - protected override void MergeData(MetadataResult source, MetadataResult target, MetadataFields[] lockedFields, bool replaceData, bool mergeMetadataSettings) + protected override void MergeData(MetadataResult source, MetadataResult target, MetadataField[] lockedFields, bool replaceData, bool mergeMetadataSettings) { ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings); } diff --git a/MediaBrowser.Providers/Music/AudioMetadataService.cs b/MediaBrowser.Providers/Music/AudioMetadataService.cs index e726fa1e2..251cbbbec 100644 --- a/MediaBrowser.Providers/Music/AudioMetadataService.cs +++ b/MediaBrowser.Providers/Music/AudioMetadataService.cs @@ -22,7 +22,7 @@ namespace MediaBrowser.Providers.Music } /// - protected override void MergeData(MetadataResult [ForeignKey("LibraryRoot_Id")] public virtual LibraryRoot LibraryRoot { get; set; } - } } diff --git a/Jellyfin.Data/Entities/LibraryRoot.cs b/Jellyfin.Data/Entities/LibraryRoot.cs index bbc23e1c9..7823db02a 100644 --- a/Jellyfin.Data/Entities/LibraryRoot.cs +++ b/Jellyfin.Data/Entities/LibraryRoot.cs @@ -186,7 +186,6 @@ namespace Jellyfin.Data.Entities /// [ForeignKey("Library_Id")] public virtual Library Library { get; set; } - } } diff --git a/Jellyfin.Data/Entities/MediaFile.cs b/Jellyfin.Data/Entities/MediaFile.cs index 719539e5c..94c39a28a 100644 --- a/Jellyfin.Data/Entities/MediaFile.cs +++ b/Jellyfin.Data/Entities/MediaFile.cs @@ -194,7 +194,6 @@ namespace Jellyfin.Data.Entities [ForeignKey("MediaFileStream_MediaFileStreams_Id")] public virtual ICollection MediaFileStreams { get; protected set; } - } } diff --git a/Jellyfin.Data/Entities/MediaFileStream.cs b/Jellyfin.Data/Entities/MediaFileStream.cs index 7b3399731..723977fdf 100644 --- a/Jellyfin.Data/Entities/MediaFileStream.cs +++ b/Jellyfin.Data/Entities/MediaFileStream.cs @@ -143,7 +143,6 @@ namespace Jellyfin.Data.Entities /************************************************************************* * Navigation properties *************************************************************************/ - } } diff --git a/Jellyfin.Data/Entities/Metadata.cs b/Jellyfin.Data/Entities/Metadata.cs index 467ee6822..6558642cf 100644 --- a/Jellyfin.Data/Entities/Metadata.cs +++ b/Jellyfin.Data/Entities/Metadata.cs @@ -374,7 +374,6 @@ namespace Jellyfin.Data.Entities [ForeignKey("PersonRole_PersonRoles_Id")] public virtual ICollection Sources { get; protected set; } - } } diff --git a/Jellyfin.Data/Entities/MetadataProvider.cs b/Jellyfin.Data/Entities/MetadataProvider.cs index 4e4f107fb..bf9689709 100644 --- a/Jellyfin.Data/Entities/MetadataProvider.cs +++ b/Jellyfin.Data/Entities/MetadataProvider.cs @@ -141,7 +141,6 @@ namespace Jellyfin.Data.Entities /************************************************************************* * Navigation properties *************************************************************************/ - } } diff --git a/Jellyfin.Data/Entities/MetadataProviderId.cs b/Jellyfin.Data/Entities/MetadataProviderId.cs index 926f223de..c49c6f42e 100644 --- a/Jellyfin.Data/Entities/MetadataProviderId.cs +++ b/Jellyfin.Data/Entities/MetadataProviderId.cs @@ -173,7 +173,6 @@ namespace Jellyfin.Data.Entities /// [ForeignKey("MetadataProvider_Id")] public virtual MetadataProvider MetadataProvider { get; set; } - } } diff --git a/Jellyfin.Data/Entities/Movie.cs b/Jellyfin.Data/Entities/Movie.cs index b359b42fc..ad2504b0d 100644 --- a/Jellyfin.Data/Entities/Movie.cs +++ b/Jellyfin.Data/Entities/Movie.cs @@ -63,7 +63,6 @@ namespace Jellyfin.Data.Entities [ForeignKey("MovieMetadata_MovieMetadata_Id")] public virtual ICollection MovieMetadata { get; protected set; } - } } diff --git a/Jellyfin.Data/Entities/MovieMetadata.cs b/Jellyfin.Data/Entities/MovieMetadata.cs index 319ae94e5..1f8f1c2a0 100644 --- a/Jellyfin.Data/Entities/MovieMetadata.cs +++ b/Jellyfin.Data/Entities/MovieMetadata.cs @@ -217,7 +217,6 @@ namespace Jellyfin.Data.Entities *************************************************************************/ [ForeignKey("Company_Studios_Id")] public virtual ICollection Studios { get; protected set; } - } } diff --git a/Jellyfin.Data/Entities/MusicAlbum.cs b/Jellyfin.Data/Entities/MusicAlbum.cs index 00cb8fe00..e07f4357b 100644 --- a/Jellyfin.Data/Entities/MusicAlbum.cs +++ b/Jellyfin.Data/Entities/MusicAlbum.cs @@ -62,7 +62,6 @@ namespace Jellyfin.Data.Entities [ForeignKey("Track_Tracks_Id")] public virtual ICollection Tracks { get; protected set; } - } } diff --git a/Jellyfin.Data/Entities/MusicAlbumMetadata.cs b/Jellyfin.Data/Entities/MusicAlbumMetadata.cs index b52ca6564..7743890a6 100644 --- a/Jellyfin.Data/Entities/MusicAlbumMetadata.cs +++ b/Jellyfin.Data/Entities/MusicAlbumMetadata.cs @@ -181,7 +181,6 @@ namespace Jellyfin.Data.Entities [ForeignKey("Company_Labels_Id")] public virtual ICollection Labels { get; protected set; } - } } diff --git a/Jellyfin.Data/Entities/Person.cs b/Jellyfin.Data/Entities/Person.cs index d893b7e39..f71418819 100644 --- a/Jellyfin.Data/Entities/Person.cs +++ b/Jellyfin.Data/Entities/Person.cs @@ -296,7 +296,6 @@ namespace Jellyfin.Data.Entities *************************************************************************/ [ForeignKey("MetadataProviderId_Sources_Id")] public virtual ICollection Sources { get; protected set; } - } } diff --git a/Jellyfin.Data/Entities/PersonRole.cs b/Jellyfin.Data/Entities/PersonRole.cs index 9bd12c7fb..a3d047115 100644 --- a/Jellyfin.Data/Entities/PersonRole.cs +++ b/Jellyfin.Data/Entities/PersonRole.cs @@ -203,7 +203,6 @@ namespace Jellyfin.Data.Entities [ForeignKey("MetadataProviderId_Sources_Id")] public virtual ICollection Sources { get; protected set; } - } } diff --git a/Jellyfin.Data/Entities/Photo.cs b/Jellyfin.Data/Entities/Photo.cs index 7abe62891..226730126 100644 --- a/Jellyfin.Data/Entities/Photo.cs +++ b/Jellyfin.Data/Entities/Photo.cs @@ -62,7 +62,6 @@ namespace Jellyfin.Data.Entities [ForeignKey("Release_Releases_Id")] public virtual ICollection Releases { get; protected set; } - } } diff --git a/Jellyfin.Data/Entities/PhotoMetadata.cs b/Jellyfin.Data/Entities/PhotoMetadata.cs index c5502f707..2bb239cdd 100644 --- a/Jellyfin.Data/Entities/PhotoMetadata.cs +++ b/Jellyfin.Data/Entities/PhotoMetadata.cs @@ -62,7 +62,6 @@ namespace Jellyfin.Data.Entities /************************************************************************* * Navigation properties *************************************************************************/ - } } diff --git a/Jellyfin.Data/Entities/ProviderMapping.cs b/Jellyfin.Data/Entities/ProviderMapping.cs index e479341ad..e86d9737f 100644 --- a/Jellyfin.Data/Entities/ProviderMapping.cs +++ b/Jellyfin.Data/Entities/ProviderMapping.cs @@ -111,7 +111,6 @@ namespace Jellyfin.Data.Entities /************************************************************************* * Navigation properties *************************************************************************/ - } } diff --git a/Jellyfin.Data/Entities/Rating.cs b/Jellyfin.Data/Entities/Rating.cs index f70ea8b33..0c8b99ca2 100644 --- a/Jellyfin.Data/Entities/Rating.cs +++ b/Jellyfin.Data/Entities/Rating.cs @@ -181,7 +181,6 @@ namespace Jellyfin.Data.Entities /// [ForeignKey("RatingSource_RatingType_Id")] public virtual RatingSource RatingType { get; set; } - } } diff --git a/Jellyfin.Data/Entities/RatingSource.cs b/Jellyfin.Data/Entities/RatingSource.cs index 070f1ae27..c829042b5 100644 --- a/Jellyfin.Data/Entities/RatingSource.cs +++ b/Jellyfin.Data/Entities/RatingSource.cs @@ -225,7 +225,6 @@ namespace Jellyfin.Data.Entities *************************************************************************/ [ForeignKey("MetadataProviderId_Source_Id")] public virtual MetadataProviderId Source { get; set; } - } } diff --git a/Jellyfin.Data/Entities/Release.cs b/Jellyfin.Data/Entities/Release.cs index d1928fcf7..35fcbb4b7 100644 --- a/Jellyfin.Data/Entities/Release.cs +++ b/Jellyfin.Data/Entities/Release.cs @@ -182,7 +182,6 @@ namespace Jellyfin.Data.Entities [ForeignKey("Chapter_Chapters_Id")] public virtual ICollection Chapters { get; protected set; } - } } diff --git a/Jellyfin.Data/Entities/Season.cs b/Jellyfin.Data/Entities/Season.cs index 96e89cde0..2a861b660 100644 --- a/Jellyfin.Data/Entities/Season.cs +++ b/Jellyfin.Data/Entities/Season.cs @@ -105,7 +105,6 @@ namespace Jellyfin.Data.Entities [ForeignKey("Episode_Episodes_Id")] public virtual ICollection Episodes { get; protected set; } - } } diff --git a/Jellyfin.Data/Entities/SeasonMetadata.cs b/Jellyfin.Data/Entities/SeasonMetadata.cs index 64ecbfbfa..10320c6bb 100644 --- a/Jellyfin.Data/Entities/SeasonMetadata.cs +++ b/Jellyfin.Data/Entities/SeasonMetadata.cs @@ -100,7 +100,6 @@ namespace Jellyfin.Data.Entities /************************************************************************* * Navigation properties *************************************************************************/ - } } diff --git a/Jellyfin.Data/Entities/Series.cs b/Jellyfin.Data/Entities/Series.cs index 4f25c38b7..cf1d6b781 100644 --- a/Jellyfin.Data/Entities/Series.cs +++ b/Jellyfin.Data/Entities/Series.cs @@ -153,7 +153,6 @@ namespace Jellyfin.Data.Entities [ForeignKey("Season_Seasons_Id")] public virtual ICollection Seasons { get; protected set; } - } } diff --git a/Jellyfin.Data/Entities/SeriesMetadata.cs b/Jellyfin.Data/Entities/SeriesMetadata.cs index 52691783f..bb31c2e4e 100644 --- a/Jellyfin.Data/Entities/SeriesMetadata.cs +++ b/Jellyfin.Data/Entities/SeriesMetadata.cs @@ -217,7 +217,6 @@ namespace Jellyfin.Data.Entities *************************************************************************/ [ForeignKey("Company_Networks_Id")] public virtual ICollection Networks { get; protected set; } - } } diff --git a/Jellyfin.Data/Entities/Track.cs b/Jellyfin.Data/Entities/Track.cs index 079d73d2b..c9e8fd1c3 100644 --- a/Jellyfin.Data/Entities/Track.cs +++ b/Jellyfin.Data/Entities/Track.cs @@ -106,7 +106,6 @@ namespace Jellyfin.Data.Entities [ForeignKey("TrackMetadata_TrackMetadata_Id")] public virtual ICollection TrackMetadata { get; protected set; } - } } diff --git a/Jellyfin.Data/Entities/TrackMetadata.cs b/Jellyfin.Data/Entities/TrackMetadata.cs index 86c9161f6..7b99c0683 100644 --- a/Jellyfin.Data/Entities/TrackMetadata.cs +++ b/Jellyfin.Data/Entities/TrackMetadata.cs @@ -62,7 +62,6 @@ namespace Jellyfin.Data.Entities /************************************************************************* * Navigation properties *************************************************************************/ - } } diff --git a/MediaBrowser.Api/BaseApiService.cs b/MediaBrowser.Api/BaseApiService.cs index 2ece16ee1..a91a9b580 100644 --- a/MediaBrowser.Api/BaseApiService.cs +++ b/MediaBrowser.Api/BaseApiService.cs @@ -268,7 +268,6 @@ namespace MediaBrowser.Api Name = name.Replace(BaseItem.SlugChar, '&'), IncludeItemTypes = new[] { typeof(T).Name }, DtoOptions = dtoOptions - }).OfType().FirstOrDefault(); result ??= libraryManager.GetItemList(new InternalItemsQuery @@ -276,7 +275,6 @@ namespace MediaBrowser.Api Name = name.Replace(BaseItem.SlugChar, '/'), IncludeItemTypes = new[] { typeof(T).Name }, DtoOptions = dtoOptions - }).OfType().FirstOrDefault(); result ??= libraryManager.GetItemList(new InternalItemsQuery @@ -284,7 +282,6 @@ namespace MediaBrowser.Api Name = name.Replace(BaseItem.SlugChar, '?'), IncludeItemTypes = new[] { typeof(T).Name }, DtoOptions = dtoOptions - }).OfType().FirstOrDefault(); return result; diff --git a/MediaBrowser.Api/ChannelService.cs b/MediaBrowser.Api/ChannelService.cs index fd9b8c396..3cab9fb66 100644 --- a/MediaBrowser.Api/ChannelService.cs +++ b/MediaBrowser.Api/ChannelService.cs @@ -240,7 +240,6 @@ namespace MediaBrowser.Api { Fields = request.GetItemFields() } - }; foreach (var filter in request.GetFilters()) diff --git a/MediaBrowser.Api/ConfigurationService.cs b/MediaBrowser.Api/ConfigurationService.cs index 316be04a0..3ad51de8d 100644 --- a/MediaBrowser.Api/ConfigurationService.cs +++ b/MediaBrowser.Api/ConfigurationService.cs @@ -17,7 +17,6 @@ namespace MediaBrowser.Api [Authenticated] public class GetConfiguration : IReturn { - } [Route("/System/Configuration/{Key}", "GET", Summary = "Gets a named configuration")] @@ -51,7 +50,6 @@ namespace MediaBrowser.Api [Authenticated(Roles = "Admin")] public class GetDefaultMetadataOptions : IReturn { - } [Route("/System/MediaEncoder/Path", "POST", Summary = "Updates the path to the media encoder")] diff --git a/MediaBrowser.Api/Devices/DeviceService.cs b/MediaBrowser.Api/Devices/DeviceService.cs index dd3f3e738..18860983e 100644 --- a/MediaBrowser.Api/Devices/DeviceService.cs +++ b/MediaBrowser.Api/Devices/DeviceService.cs @@ -92,7 +92,6 @@ namespace MediaBrowser.Api.Devices var sessions = _authRepo.Get(new AuthenticationInfoQuery { DeviceId = request.Id - }).Items; foreach (var session in sessions) diff --git a/MediaBrowser.Api/EnvironmentService.cs b/MediaBrowser.Api/EnvironmentService.cs index 82d471412..fddf78465 100644 --- a/MediaBrowser.Api/EnvironmentService.cs +++ b/MediaBrowser.Api/EnvironmentService.cs @@ -100,7 +100,6 @@ namespace MediaBrowser.Api [Route("/Environment/DefaultDirectoryBrowser", "GET", Summary = "Gets the parent path of a given path")] public class GetDefaultDirectoryBrowser : IReturn { - } /// diff --git a/MediaBrowser.Api/FilterService.cs b/MediaBrowser.Api/FilterService.cs index bd67ec41f..833a684a5 100644 --- a/MediaBrowser.Api/FilterService.cs +++ b/MediaBrowser.Api/FilterService.cs @@ -150,7 +150,6 @@ namespace MediaBrowser.Api { Name = i.Item1.Name, Id = i.Item1.Id - }).ToArray(); } else @@ -159,7 +158,6 @@ namespace MediaBrowser.Api { Name = i.Item1.Name, Id = i.Item1.Id - }).ToArray(); } diff --git a/MediaBrowser.Api/IHasItemFields.cs b/MediaBrowser.Api/IHasItemFields.cs index 85b4a7e2d..6359de77d 100644 --- a/MediaBrowser.Api/IHasItemFields.cs +++ b/MediaBrowser.Api/IHasItemFields.cs @@ -43,7 +43,6 @@ namespace MediaBrowser.Api } return null; - }).Where(i => i.HasValue).Select(i => i.Value).ToArray(); } } diff --git a/MediaBrowser.Api/Images/ImageService.cs b/MediaBrowser.Api/Images/ImageService.cs index 0b8ddeacd..6f2956c5d 100644 --- a/MediaBrowser.Api/Images/ImageService.cs +++ b/MediaBrowser.Api/Images/ImageService.cs @@ -743,7 +743,6 @@ namespace MediaBrowser.Api.Images Path = imageResult.Item1, FileShare = FileShare.Read - }).ConfigureAwait(false); } diff --git a/MediaBrowser.Api/Images/RemoteImageService.cs b/MediaBrowser.Api/Images/RemoteImageService.cs index 358ac30fa..2633a5d3c 100644 --- a/MediaBrowser.Api/Images/RemoteImageService.cs +++ b/MediaBrowser.Api/Images/RemoteImageService.cs @@ -152,7 +152,6 @@ namespace MediaBrowser.Api.Images IncludeAllLanguages = request.IncludeAllLanguages, IncludeDisabledProviders = true, ImageType = request.Type - }, CancellationToken.None).ConfigureAwait(false); var imagesList = images.ToArray(); diff --git a/MediaBrowser.Api/Library/LibraryService.cs b/MediaBrowser.Api/Library/LibraryService.cs index 2b4694925..284a2c11b 100644 --- a/MediaBrowser.Api/Library/LibraryService.cs +++ b/MediaBrowser.Api/Library/LibraryService.cs @@ -562,7 +562,6 @@ namespace MediaBrowser.Api.Library _authContext) { Request = Request, - }.GetSimilarItemsResult(request); } @@ -660,7 +659,6 @@ namespace MediaBrowser.Api.Library { EnableImages = false } - }).Where(i => string.Equals(request.TvdbId, i.GetProviderId(MetadataProvider.Tvdb), StringComparison.OrdinalIgnoreCase)).ToArray(); foreach (var item in series) @@ -689,7 +687,6 @@ namespace MediaBrowser.Api.Library { EnableImages = false } - }); if (!string.IsNullOrWhiteSpace(request.ImdbId)) diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs index 279fd6ee9..b00a5fec8 100644 --- a/MediaBrowser.Api/LiveTv/LiveTvService.cs +++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs @@ -679,7 +679,6 @@ namespace MediaBrowser.Api.LiveTv [Authenticated] public class GetTunerHostTypes : IReturn> { - } [Route("/LiveTv/Tuners/Discvover", "GET")] @@ -826,7 +825,6 @@ namespace MediaBrowser.Api.LiveTv { Name = i.Name, Id = i.Id - }).ToList(), Mappings = mappings, @@ -845,7 +843,6 @@ namespace MediaBrowser.Api.LiveTv { Url = "https://json.schedulesdirect.org/20141201/available/countries", BufferContent = false - }).ConfigureAwait(false); return ResultFactory.GetResult(Request, response, "application/json"); @@ -958,7 +955,6 @@ namespace MediaBrowser.Api.LiveTv SortBy = request.GetOrderBy(), SortOrder = request.SortOrder ?? SortOrder.Ascending, AddCurrentProgram = request.AddCurrentProgram - }, options, CancellationToken.None); var user = request.UserId.Equals(Guid.Empty) ? null : _userManager.GetUserById(request.UserId); @@ -1113,7 +1109,6 @@ namespace MediaBrowser.Api.LiveTv Fields = request.GetItemFields(), ImageTypeLimit = request.ImageTypeLimit, EnableImages = request.EnableImages - }, options); return ToOptimizedResult(result); @@ -1152,7 +1147,6 @@ namespace MediaBrowser.Api.LiveTv SeriesTimerId = request.SeriesTimerId, IsActive = request.IsActive, IsScheduled = request.IsScheduled - }, CancellationToken.None).ConfigureAwait(false); return ToOptimizedResult(result); @@ -1188,7 +1182,6 @@ namespace MediaBrowser.Api.LiveTv { SortOrder = request.SortOrder, SortBy = request.SortBy - }, CancellationToken.None).ConfigureAwait(false); return ToOptimizedResult(result); diff --git a/MediaBrowser.Api/Movies/CollectionService.cs b/MediaBrowser.Api/Movies/CollectionService.cs index 95a37dfc5..e9629439d 100644 --- a/MediaBrowser.Api/Movies/CollectionService.cs +++ b/MediaBrowser.Api/Movies/CollectionService.cs @@ -79,7 +79,6 @@ namespace MediaBrowser.Api.Movies ParentId = parentId, ItemIdList = SplitValue(request.Ids, ','), UserIds = new[] { userId } - }); var dtoOptions = GetDtoOptions(_authContext, request); diff --git a/MediaBrowser.Api/Movies/MoviesService.cs b/MediaBrowser.Api/Movies/MoviesService.cs index 281c7e613..88ca0aa23 100644 --- a/MediaBrowser.Api/Movies/MoviesService.cs +++ b/MediaBrowser.Api/Movies/MoviesService.cs @@ -194,7 +194,6 @@ namespace MediaBrowser.Api.Movies ParentId = parentIdGuid, Recursive = true, DtoOptions = dtoOptions - }); var mostRecentMovies = recentlyPlayedMovies.Take(6).ToList(); @@ -279,7 +278,6 @@ namespace MediaBrowser.Api.Movies IsMovie = true, EnableGroupByMetadataKey = true, DtoOptions = dtoOptions - }).GroupBy(i => i.GetProviderId(MetadataProvider.Imdb) ?? Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture)) .Select(x => x.First()) .Take(itemLimit) @@ -320,7 +318,6 @@ namespace MediaBrowser.Api.Movies IsMovie = true, EnableGroupByMetadataKey = true, DtoOptions = dtoOptions - }).GroupBy(i => i.GetProviderId(MetadataProvider.Imdb) ?? Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture)) .Select(x => x.First()) .Take(itemLimit) @@ -360,7 +357,6 @@ namespace MediaBrowser.Api.Movies SimilarTo = item, EnableGroupByMetadataKey = true, DtoOptions = dtoOptions - }); if (similar.Count > 0) diff --git a/MediaBrowser.Api/Movies/TrailersService.cs b/MediaBrowser.Api/Movies/TrailersService.cs index 0b5334235..a7758b100 100644 --- a/MediaBrowser.Api/Movies/TrailersService.cs +++ b/MediaBrowser.Api/Movies/TrailersService.cs @@ -82,7 +82,6 @@ namespace MediaBrowser.Api.Movies _authContext) { Request = Request, - }.Get(getItems); } } diff --git a/MediaBrowser.Api/Music/InstantMixService.cs b/MediaBrowser.Api/Music/InstantMixService.cs index 7d10c9427..ebd3eb64a 100644 --- a/MediaBrowser.Api/Music/InstantMixService.cs +++ b/MediaBrowser.Api/Music/InstantMixService.cs @@ -192,6 +192,5 @@ namespace MediaBrowser.Api.Music return result; } - } } diff --git a/MediaBrowser.Api/Playback/MediaInfoService.cs b/MediaBrowser.Api/Playback/MediaInfoService.cs index 2c6534cc0..2dc62fda7 100644 --- a/MediaBrowser.Api/Playback/MediaInfoService.cs +++ b/MediaBrowser.Api/Playback/MediaInfoService.cs @@ -646,7 +646,6 @@ namespace MediaBrowser.Api.Playback } return 1; - }).ThenBy(i => { // Let's assume direct streaming a file is just as desirable as direct playing a remote url @@ -656,7 +655,6 @@ namespace MediaBrowser.Api.Playback } return 1; - }).ThenBy(i => { return i.Protocol switch @@ -672,7 +670,6 @@ namespace MediaBrowser.Api.Playback } return 1; - }).ThenBy(originalList.IndexOf) .ToArray(); } diff --git a/MediaBrowser.Api/Playback/Progressive/VideoService.cs b/MediaBrowser.Api/Playback/Progressive/VideoService.cs index 4de81655c..a35e6c201 100644 --- a/MediaBrowser.Api/Playback/Progressive/VideoService.cs +++ b/MediaBrowser.Api/Playback/Progressive/VideoService.cs @@ -59,7 +59,6 @@ namespace MediaBrowser.Api.Playback.Progressive [Route("/Videos/{Id}/stream", "HEAD")] public class GetVideoStream : VideoStreamRequest { - } /// diff --git a/MediaBrowser.Api/Playback/UniversalAudioService.cs b/MediaBrowser.Api/Playback/UniversalAudioService.cs index a3b319d44..b2d101a5b 100644 --- a/MediaBrowser.Api/Playback/UniversalAudioService.cs +++ b/MediaBrowser.Api/Playback/UniversalAudioService.cs @@ -259,7 +259,6 @@ namespace MediaBrowser.Api.Playback UserId = request.UserId, DeviceProfile = deviceProfile, MediaSourceId = request.MediaSourceId - }).ConfigureAwait(false); var mediaSource = playbackInfoResult.MediaSources[0]; diff --git a/MediaBrowser.Api/PlaylistService.cs b/MediaBrowser.Api/PlaylistService.cs index 953b00e35..d5def03be 100644 --- a/MediaBrowser.Api/PlaylistService.cs +++ b/MediaBrowser.Api/PlaylistService.cs @@ -161,7 +161,6 @@ namespace MediaBrowser.Api ItemIdList = GetGuids(request.Ids), UserId = request.UserId, MediaType = request.MediaType - }).ConfigureAwait(false); return ToOptimizedResult(result); diff --git a/MediaBrowser.Api/SearchService.cs b/MediaBrowser.Api/SearchService.cs index e9d339c6e..4a2f96ed8 100644 --- a/MediaBrowser.Api/SearchService.cs +++ b/MediaBrowser.Api/SearchService.cs @@ -180,7 +180,6 @@ namespace MediaBrowser.Api IsNews = request.IsNews, IsSeries = request.IsSeries, IsSports = request.IsSports - }); return new SearchHintResult diff --git a/MediaBrowser.Api/SimilarItemsHelper.cs b/MediaBrowser.Api/SimilarItemsHelper.cs index dcd22280a..90c324ff3 100644 --- a/MediaBrowser.Api/SimilarItemsHelper.cs +++ b/MediaBrowser.Api/SimilarItemsHelper.cs @@ -218,6 +218,5 @@ namespace MediaBrowser.Api return points; } - } } diff --git a/MediaBrowser.Api/System/SystemService.cs b/MediaBrowser.Api/System/SystemService.cs index c57cc93d5..4f10a4ad2 100644 --- a/MediaBrowser.Api/System/SystemService.cs +++ b/MediaBrowser.Api/System/SystemService.cs @@ -24,20 +24,17 @@ namespace MediaBrowser.Api.System [Authenticated(EscapeParentalControl = true, AllowBeforeStartupWizard = true)] public class GetSystemInfo : IReturn { - } [Route("/System/Info/Public", "GET", Summary = "Gets public information about the server")] public class GetPublicSystemInfo : IReturn { - } [Route("/System/Ping", "POST")] [Route("/System/Ping", "GET")] public class PingSystem : IReturnVoid { - } /// @@ -83,7 +80,6 @@ namespace MediaBrowser.Api.System [Authenticated] public class GetWakeOnLanInfo : IReturn { - } /// @@ -153,7 +149,6 @@ namespace MediaBrowser.Api.System DateModified = _fileSystem.GetLastWriteTimeUtc(i), Name = i.Name, Size = i.Length - }).OrderByDescending(i => i.DateModified) .ThenByDescending(i => i.DateCreated) .ThenBy(i => i.Name) diff --git a/MediaBrowser.Api/TvShowsService.cs b/MediaBrowser.Api/TvShowsService.cs index 0c23d8b29..23062b67b 100644 --- a/MediaBrowser.Api/TvShowsService.cs +++ b/MediaBrowser.Api/TvShowsService.cs @@ -306,7 +306,6 @@ namespace MediaBrowser.Api ParentId = parentIdGuid, Recursive = true, DtoOptions = options - }); var returnItems = _dtoService.GetBaseItemDtos(itemsResult, options, user); @@ -390,7 +389,6 @@ namespace MediaBrowser.Api IsMissing = request.IsMissing, IsSpecialSeason = request.IsSpecialSeason, AdjacentTo = request.AdjacentTo - }); var dtoOptions = GetDtoOptions(_authContext, request); diff --git a/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs b/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs index a1ec08467..4802849f4 100644 --- a/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs +++ b/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs @@ -322,7 +322,6 @@ namespace MediaBrowser.Api.UserLibrary { ibnItems = ibnItems.Take(request.Limit.Value); } - } var tuples = ibnItems.Select(i => new Tuple>(i, new List())); diff --git a/MediaBrowser.Api/UserLibrary/UserViewsService.cs b/MediaBrowser.Api/UserLibrary/UserViewsService.cs index 0fffb0622..73d5ec6de 100644 --- a/MediaBrowser.Api/UserLibrary/UserViewsService.cs +++ b/MediaBrowser.Api/UserLibrary/UserViewsService.cs @@ -129,7 +129,6 @@ namespace MediaBrowser.Api.UserLibrary { Name = i.Name, Id = i.Id.ToString("N", CultureInfo.InvariantCulture) - }) .OrderBy(i => i.Name) .ToArray(); diff --git a/MediaBrowser.Controller/Channels/ISearchableChannel.cs b/MediaBrowser.Controller/Channels/ISearchableChannel.cs index d5b76a160..48043ad7a 100644 --- a/MediaBrowser.Controller/Channels/ISearchableChannel.cs +++ b/MediaBrowser.Controller/Channels/ISearchableChannel.cs @@ -35,12 +35,10 @@ namespace MediaBrowser.Controller.Channels public interface IDisableMediaSourceDisplay { - } public interface ISupportsMediaProbe { - } public interface IHasFolderAttributes diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 52fe83af0..3b08bd237 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -767,7 +767,6 @@ namespace MediaBrowser.Controller.Entities get => GetParent() as Folder; set { - } } @@ -1064,7 +1063,6 @@ namespace MediaBrowser.Controller.Entities } return 1; - }).ThenBy(i => i.Video3DFormat.HasValue ? 1 : 0) .ThenByDescending(i => { @@ -1347,12 +1345,10 @@ namespace MediaBrowser.Controller.Entities protected virtual void TriggerOnRefreshStart() { - } protected virtual void TriggerOnRefreshComplete() { - } /// diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index 366b3bd70..3a01b4379 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -500,7 +500,6 @@ namespace MediaBrowser.Controller.Entities if (series != null) { await series.RefreshMetadata(refreshOptions, cancellationToken).ConfigureAwait(false); - } await container.RefreshAllMetadata(refreshOptions, progress, cancellationToken).ConfigureAwait(false); } @@ -615,7 +614,6 @@ namespace MediaBrowser.Controller.Entities { EnableImages = false } - }); return result.TotalRecordCount; @@ -1629,7 +1627,6 @@ namespace MediaBrowser.Controller.Entities Recursive = true, IsFolder = false, EnableTotalRecordCount = false - }); // Sweep through recursively and update status @@ -1647,7 +1644,6 @@ namespace MediaBrowser.Controller.Entities IsFolder = false, IsVirtualItem = false, EnableTotalRecordCount = false - }); return itemsResult diff --git a/MediaBrowser.Controller/Entities/UserViewBuilder.cs b/MediaBrowser.Controller/Entities/UserViewBuilder.cs index 8162fb4eb..dbfef0777 100644 --- a/MediaBrowser.Controller/Entities/UserViewBuilder.cs +++ b/MediaBrowser.Controller/Entities/UserViewBuilder.cs @@ -270,7 +270,6 @@ namespace MediaBrowser.Controller.Entities _logger.LogError(ex, "Error getting genre"); return null; } - }) .Where(i => i != null) .Select(i => GetUserViewWithName(i.Name, SpecialFolder.MovieGenre, i.SortName, parent)); @@ -347,7 +346,6 @@ namespace MediaBrowser.Controller.Entities Limit = query.Limit, StartIndex = query.StartIndex, UserId = query.User.Id - }, parentFolders, query.DtoOptions); return result; @@ -384,7 +382,6 @@ namespace MediaBrowser.Controller.Entities IncludeItemTypes = new[] { typeof(Series).Name }, Recursive = true, EnableTotalRecordCount = false - }).Items .SelectMany(i => i.Genres) .DistinctNames() @@ -399,7 +396,6 @@ namespace MediaBrowser.Controller.Entities _logger.LogError(ex, "Error getting genre"); return null; } - }) .Where(i => i != null) .Select(i => GetUserViewWithName(i.Name, SpecialFolder.TvGenre, i.SortName, parent)); diff --git a/MediaBrowser.Controller/Entities/Video.cs b/MediaBrowser.Controller/Entities/Video.cs index 72eb67a06..4cfa0e74d 100644 --- a/MediaBrowser.Controller/Entities/Video.cs +++ b/MediaBrowser.Controller/Entities/Video.cs @@ -535,7 +535,6 @@ namespace MediaBrowser.Controller.Entities { ItemId = Id, Index = DefaultVideoStreamIndex.Value - }).FirstOrDefault(); } diff --git a/MediaBrowser.Controller/IO/FileData.cs b/MediaBrowser.Controller/IO/FileData.cs index 848e4fb16..aa7373815 100644 --- a/MediaBrowser.Controller/IO/FileData.cs +++ b/MediaBrowser.Controller/IO/FileData.cs @@ -118,7 +118,6 @@ namespace MediaBrowser.Controller.IO } return returnResult; } - } } diff --git a/MediaBrowser.Controller/Library/ItemResolveArgs.cs b/MediaBrowser.Controller/Library/ItemResolveArgs.cs index 0222b926e..cca85cd3b 100644 --- a/MediaBrowser.Controller/Library/ItemResolveArgs.cs +++ b/MediaBrowser.Controller/Library/ItemResolveArgs.cs @@ -89,7 +89,6 @@ namespace MediaBrowser.Controller.Library return parentDir.Length > _appPaths.RootFolderPath.Length && parentDir.StartsWith(_appPaths.RootFolderPath, StringComparison.OrdinalIgnoreCase); - } } @@ -129,7 +128,6 @@ namespace MediaBrowser.Controller.Library } return item != null; - } return false; } diff --git a/MediaBrowser.Controller/LiveTv/LiveTvConflictException.cs b/MediaBrowser.Controller/LiveTv/LiveTvConflictException.cs index df8f91eec..92b8ee67c 100644 --- a/MediaBrowser.Controller/LiveTv/LiveTvConflictException.cs +++ b/MediaBrowser.Controller/LiveTv/LiveTvConflictException.cs @@ -9,12 +9,10 @@ namespace MediaBrowser.Controller.LiveTv { public LiveTvConflictException() { - } public LiveTvConflictException(string message) : base(message) { - } } } diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 23cb3dbbc..0ca42c0e0 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -759,7 +759,6 @@ namespace MediaBrowser.Controller.MediaEncoding } param += " -look_ahead 0"; - } else if (string.Equals(videoEncoder, "h264_nvenc", StringComparison.OrdinalIgnoreCase) // h264 (h264_nvenc) || string.Equals(videoEncoder, "hevc_nvenc", StringComparison.OrdinalIgnoreCase)) diff --git a/MediaBrowser.Controller/Persistence/IUserDataRepository.cs b/MediaBrowser.Controller/Persistence/IUserDataRepository.cs index a4bdf60d7..4c327eeef 100644 --- a/MediaBrowser.Controller/Persistence/IUserDataRepository.cs +++ b/MediaBrowser.Controller/Persistence/IUserDataRepository.cs @@ -44,6 +44,5 @@ namespace MediaBrowser.Controller.Persistence /// /// void SaveAllUserData(long userId, UserItemData[] userData, CancellationToken cancellationToken); - } } diff --git a/MediaBrowser.Controller/Plugins/IServerEntryPoint.cs b/MediaBrowser.Controller/Plugins/IServerEntryPoint.cs index 1e8654c4d..b44e2531e 100644 --- a/MediaBrowser.Controller/Plugins/IServerEntryPoint.cs +++ b/MediaBrowser.Controller/Plugins/IServerEntryPoint.cs @@ -22,6 +22,5 @@ namespace MediaBrowser.Controller.Plugins /// public interface IRunBeforeStartup { - } } diff --git a/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs b/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs index 9fb28c334..0ceb55c57 100644 --- a/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs +++ b/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs @@ -255,7 +255,6 @@ namespace MediaBrowser.LocalMetadata.Parsers } return null; - }).Where(i => i.HasValue).Select(i => i.Value).ToArray(); } @@ -680,7 +679,6 @@ namespace MediaBrowser.LocalMetadata.Parsers } break; - } } } @@ -1260,6 +1258,5 @@ namespace MediaBrowser.LocalMetadata.Parsers { return val.Split(separators, options); } - } } diff --git a/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs b/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs index a82f2108f..f02999370 100644 --- a/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs +++ b/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs @@ -269,7 +269,6 @@ namespace MediaBrowser.MediaEncoding.Attachments if (disposing) { - } _disposed = true; diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index 18e4a38c6..a4896d5f9 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -920,7 +920,6 @@ namespace MediaBrowser.MediaEncoding.Encoder var fileParts = _fileSystem.GetFileNameWithoutExtension(f).Split('_'); return fileParts.Length == 3 && string.Equals(title, fileParts[1], StringComparison.OrdinalIgnoreCase); - }).ToList(); // If this resulted in not getting any vobs, just take them all diff --git a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs index ed5f77053..7d57a691e 100644 --- a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs +++ b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs @@ -413,7 +413,6 @@ namespace MediaBrowser.MediaEncoding.Probing .Where(i => !string.IsNullOrWhiteSpace(i)) .Distinct(StringComparer.OrdinalIgnoreCase) .ToArray(); - } else if (string.Equals(key, "screenwriters", StringComparison.OrdinalIgnoreCase)) { @@ -425,7 +424,6 @@ namespace MediaBrowser.MediaEncoding.Probing Type = PersonType.Writer }); } - } else if (string.Equals(key, "producers", StringComparison.OrdinalIgnoreCase)) { @@ -1028,7 +1026,6 @@ namespace MediaBrowser.MediaEncoding.Probing audio.AlbumArtists = SplitArtists(albumArtist, _nameDelimiters, true) .DistinctNames() .ToArray(); - } if (audio.AlbumArtists.Length == 0) diff --git a/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs b/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs index ebacc7d9f..bae2f5417 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs @@ -261,7 +261,6 @@ namespace MediaBrowser.MediaEncoding.Subtitles text += ""; } } - } text = text.Replace(@"{\i1}", ""); diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs index f08af6045..7e9894f0a 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs @@ -640,7 +640,6 @@ namespace MediaBrowser.MediaEncoding.Subtitles } catch (FileNotFoundException) { - } catch (IOException ex) { diff --git a/MediaBrowser.Model/Dlna/MediaFormatProfileResolver.cs b/MediaBrowser.Model/Dlna/MediaFormatProfileResolver.cs index 10e9179c0..c03a8060f 100644 --- a/MediaBrowser.Model/Dlna/MediaFormatProfileResolver.cs +++ b/MediaBrowser.Model/Dlna/MediaFormatProfileResolver.cs @@ -158,7 +158,6 @@ namespace MediaBrowser.Model.Dlna return new MediaFormatProfile[] { ValueOf(string.Format("VC1_TS_HD_DTS{0}", suffix)) }; } - } else if (string.Equals(videoCodec, "mpeg4", StringComparison.OrdinalIgnoreCase) || string.Equals(videoCodec, "msmpeg4", StringComparison.OrdinalIgnoreCase)) { diff --git a/MediaBrowser.Model/Dlna/ProfileCondition.cs b/MediaBrowser.Model/Dlna/ProfileCondition.cs index f8b5dee81..4b39d6875 100644 --- a/MediaBrowser.Model/Dlna/ProfileCondition.cs +++ b/MediaBrowser.Model/Dlna/ProfileCondition.cs @@ -15,7 +15,6 @@ namespace MediaBrowser.Model.Dlna public ProfileCondition(ProfileConditionType condition, ProfileConditionValue property, string value) : this(condition, property, value, false) { - } public ProfileCondition(ProfileConditionType condition, ProfileConditionValue property, string value, bool isRequired) diff --git a/MediaBrowser.Model/Dlna/SortCriteria.cs b/MediaBrowser.Model/Dlna/SortCriteria.cs index 3f8985fdc..1f7fa76ad 100644 --- a/MediaBrowser.Model/Dlna/SortCriteria.cs +++ b/MediaBrowser.Model/Dlna/SortCriteria.cs @@ -10,7 +10,6 @@ namespace MediaBrowser.Model.Dlna public SortCriteria(string value) { - } } } diff --git a/MediaBrowser.Model/Dlna/StreamBuilder.cs b/MediaBrowser.Model/Dlna/StreamBuilder.cs index 8ebd30b72..3fe5cf774 100644 --- a/MediaBrowser.Model/Dlna/StreamBuilder.cs +++ b/MediaBrowser.Model/Dlna/StreamBuilder.cs @@ -109,7 +109,6 @@ namespace MediaBrowser.Model.Dlna } return 1; - }).ThenBy(i => { switch (i.PlayMethod) @@ -121,7 +120,6 @@ namespace MediaBrowser.Model.Dlna default: return 1; } - }).ThenBy(i => { switch (i.MediaSource.Protocol) @@ -131,7 +129,6 @@ namespace MediaBrowser.Model.Dlna default: return 1; } - }).ThenBy(i => { if (maxBitrate > 0) @@ -143,7 +140,6 @@ namespace MediaBrowser.Model.Dlna } return 0; - }).ThenBy(streams.IndexOf); } diff --git a/MediaBrowser.Model/Entities/MediaStream.cs b/MediaBrowser.Model/Entities/MediaStream.cs index 12eaa184c..3db72f78a 100644 --- a/MediaBrowser.Model/Entities/MediaStream.cs +++ b/MediaBrowser.Model/Entities/MediaStream.cs @@ -208,7 +208,6 @@ namespace MediaBrowser.Model.Entities if (Type == MediaStreamType.Video) { - } return null; diff --git a/MediaBrowser.Model/Entities/PackageReviewInfo.cs b/MediaBrowser.Model/Entities/PackageReviewInfo.cs index 1ebbc3323..5b22b34ac 100644 --- a/MediaBrowser.Model/Entities/PackageReviewInfo.cs +++ b/MediaBrowser.Model/Entities/PackageReviewInfo.cs @@ -36,6 +36,5 @@ namespace MediaBrowser.Model.Entities /// Gets or sets the time of review. /// public DateTime timestamp { get; set; } - } } diff --git a/MediaBrowser.Model/LiveTv/TimerInfoDto.cs b/MediaBrowser.Model/LiveTv/TimerInfoDto.cs index 19039d448..0b9b4141a 100644 --- a/MediaBrowser.Model/LiveTv/TimerInfoDto.cs +++ b/MediaBrowser.Model/LiveTv/TimerInfoDto.cs @@ -41,6 +41,5 @@ namespace MediaBrowser.Model.LiveTv /// /// The program information. public BaseItemDto ProgramInfo { get; set; } - } } diff --git a/MediaBrowser.Model/Net/HttpException.cs b/MediaBrowser.Model/Net/HttpException.cs index 4b15e30f0..48ff5d51c 100644 --- a/MediaBrowser.Model/Net/HttpException.cs +++ b/MediaBrowser.Model/Net/HttpException.cs @@ -28,7 +28,6 @@ namespace MediaBrowser.Model.Net public HttpException(string message, Exception innerException) : base(message, innerException) { - } /// diff --git a/MediaBrowser.Model/Providers/RemoteSearchResult.cs b/MediaBrowser.Model/Providers/RemoteSearchResult.cs index c96eb0b59..989741c01 100644 --- a/MediaBrowser.Model/Providers/RemoteSearchResult.cs +++ b/MediaBrowser.Model/Providers/RemoteSearchResult.cs @@ -51,6 +51,5 @@ namespace MediaBrowser.Model.Providers public RemoteSearchResult[] Artists { get; set; } - } } diff --git a/MediaBrowser.Providers/Manager/ItemImageProvider.cs b/MediaBrowser.Providers/Manager/ItemImageProvider.cs index ee9a32966..7901503d3 100644 --- a/MediaBrowser.Providers/Manager/ItemImageProvider.cs +++ b/MediaBrowser.Providers/Manager/ItemImageProvider.cs @@ -335,7 +335,6 @@ namespace MediaBrowser.Providers.Manager } catch (FileNotFoundException) { - } } @@ -529,7 +528,6 @@ namespace MediaBrowser.Providers.Manager { Path = path, Type = imageType - }, newIndex); } diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs index 31c239e24..5853c7714 100644 --- a/MediaBrowser.Providers/Manager/ProviderManager.cs +++ b/MediaBrowser.Providers/Manager/ProviderManager.cs @@ -905,7 +905,6 @@ namespace MediaBrowser.Providers.Manager i.UrlFormatString, value) }; - }).Where(i => i != null).Concat(item.GetRelatedUrls()); } diff --git a/MediaBrowser.Providers/Manager/ProviderUtils.cs b/MediaBrowser.Providers/Manager/ProviderUtils.cs index 7f2a1410b..60410032e 100644 --- a/MediaBrowser.Providers/Manager/ProviderUtils.cs +++ b/MediaBrowser.Providers/Manager/ProviderUtils.cs @@ -111,7 +111,6 @@ namespace MediaBrowser.Providers.Manager if (replaceData || targetResult.People == null || targetResult.People.Count == 0) { targetResult.People = sourceResult.People; - } else if (targetResult.People != null && sourceResult.People != null) { diff --git a/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs b/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs index 7023ef706..ba87e0570 100644 --- a/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs +++ b/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs @@ -79,7 +79,6 @@ namespace MediaBrowser.Providers.MediaInfo } catch { - } } diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs b/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs index 1e7ae5e74..73c89e815 100644 --- a/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs +++ b/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs @@ -63,7 +63,6 @@ namespace MediaBrowser.Providers.MediaInfo Path = path, Protocol = protocol } - }, cancellationToken).ConfigureAwait(false); cancellationToken.ThrowIfCancellationRequested(); diff --git a/MediaBrowser.Providers/MediaInfo/SubtitleResolver.cs b/MediaBrowser.Providers/MediaInfo/SubtitleResolver.cs index c0eee54fe..1477488d7 100644 --- a/MediaBrowser.Providers/MediaInfo/SubtitleResolver.cs +++ b/MediaBrowser.Providers/MediaInfo/SubtitleResolver.cs @@ -60,7 +60,6 @@ namespace MediaBrowser.Providers.MediaInfo } catch (IOException) { - } return streams; diff --git a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeriesProvider.cs b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeriesProvider.cs index c9edcc8e9..30de1391d 100644 --- a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeriesProvider.cs +++ b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeriesProvider.cs @@ -247,7 +247,6 @@ namespace MediaBrowser.Providers.Plugins.TheTvdb ProductionYear = firstAired.Year, SearchProviderName = Name, ImageUrl = TvdbUtils.BannerUrl + seriesSearchResult.Banner - }; try diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Movies/GenericTmdbMovieInfo.cs b/MediaBrowser.Providers/Plugins/Tmdb/Movies/GenericTmdbMovieInfo.cs index 2f75f7cba..2c6e08921 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/Movies/GenericTmdbMovieInfo.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/Movies/GenericTmdbMovieInfo.cs @@ -304,6 +304,5 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Movies }).ToArray(); } } - } } diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieProvider.cs index 64d3ecd7b..faeb48b12 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieProvider.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieProvider.cs @@ -149,7 +149,6 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Movies Url = string.Format(TmdbConfigUrl, TmdbUtils.ApiKey), CancellationToken = cancellationToken, AcceptHeader = TmdbUtils.AcceptHeader - }).ConfigureAwait(false)) { using (Stream json = response.Content) @@ -344,7 +343,6 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Movies AcceptHeader = TmdbUtils.AcceptHeader, CacheMode = cacheMode, CacheLength = cacheLength - }).ConfigureAwait(false)) { using (var json = response.Content) @@ -389,7 +387,6 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Movies AcceptHeader = TmdbUtils.AcceptHeader, CacheMode = cacheMode, CacheLength = cacheLength - }).ConfigureAwait(false)) { using (var json = response.Content) diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbSearch.cs b/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbSearch.cs index 3e52c72e0..c5dc060c0 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbSearch.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbSearch.cs @@ -203,7 +203,6 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Movies remoteResult.SetProviderId(MetadataProvider.Tmdb, i.Id.ToString(_usCulture)); return remoteResult; - }) .ToList(); } @@ -224,7 +223,6 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Movies Url = url3, CancellationToken = cancellationToken, AcceptHeader = TmdbUtils.AcceptHeader - }).ConfigureAwait(false)) { using (var json = response.Content) @@ -256,7 +254,6 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Movies remoteResult.SetProviderId(MetadataProvider.Tmdb, i.Id.ToString(_usCulture)); return remoteResult; - }) .ToList(); } diff --git a/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonProvider.cs index 6b63ff664..654e42a90 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonProvider.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonProvider.cs @@ -232,7 +232,6 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.People Url = url, CancellationToken = cancellationToken, AcceptHeader = TmdbUtils.AcceptHeader - }).ConfigureAwait(false)) { using (var json = response.Content) diff --git a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeProviderBase.cs b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeProviderBase.cs index f82f5f2ab..ab1f9dab5 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeProviderBase.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeProviderBase.cs @@ -127,7 +127,6 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV Url = url, CancellationToken = cancellationToken, AcceptHeader = TmdbUtils.AcceptHeader - }).ConfigureAwait(false)) { using (var json = response.Content) diff --git a/MediaBrowser.Providers/Studios/StudiosImageProvider.cs b/MediaBrowser.Providers/Studios/StudiosImageProvider.cs index cbef27a09..e92e5ceab 100644 --- a/MediaBrowser.Providers/Studios/StudiosImageProvider.cs +++ b/MediaBrowser.Providers/Studios/StudiosImageProvider.cs @@ -201,6 +201,5 @@ namespace MediaBrowser.Providers.Studios } } } - } } diff --git a/MediaBrowser.Providers/Subtitles/SubtitleManager.cs b/MediaBrowser.Providers/Subtitles/SubtitleManager.cs index c6ffc460c..8086533eb 100644 --- a/MediaBrowser.Providers/Subtitles/SubtitleManager.cs +++ b/MediaBrowser.Providers/Subtitles/SubtitleManager.cs @@ -311,7 +311,6 @@ namespace MediaBrowser.Providers.Subtitles Index = index, ItemId = item.Id, Type = MediaStreamType.Subtitle - }).First(); var path = stream.Path; @@ -365,9 +364,7 @@ namespace MediaBrowser.Providers.Subtitles { Name = i.Name, Id = GetProviderId(i.Name) - }).ToArray(); } - } } diff --git a/MediaBrowser.Providers/TV/TvExternalIds.cs b/MediaBrowser.Providers/TV/TvExternalIds.cs index bd59606e7..ec7873eaa 100644 --- a/MediaBrowser.Providers/TV/TvExternalIds.cs +++ b/MediaBrowser.Providers/TV/TvExternalIds.cs @@ -33,7 +33,6 @@ namespace MediaBrowser.Providers.TV /// public bool Supports(IHasProviderIds item) => item is Series; - } public class TvdbSeasonExternalId : IExternalId diff --git a/MediaBrowser.WebDashboard/jellyfin-web b/MediaBrowser.WebDashboard/jellyfin-web new file mode 120000 index 000000000..a1757cfbb --- /dev/null +++ b/MediaBrowser.WebDashboard/jellyfin-web @@ -0,0 +1 @@ +/home/telans/src/jellyfin-web/dist/ \ No newline at end of file diff --git a/RSSDP/DeviceAvailableEventArgs.cs b/RSSDP/DeviceAvailableEventArgs.cs index 21ac7c631..439cee467 100644 --- a/RSSDP/DeviceAvailableEventArgs.cs +++ b/RSSDP/DeviceAvailableEventArgs.cs @@ -54,6 +54,5 @@ namespace Rssdp } #endregion - } } diff --git a/RSSDP/DeviceEventArgs.cs b/RSSDP/DeviceEventArgs.cs index 05eb4a256..faeff8347 100644 --- a/RSSDP/DeviceEventArgs.cs +++ b/RSSDP/DeviceEventArgs.cs @@ -41,6 +41,5 @@ namespace Rssdp } #endregion - } } diff --git a/RSSDP/HttpRequestParser.cs b/RSSDP/HttpRequestParser.cs index 279ef883c..3fc328b8c 100644 --- a/RSSDP/HttpRequestParser.cs +++ b/RSSDP/HttpRequestParser.cs @@ -85,6 +85,5 @@ namespace Rssdp.Infrastructure } #endregion - } } diff --git a/RSSDP/ISsdpCommunicationsServer.cs b/RSSDP/ISsdpCommunicationsServer.cs index 8cf65df11..02c3af0e5 100644 --- a/RSSDP/ISsdpCommunicationsServer.cs +++ b/RSSDP/ISsdpCommunicationsServer.cs @@ -61,6 +61,5 @@ namespace Rssdp.Infrastructure bool IsShared { get; set; } #endregion - } } diff --git a/RSSDP/SsdpCommunicationsServer.cs b/RSSDP/SsdpCommunicationsServer.cs index 328e6137a..863f2b15c 100644 --- a/RSSDP/SsdpCommunicationsServer.cs +++ b/RSSDP/SsdpCommunicationsServer.cs @@ -195,11 +195,9 @@ namespace Rssdp.Infrastructure } catch (ObjectDisposedException) { - } catch (OperationCanceledException) { - } catch (Exception ex) { diff --git a/RSSDP/SsdpConstants.cs b/RSSDP/SsdpConstants.cs index 28a014fce..798f050e1 100644 --- a/RSSDP/SsdpConstants.cs +++ b/RSSDP/SsdpConstants.cs @@ -57,6 +57,5 @@ namespace Rssdp.Infrastructure internal const string SsdpByeByeNotification = "ssdp:byebye"; internal const int UdpResendCount = 3; - } } diff --git a/RSSDP/SsdpDevice.cs b/RSSDP/SsdpDevice.cs index 09f729e83..691ba2a14 100644 --- a/RSSDP/SsdpDevice.cs +++ b/RSSDP/SsdpDevice.cs @@ -349,6 +349,5 @@ namespace Rssdp } #endregion - } } diff --git a/RSSDP/SsdpDeviceLocator.cs b/RSSDP/SsdpDeviceLocator.cs index 4651d3bb6..a626e13b9 100644 --- a/RSSDP/SsdpDeviceLocator.cs +++ b/RSSDP/SsdpDeviceLocator.cs @@ -120,7 +120,6 @@ namespace Rssdp.Infrastructure } catch (Exception) { - } } @@ -613,6 +612,5 @@ namespace Rssdp.Infrastructure } #endregion - } } diff --git a/RSSDP/SsdpDevicePublisher.cs b/RSSDP/SsdpDevicePublisher.cs index 6a8cda835..5dfb6a8c2 100644 --- a/RSSDP/SsdpDevicePublisher.cs +++ b/RSSDP/SsdpDevicePublisher.cs @@ -335,7 +335,6 @@ namespace Rssdp.Infrastructure } catch (Exception) { - } // WriteTrace(String.Format("Sent search response to " + endPoint.ToString()), device); -- cgit v1.2.3 From 9b528aabc24c786c8617a9f87c2ce1eaba2c0b15 Mon Sep 17 00:00:00 2001 From: telans Date: Sun, 14 Jun 2020 22:14:14 +1200 Subject: misc --- MediaBrowser.Controller/SyncPlay/GroupInfo.cs | 6 +++--- MediaBrowser.Model/SyncPlay/GroupUpdateType.cs | 10 ++++++++++ MediaBrowser.Model/SyncPlay/PlaybackRequestType.cs | 7 ++++++- MediaBrowser.Model/SyncPlay/SendCommandType.cs | 2 ++ 4 files changed, 21 insertions(+), 4 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/SyncPlay/GroupInfo.cs b/MediaBrowser.Controller/SyncPlay/GroupInfo.cs index 28a3ac505..ef8df7d02 100644 --- a/MediaBrowser.Controller/SyncPlay/GroupInfo.cs +++ b/MediaBrowser.Controller/SyncPlay/GroupInfo.cs @@ -14,7 +14,7 @@ namespace MediaBrowser.Controller.SyncPlay public class GroupInfo { /// - /// Default ping value used for sessions. + /// Gets the default ping value used for sessions. /// public long DefaulPing { get; } = 500; @@ -31,13 +31,13 @@ namespace MediaBrowser.Controller.SyncPlay public BaseItem PlayingItem { get; set; } /// - /// Gets or sets whether playback is paused. + /// Gets or sets a value indicating whether playback is paused. /// /// Playback is paused. public bool IsPaused { get; set; } /// - /// Gets or sets the position ticks. + /// Gets or sets a value indicating whether there are position ticks. /// /// The position ticks. public long PositionTicks { get; set; } diff --git a/MediaBrowser.Model/SyncPlay/GroupUpdateType.cs b/MediaBrowser.Model/SyncPlay/GroupUpdateType.cs index 89d245787..c749f7b13 100644 --- a/MediaBrowser.Model/SyncPlay/GroupUpdateType.cs +++ b/MediaBrowser.Model/SyncPlay/GroupUpdateType.cs @@ -9,42 +9,52 @@ namespace MediaBrowser.Model.SyncPlay /// The user-joined update. Tells members of a group about a new user. /// UserJoined, + /// /// The user-left update. Tells members of a group that a user left. /// UserLeft, + /// /// The group-joined update. Tells a user that the group has been joined. /// GroupJoined, + /// /// The group-left update. Tells a user that the group has been left. /// GroupLeft, + /// /// The group-wait update. Tells members of the group that a user is buffering. /// GroupWait, + /// /// The prepare-session update. Tells a user to load some content. /// PrepareSession, + /// /// The not-in-group error. Tells a user that they don't belong to a group. /// NotInGroup, + /// /// The group-does-not-exist error. Sent when trying to join a non-existing group. /// GroupDoesNotExist, + /// /// The create-group-denied error. Sent when a user tries to create a group without required permissions. /// CreateGroupDenied, + /// /// The join-group-denied error. Sent when a user tries to join a group without required permissions. /// JoinGroupDenied, + /// /// The library-access-denied error. Sent when a user tries to join a group without required access to the library. /// diff --git a/MediaBrowser.Model/SyncPlay/PlaybackRequestType.cs b/MediaBrowser.Model/SyncPlay/PlaybackRequestType.cs index f1e175fde..671f4e01f 100644 --- a/MediaBrowser.Model/SyncPlay/PlaybackRequestType.cs +++ b/MediaBrowser.Model/SyncPlay/PlaybackRequestType.cs @@ -1,7 +1,7 @@ namespace MediaBrowser.Model.SyncPlay { /// - /// Enum PlaybackRequestType + /// Enum PlaybackRequestType. /// public enum PlaybackRequestType { @@ -9,22 +9,27 @@ namespace MediaBrowser.Model.SyncPlay /// A user is requesting a play command for the group. /// Play = 0, + /// /// A user is requesting a pause command for the group. /// Pause = 1, + /// /// A user is requesting a seek command for the group. /// Seek = 2, + /// /// A user is signaling that playback is buffering. /// Buffering = 3, + /// /// A user is signaling that playback resumed. /// BufferingDone = 4, + /// /// A user is reporting its ping. /// diff --git a/MediaBrowser.Model/SyncPlay/SendCommandType.cs b/MediaBrowser.Model/SyncPlay/SendCommandType.cs index 113719871..86dec9e90 100644 --- a/MediaBrowser.Model/SyncPlay/SendCommandType.cs +++ b/MediaBrowser.Model/SyncPlay/SendCommandType.cs @@ -9,10 +9,12 @@ namespace MediaBrowser.Model.SyncPlay /// The play command. Instructs users to start playback. /// Play = 0, + /// /// The pause command. Instructs users to pause playback. /// Pause = 1, + /// /// The seek command. Instructs users to seek to a specified time. /// -- cgit v1.2.3 From afc9224edea4156729264070b317929ff5eaf56e Mon Sep 17 00:00:00 2001 From: telans Date: Sun, 14 Jun 2020 22:20:19 +1200 Subject: fix SA1111 --- .../SyncPlay/SyncPlayController.cs | 24 ++++++++-------------- .../SyncPlay/SyncPlayManager.cs | 12 ++++------- MediaBrowser.Controller/Entities/BaseItem.cs | 3 +-- 3 files changed, 13 insertions(+), 26 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/SyncPlay/SyncPlayController.cs b/Emby.Server.Implementations/SyncPlay/SyncPlayController.cs index d0812a13f..b1f8fd330 100644 --- a/Emby.Server.Implementations/SyncPlay/SyncPlayController.cs +++ b/Emby.Server.Implementations/SyncPlay/SyncPlayController.cs @@ -102,20 +102,15 @@ namespace Emby.Server.Implementations.SyncPlay return new SessionInfo[] { from }; case BroadcastType.AllGroup: return _group.Participants.Values.Select( - session => session.Session - ).ToArray(); + session => session.Session).ToArray(); case BroadcastType.AllExceptCurrentSession: return _group.Participants.Values.Select( - session => session.Session - ).Where( - session => !session.Id.Equals(from.Id) - ).ToArray(); + session => session.Session).Where( + session => !session.Id.Equals(from.Id)).ToArray(); case BroadcastType.AllReady: return _group.Participants.Values.Where( - session => !session.IsBuffering - ).Select( - session => session.Session - ).ToArray(); + session => !session.IsBuffering).Select( + session => session.Session).ToArray(); default: return Array.Empty(); } @@ -314,8 +309,7 @@ namespace Emby.Server.Implementations.SyncPlay // Playback synchronization will mainly happen client side _group.IsPaused = false; _group.LastActivity = DateTime.UtcNow.AddMilliseconds( - delay - ); + delay); var command = NewSyncPlayCommand(SendCommandType.Play); SendCommand(session, BroadcastType.AllGroup, command, cancellationToken); @@ -449,8 +443,7 @@ namespace Emby.Server.Implementations.SyncPlay { // Client that was buffering is recovering, notifying others to resume _group.LastActivity = currentTime.AddMilliseconds( - delay - ); + delay); var command = NewSyncPlayCommand(SendCommandType.Play); SendCommand(session, BroadcastType.AllExceptCurrentSession, command, cancellationToken); } @@ -461,8 +454,7 @@ namespace Emby.Server.Implementations.SyncPlay delay = delay < _group.DefaulPing ? _group.DefaulPing : delay; _group.LastActivity = currentTime.AddMilliseconds( - delay - ); + delay); var command = NewSyncPlayCommand(SendCommandType.Play); SendCommand(session, BroadcastType.AllGroup, command, cancellationToken); diff --git a/Emby.Server.Implementations/SyncPlay/SyncPlayManager.cs b/Emby.Server.Implementations/SyncPlay/SyncPlayManager.cs index ecc3eeb39..45a43fd78 100644 --- a/Emby.Server.Implementations/SyncPlay/SyncPlayManager.cs +++ b/Emby.Server.Implementations/SyncPlay/SyncPlayManager.cs @@ -297,19 +297,15 @@ namespace Emby.Server.Implementations.SyncPlay if (!filterItemId.Equals(Guid.Empty)) { return _groups.Values.Where( - group => group.GetPlayingItemId().Equals(filterItemId) && HasAccessToItem(user, group.GetPlayingItemId()) - ).Select( - group => group.GetInfo() - ).ToList(); + group => group.GetPlayingItemId().Equals(filterItemId) && HasAccessToItem(user, group.GetPlayingItemId())).Select( + group => group.GetInfo()).ToList(); } // Otherwise show all available groups else { return _groups.Values.Where( - group => HasAccessToItem(user, group.GetPlayingItemId()) - ).Select( - group => group.GetInfo() - ).ToList(); + group => HasAccessToItem(user, group.GetPlayingItemId())).Select( + group => group.GetInfo()).ToList(); } } diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 3b08bd237..f2de1f2b1 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -1245,8 +1245,7 @@ namespace MediaBrowser.Controller.Entities // Support plex/xbmc convention files.AddRange(fileSystemChildren - .Where(i => !i.IsDirectory && string.Equals(FileSystem.GetFileNameWithoutExtension(i), ThemeSongFilename, StringComparison.OrdinalIgnoreCase)) - ); + .Where(i => !i.IsDirectory && string.Equals(FileSystem.GetFileNameWithoutExtension(i), ThemeSongFilename, StringComparison.OrdinalIgnoreCase))); return LibraryManager.ResolvePaths(files, directoryService, null, new LibraryOptions()) .OfType() -- cgit v1.2.3 From 4aac93672115d96ab77534f2b6a32a23482dab38 Mon Sep 17 00:00:00 2001 From: crobibero Date: Mon, 15 Jun 2020 12:49:54 -0600 Subject: Add more authorization handlers, actually authorize requests --- .../HttpServer/Security/AuthService.cs | 45 +++++---- Jellyfin.Api/Auth/BaseAuthorizationHandler.cs | 102 +++++++++++++++++++++ Jellyfin.Api/Auth/CustomAuthenticationHandler.cs | 25 ++--- .../DefaultAuthorizationHandler.cs | 42 +++++++++ .../DefaultAuthorizationRequirement.cs | 11 +++ .../FirstTimeSetupOrElevatedHandler.cs | 21 ++++- .../IgnoreSchedulePolicy/IgnoreScheduleHandler.cs | 42 +++++++++ .../IgnoreScheduleRequirement.cs | 11 +++ .../Auth/LocalAccessPolicy/LocalAccessHandler.cs | 44 +++++++++ .../LocalAccessPolicy/LocalAccessRequirement.cs | 11 +++ .../RequiresElevationHandler.cs | 26 +++++- Jellyfin.Api/Constants/InternalClaimTypes.cs | 38 ++++++++ Jellyfin.Api/Constants/Policies.cs | 15 +++ Jellyfin.Api/Helpers/ClaimHelpers.cs | 77 ++++++++++++++++ .../Extensions/ApiServiceCollectionExtensions.cs | 31 ++++++- MediaBrowser.Controller/Net/IAuthService.cs | 25 ++++- 16 files changed, 525 insertions(+), 41 deletions(-) create mode 100644 Jellyfin.Api/Auth/BaseAuthorizationHandler.cs create mode 100644 Jellyfin.Api/Auth/DefaultAuthorizationPolicy/DefaultAuthorizationHandler.cs create mode 100644 Jellyfin.Api/Auth/DefaultAuthorizationPolicy/DefaultAuthorizationRequirement.cs create mode 100644 Jellyfin.Api/Auth/IgnoreSchedulePolicy/IgnoreScheduleHandler.cs create mode 100644 Jellyfin.Api/Auth/IgnoreSchedulePolicy/IgnoreScheduleRequirement.cs create mode 100644 Jellyfin.Api/Auth/LocalAccessPolicy/LocalAccessHandler.cs create mode 100644 Jellyfin.Api/Auth/LocalAccessPolicy/LocalAccessRequirement.cs create mode 100644 Jellyfin.Api/Constants/InternalClaimTypes.cs create mode 100644 Jellyfin.Api/Helpers/ClaimHelpers.cs (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/HttpServer/Security/AuthService.cs b/Emby.Server.Implementations/HttpServer/Security/AuthService.cs index c65d4694a..6a2d8fdbb 100644 --- a/Emby.Server.Implementations/HttpServer/Security/AuthService.cs +++ b/Emby.Server.Implementations/HttpServer/Security/AuthService.cs @@ -39,9 +39,9 @@ namespace Emby.Server.Implementations.HttpServer.Security _networkManager = networkManager; } - public void Authenticate(IRequest request, IAuthenticationAttributes authAttribtues) + public void Authenticate(IRequest request, IAuthenticationAttributes authAttributes) { - ValidateUser(request, authAttribtues); + ValidateUser(request, authAttributes); } public User Authenticate(HttpRequest request, IAuthenticationAttributes authAttributes) @@ -51,17 +51,33 @@ namespace Emby.Server.Implementations.HttpServer.Security return user; } - private User ValidateUser(IRequest request, IAuthenticationAttributes authAttribtues) + public AuthorizationInfo Authenticate(HttpRequest request) + { + var auth = _authorizationContext.GetAuthorizationInfo(request); + if (auth?.User == null) + { + return null; + } + + if (auth.User.HasPermission(PermissionKind.IsDisabled)) + { + throw new SecurityException("User account has been disabled."); + } + + return auth; + } + + private User ValidateUser(IRequest request, IAuthenticationAttributes authAttributes) { // This code is executed before the service var auth = _authorizationContext.GetAuthorizationInfo(request); - if (!IsExemptFromAuthenticationToken(authAttribtues, request)) + if (!IsExemptFromAuthenticationToken(authAttributes, request)) { ValidateSecurityToken(request, auth.Token); } - if (authAttribtues.AllowLocalOnly && !request.IsLocal) + if (authAttributes.AllowLocalOnly && !request.IsLocal) { throw new SecurityException("Operation not found."); } @@ -75,14 +91,14 @@ namespace Emby.Server.Implementations.HttpServer.Security if (user != null) { - ValidateUserAccess(user, request, authAttribtues, auth); + ValidateUserAccess(user, request, authAttributes); } var info = GetTokenInfo(request); - if (!IsExemptFromRoles(auth, authAttribtues, request, info)) + if (!IsExemptFromRoles(auth, authAttributes, request, info)) { - var roles = authAttribtues.GetRoles(); + var roles = authAttributes.GetRoles(); ValidateRoles(roles, user); } @@ -106,8 +122,7 @@ namespace Emby.Server.Implementations.HttpServer.Security private void ValidateUserAccess( User user, IRequest request, - IAuthenticationAttributes authAttributes, - AuthorizationInfo auth) + IAuthenticationAttributes authAttributes) { if (user.HasPermission(PermissionKind.IsDisabled)) { @@ -230,16 +245,6 @@ namespace Emby.Server.Implementations.HttpServer.Security { throw new AuthenticationException("Access token is invalid or expired."); } - - //if (!string.IsNullOrEmpty(info.UserId)) - //{ - // var user = _userManager.GetUserById(info.UserId); - - // if (user == null || user.Configuration.IsDisabled) - // { - // throw new SecurityException("User account has been disabled."); - // } - //} } } } diff --git a/Jellyfin.Api/Auth/BaseAuthorizationHandler.cs b/Jellyfin.Api/Auth/BaseAuthorizationHandler.cs new file mode 100644 index 000000000..b5b9d8904 --- /dev/null +++ b/Jellyfin.Api/Auth/BaseAuthorizationHandler.cs @@ -0,0 +1,102 @@ +#nullable enable + +using System.Net; +using System.Security.Claims; +using Jellyfin.Api.Helpers; +using Jellyfin.Data.Enums; +using MediaBrowser.Common.Net; +using MediaBrowser.Controller.Library; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http; + +namespace Jellyfin.Api.Auth +{ + /// + /// Base authorization handler. + /// + /// Type of Authorization Requirement. + public abstract class BaseAuthorizationHandler : AuthorizationHandler + where T : IAuthorizationRequirement + { + private readonly IUserManager _userManager; + private readonly INetworkManager _networkManager; + private readonly IHttpContextAccessor _httpContextAccessor; + + /// + /// Initializes a new instance of the class. + /// + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + protected BaseAuthorizationHandler( + IUserManager userManager, + INetworkManager networkManager, + IHttpContextAccessor httpContextAccessor) + { + _userManager = userManager; + _networkManager = networkManager; + _httpContextAccessor = httpContextAccessor; + } + + /// + /// Validate authenticated claims. + /// + /// Request claims. + /// Whether to ignore parental control. + /// Whether access is to be allowed locally only. + /// Validated claim status. + protected bool ValidateClaims( + ClaimsPrincipal claimsPrincipal, + bool ignoreSchedule = false, + bool localAccessOnly = false) + { + // Ensure claim has userId. + var userId = ClaimHelpers.GetUserId(claimsPrincipal); + if (userId == null) + { + return false; + } + + // Ensure userId links to a valid user. + var user = _userManager.GetUserById(userId.Value); + if (user == null) + { + return false; + } + + // Ensure user is not disabled. + if (user.HasPermission(PermissionKind.IsDisabled)) + { + return false; + } + + var ip = NormalizeIp(_httpContextAccessor.HttpContext.Connection.RemoteIpAddress).ToString(); + var isInLocalNetwork = _networkManager.IsInLocalNetwork(ip); + // User cannot access remotely and user is remote + if (!user.HasPermission(PermissionKind.EnableRemoteAccess) && !isInLocalNetwork) + { + return false; + } + + if (localAccessOnly && !isInLocalNetwork) + { + return false; + } + + // User attempting to access out of parental control hours. + if (!ignoreSchedule + && !user.HasPermission(PermissionKind.IsAdministrator) + && !user.IsParentalScheduleAllowed()) + { + return false; + } + + return true; + } + + private static IPAddress NormalizeIp(IPAddress ip) + { + return ip.IsIPv4MappedToIPv6 ? ip.MapToIPv4() : ip; + } + } +} diff --git a/Jellyfin.Api/Auth/CustomAuthenticationHandler.cs b/Jellyfin.Api/Auth/CustomAuthenticationHandler.cs index a5c4e9974..d4d40da57 100644 --- a/Jellyfin.Api/Auth/CustomAuthenticationHandler.cs +++ b/Jellyfin.Api/Auth/CustomAuthenticationHandler.cs @@ -1,3 +1,6 @@ +#nullable enable + +using System.Globalization; using System.Security.Authentication; using System.Security.Claims; using System.Text.Encodings.Web; @@ -39,15 +42,10 @@ namespace Jellyfin.Api.Auth /// protected override Task HandleAuthenticateAsync() { - var authenticatedAttribute = new AuthenticatedAttribute - { - IgnoreLegacyAuth = true - }; - try { - var user = _authService.Authenticate(Request, authenticatedAttribute); - if (user == null) + var authorizationInfo = _authService.Authenticate(Request); + if (authorizationInfo == null) { return Task.FromResult(AuthenticateResult.NoResult()); // TODO return when legacy API is removed. @@ -57,11 +55,16 @@ namespace Jellyfin.Api.Auth var claims = new[] { - new Claim(ClaimTypes.Name, user.Username), - new Claim( - ClaimTypes.Role, - value: user.HasPermission(PermissionKind.IsAdministrator) ? UserRoles.Administrator : UserRoles.User) + new Claim(ClaimTypes.Name, authorizationInfo.User.Username), + new Claim(ClaimTypes.Role, value: authorizationInfo.User.HasPermission(PermissionKind.IsAdministrator) ? UserRoles.Administrator : UserRoles.User), + new Claim(InternalClaimTypes.UserId, authorizationInfo.UserId.ToString("N", CultureInfo.InvariantCulture)), + new Claim(InternalClaimTypes.DeviceId, authorizationInfo.DeviceId), + new Claim(InternalClaimTypes.Device, authorizationInfo.Device), + new Claim(InternalClaimTypes.Client, authorizationInfo.Client), + new Claim(InternalClaimTypes.Version, authorizationInfo.Version), + new Claim(InternalClaimTypes.Token, authorizationInfo.Token) }; + var identity = new ClaimsIdentity(claims, Scheme.Name); var principal = new ClaimsPrincipal(identity); var ticket = new AuthenticationTicket(principal, Scheme.Name); diff --git a/Jellyfin.Api/Auth/DefaultAuthorizationPolicy/DefaultAuthorizationHandler.cs b/Jellyfin.Api/Auth/DefaultAuthorizationPolicy/DefaultAuthorizationHandler.cs new file mode 100644 index 000000000..b5913daab --- /dev/null +++ b/Jellyfin.Api/Auth/DefaultAuthorizationPolicy/DefaultAuthorizationHandler.cs @@ -0,0 +1,42 @@ +using System.Threading.Tasks; +using MediaBrowser.Common.Net; +using MediaBrowser.Controller.Library; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http; + +namespace Jellyfin.Api.Auth.DefaultAuthorizationPolicy +{ + /// + /// Default authorization handler. + /// + public class DefaultAuthorizationHandler : BaseAuthorizationHandler + { + /// + /// Initializes a new instance of the class. + /// + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + public DefaultAuthorizationHandler( + IUserManager userManager, + INetworkManager networkManager, + IHttpContextAccessor httpContextAccessor) + : base(userManager, networkManager, httpContextAccessor) + { + } + + /// + protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, DefaultAuthorizationRequirement requirement) + { + var validated = ValidateClaims(context.User); + if (!validated) + { + context.Fail(); + return Task.CompletedTask; + } + + context.Succeed(requirement); + return Task.CompletedTask; + } + } +} diff --git a/Jellyfin.Api/Auth/DefaultAuthorizationPolicy/DefaultAuthorizationRequirement.cs b/Jellyfin.Api/Auth/DefaultAuthorizationPolicy/DefaultAuthorizationRequirement.cs new file mode 100644 index 000000000..7cea00b69 --- /dev/null +++ b/Jellyfin.Api/Auth/DefaultAuthorizationPolicy/DefaultAuthorizationRequirement.cs @@ -0,0 +1,11 @@ +using Microsoft.AspNetCore.Authorization; + +namespace Jellyfin.Api.Auth.DefaultAuthorizationPolicy +{ + /// + /// The default authorization requirement. + /// + public class DefaultAuthorizationRequirement : IAuthorizationRequirement + { + } +} diff --git a/Jellyfin.Api/Auth/FirstTimeSetupOrElevatedPolicy/FirstTimeSetupOrElevatedHandler.cs b/Jellyfin.Api/Auth/FirstTimeSetupOrElevatedPolicy/FirstTimeSetupOrElevatedHandler.cs index 34aa5d12c..0b12f7d3c 100644 --- a/Jellyfin.Api/Auth/FirstTimeSetupOrElevatedPolicy/FirstTimeSetupOrElevatedHandler.cs +++ b/Jellyfin.Api/Auth/FirstTimeSetupOrElevatedPolicy/FirstTimeSetupOrElevatedHandler.cs @@ -1,22 +1,33 @@ using System.Threading.Tasks; using Jellyfin.Api.Constants; using MediaBrowser.Common.Configuration; +using MediaBrowser.Common.Net; +using MediaBrowser.Controller.Library; using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http; namespace Jellyfin.Api.Auth.FirstTimeSetupOrElevatedPolicy { /// /// Authorization handler for requiring first time setup or elevated privileges. /// - public class FirstTimeSetupOrElevatedHandler : AuthorizationHandler + public class FirstTimeSetupOrElevatedHandler : BaseAuthorizationHandler { private readonly IConfigurationManager _configurationManager; /// /// Initializes a new instance of the class. /// - /// The jellyfin configuration manager. - public FirstTimeSetupOrElevatedHandler(IConfigurationManager configurationManager) + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + public FirstTimeSetupOrElevatedHandler( + IConfigurationManager configurationManager, + IUserManager userManager, + INetworkManager networkManager, + IHttpContextAccessor httpContextAccessor) + : base(userManager, networkManager, httpContextAccessor) { _configurationManager = configurationManager; } @@ -28,7 +39,9 @@ namespace Jellyfin.Api.Auth.FirstTimeSetupOrElevatedPolicy { context.Succeed(firstTimeSetupOrElevatedRequirement); } - else if (context.User.IsInRole(UserRoles.Administrator)) + + var validated = ValidateClaims(context.User); + if (validated && context.User.IsInRole(UserRoles.Administrator)) { context.Succeed(firstTimeSetupOrElevatedRequirement); } diff --git a/Jellyfin.Api/Auth/IgnoreSchedulePolicy/IgnoreScheduleHandler.cs b/Jellyfin.Api/Auth/IgnoreSchedulePolicy/IgnoreScheduleHandler.cs new file mode 100644 index 000000000..9afa0b28f --- /dev/null +++ b/Jellyfin.Api/Auth/IgnoreSchedulePolicy/IgnoreScheduleHandler.cs @@ -0,0 +1,42 @@ +using System.Threading.Tasks; +using MediaBrowser.Common.Net; +using MediaBrowser.Controller.Library; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http; + +namespace Jellyfin.Api.Auth.IgnoreSchedulePolicy +{ + /// + /// Escape schedule controls handler. + /// + public class IgnoreScheduleHandler : BaseAuthorizationHandler + { + /// + /// Initializes a new instance of the class. + /// + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + public IgnoreScheduleHandler( + IUserManager userManager, + INetworkManager networkManager, + IHttpContextAccessor httpContextAccessor) + : base(userManager, networkManager, httpContextAccessor) + { + } + + /// + protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, IgnoreScheduleRequirement requirement) + { + var validated = ValidateClaims(context.User, ignoreSchedule: true); + if (!validated) + { + context.Fail(); + return Task.CompletedTask; + } + + context.Succeed(requirement); + return Task.CompletedTask; + } + } +} diff --git a/Jellyfin.Api/Auth/IgnoreSchedulePolicy/IgnoreScheduleRequirement.cs b/Jellyfin.Api/Auth/IgnoreSchedulePolicy/IgnoreScheduleRequirement.cs new file mode 100644 index 000000000..d5bb61ce6 --- /dev/null +++ b/Jellyfin.Api/Auth/IgnoreSchedulePolicy/IgnoreScheduleRequirement.cs @@ -0,0 +1,11 @@ +using Microsoft.AspNetCore.Authorization; + +namespace Jellyfin.Api.Auth.IgnoreSchedulePolicy +{ + /// + /// Escape schedule controls requirement. + /// + public class IgnoreScheduleRequirement : IAuthorizationRequirement + { + } +} diff --git a/Jellyfin.Api/Auth/LocalAccessPolicy/LocalAccessHandler.cs b/Jellyfin.Api/Auth/LocalAccessPolicy/LocalAccessHandler.cs new file mode 100644 index 000000000..af73352bc --- /dev/null +++ b/Jellyfin.Api/Auth/LocalAccessPolicy/LocalAccessHandler.cs @@ -0,0 +1,44 @@ +using System.Threading.Tasks; +using MediaBrowser.Common.Net; +using MediaBrowser.Controller.Library; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http; + +namespace Jellyfin.Api.Auth.LocalAccessPolicy +{ + /// + /// Local access handler. + /// + public class LocalAccessHandler : BaseAuthorizationHandler + { + /// + /// Initializes a new instance of the class. + /// + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + public LocalAccessHandler( + IUserManager userManager, + INetworkManager networkManager, + IHttpContextAccessor httpContextAccessor) + : base(userManager, networkManager, httpContextAccessor) + { + } + + /// + protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, LocalAccessRequirement requirement) + { + var validated = ValidateClaims(context.User, localAccessOnly: true); + if (!validated) + { + context.Fail(); + } + else + { + context.Succeed(requirement); + } + + return Task.CompletedTask; + } + } +} diff --git a/Jellyfin.Api/Auth/LocalAccessPolicy/LocalAccessRequirement.cs b/Jellyfin.Api/Auth/LocalAccessPolicy/LocalAccessRequirement.cs new file mode 100644 index 000000000..761127fa4 --- /dev/null +++ b/Jellyfin.Api/Auth/LocalAccessPolicy/LocalAccessRequirement.cs @@ -0,0 +1,11 @@ +using Microsoft.AspNetCore.Authorization; + +namespace Jellyfin.Api.Auth.LocalAccessPolicy +{ + /// + /// The local access authorization requirement. + /// + public class LocalAccessRequirement : IAuthorizationRequirement + { + } +} diff --git a/Jellyfin.Api/Auth/RequiresElevationPolicy/RequiresElevationHandler.cs b/Jellyfin.Api/Auth/RequiresElevationPolicy/RequiresElevationHandler.cs index 2d3bb1aa4..b235c4b63 100644 --- a/Jellyfin.Api/Auth/RequiresElevationPolicy/RequiresElevationHandler.cs +++ b/Jellyfin.Api/Auth/RequiresElevationPolicy/RequiresElevationHandler.cs @@ -1,21 +1,43 @@ using System.Threading.Tasks; using Jellyfin.Api.Constants; +using MediaBrowser.Common.Net; +using MediaBrowser.Controller.Library; using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http; namespace Jellyfin.Api.Auth.RequiresElevationPolicy { /// /// Authorization handler for requiring elevated privileges. /// - public class RequiresElevationHandler : AuthorizationHandler + public class RequiresElevationHandler : BaseAuthorizationHandler { + /// + /// Initializes a new instance of the class. + /// + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + public RequiresElevationHandler( + IUserManager userManager, + INetworkManager networkManager, + IHttpContextAccessor httpContextAccessor) + : base(userManager, networkManager, httpContextAccessor) + { + } + /// protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, RequiresElevationRequirement requirement) { - if (context.User.IsInRole(UserRoles.Administrator)) + var validated = ValidateClaims(context.User); + if (validated && context.User.IsInRole(UserRoles.Administrator)) { context.Succeed(requirement); } + else + { + context.Fail(); + } return Task.CompletedTask; } diff --git a/Jellyfin.Api/Constants/InternalClaimTypes.cs b/Jellyfin.Api/Constants/InternalClaimTypes.cs new file mode 100644 index 000000000..4d7c7135d --- /dev/null +++ b/Jellyfin.Api/Constants/InternalClaimTypes.cs @@ -0,0 +1,38 @@ +namespace Jellyfin.Api.Constants +{ + /// + /// Internal claim types for authorization. + /// + public static class InternalClaimTypes + { + /// + /// User Id. + /// + public const string UserId = "Jellyfin-UserId"; + + /// + /// Device Id. + /// + public const string DeviceId = "Jellyfin-DeviceId"; + + /// + /// Device. + /// + public const string Device = "Jellyfin-Device"; + + /// + /// Client. + /// + public const string Client = "Jellyfin-Client"; + + /// + /// Version. + /// + public const string Version = "Jellyfin-Version"; + + /// + /// Token. + /// + public const string Token = "Jellyfin-Token"; + } +} diff --git a/Jellyfin.Api/Constants/Policies.cs b/Jellyfin.Api/Constants/Policies.cs index e2b383f75..cf574e43d 100644 --- a/Jellyfin.Api/Constants/Policies.cs +++ b/Jellyfin.Api/Constants/Policies.cs @@ -5,6 +5,11 @@ namespace Jellyfin.Api.Constants /// public static class Policies { + /// + /// Policy name for default authorization. + /// + public const string DefaultAuthorization = "DefaultAuthorization"; + /// /// Policy name for requiring first time setup or elevated privileges. /// @@ -14,5 +19,15 @@ namespace Jellyfin.Api.Constants /// Policy name for requiring elevated privileges. /// public const string RequiresElevation = "RequiresElevation"; + + /// + /// Policy name for allowing local access only. + /// + public const string LocalAccessOnly = "LocalAccessOnly"; + + /// + /// Policy name for escaping schedule controls. + /// + public const string IgnoreSchedule = "IgnoreSchedule"; } } diff --git a/Jellyfin.Api/Helpers/ClaimHelpers.cs b/Jellyfin.Api/Helpers/ClaimHelpers.cs new file mode 100644 index 000000000..a07d4ed82 --- /dev/null +++ b/Jellyfin.Api/Helpers/ClaimHelpers.cs @@ -0,0 +1,77 @@ +#nullable enable + +using System; +using System.Linq; +using System.Security.Claims; +using Jellyfin.Api.Constants; + +namespace Jellyfin.Api.Helpers +{ + /// + /// Claim Helpers. + /// + public static class ClaimHelpers + { + /// + /// Get user id from claims. + /// + /// Current claims principal. + /// User id. + public static Guid? GetUserId(in ClaimsPrincipal user) + { + var value = GetClaimValue(user, InternalClaimTypes.UserId); + return string.IsNullOrEmpty(value) + ? null + : (Guid?)Guid.Parse(value); + } + + /// + /// Get device id from claims. + /// + /// Current claims principal. + /// Device id. + public static string? GetDeviceId(in ClaimsPrincipal user) + => GetClaimValue(user, InternalClaimTypes.DeviceId); + + /// + /// Get device from claims. + /// + /// Current claims principal. + /// Device. + public static string? GetDevice(in ClaimsPrincipal user) + => GetClaimValue(user, InternalClaimTypes.Device); + + /// + /// Get client from claims. + /// + /// Current claims principal. + /// Client. + public static string? GetClient(in ClaimsPrincipal user) + => GetClaimValue(user, InternalClaimTypes.Client); + + /// + /// Get version from claims. + /// + /// Current claims principal. + /// Version. + public static string? GetVersion(in ClaimsPrincipal user) + => GetClaimValue(user, InternalClaimTypes.Version); + + /// + /// Get token from claims. + /// + /// Current claims principal. + /// Token. + public static string? GetToken(in ClaimsPrincipal user) + => GetClaimValue(user, InternalClaimTypes.Token); + + private static string? GetClaimValue(in ClaimsPrincipal user, string name) + { + return user?.Identities + .SelectMany(c => c.Claims) + .Where(claim => claim.Type.Equals(name, StringComparison.OrdinalIgnoreCase)) + .Select(claim => claim.Value) + .FirstOrDefault(); + } + } +} diff --git a/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs b/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs index 9cdaa0eb1..1ec77d716 100644 --- a/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs +++ b/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs @@ -5,7 +5,10 @@ using System.Linq; using System.Reflection; using Jellyfin.Api; using Jellyfin.Api.Auth; +using Jellyfin.Api.Auth.DefaultAuthorizationPolicy; using Jellyfin.Api.Auth.FirstTimeSetupOrElevatedPolicy; +using Jellyfin.Api.Auth.IgnoreSchedulePolicy; +using Jellyfin.Api.Auth.LocalAccessPolicy; using Jellyfin.Api.Auth.RequiresElevationPolicy; using Jellyfin.Api.Constants; using Jellyfin.Api.Controllers; @@ -33,16 +36,19 @@ namespace Jellyfin.Server.Extensions /// The updated service collection. public static IServiceCollection AddJellyfinApiAuthorization(this IServiceCollection serviceCollection) { + serviceCollection.AddSingleton(); serviceCollection.AddSingleton(); + serviceCollection.AddSingleton(); + serviceCollection.AddSingleton(); serviceCollection.AddSingleton(); return serviceCollection.AddAuthorizationCore(options => { options.AddPolicy( - Policies.RequiresElevation, + Policies.DefaultAuthorization, policy => { policy.AddAuthenticationSchemes(AuthenticationSchemes.CustomAuthentication); - policy.AddRequirements(new RequiresElevationRequirement()); + policy.AddRequirements(new DefaultAuthorizationRequirement()); }); options.AddPolicy( Policies.FirstTimeSetupOrElevated, @@ -51,6 +57,27 @@ namespace Jellyfin.Server.Extensions policy.AddAuthenticationSchemes(AuthenticationSchemes.CustomAuthentication); policy.AddRequirements(new FirstTimeSetupOrElevatedRequirement()); }); + options.AddPolicy( + Policies.IgnoreSchedule, + policy => + { + policy.AddAuthenticationSchemes(AuthenticationSchemes.CustomAuthentication); + policy.AddRequirements(new IgnoreScheduleRequirement()); + }); + options.AddPolicy( + Policies.LocalAccessOnly, + policy => + { + policy.AddAuthenticationSchemes(AuthenticationSchemes.CustomAuthentication); + policy.AddRequirements(new LocalAccessRequirement()); + }); + options.AddPolicy( + Policies.RequiresElevation, + policy => + { + policy.AddAuthenticationSchemes(AuthenticationSchemes.CustomAuthentication); + policy.AddRequirements(new RequiresElevationRequirement()); + }); }); } diff --git a/MediaBrowser.Controller/Net/IAuthService.cs b/MediaBrowser.Controller/Net/IAuthService.cs index d8f6d19da..2055a656a 100644 --- a/MediaBrowser.Controller/Net/IAuthService.cs +++ b/MediaBrowser.Controller/Net/IAuthService.cs @@ -6,10 +6,31 @@ using Microsoft.AspNetCore.Http; namespace MediaBrowser.Controller.Net { + /// + /// IAuthService. + /// public interface IAuthService { - void Authenticate(IRequest request, IAuthenticationAttributes authAttribtues); + /// + /// Authenticate and authorize request. + /// + /// Request. + /// Authorization attributes. + void Authenticate(IRequest request, IAuthenticationAttributes authAttribtutes); - User? Authenticate(HttpRequest request, IAuthenticationAttributes authAttribtues); + /// + /// Authenticate and authorize request. + /// + /// Request. + /// Authorization attributes. + /// Authenticated user. + User? Authenticate(HttpRequest request, IAuthenticationAttributes authAttribtutes); + + /// + /// Authenticate request. + /// + /// The request. + /// Authorization information. Null if unauthenticated. + AuthorizationInfo Authenticate(HttpRequest request); } } -- cgit v1.2.3 From a8adbef74fc8300190c463a9c585b55dcfb0c78e Mon Sep 17 00:00:00 2001 From: crobibero Date: Mon, 15 Jun 2020 13:21:18 -0600 Subject: Add GetAuthorizationInfo for netcore HttpRequest --- .../HttpServer/Security/AuthorizationContext.cs | 132 +++++++++++++++------ .../Net/IAuthorizationContext.cs | 11 ++ 2 files changed, 104 insertions(+), 39 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs b/Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs index 9558cb4c6..deb9b5ebb 100644 --- a/Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs +++ b/Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs @@ -8,6 +8,7 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Net; using MediaBrowser.Controller.Security; using MediaBrowser.Model.Services; +using Microsoft.AspNetCore.Http; using Microsoft.Net.Http.Headers; namespace Emby.Server.Implementations.HttpServer.Security @@ -38,6 +39,14 @@ namespace Emby.Server.Implementations.HttpServer.Security return GetAuthorization(requestContext); } + public AuthorizationInfo GetAuthorizationInfo(HttpRequest requestContext) + { + var auth = GetAuthorizationDictionary(requestContext); + var (authInfo, _) = + GetAuthorizationInfoFromDictionary(auth, requestContext.Headers, requestContext.Query); + return authInfo; + } + /// /// Gets the authorization. /// @@ -46,7 +55,23 @@ namespace Emby.Server.Implementations.HttpServer.Security private AuthorizationInfo GetAuthorization(IRequest httpReq) { var auth = GetAuthorizationDictionary(httpReq); + var (authInfo, originalAuthInfo) = + GetAuthorizationInfoFromDictionary(auth, httpReq.Headers, httpReq.QueryString); + + if (originalAuthInfo != null) + { + httpReq.Items["OriginalAuthenticationInfo"] = originalAuthInfo; + } + httpReq.Items["AuthorizationInfo"] = authInfo; + return authInfo; + } + + private (AuthorizationInfo authInfo, AuthenticationInfo originalAuthenticationInfo) GetAuthorizationInfoFromDictionary( + in Dictionary auth, + in IHeaderDictionary headers, + in IQueryCollection queryString) + { string deviceId = null; string device = null; string client = null; @@ -64,19 +89,31 @@ namespace Emby.Server.Implementations.HttpServer.Security if (string.IsNullOrEmpty(token)) { - token = httpReq.Headers["X-Emby-Token"]; + token = headers["X-Jellyfin-Token"]; + } + + if (string.IsNullOrEmpty(token)) + { + token = headers["X-Emby-Token"]; } if (string.IsNullOrEmpty(token)) { - token = httpReq.Headers["X-MediaBrowser-Token"]; + token = headers["X-MediaBrowser-Token"]; } + if (string.IsNullOrEmpty(token)) { - token = httpReq.QueryString["api_key"]; + token = queryString["ApiKey"]; } - var info = new AuthorizationInfo + // TODO depricate this query parameter. + if (string.IsNullOrEmpty(token)) + { + token = queryString["api_key"]; + } + + var authInfo = new AuthorizationInfo { Client = client, Device = device, @@ -85,6 +122,7 @@ namespace Emby.Server.Implementations.HttpServer.Security Token = token }; + AuthenticationInfo originalAuthenticationInfo = null; if (!string.IsNullOrWhiteSpace(token)) { var result = _authRepo.Get(new AuthenticationInfoQuery @@ -92,81 +130,77 @@ namespace Emby.Server.Implementations.HttpServer.Security AccessToken = token }); - var tokenInfo = result.Items.Count > 0 ? result.Items[0] : null; + originalAuthenticationInfo = result.Items.Count > 0 ? result.Items[0] : null; - if (tokenInfo != null) + if (originalAuthenticationInfo != null) { var updateToken = false; // TODO: Remove these checks for IsNullOrWhiteSpace - if (string.IsNullOrWhiteSpace(info.Client)) + if (string.IsNullOrWhiteSpace(authInfo.Client)) { - info.Client = tokenInfo.AppName; + authInfo.Client = originalAuthenticationInfo.AppName; } - if (string.IsNullOrWhiteSpace(info.DeviceId)) + if (string.IsNullOrWhiteSpace(authInfo.DeviceId)) { - info.DeviceId = tokenInfo.DeviceId; + authInfo.DeviceId = originalAuthenticationInfo.DeviceId; } // Temporary. TODO - allow clients to specify that the token has been shared with a casting device - var allowTokenInfoUpdate = info.Client == null || info.Client.IndexOf("chromecast", StringComparison.OrdinalIgnoreCase) == -1; + var allowTokenInfoUpdate = authInfo.Client == null || authInfo.Client.IndexOf("chromecast", StringComparison.OrdinalIgnoreCase) == -1; - if (string.IsNullOrWhiteSpace(info.Device)) + if (string.IsNullOrWhiteSpace(authInfo.Device)) { - info.Device = tokenInfo.DeviceName; + authInfo.Device = originalAuthenticationInfo.DeviceName; } - - else if (!string.Equals(info.Device, tokenInfo.DeviceName, StringComparison.OrdinalIgnoreCase)) + else if (!string.Equals(authInfo.Device, originalAuthenticationInfo.DeviceName, StringComparison.OrdinalIgnoreCase)) { if (allowTokenInfoUpdate) { updateToken = true; - tokenInfo.DeviceName = info.Device; + originalAuthenticationInfo.DeviceName = authInfo.Device; } } - if (string.IsNullOrWhiteSpace(info.Version)) + if (string.IsNullOrWhiteSpace(authInfo.Version)) { - info.Version = tokenInfo.AppVersion; + authInfo.Version = originalAuthenticationInfo.AppVersion; } - else if (!string.Equals(info.Version, tokenInfo.AppVersion, StringComparison.OrdinalIgnoreCase)) + else if (!string.Equals(authInfo.Version, originalAuthenticationInfo.AppVersion, StringComparison.OrdinalIgnoreCase)) { if (allowTokenInfoUpdate) { updateToken = true; - tokenInfo.AppVersion = info.Version; + originalAuthenticationInfo.AppVersion = authInfo.Version; } } - if ((DateTime.UtcNow - tokenInfo.DateLastActivity).TotalMinutes > 3) + if ((DateTime.UtcNow - originalAuthenticationInfo.DateLastActivity).TotalMinutes > 3) { - tokenInfo.DateLastActivity = DateTime.UtcNow; + originalAuthenticationInfo.DateLastActivity = DateTime.UtcNow; updateToken = true; } - if (!tokenInfo.UserId.Equals(Guid.Empty)) + if (!originalAuthenticationInfo.UserId.Equals(Guid.Empty)) { - info.User = _userManager.GetUserById(tokenInfo.UserId); + authInfo.User = _userManager.GetUserById(originalAuthenticationInfo.UserId); - if (info.User != null && !string.Equals(info.User.Username, tokenInfo.UserName, StringComparison.OrdinalIgnoreCase)) + if (authInfo.User != null && !string.Equals(authInfo.User.Username, originalAuthenticationInfo.UserName, StringComparison.OrdinalIgnoreCase)) { - tokenInfo.UserName = info.User.Username; + originalAuthenticationInfo.UserName = authInfo.User.Username; updateToken = true; } } if (updateToken) { - _authRepo.Update(tokenInfo); + _authRepo.Update(originalAuthenticationInfo); } } - httpReq.Items["OriginalAuthenticationInfo"] = tokenInfo; } - httpReq.Items["AuthorizationInfo"] = info; - - return info; + return (authInfo, originalAuthenticationInfo); } /// @@ -176,7 +210,32 @@ namespace Emby.Server.Implementations.HttpServer.Security /// Dictionary{System.StringSystem.String}. private Dictionary GetAuthorizationDictionary(IRequest httpReq) { - var auth = httpReq.Headers["X-Emby-Authorization"]; + var auth = httpReq.Headers["X-Jellyfin-Authorization"]; + if (string.IsNullOrEmpty(auth)) + { + auth = httpReq.Headers["X-Emby-Authorization"]; + } + + if (string.IsNullOrEmpty(auth)) + { + auth = httpReq.Headers[HeaderNames.Authorization]; + } + + return GetAuthorization(auth); + } + + /// + /// Gets the auth. + /// + /// The HTTP req. + /// Dictionary{System.StringSystem.String}. + private Dictionary GetAuthorizationDictionary(HttpRequest httpReq) + { + var auth = httpReq.Headers["X-Jellyfin-Authorization"]; + if (string.IsNullOrEmpty(auth)) + { + auth = httpReq.Headers["X-Emby-Authorization"]; + } if (string.IsNullOrEmpty(auth)) { @@ -206,7 +265,7 @@ namespace Emby.Server.Implementations.HttpServer.Security return null; } - var acceptedNames = new[] { "MediaBrowser", "Emby" }; + var acceptedNames = new[] { "MediaBrowser", "Emby", "Jellyfin" }; // It has to be a digest request if (!acceptedNames.Contains(parts[0], StringComparer.OrdinalIgnoreCase)) @@ -236,12 +295,7 @@ namespace Emby.Server.Implementations.HttpServer.Security private static string NormalizeValue(string value) { - if (string.IsNullOrEmpty(value)) - { - return value; - } - - return WebUtility.HtmlEncode(value); + return string.IsNullOrEmpty(value) ? value : WebUtility.HtmlEncode(value); } } } diff --git a/MediaBrowser.Controller/Net/IAuthorizationContext.cs b/MediaBrowser.Controller/Net/IAuthorizationContext.cs index 61598391f..37a7425b9 100644 --- a/MediaBrowser.Controller/Net/IAuthorizationContext.cs +++ b/MediaBrowser.Controller/Net/IAuthorizationContext.cs @@ -1,7 +1,11 @@ using MediaBrowser.Model.Services; +using Microsoft.AspNetCore.Http; namespace MediaBrowser.Controller.Net { + /// + /// IAuthorization context. + /// public interface IAuthorizationContext { /// @@ -17,5 +21,12 @@ namespace MediaBrowser.Controller.Net /// The request context. /// AuthorizationInfo. AuthorizationInfo GetAuthorizationInfo(IRequest requestContext); + + /// + /// Gets the authorization information. + /// + /// The request context. + /// AuthorizationInfo. + AuthorizationInfo GetAuthorizationInfo(HttpRequest requestContext); } } -- cgit v1.2.3 From 9018f8d8be10bc4812f7d1bd230a1516eca61eea Mon Sep 17 00:00:00 2001 From: telans Date: Tue, 16 Jun 2020 10:37:52 +1200 Subject: Add full stop at end of comments (SA1629) --- Emby.Dlna/Didl/DidlBuilder.cs | 2 +- Emby.Dlna/DlnaManager.cs | 2 +- Emby.Dlna/PlayTo/Device.cs | 2 +- Emby.Naming/Common/MediaType.cs | 6 +- Emby.Server.Implementations/ApplicationHost.cs | 2 +- .../Data/BaseSqliteRepository.cs | 4 +- .../Data/SqliteDisplayPreferencesRepository.cs | 6 +- .../Data/SqliteItemRepository.cs | 10 +-- .../Data/SqliteUserDataRepository.cs | 6 +- Emby.Server.Implementations/Dto/DtoService.cs | 8 +-- .../HttpClientManager/HttpClientManager.cs | 2 +- .../HttpServer/FileWriter.cs | 4 +- .../HttpServer/HttpListenerHost.cs | 2 +- .../HttpServer/HttpResultFactory.cs | 2 +- .../HttpServer/RangeRequestWriter.cs | 8 +-- .../Library/CoreResolutionIgnoreRule.cs | 2 +- .../Library/IgnorePatterns.cs | 6 +- .../Library/LibraryManager.cs | 14 ++-- .../Library/ResolverHelper.cs | 2 +- .../Library/Resolvers/ItemResolver.cs | 2 +- .../Library/UserDataManager.cs | 4 +- .../LiveTv/RefreshChannelsScheduledTask.cs | 2 +- .../Networking/NetworkManager.cs | 2 +- .../ScheduledTasks/ScheduledTaskWorker.cs | 18 +++--- .../ScheduledTasks/TaskManager.cs | 8 +-- .../ScheduledTasks/Tasks/DeleteCacheFileTask.cs | 8 +-- .../Tasks/DeleteTranscodeFileTask.cs | 2 +- .../ScheduledTasks/Triggers/DailyTrigger.cs | 4 +- .../ScheduledTasks/Triggers/IntervalTrigger.cs | 6 +- .../ScheduledTasks/Triggers/StartupTrigger.cs | 4 +- .../ScheduledTasks/Triggers/WeeklyTrigger.cs | 8 +-- .../Services/ServiceHandler.cs | 2 +- .../Services/UrlExtensions.cs | 2 +- .../Session/SessionManager.cs | 2 +- .../Session/SessionWebSocketListener.cs | 6 +- .../Sorting/AlbumArtistComparer.cs | 2 +- .../Sorting/AlbumComparer.cs | 2 +- .../Sorting/CriticRatingComparer.cs | 2 +- .../Sorting/DateCreatedComparer.cs | 2 +- .../Sorting/DatePlayedComparer.cs | 2 +- .../Sorting/NameComparer.cs | 2 +- .../Sorting/PlayCountComparer.cs | 2 +- .../Sorting/PremiereDateComparer.cs | 2 +- .../Sorting/ProductionYearComparer.cs | 2 +- .../Sorting/RandomComparer.cs | 2 +- .../Sorting/RuntimeComparer.cs | 2 +- .../Sorting/SortNameComparer.cs | 2 +- Emby.Server.Implementations/Udp/UdpServer.cs | 2 +- Jellyfin.Data/Entities/Artwork.cs | 14 ++-- Jellyfin.Data/Entities/Book.cs | 2 +- Jellyfin.Data/Entities/BookMetadata.cs | 4 +- Jellyfin.Data/Entities/Chapter.cs | 20 +++--- Jellyfin.Data/Entities/Collection.cs | 10 +-- Jellyfin.Data/Entities/CollectionItem.cs | 10 +-- Jellyfin.Data/Entities/Company.cs | 8 +-- Jellyfin.Data/Entities/CompanyMetadata.cs | 10 +-- Jellyfin.Data/Entities/CustomItem.cs | 2 +- Jellyfin.Data/Entities/CustomItemMetadata.cs | 2 +- Jellyfin.Data/Entities/Episode.cs | 4 +- Jellyfin.Data/Entities/EpisodeMetadata.cs | 8 +-- Jellyfin.Data/Entities/Genre.cs | 10 +-- Jellyfin.Data/Entities/Library.cs | 10 +-- Jellyfin.Data/Entities/LibraryItem.cs | 16 ++--- Jellyfin.Data/Entities/LibraryRoot.cs | 16 ++--- Jellyfin.Data/Entities/MediaFile.cs | 16 ++--- Jellyfin.Data/Entities/MediaFileStream.cs | 12 ++-- Jellyfin.Data/Entities/Metadata.cs | 30 ++++----- Jellyfin.Data/Entities/MetadataProvider.cs | 10 +-- Jellyfin.Data/Entities/MetadataProviderId.cs | 12 ++-- Jellyfin.Data/Entities/Movie.cs | 2 +- Jellyfin.Data/Entities/MovieMetadata.cs | 10 +-- Jellyfin.Data/Entities/MusicAlbum.cs | 2 +- Jellyfin.Data/Entities/MusicAlbumMetadata.cs | 8 +-- Jellyfin.Data/Entities/Person.cs | 24 +++---- Jellyfin.Data/Entities/PersonRole.cs | 16 ++--- Jellyfin.Data/Entities/Photo.cs | 2 +- Jellyfin.Data/Entities/PhotoMetadata.cs | 2 +- Jellyfin.Data/Entities/ProviderMapping.cs | 6 +- Jellyfin.Data/Entities/Rating.cs | 14 ++-- Jellyfin.Data/Entities/RatingSource.cs | 20 +++--- Jellyfin.Data/Entities/Release.cs | 10 +-- Jellyfin.Data/Entities/Season.cs | 4 +- Jellyfin.Data/Entities/SeasonMetadata.cs | 4 +- Jellyfin.Data/Entities/Series.cs | 10 +-- Jellyfin.Data/Entities/SeriesMetadata.cs | 10 +-- Jellyfin.Data/Entities/Track.cs | 4 +- Jellyfin.Data/Entities/TrackMetadata.cs | 2 +- Jellyfin.Data/Enums/PreferenceKind.cs | 2 +- Jellyfin.Server.Implementations/JellyfinDb.cs | 2 +- MediaBrowser.Api/ApiEntryPoint.cs | 4 +- MediaBrowser.Api/BaseApiService.cs | 2 +- MediaBrowser.Api/ChannelService.cs | 6 +- MediaBrowser.Api/ConfigurationService.cs | 8 +-- MediaBrowser.Api/DisplayPreferencesService.cs | 8 +-- MediaBrowser.Api/EnvironmentService.cs | 12 ++-- MediaBrowser.Api/IHasItemFields.cs | 2 +- MediaBrowser.Api/Images/ImageByNameService.cs | 10 +-- MediaBrowser.Api/Images/ImageRequest.cs | 12 ++-- MediaBrowser.Api/Images/ImageService.cs | 20 +++--- MediaBrowser.Api/Images/RemoteImageService.cs | 2 +- MediaBrowser.Api/Library/LibraryService.cs | 14 ++-- .../Library/LibraryStructureService.cs | 8 +-- MediaBrowser.Api/LiveTv/LiveTvService.cs | 14 ++-- MediaBrowser.Api/LocalizationService.cs | 12 ++-- MediaBrowser.Api/Movies/MoviesService.cs | 4 +- MediaBrowser.Api/Movies/TrailersService.cs | 6 +- MediaBrowser.Api/Music/AlbumsService.cs | 6 +- MediaBrowser.Api/PackageService.cs | 10 +-- MediaBrowser.Api/Playback/BaseStreamingService.cs | 2 +- MediaBrowser.Api/Playback/Hls/BaseHlsService.cs | 2 +- MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs | 6 +- MediaBrowser.Api/Playback/Hls/VideoHlsService.cs | 2 +- .../Playback/Progressive/AudioService.cs | 4 +- .../Progressive/BaseProgressiveStreamingService.cs | 2 +- .../Playback/Progressive/VideoService.cs | 4 +- .../Playback/StaticRemoteStreamWriter.cs | 6 +- MediaBrowser.Api/Playback/StreamRequest.cs | 2 +- MediaBrowser.Api/PlaylistService.cs | 4 +- MediaBrowser.Api/PluginService.cs | 20 +++--- .../ScheduledTasks/ScheduledTaskService.cs | 12 ++-- .../ScheduledTasksWebSocketListener.cs | 2 +- MediaBrowser.Api/SearchService.cs | 10 +-- .../Sessions/SessionInfoWebSocketListener.cs | 4 +- MediaBrowser.Api/Sessions/SessionService.cs | 4 +- MediaBrowser.Api/SimilarItemsHelper.cs | 8 +-- MediaBrowser.Api/System/ActivityLogService.cs | 2 +- .../System/ActivityLogWebSocketListener.cs | 4 +- MediaBrowser.Api/System/SystemService.cs | 8 +-- MediaBrowser.Api/TvShowsService.cs | 22 +++---- MediaBrowser.Api/UserLibrary/ArtistsService.cs | 4 +- .../UserLibrary/BaseItemsByNameService.cs | 6 +- MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs | 22 +++---- MediaBrowser.Api/UserLibrary/GenresService.cs | 6 +- MediaBrowser.Api/UserLibrary/ItemsService.cs | 10 +-- MediaBrowser.Api/UserLibrary/PersonsService.cs | 6 +- MediaBrowser.Api/UserLibrary/PlaystateService.cs | 10 +-- MediaBrowser.Api/UserLibrary/StudiosService.cs | 6 +- MediaBrowser.Api/UserLibrary/UserLibraryService.cs | 20 +++--- MediaBrowser.Api/UserLibrary/YearsService.cs | 6 +- MediaBrowser.Api/UserService.cs | 24 +++---- .../Channels/InternalChannelFeatures.cs | 2 +- .../Configuration/IServerConfigurationManager.cs | 2 +- MediaBrowser.Controller/Drawing/IImageProcessor.cs | 2 +- MediaBrowser.Controller/Dto/IDtoService.cs | 2 +- .../Entities/AggregateFolder.cs | 2 +- MediaBrowser.Controller/Entities/Audio/Audio.cs | 2 +- .../Entities/Audio/MusicAlbum.cs | 2 +- .../Entities/Audio/MusicArtist.cs | 6 +- .../Entities/Audio/MusicGenre.cs | 6 +- MediaBrowser.Controller/Entities/BaseItem.cs | 28 ++++---- .../Entities/CollectionFolder.cs | 4 +- MediaBrowser.Controller/Entities/Extensions.cs | 2 +- MediaBrowser.Controller/Entities/Folder.cs | 12 ++-- MediaBrowser.Controller/Entities/Genre.cs | 6 +- .../Entities/ICollectionFolder.cs | 2 +- .../Entities/IHasAspectRatio.cs | 2 +- .../Entities/IHasDisplayOrder.cs | 2 +- .../Entities/IHasScreenshots.cs | 2 +- MediaBrowser.Controller/Entities/LinkedChild.cs | 2 +- MediaBrowser.Controller/Entities/Movies/BoxSet.cs | 2 +- MediaBrowser.Controller/Entities/Movies/Movie.cs | 2 +- MediaBrowser.Controller/Entities/Person.cs | 4 +- MediaBrowser.Controller/Entities/Studio.cs | 6 +- MediaBrowser.Controller/Entities/TV/Episode.cs | 4 +- MediaBrowser.Controller/Entities/TV/Season.cs | 6 +- MediaBrowser.Controller/Entities/TV/Series.cs | 4 +- MediaBrowser.Controller/Entities/Trailer.cs | 2 +- MediaBrowser.Controller/Entities/UserItemData.cs | 6 +- MediaBrowser.Controller/Entities/Video.cs | 2 +- MediaBrowser.Controller/Entities/Year.cs | 6 +- .../Extensions/StringExtensions.cs | 2 +- MediaBrowser.Controller/IServerApplicationHost.cs | 2 +- MediaBrowser.Controller/IServerApplicationPaths.cs | 16 ++--- MediaBrowser.Controller/Library/IIntroProvider.cs | 2 +- MediaBrowser.Controller/Library/ILibraryManager.cs | 14 ++-- .../Library/ILibraryPostScanTask.cs | 2 +- MediaBrowser.Controller/Library/IMetadataSaver.cs | 2 +- MediaBrowser.Controller/Library/ISearchEngine.cs | 2 +- .../Library/IUserDataManager.cs | 6 +- MediaBrowser.Controller/Library/IUserManager.cs | 2 +- .../Library/ItemChangeEventArgs.cs | 2 +- MediaBrowser.Controller/Library/ItemResolveArgs.cs | 2 +- .../Library/PlaybackProgressEventArgs.cs | 2 +- MediaBrowser.Controller/Library/Profiler.cs | 8 +-- MediaBrowser.Controller/Library/SearchHintInfo.cs | 2 +- MediaBrowser.Controller/Library/TVUtils.cs | 2 +- .../Library/UserDataSaveEventArgs.cs | 2 +- MediaBrowser.Controller/LiveTv/ChannelInfo.cs | 6 +- MediaBrowser.Controller/LiveTv/ILiveTvManager.cs | 2 +- MediaBrowser.Controller/LiveTv/LiveTvProgram.cs | 2 +- MediaBrowser.Controller/LiveTv/ProgramInfo.cs | 6 +- MediaBrowser.Controller/LiveTv/RecordingInfo.cs | 4 +- .../MediaEncoding/EncodingHelper.cs | 14 ++-- .../MediaEncoding/EncodingJobInfo.cs | 18 +++--- .../MediaEncoding/IMediaEncoder.cs | 2 +- .../MediaEncoding/MediaEncoderHelpers.cs | 2 +- .../Net/BasePeriodicWebSocketListener.cs | 10 +-- MediaBrowser.Controller/Net/IHttpResultFactory.cs | 2 +- MediaBrowser.Controller/Net/IHttpServer.cs | 6 +- MediaBrowser.Controller/Net/IWebSocketListener.cs | 2 +- .../Net/WebSocketMessageInfo.cs | 2 +- .../Persistence/IItemRepository.cs | 8 +-- MediaBrowser.Controller/Persistence/IRepository.cs | 4 +- .../Persistence/IUserDataRepository.cs | 6 +- .../Plugins/IPluginConfigurationPage.cs | 8 +-- .../Providers/IMetadataProvider.cs | 2 +- .../Providers/MetadataRefreshMode.cs | 8 +-- .../Providers/MetadataResult.cs | 2 +- .../Providers/VideoContentType.cs | 6 +- .../Resolvers/BaseItemResolver.cs | 4 +- MediaBrowser.Controller/Resolvers/IItemResolver.cs | 2 +- .../Resolvers/ResolverPriority.cs | 10 +-- MediaBrowser.Controller/Session/ISessionManager.cs | 8 +-- .../Sorting/IBaseItemComparer.cs | 2 +- .../Sorting/IUserBaseItemComparer.cs | 2 +- .../Sync/IRemoteSyncProvider.cs | 2 +- .../Parsers/BaseItemXmlParser.cs | 10 +-- .../BdInfo/BdInfoExaminer.cs | 2 +- MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 4 +- .../Probing/FFProbeHelpers.cs | 8 +-- .../Probing/ProbeResultNormalizer.cs | 10 +-- .../Subtitles/SubtitleEncoder.cs | 2 +- MediaBrowser.Model/Channels/ChannelFeatures.cs | 2 +- MediaBrowser.Model/Channels/ChannelQuery.cs | 4 +- .../Configuration/BaseApplicationConfiguration.cs | 2 +- .../Configuration/MetadataPluginType.cs | 2 +- .../Configuration/ServerConfiguration.cs | 6 +- .../Configuration/UserConfiguration.cs | 2 +- MediaBrowser.Model/Dlna/AudioOptions.cs | 2 +- MediaBrowser.Model/Dlna/StreamInfo.cs | 26 ++++---- MediaBrowser.Model/Dlna/SubtitleDeliveryMethod.cs | 8 +-- MediaBrowser.Model/Dto/BaseItemDto.cs | 2 +- MediaBrowser.Model/Dto/ImageOptions.cs | 2 +- MediaBrowser.Model/Dto/MediaSourceInfo.cs | 2 +- MediaBrowser.Model/Entities/DisplayPreferences.cs | 2 +- MediaBrowser.Model/Entities/MediaStream.cs | 2 +- MediaBrowser.Model/Entities/MetadataProvider.cs | 12 ++-- MediaBrowser.Model/Entities/VirtualFolderInfo.cs | 2 +- MediaBrowser.Model/IO/IZipClient.cs | 2 +- MediaBrowser.Model/LiveTv/ChannelType.cs | 2 +- MediaBrowser.Model/LiveTv/LiveTvChannelQuery.cs | 8 +-- MediaBrowser.Model/LiveTv/RecordingQuery.cs | 4 +- MediaBrowser.Model/LiveTv/SeriesTimerQuery.cs | 2 +- MediaBrowser.Model/Net/NetworkShare.cs | 10 +-- .../Notifications/NotificationOption.cs | 2 +- MediaBrowser.Model/Querying/ItemFields.cs | 74 +++++++++++----------- MediaBrowser.Model/Querying/ItemSortBy.cs | 2 +- MediaBrowser.Model/Querying/NextUpQuery.cs | 4 +- MediaBrowser.Model/Querying/QueryResult.cs | 2 +- .../Querying/UpcomingEpisodesQuery.cs | 4 +- MediaBrowser.Model/Search/SearchQuery.cs | 4 +- MediaBrowser.Model/Services/ApiMemberAttribute.cs | 2 +- MediaBrowser.Model/Services/IRequest.cs | 8 +-- .../Services/IRequiresRequestStream.cs | 2 +- MediaBrowser.Model/Session/PlayRequest.cs | 4 +- MediaBrowser.Model/Sync/SyncCategory.cs | 6 +- MediaBrowser.Model/System/SystemInfo.cs | 2 +- MediaBrowser.Model/Tasks/IScheduledTaskWorker.cs | 2 +- MediaBrowser.Model/Tasks/ITaskManager.cs | 2 +- MediaBrowser.Providers/Manager/ImageSaver.cs | 6 +- .../Manager/ItemImageProvider.cs | 4 +- MediaBrowser.Providers/Manager/ProviderManager.cs | 2 +- .../MediaInfo/AudioImageProvider.cs | 2 +- .../MediaInfo/FFProbeAudioInfo.cs | 2 +- .../MediaInfo/FFProbeVideoInfo.cs | 2 +- .../Plugins/Tmdb/Models/Search/MovieResult.cs | 2 +- .../Plugins/Tmdb/Movies/TmdbMovieProvider.cs | 4 +- .../TV/MissingEpisodeProvider.cs | 4 +- RSSDP/DiscoveredSsdpDevice.cs | 2 +- 269 files changed, 816 insertions(+), 816 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Dlna/Didl/DidlBuilder.cs b/Emby.Dlna/Didl/DidlBuilder.cs index 6ded76f7d..0f53bf2a4 100644 --- a/Emby.Dlna/Didl/DidlBuilder.cs +++ b/Emby.Dlna/Didl/DidlBuilder.cs @@ -705,7 +705,7 @@ namespace Emby.Dlna.Didl } /// - /// Adds fields used by both items and folders + /// Adds fields used by both items and folders. /// private void AddCommonFields(BaseItem item, StubType? itemStubType, BaseItem context, XmlWriter writer, Filter filter) { diff --git a/Emby.Dlna/DlnaManager.cs b/Emby.Dlna/DlnaManager.cs index e5f483950..6b7063c5d 100644 --- a/Emby.Dlna/DlnaManager.cs +++ b/Emby.Dlna/DlnaManager.cs @@ -473,7 +473,7 @@ namespace Emby.Dlna /// /// Recreates the object using serialization, to ensure it's not a subclass. - /// If it's a subclass it may not serlialize properly to xml (different root element tag name) + /// If it's a subclass it may not serlialize properly to xml (different root element tag name). /// /// /// diff --git a/Emby.Dlna/PlayTo/Device.cs b/Emby.Dlna/PlayTo/Device.cs index 86b72e264..6442ac5cc 100644 --- a/Emby.Dlna/PlayTo/Device.cs +++ b/Emby.Dlna/PlayTo/Device.cs @@ -232,7 +232,7 @@ namespace Emby.Dlna.PlayTo } /// - /// Sets volume on a scale of 0-100 + /// Sets volume on a scale of 0-100. /// public async Task SetVolume(int value, CancellationToken cancellationToken) { diff --git a/Emby.Naming/Common/MediaType.cs b/Emby.Naming/Common/MediaType.cs index cc18ce4cd..148833765 100644 --- a/Emby.Naming/Common/MediaType.cs +++ b/Emby.Naming/Common/MediaType.cs @@ -5,17 +5,17 @@ namespace Emby.Naming.Common public enum MediaType { /// - /// The audio + /// The audio. /// Audio = 0, /// - /// The photo + /// The photo. /// Photo = 1, /// - /// The video + /// The video. /// Video = 2 } diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index 5772dd479..23f0571a1 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -956,7 +956,7 @@ namespace Emby.Server.Implementations } /// - /// Notifies that the kernel that a change has been made that requires a restart + /// Notifies that the kernel that a change has been made that requires a restart. /// public void NotifyPendingRestart() { diff --git a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs index 53c9ccdbf..8a3716380 100644 --- a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs +++ b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs @@ -247,12 +247,12 @@ namespace Emby.Server.Implementations.Data public enum SynchronousMode { /// - /// SQLite continues without syncing as soon as it has handed data off to the operating system + /// SQLite continues without syncing as soon as it has handed data off to the operating system. /// Off = 0, /// - /// SQLite database engine will still sync at the most critical moments + /// SQLite database engine will still sync at the most critical moments. /// Normal = 1, diff --git a/Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs b/Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs index 63d0321b7..5597155a8 100644 --- a/Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs @@ -59,7 +59,7 @@ namespace Emby.Server.Implementations.Data } /// - /// Opens the connection to the database + /// Opens the connection to the database. /// /// Task. private void InitializeInternal() @@ -77,7 +77,7 @@ namespace Emby.Server.Implementations.Data } /// - /// Save the display preferences associated with an item in the repo + /// Save the display preferences associated with an item in the repo. /// /// The display preferences. /// The user id. @@ -122,7 +122,7 @@ namespace Emby.Server.Implementations.Data } /// - /// Save all display preferences associated with a user in the repo + /// Save all display preferences associated with a user in the repo. /// /// The display preferences. /// The user id. diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index d33125661..13b581fc0 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -102,7 +102,7 @@ namespace Emby.Server.Implementations.Data protected override TempStoreMode TempStore => TempStoreMode.Memory; /// - /// Opens the connection to the database + /// Opens the connection to the database. /// public void Initialize(SqliteUserDataRepository userDataRepo, IUserManager userManager) { @@ -548,7 +548,7 @@ namespace Emby.Server.Implementations.Data } /// - /// Save a standard item in the repo + /// Save a standard item in the repo. /// /// The item. /// The cancellation token. @@ -1204,7 +1204,7 @@ namespace Emby.Server.Implementations.Data } /// - /// Internal retrieve from items or users table + /// Internal retrieve from items or users table. /// /// The id. /// BaseItem. @@ -1918,7 +1918,7 @@ namespace Emby.Server.Implementations.Data } /// - /// Gets chapters for an item + /// Gets chapters for an item. /// /// The item. /// IEnumerable{ChapterInfo}. @@ -1946,7 +1946,7 @@ namespace Emby.Server.Implementations.Data } /// - /// Gets a single chapter for an item + /// Gets a single chapter for an item. /// /// The item. /// The index. diff --git a/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs b/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs index 7e66fa072..663c226a2 100644 --- a/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs @@ -235,7 +235,7 @@ namespace Emby.Server.Implementations.Data } /// - /// Persist all user data for the specified user + /// Persist all user data for the specified user. /// private void PersistAllUserData(long internalUserId, UserItemData[] userDataList, CancellationToken cancellationToken) { @@ -309,7 +309,7 @@ namespace Emby.Server.Implementations.Data } /// - /// Return all user-data associated with the given user + /// Return all user-data associated with the given user. /// /// /// @@ -339,7 +339,7 @@ namespace Emby.Server.Implementations.Data } /// - /// Read a row from the specified reader into the provided userData object + /// Read a row from the specified reader into the provided userData object. /// /// private UserItemData ReadRow(IReadOnlyList reader) diff --git a/Emby.Server.Implementations/Dto/DtoService.cs b/Emby.Server.Implementations/Dto/DtoService.cs index 41ff7e3ab..c3bb7a814 100644 --- a/Emby.Server.Implementations/Dto/DtoService.cs +++ b/Emby.Server.Implementations/Dto/DtoService.cs @@ -74,7 +74,7 @@ namespace Emby.Server.Implementations.Dto } /// - /// Converts a BaseItem to a DTOBaseItem + /// Converts a BaseItem to a DTOBaseItem. /// /// The item. /// The fields. @@ -442,7 +442,7 @@ namespace Emby.Server.Implementations.Dto } /// - /// Gets client-side Id of a server-side BaseItem + /// Gets client-side Id of a server-side BaseItem. /// /// The item. /// System.String. @@ -537,7 +537,7 @@ namespace Emby.Server.Implementations.Dto } /// - /// Attaches People DTO's to a DTOBaseItem + /// Attaches People DTO's to a DTOBaseItem. /// /// The dto. /// The item. @@ -725,7 +725,7 @@ namespace Emby.Server.Implementations.Dto } /// - /// Sets simple property values on a DTOBaseItem + /// Sets simple property values on a DTOBaseItem. /// /// The dto. /// The item. diff --git a/Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs b/Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs index 87977494a..25adc5812 100644 --- a/Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs +++ b/Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs @@ -140,7 +140,7 @@ namespace Emby.Server.Implementations.HttpClientManager => SendAsync(options, HttpMethod.Get); /// - /// Performs a GET request and returns the resulting stream + /// Performs a GET request and returns the resulting stream. /// /// The options. /// Task{Stream}. diff --git a/Emby.Server.Implementations/HttpServer/FileWriter.cs b/Emby.Server.Implementations/HttpServer/FileWriter.cs index 0b61e40b0..590eee1b4 100644 --- a/Emby.Server.Implementations/HttpServer/FileWriter.cs +++ b/Emby.Server.Implementations/HttpServer/FileWriter.cs @@ -32,12 +32,12 @@ namespace Emby.Server.Implementations.HttpServer private readonly IFileSystem _fileSystem; /// - /// The _options + /// The _options. /// private readonly IDictionary _options = new Dictionary(); /// - /// The _requested ranges + /// The _requested ranges. /// private List> _requestedRanges; diff --git a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs index 1b6e4b554..ca8cb4087 100644 --- a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs +++ b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs @@ -591,7 +591,7 @@ namespace Emby.Server.Implementations.HttpServer } /// - /// Get the default CORS headers + /// Get the default CORS headers. /// /// /// diff --git a/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs b/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs index d254d394f..ad31b3e1e 100644 --- a/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs +++ b/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs @@ -692,7 +692,7 @@ namespace Emby.Server.Implementations.HttpServer /// - /// When the browser sends the IfModifiedDate, it's precision is limited to seconds, so this will account for that + /// When the browser sends the IfModifiedDate, it's precision is limited to seconds, so this will account for that. /// /// The date. /// DateTime. diff --git a/Emby.Server.Implementations/HttpServer/RangeRequestWriter.cs b/Emby.Server.Implementations/HttpServer/RangeRequestWriter.cs index 8b9028f6b..d83869077 100644 --- a/Emby.Server.Implementations/HttpServer/RangeRequestWriter.cs +++ b/Emby.Server.Implementations/HttpServer/RangeRequestWriter.cs @@ -34,17 +34,17 @@ namespace Emby.Server.Implementations.HttpServer private const int BufferSize = 81920; /// - /// The _options + /// The _options. /// private readonly Dictionary _options = new Dictionary(); /// - /// The us culture + /// The us culture. /// private static readonly CultureInfo UsCulture = new CultureInfo("en-US"); /// - /// Additional HTTP Headers + /// Additional HTTP Headers. /// /// The headers. public IDictionary Headers => _options; @@ -110,7 +110,7 @@ namespace Emby.Server.Implementations.HttpServer } /// - /// The _requested ranges + /// The _requested ranges. /// private List> _requestedRanges; /// diff --git a/Emby.Server.Implementations/Library/CoreResolutionIgnoreRule.cs b/Emby.Server.Implementations/Library/CoreResolutionIgnoreRule.cs index 218e5a0c6..e140009ea 100644 --- a/Emby.Server.Implementations/Library/CoreResolutionIgnoreRule.cs +++ b/Emby.Server.Implementations/Library/CoreResolutionIgnoreRule.cs @@ -8,7 +8,7 @@ using MediaBrowser.Model.IO; namespace Emby.Server.Implementations.Library { /// - /// Provides the core resolver ignore rules + /// Provides the core resolver ignore rules. /// public class CoreResolutionIgnoreRule : IResolverIgnoreRule { diff --git a/Emby.Server.Implementations/Library/IgnorePatterns.cs b/Emby.Server.Implementations/Library/IgnorePatterns.cs index d12b5855b..8c4098948 100644 --- a/Emby.Server.Implementations/Library/IgnorePatterns.cs +++ b/Emby.Server.Implementations/Library/IgnorePatterns.cs @@ -4,12 +4,12 @@ using DotNet.Globbing; namespace Emby.Server.Implementations.Library { /// - /// Glob patterns for files to ignore + /// Glob patterns for files to ignore. /// public static class IgnorePatterns { /// - /// Files matching these glob patterns will be ignored + /// Files matching these glob patterns will be ignored. /// public static readonly string[] Patterns = new string[] { @@ -64,7 +64,7 @@ namespace Emby.Server.Implementations.Library private static readonly Glob[] _globs = Patterns.Select(p => Glob.Parse(p, _globOptions)).ToArray(); /// - /// Returns true if the supplied path should be ignored + /// Returns true if the supplied path should be ignored. /// public static bool ShouldIgnore(string path) { diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index 1d4651da2..799ce28a0 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -97,13 +97,13 @@ namespace Emby.Server.Implementations.Library private IIntroProvider[] IntroProviders { get; set; } /// - /// Gets or sets the list of entity resolution ignore rules + /// Gets or sets the list of entity resolution ignore rules. /// /// The entity resolution ignore rules. private IResolverIgnoreRule[] EntityResolutionIgnoreRules { get; set; } /// - /// Gets or sets the list of currently registered entity resolvers + /// Gets or sets the list of currently registered entity resolvers. /// /// The entity resolvers enumerable. private IItemResolver[] EntityResolvers { get; set; } @@ -209,12 +209,12 @@ namespace Emby.Server.Implementations.Library } /// - /// The _root folder + /// The _root folder. /// private volatile AggregateFolder _rootFolder; /// - /// The _root folder sync lock + /// The _root folder sync lock. /// private readonly object _rootFolderSyncLock = new object(); @@ -627,7 +627,7 @@ namespace Emby.Server.Implementations.Library } /// - /// Determines whether a path should be ignored based on its contents - called after the contents have been read + /// Determines whether a path should be ignored based on its contents - called after the contents have been read. /// /// The args. /// true if XXXX, false otherwise @@ -909,7 +909,7 @@ namespace Emby.Server.Implementations.Library } /// - /// Gets a Genre + /// Gets a Genre. /// /// The name. /// Task{Genre}. @@ -990,7 +990,7 @@ namespace Emby.Server.Implementations.Library } /// - /// Reloads the root media folder + /// Reloads the root media folder. /// /// The progress. /// The cancellation token. diff --git a/Emby.Server.Implementations/Library/ResolverHelper.cs b/Emby.Server.Implementations/Library/ResolverHelper.cs index 7ca15b4e5..4e4cac75b 100644 --- a/Emby.Server.Implementations/Library/ResolverHelper.cs +++ b/Emby.Server.Implementations/Library/ResolverHelper.cs @@ -107,7 +107,7 @@ namespace Emby.Server.Implementations.Library } /// - /// Ensures DateCreated and DateModified have values + /// Ensures DateCreated and DateModified have values. /// /// The file system. /// The item. diff --git a/Emby.Server.Implementations/Library/Resolvers/ItemResolver.cs b/Emby.Server.Implementations/Library/Resolvers/ItemResolver.cs index 32ccc7fdd..9ca76095b 100644 --- a/Emby.Server.Implementations/Library/Resolvers/ItemResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/ItemResolver.cs @@ -28,7 +28,7 @@ namespace Emby.Server.Implementations.Library.Resolvers public virtual ResolverPriority Priority => ResolverPriority.First; /// - /// Sets initial values on the newly resolved item + /// Sets initial values on the newly resolved item. /// /// The item. /// The args. diff --git a/Emby.Server.Implementations/Library/UserDataManager.cs b/Emby.Server.Implementations/Library/UserDataManager.cs index 9e17fa672..175b3af57 100644 --- a/Emby.Server.Implementations/Library/UserDataManager.cs +++ b/Emby.Server.Implementations/Library/UserDataManager.cs @@ -103,7 +103,7 @@ namespace Emby.Server.Implementations.Library } /// - /// Retrieve all user data for the given user + /// Retrieve all user data for the given user. /// /// /// @@ -188,7 +188,7 @@ namespace Emby.Server.Implementations.Library } /// - /// Converts a UserItemData to a DTOUserItemData + /// Converts a UserItemData to a DTOUserItemData. /// /// The data. /// DtoUserItemData. diff --git a/Emby.Server.Implementations/LiveTv/RefreshChannelsScheduledTask.cs b/Emby.Server.Implementations/LiveTv/RefreshChannelsScheduledTask.cs index 8e7d60a15..f1b61f7c7 100644 --- a/Emby.Server.Implementations/LiveTv/RefreshChannelsScheduledTask.cs +++ b/Emby.Server.Implementations/LiveTv/RefreshChannelsScheduledTask.cs @@ -35,7 +35,7 @@ namespace Emby.Server.Implementations.LiveTv } /// - /// Creates the triggers that define when the task will run + /// Creates the triggers that define when the task will run. /// /// IEnumerable{BaseTaskTrigger}. public IEnumerable GetDefaultTriggers() diff --git a/Emby.Server.Implementations/Networking/NetworkManager.cs b/Emby.Server.Implementations/Networking/NetworkManager.cs index 2909cdd0d..d12b5a937 100644 --- a/Emby.Server.Implementations/Networking/NetworkManager.cs +++ b/Emby.Server.Implementations/Networking/NetworkManager.cs @@ -411,7 +411,7 @@ namespace Emby.Server.Implementations.Networking } /// - /// Gets a random port number that is currently available + /// Gets a random port number that is currently available. /// /// System.Int32. public int GetRandomUnusedTcpPort() diff --git a/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs b/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs index e58c335a8..1995d1309 100644 --- a/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs +++ b/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs @@ -18,7 +18,7 @@ using Microsoft.Extensions.Logging; namespace Emby.Server.Implementations.ScheduledTasks { /// - /// Class ScheduledTaskWorker + /// Class ScheduledTaskWorker. /// public class ScheduledTaskWorker : IScheduledTaskWorker { @@ -111,11 +111,11 @@ namespace Emby.Server.Implementations.ScheduledTasks private bool _readFromFile = false; /// - /// The _last execution result + /// The _last execution result. /// private TaskResult _lastExecutionResult; /// - /// The _last execution result sync lock + /// The _last execution result sync lock. /// private readonly object _lastExecutionResultSyncLock = new object(); /// @@ -182,7 +182,7 @@ namespace Emby.Server.Implementations.ScheduledTasks public string Category => ScheduledTask.Category; /// - /// Gets the current cancellation token + /// Gets the current cancellation token. /// /// The current cancellation token source. private CancellationTokenSource CurrentCancellationTokenSource { get; set; } @@ -278,7 +278,7 @@ namespace Emby.Server.Implementations.ScheduledTasks } /// - /// The _id + /// The _id. /// private string _id; @@ -358,7 +358,7 @@ namespace Emby.Server.Implementations.ScheduledTasks private Task _currentTask; /// - /// Executes the task + /// Executes the task. /// /// Task options. /// Task. @@ -453,7 +453,7 @@ namespace Emby.Server.Implementations.ScheduledTasks } /// - /// Stops the task if it is currently executing + /// Stops the task if it is currently executing. /// /// Cannot cancel a Task unless it is in the Running state. public void Cancel() @@ -683,7 +683,7 @@ namespace Emby.Server.Implementations.ScheduledTasks } /// - /// Converts a TaskTriggerInfo into a concrete BaseTaskTrigger + /// Converts a TaskTriggerInfo into a concrete BaseTaskTrigger. /// /// The info. /// BaseTaskTrigger. @@ -753,7 +753,7 @@ namespace Emby.Server.Implementations.ScheduledTasks } /// - /// Disposes each trigger + /// Disposes each trigger. /// private void DisposeTriggers() { diff --git a/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs b/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs index 94220ac5d..0ad4253e4 100644 --- a/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs +++ b/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs @@ -15,7 +15,7 @@ using Microsoft.Extensions.Logging; namespace Emby.Server.Implementations.ScheduledTasks { /// - /// Class TaskManager + /// Class TaskManager. /// public class TaskManager : ITaskManager { @@ -23,13 +23,13 @@ namespace Emby.Server.Implementations.ScheduledTasks public event EventHandler TaskCompleted; /// - /// Gets the list of Scheduled Tasks + /// Gets the list of Scheduled Tasks. /// /// The scheduled tasks. public IScheduledTaskWorker[] ScheduledTasks { get; private set; } /// - /// The _task queue + /// The _task queue. /// private readonly ConcurrentQueue> _taskQueue = new ConcurrentQueue>(); @@ -81,7 +81,7 @@ namespace Emby.Server.Implementations.ScheduledTasks } /// - /// Cancels if running + /// Cancels if running. /// /// public void CancelIfRunning() diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs index 966b549b2..e29fcfb5f 100644 --- a/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs +++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs @@ -13,7 +13,7 @@ using MediaBrowser.Model.Globalization; namespace Emby.Server.Implementations.ScheduledTasks.Tasks { /// - /// Deletes old cache files + /// Deletes old cache files. /// public class DeleteCacheFileTask : IScheduledTask, IConfigurableScheduledTask { @@ -44,7 +44,7 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks } /// - /// Creates the triggers that define when the task will run + /// Creates the triggers that define when the task will run. /// /// IEnumerable{BaseTaskTrigger}. public IEnumerable GetDefaultTriggers() @@ -57,7 +57,7 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks } /// - /// Returns the task to be executed + /// Returns the task to be executed. /// /// The cancellation token. /// The progress. @@ -93,7 +93,7 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks /// - /// Deletes the cache files from directory with a last write time less than a given date + /// Deletes the cache files from directory with a last write time less than a given date. /// /// The task cancellation token. /// The directory. diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteTranscodeFileTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteTranscodeFileTask.cs index 53cf9a0a5..691408167 100644 --- a/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteTranscodeFileTask.cs +++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteTranscodeFileTask.cs @@ -13,7 +13,7 @@ using MediaBrowser.Model.Globalization; namespace Emby.Server.Implementations.ScheduledTasks.Tasks { /// - /// Deletes all transcoding temp files + /// Deletes all transcoding temp files. /// public class DeleteTranscodeFileTask : IScheduledTask, IConfigurableScheduledTask { diff --git a/Emby.Server.Implementations/ScheduledTasks/Triggers/DailyTrigger.cs b/Emby.Server.Implementations/ScheduledTasks/Triggers/DailyTrigger.cs index c7819d4c0..eb628ec5f 100644 --- a/Emby.Server.Implementations/ScheduledTasks/Triggers/DailyTrigger.cs +++ b/Emby.Server.Implementations/ScheduledTasks/Triggers/DailyTrigger.cs @@ -28,7 +28,7 @@ namespace Emby.Server.Implementations.ScheduledTasks private Timer Timer { get; set; } /// - /// Stars waiting for the trigger action + /// Stars waiting for the trigger action. /// /// The last result. /// The logger. @@ -51,7 +51,7 @@ namespace Emby.Server.Implementations.ScheduledTasks } /// - /// Stops waiting for the trigger action + /// Stops waiting for the trigger action. /// public void Stop() { diff --git a/Emby.Server.Implementations/ScheduledTasks/Triggers/IntervalTrigger.cs b/Emby.Server.Implementations/ScheduledTasks/Triggers/IntervalTrigger.cs index 74cd4ef1e..247a6785a 100644 --- a/Emby.Server.Implementations/ScheduledTasks/Triggers/IntervalTrigger.cs +++ b/Emby.Server.Implementations/ScheduledTasks/Triggers/IntervalTrigger.cs @@ -7,7 +7,7 @@ using Microsoft.Extensions.Logging; namespace Emby.Server.Implementations.ScheduledTasks { /// - /// Represents a task trigger that runs repeatedly on an interval + /// Represents a task trigger that runs repeatedly on an interval. /// public class IntervalTrigger : ITaskTrigger { @@ -31,7 +31,7 @@ namespace Emby.Server.Implementations.ScheduledTasks private DateTime _lastStartDate; /// - /// Stars waiting for the trigger action + /// Stars waiting for the trigger action. /// /// The last result. /// The logger. @@ -70,7 +70,7 @@ namespace Emby.Server.Implementations.ScheduledTasks } /// - /// Stops waiting for the trigger action + /// Stops waiting for the trigger action. /// public void Stop() { diff --git a/Emby.Server.Implementations/ScheduledTasks/Triggers/StartupTrigger.cs b/Emby.Server.Implementations/ScheduledTasks/Triggers/StartupTrigger.cs index e171a9e9f..96e5d8897 100644 --- a/Emby.Server.Implementations/ScheduledTasks/Triggers/StartupTrigger.cs +++ b/Emby.Server.Implementations/ScheduledTasks/Triggers/StartupTrigger.cs @@ -25,7 +25,7 @@ namespace Emby.Server.Implementations.ScheduledTasks } /// - /// Stars waiting for the trigger action + /// Stars waiting for the trigger action. /// /// The last result. /// The logger. @@ -42,7 +42,7 @@ namespace Emby.Server.Implementations.ScheduledTasks } /// - /// Stops waiting for the trigger action + /// Stops waiting for the trigger action. /// public void Stop() { diff --git a/Emby.Server.Implementations/ScheduledTasks/Triggers/WeeklyTrigger.cs b/Emby.Server.Implementations/ScheduledTasks/Triggers/WeeklyTrigger.cs index ad0b57af6..4f1bf5c19 100644 --- a/Emby.Server.Implementations/ScheduledTasks/Triggers/WeeklyTrigger.cs +++ b/Emby.Server.Implementations/ScheduledTasks/Triggers/WeeklyTrigger.cs @@ -6,12 +6,12 @@ using Microsoft.Extensions.Logging; namespace Emby.Server.Implementations.ScheduledTasks { /// - /// Represents a task trigger that fires on a weekly basis + /// Represents a task trigger that fires on a weekly basis. /// public class WeeklyTrigger : ITaskTrigger { /// - /// Get the time of day to trigger the task to run + /// Get the time of day to trigger the task to run. /// /// The time of day. public TimeSpan TimeOfDay { get; set; } @@ -34,7 +34,7 @@ namespace Emby.Server.Implementations.ScheduledTasks private Timer Timer { get; set; } /// - /// Stars waiting for the trigger action + /// Stars waiting for the trigger action. /// /// The last result. /// The logger. @@ -77,7 +77,7 @@ namespace Emby.Server.Implementations.ScheduledTasks } /// - /// Stops waiting for the trigger action + /// Stops waiting for the trigger action. /// public void Stop() { diff --git a/Emby.Server.Implementations/Services/ServiceHandler.cs b/Emby.Server.Implementations/Services/ServiceHandler.cs index 7f44357e1..a42f88ea0 100644 --- a/Emby.Server.Implementations/Services/ServiceHandler.cs +++ b/Emby.Server.Implementations/Services/ServiceHandler.cs @@ -180,7 +180,7 @@ namespace Emby.Server.Implementations.Services => string.Equals(method, expected, StringComparison.OrdinalIgnoreCase); /// - /// Duplicate params have their values joined together in a comma-delimited string + /// Duplicate params have their values joined together in a comma-delimited string. /// private static Dictionary GetFlattenedRequestParams(HttpRequest request) { diff --git a/Emby.Server.Implementations/Services/UrlExtensions.cs b/Emby.Server.Implementations/Services/UrlExtensions.cs index e3b6aa197..92e36b60e 100644 --- a/Emby.Server.Implementations/Services/UrlExtensions.cs +++ b/Emby.Server.Implementations/Services/UrlExtensions.cs @@ -9,7 +9,7 @@ namespace Emby.Server.Implementations.Services /// Donated by Ivan Korneliuk from his post: /// http://korneliuk.blogspot.com/2012/08/servicestack-reusing-dtos.html /// - /// Modified to only allow using routes matching the supplied HTTP Verb + /// Modified to only allow using routes matching the supplied HTTP Verb. /// public static class UrlExtensions { diff --git a/Emby.Server.Implementations/Session/SessionManager.cs b/Emby.Server.Implementations/Session/SessionManager.cs index 07e443ef5..75fdedd10 100644 --- a/Emby.Server.Implementations/Session/SessionManager.cs +++ b/Emby.Server.Implementations/Session/SessionManager.cs @@ -843,7 +843,7 @@ namespace Emby.Server.Implementations.Session } /// - /// Used to report that playback has ended for an item + /// Used to report that playback has ended for an item. /// /// The info. /// Task. diff --git a/Emby.Server.Implementations/Session/SessionWebSocketListener.cs b/Emby.Server.Implementations/Session/SessionWebSocketListener.cs index ef32c692c..a891e03f9 100644 --- a/Emby.Server.Implementations/Session/SessionWebSocketListener.cs +++ b/Emby.Server.Implementations/Session/SessionWebSocketListener.cs @@ -14,7 +14,7 @@ using Microsoft.Extensions.Logging; namespace Emby.Server.Implementations.Session { /// - /// Class SessionWebSocketListener + /// Class SessionWebSocketListener. /// public sealed class SessionWebSocketListener : IWebSocketListener, IDisposable { @@ -34,12 +34,12 @@ namespace Emby.Server.Implementations.Session public const float ForceKeepAliveFactor = 0.75f; /// - /// The _session manager + /// The _session manager. /// private readonly ISessionManager _sessionManager; /// - /// The _logger + /// The _logger. /// private readonly ILogger _logger; private readonly ILoggerFactory _loggerFactory; diff --git a/Emby.Server.Implementations/Sorting/AlbumArtistComparer.cs b/Emby.Server.Implementations/Sorting/AlbumArtistComparer.cs index 0804b01fc..7657cc74e 100644 --- a/Emby.Server.Implementations/Sorting/AlbumArtistComparer.cs +++ b/Emby.Server.Implementations/Sorting/AlbumArtistComparer.cs @@ -8,7 +8,7 @@ using MediaBrowser.Model.Querying; namespace Emby.Server.Implementations.Sorting { /// - /// Class AlbumArtistComparer + /// Class AlbumArtistComparer. /// public class AlbumArtistComparer : IBaseItemComparer { diff --git a/Emby.Server.Implementations/Sorting/AlbumComparer.cs b/Emby.Server.Implementations/Sorting/AlbumComparer.cs index 3831a0d2d..7dfdd9ecf 100644 --- a/Emby.Server.Implementations/Sorting/AlbumComparer.cs +++ b/Emby.Server.Implementations/Sorting/AlbumComparer.cs @@ -7,7 +7,7 @@ using MediaBrowser.Model.Querying; namespace Emby.Server.Implementations.Sorting { /// - /// Class AlbumComparer + /// Class AlbumComparer. /// public class AlbumComparer : IBaseItemComparer { diff --git a/Emby.Server.Implementations/Sorting/CriticRatingComparer.cs b/Emby.Server.Implementations/Sorting/CriticRatingComparer.cs index adb78dec5..fa136c36d 100644 --- a/Emby.Server.Implementations/Sorting/CriticRatingComparer.cs +++ b/Emby.Server.Implementations/Sorting/CriticRatingComparer.cs @@ -5,7 +5,7 @@ using MediaBrowser.Model.Querying; namespace Emby.Server.Implementations.Sorting { /// - /// Class CriticRatingComparer + /// Class CriticRatingComparer. /// public class CriticRatingComparer : IBaseItemComparer { diff --git a/Emby.Server.Implementations/Sorting/DateCreatedComparer.cs b/Emby.Server.Implementations/Sorting/DateCreatedComparer.cs index 8501bd9ee..ea981e840 100644 --- a/Emby.Server.Implementations/Sorting/DateCreatedComparer.cs +++ b/Emby.Server.Implementations/Sorting/DateCreatedComparer.cs @@ -6,7 +6,7 @@ using MediaBrowser.Model.Querying; namespace Emby.Server.Implementations.Sorting { /// - /// Class DateCreatedComparer + /// Class DateCreatedComparer. /// public class DateCreatedComparer : IBaseItemComparer { diff --git a/Emby.Server.Implementations/Sorting/DatePlayedComparer.cs b/Emby.Server.Implementations/Sorting/DatePlayedComparer.cs index 5e527ea25..16bd2aff8 100644 --- a/Emby.Server.Implementations/Sorting/DatePlayedComparer.cs +++ b/Emby.Server.Implementations/Sorting/DatePlayedComparer.cs @@ -8,7 +8,7 @@ using MediaBrowser.Model.Querying; namespace Emby.Server.Implementations.Sorting { /// - /// Class DatePlayedComparer + /// Class DatePlayedComparer. /// public class DatePlayedComparer : IUserBaseItemComparer { diff --git a/Emby.Server.Implementations/Sorting/NameComparer.cs b/Emby.Server.Implementations/Sorting/NameComparer.cs index 4eb1549f5..da020d8d8 100644 --- a/Emby.Server.Implementations/Sorting/NameComparer.cs +++ b/Emby.Server.Implementations/Sorting/NameComparer.cs @@ -6,7 +6,7 @@ using MediaBrowser.Model.Querying; namespace Emby.Server.Implementations.Sorting { /// - /// Class NameComparer + /// Class NameComparer. /// public class NameComparer : IBaseItemComparer { diff --git a/Emby.Server.Implementations/Sorting/PlayCountComparer.cs b/Emby.Server.Implementations/Sorting/PlayCountComparer.cs index afbaaf6ab..5c2830322 100644 --- a/Emby.Server.Implementations/Sorting/PlayCountComparer.cs +++ b/Emby.Server.Implementations/Sorting/PlayCountComparer.cs @@ -7,7 +7,7 @@ using MediaBrowser.Model.Querying; namespace Emby.Server.Implementations.Sorting { /// - /// Class PlayCountComparer + /// Class PlayCountComparer. /// public class PlayCountComparer : IUserBaseItemComparer { diff --git a/Emby.Server.Implementations/Sorting/PremiereDateComparer.cs b/Emby.Server.Implementations/Sorting/PremiereDateComparer.cs index 0c944a7a0..a24dc4030 100644 --- a/Emby.Server.Implementations/Sorting/PremiereDateComparer.cs +++ b/Emby.Server.Implementations/Sorting/PremiereDateComparer.cs @@ -6,7 +6,7 @@ using MediaBrowser.Model.Querying; namespace Emby.Server.Implementations.Sorting { /// - /// Class PremiereDateComparer + /// Class PremiereDateComparer. /// public class PremiereDateComparer : IBaseItemComparer { diff --git a/Emby.Server.Implementations/Sorting/ProductionYearComparer.cs b/Emby.Server.Implementations/Sorting/ProductionYearComparer.cs index 472a07eb3..e2857df0b 100644 --- a/Emby.Server.Implementations/Sorting/ProductionYearComparer.cs +++ b/Emby.Server.Implementations/Sorting/ProductionYearComparer.cs @@ -5,7 +5,7 @@ using MediaBrowser.Model.Querying; namespace Emby.Server.Implementations.Sorting { /// - /// Class ProductionYearComparer + /// Class ProductionYearComparer. /// public class ProductionYearComparer : IBaseItemComparer { diff --git a/Emby.Server.Implementations/Sorting/RandomComparer.cs b/Emby.Server.Implementations/Sorting/RandomComparer.cs index bde8b4534..7739d0418 100644 --- a/Emby.Server.Implementations/Sorting/RandomComparer.cs +++ b/Emby.Server.Implementations/Sorting/RandomComparer.cs @@ -6,7 +6,7 @@ using MediaBrowser.Model.Querying; namespace Emby.Server.Implementations.Sorting { /// - /// Class RandomComparer + /// Class RandomComparer. /// public class RandomComparer : IBaseItemComparer { diff --git a/Emby.Server.Implementations/Sorting/RuntimeComparer.cs b/Emby.Server.Implementations/Sorting/RuntimeComparer.cs index 1d2bdde26..f165123ea 100644 --- a/Emby.Server.Implementations/Sorting/RuntimeComparer.cs +++ b/Emby.Server.Implementations/Sorting/RuntimeComparer.cs @@ -6,7 +6,7 @@ using MediaBrowser.Model.Querying; namespace Emby.Server.Implementations.Sorting { /// - /// Class RuntimeComparer + /// Class RuntimeComparer. /// public class RuntimeComparer : IBaseItemComparer { diff --git a/Emby.Server.Implementations/Sorting/SortNameComparer.cs b/Emby.Server.Implementations/Sorting/SortNameComparer.cs index cc0571c78..93389fc3e 100644 --- a/Emby.Server.Implementations/Sorting/SortNameComparer.cs +++ b/Emby.Server.Implementations/Sorting/SortNameComparer.cs @@ -6,7 +6,7 @@ using MediaBrowser.Model.Querying; namespace Emby.Server.Implementations.Sorting { /// - /// Class SortNameComparer + /// Class SortNameComparer. /// public class SortNameComparer : IBaseItemComparer { diff --git a/Emby.Server.Implementations/Udp/UdpServer.cs b/Emby.Server.Implementations/Udp/UdpServer.cs index a26f714b1..bf8a436b4 100644 --- a/Emby.Server.Implementations/Udp/UdpServer.cs +++ b/Emby.Server.Implementations/Udp/UdpServer.cs @@ -18,7 +18,7 @@ namespace Emby.Server.Implementations.Udp public sealed class UdpServer : IDisposable { /// - /// The _logger + /// The _logger. /// private readonly ILogger _logger; private readonly IServerApplicationHost _appHost; diff --git a/Jellyfin.Data/Entities/Artwork.cs b/Jellyfin.Data/Entities/Artwork.cs index 214fb4cb1..891904cc3 100644 --- a/Jellyfin.Data/Entities/Artwork.cs +++ b/Jellyfin.Data/Entities/Artwork.cs @@ -24,7 +24,7 @@ namespace Jellyfin.Data.Entities } /// - /// Public constructor with required data + /// Public constructor with required data. /// /// /// @@ -64,7 +64,7 @@ namespace Jellyfin.Data.Entities *************************************************************************/ /// - /// Backing field for Id + /// Backing field for Id. /// internal int _Id; /// @@ -77,7 +77,7 @@ namespace Jellyfin.Data.Entities partial void GetId(ref int result); /// - /// Identity, Indexed, Required + /// Identity, Indexed, Required. /// [Key] [Required] @@ -101,7 +101,7 @@ namespace Jellyfin.Data.Entities } /// - /// Backing field for Path + /// Backing field for Path. /// protected string _Path; /// @@ -139,7 +139,7 @@ namespace Jellyfin.Data.Entities } /// - /// Backing field for Kind + /// Backing field for Kind. /// internal Enums.ArtKind _Kind; /// @@ -152,7 +152,7 @@ namespace Jellyfin.Data.Entities partial void GetKind(ref Enums.ArtKind result); /// - /// Indexed, Required + /// Indexed, Required. /// [Required] public Enums.ArtKind Kind @@ -175,7 +175,7 @@ namespace Jellyfin.Data.Entities } /// - /// Required, ConcurrenyToken + /// Required, ConcurrenyToken. /// [ConcurrencyCheck] [Required] diff --git a/Jellyfin.Data/Entities/Book.cs b/Jellyfin.Data/Entities/Book.cs index faefc7400..c4d12496e 100644 --- a/Jellyfin.Data/Entities/Book.cs +++ b/Jellyfin.Data/Entities/Book.cs @@ -28,7 +28,7 @@ namespace Jellyfin.Data.Entities } /// - /// Public constructor with required data + /// Public constructor with required data. /// /// This is whats gets displayed in the Urls and API requests. This could also be a string. public Book(Guid urlid, DateTime dateadded) diff --git a/Jellyfin.Data/Entities/BookMetadata.cs b/Jellyfin.Data/Entities/BookMetadata.cs index dd389b64a..474f906a1 100644 --- a/Jellyfin.Data/Entities/BookMetadata.cs +++ b/Jellyfin.Data/Entities/BookMetadata.cs @@ -27,7 +27,7 @@ namespace Jellyfin.Data.Entities } /// - /// Public constructor with required data + /// Public constructor with required data. /// /// The title or name of the object /// ISO-639-3 3-character language codes @@ -64,7 +64,7 @@ namespace Jellyfin.Data.Entities *************************************************************************/ /// - /// Backing field for ISBN + /// Backing field for ISBN. /// protected long? _ISBN; /// diff --git a/Jellyfin.Data/Entities/Chapter.cs b/Jellyfin.Data/Entities/Chapter.cs index 9b3a5e827..5a5cdaa8f 100644 --- a/Jellyfin.Data/Entities/Chapter.cs +++ b/Jellyfin.Data/Entities/Chapter.cs @@ -25,7 +25,7 @@ namespace Jellyfin.Data.Entities } /// - /// Public constructor with required data + /// Public constructor with required data. /// /// ISO-639-3 3-character language codes /// @@ -60,7 +60,7 @@ namespace Jellyfin.Data.Entities *************************************************************************/ /// - /// Backing field for Id + /// Backing field for Id. /// internal int _Id; /// @@ -73,7 +73,7 @@ namespace Jellyfin.Data.Entities partial void GetId(ref int result); /// - /// Identity, Indexed, Required + /// Identity, Indexed, Required. /// [Key] [Required] @@ -98,7 +98,7 @@ namespace Jellyfin.Data.Entities } /// - /// Backing field for Name + /// Backing field for Name. /// protected string _Name; /// @@ -135,7 +135,7 @@ namespace Jellyfin.Data.Entities } /// - /// Backing field for Language + /// Backing field for Language. /// protected string _Language; /// @@ -149,7 +149,7 @@ namespace Jellyfin.Data.Entities /// /// Required, Min length = 3, Max length = 3 - /// ISO-639-3 3-character language codes + /// ISO-639-3 3-character language codes. /// [Required] [MinLength(3)] @@ -175,7 +175,7 @@ namespace Jellyfin.Data.Entities } /// - /// Backing field for TimeStart + /// Backing field for TimeStart. /// protected long _TimeStart; /// @@ -188,7 +188,7 @@ namespace Jellyfin.Data.Entities partial void GetTimeStart(ref long result); /// - /// Required + /// Required. /// [Required] public long TimeStart @@ -211,7 +211,7 @@ namespace Jellyfin.Data.Entities } /// - /// Backing field for TimeEnd + /// Backing field for TimeEnd. /// protected long? _TimeEnd; /// @@ -243,7 +243,7 @@ namespace Jellyfin.Data.Entities } /// - /// Required, ConcurrenyToken + /// Required, ConcurrenyToken. /// [ConcurrencyCheck] [Required] diff --git a/Jellyfin.Data/Entities/Collection.cs b/Jellyfin.Data/Entities/Collection.cs index c040cfe33..87c9487c0 100644 --- a/Jellyfin.Data/Entities/Collection.cs +++ b/Jellyfin.Data/Entities/Collection.cs @@ -9,7 +9,7 @@ namespace Jellyfin.Data.Entities partial void Init(); /// - /// Default constructor + /// Default constructor. /// public Collection() { @@ -23,7 +23,7 @@ namespace Jellyfin.Data.Entities *************************************************************************/ /// - /// Backing field for Id + /// Backing field for Id. /// internal int _Id; /// @@ -36,7 +36,7 @@ namespace Jellyfin.Data.Entities partial void GetId(ref int result); /// - /// Identity, Indexed, Required + /// Identity, Indexed, Required. /// [Key] [Required] @@ -61,7 +61,7 @@ namespace Jellyfin.Data.Entities } /// - /// Backing field for Name + /// Backing field for Name. /// protected string _Name; /// @@ -98,7 +98,7 @@ namespace Jellyfin.Data.Entities } /// - /// Required, ConcurrenyToken + /// Required, ConcurrenyToken. /// [ConcurrencyCheck] [Required] diff --git a/Jellyfin.Data/Entities/CollectionItem.cs b/Jellyfin.Data/Entities/CollectionItem.cs index c5e54c3a2..fc3705fe0 100644 --- a/Jellyfin.Data/Entities/CollectionItem.cs +++ b/Jellyfin.Data/Entities/CollectionItem.cs @@ -28,7 +28,7 @@ namespace Jellyfin.Data.Entities } /// - /// Public constructor with required data + /// Public constructor with required data. /// /// /// @@ -67,7 +67,7 @@ namespace Jellyfin.Data.Entities *************************************************************************/ /// - /// Backing field for Id + /// Backing field for Id. /// internal int _Id; /// @@ -80,7 +80,7 @@ namespace Jellyfin.Data.Entities partial void GetId(ref int result); /// - /// Identity, Indexed, Required + /// Identity, Indexed, Required. /// [Key] [Required] @@ -105,7 +105,7 @@ namespace Jellyfin.Data.Entities } /// - /// Required, ConcurrenyToken + /// Required, ConcurrenyToken. /// [ConcurrencyCheck] [Required] @@ -121,7 +121,7 @@ namespace Jellyfin.Data.Entities *************************************************************************/ /// - /// Required + /// Required. /// [ForeignKey("LibraryItem_Id")] public virtual LibraryItem LibraryItem { get; set; } diff --git a/Jellyfin.Data/Entities/Company.cs b/Jellyfin.Data/Entities/Company.cs index 7d6f3b207..2af05b8a1 100644 --- a/Jellyfin.Data/Entities/Company.cs +++ b/Jellyfin.Data/Entities/Company.cs @@ -28,7 +28,7 @@ namespace Jellyfin.Data.Entities } /// - /// Public constructor with required data + /// Public constructor with required data. /// /// /// @@ -75,7 +75,7 @@ namespace Jellyfin.Data.Entities *************************************************************************/ /// - /// Backing field for Id + /// Backing field for Id. /// internal int _Id; /// @@ -88,7 +88,7 @@ namespace Jellyfin.Data.Entities partial void GetId(ref int result); /// - /// Identity, Indexed, Required + /// Identity, Indexed, Required. /// [Key] [Required] @@ -113,7 +113,7 @@ namespace Jellyfin.Data.Entities } /// - /// Required, ConcurrenyToken + /// Required, ConcurrenyToken. /// [ConcurrencyCheck] [Required] diff --git a/Jellyfin.Data/Entities/CompanyMetadata.cs b/Jellyfin.Data/Entities/CompanyMetadata.cs index 1ad03b4f9..64d59fbd2 100644 --- a/Jellyfin.Data/Entities/CompanyMetadata.cs +++ b/Jellyfin.Data/Entities/CompanyMetadata.cs @@ -24,7 +24,7 @@ namespace Jellyfin.Data.Entities } /// - /// Public constructor with required data + /// Public constructor with required data. /// /// The title or name of the object /// ISO-639-3 3-character language codes @@ -60,7 +60,7 @@ namespace Jellyfin.Data.Entities *************************************************************************/ /// - /// Backing field for Description + /// Backing field for Description. /// protected string _Description; /// @@ -97,7 +97,7 @@ namespace Jellyfin.Data.Entities } /// - /// Backing field for Headquarters + /// Backing field for Headquarters. /// protected string _Headquarters; /// @@ -134,7 +134,7 @@ namespace Jellyfin.Data.Entities } /// - /// Backing field for Country + /// Backing field for Country. /// protected string _Country; /// @@ -171,7 +171,7 @@ namespace Jellyfin.Data.Entities } /// - /// Backing field for Homepage + /// Backing field for Homepage. /// protected string _Homepage; /// diff --git a/Jellyfin.Data/Entities/CustomItem.cs b/Jellyfin.Data/Entities/CustomItem.cs index 5f6fc3a23..446391591 100644 --- a/Jellyfin.Data/Entities/CustomItem.cs +++ b/Jellyfin.Data/Entities/CustomItem.cs @@ -28,7 +28,7 @@ namespace Jellyfin.Data.Entities } /// - /// Public constructor with required data + /// Public constructor with required data. /// /// This is whats gets displayed in the Urls and API requests. This could also be a string. public CustomItem(Guid urlid, DateTime dateadded) diff --git a/Jellyfin.Data/Entities/CustomItemMetadata.cs b/Jellyfin.Data/Entities/CustomItemMetadata.cs index ee37aaaa9..b81408aa6 100644 --- a/Jellyfin.Data/Entities/CustomItemMetadata.cs +++ b/Jellyfin.Data/Entities/CustomItemMetadata.cs @@ -23,7 +23,7 @@ namespace Jellyfin.Data.Entities } /// - /// Public constructor with required data + /// Public constructor with required data. /// /// The title or name of the object /// ISO-639-3 3-character language codes diff --git a/Jellyfin.Data/Entities/Episode.cs b/Jellyfin.Data/Entities/Episode.cs index 88531205f..132af9bdc 100644 --- a/Jellyfin.Data/Entities/Episode.cs +++ b/Jellyfin.Data/Entities/Episode.cs @@ -31,7 +31,7 @@ namespace Jellyfin.Data.Entities } /// - /// Public constructor with required data + /// Public constructor with required data. /// /// This is whats gets displayed in the Urls and API requests. This could also be a string. /// @@ -66,7 +66,7 @@ namespace Jellyfin.Data.Entities *************************************************************************/ /// - /// Backing field for EpisodeNumber + /// Backing field for EpisodeNumber. /// protected int? _EpisodeNumber; /// diff --git a/Jellyfin.Data/Entities/EpisodeMetadata.cs b/Jellyfin.Data/Entities/EpisodeMetadata.cs index 0aa4b4270..a4e50fca2 100644 --- a/Jellyfin.Data/Entities/EpisodeMetadata.cs +++ b/Jellyfin.Data/Entities/EpisodeMetadata.cs @@ -24,7 +24,7 @@ namespace Jellyfin.Data.Entities } /// - /// Public constructor with required data + /// Public constructor with required data. /// /// The title or name of the object /// ISO-639-3 3-character language codes @@ -60,7 +60,7 @@ namespace Jellyfin.Data.Entities *************************************************************************/ /// - /// Backing field for Outline + /// Backing field for Outline. /// protected string _Outline; /// @@ -97,7 +97,7 @@ namespace Jellyfin.Data.Entities } /// - /// Backing field for Plot + /// Backing field for Plot. /// protected string _Plot; /// @@ -134,7 +134,7 @@ namespace Jellyfin.Data.Entities } /// - /// Backing field for Tagline + /// Backing field for Tagline. /// protected string _Tagline; /// diff --git a/Jellyfin.Data/Entities/Genre.cs b/Jellyfin.Data/Entities/Genre.cs index ff0710671..a38c019fb 100644 --- a/Jellyfin.Data/Entities/Genre.cs +++ b/Jellyfin.Data/Entities/Genre.cs @@ -25,7 +25,7 @@ namespace Jellyfin.Data.Entities } /// - /// Public constructor with required data + /// Public constructor with required data. /// /// /// @@ -56,7 +56,7 @@ namespace Jellyfin.Data.Entities *************************************************************************/ /// - /// Backing field for Id + /// Backing field for Id. /// internal int _Id; /// @@ -69,7 +69,7 @@ namespace Jellyfin.Data.Entities partial void GetId(ref int result); /// - /// Identity, Indexed, Required + /// Identity, Indexed, Required. /// [Key] [Required] @@ -94,7 +94,7 @@ namespace Jellyfin.Data.Entities } /// - /// Backing field for Name + /// Backing field for Name. /// internal string _Name; /// @@ -132,7 +132,7 @@ namespace Jellyfin.Data.Entities } /// - /// Required, ConcurrenyToken + /// Required, ConcurrenyToken. /// [ConcurrencyCheck] [Required] diff --git a/Jellyfin.Data/Entities/Library.cs b/Jellyfin.Data/Entities/Library.cs index a5cc5c8da..c5609d858 100644 --- a/Jellyfin.Data/Entities/Library.cs +++ b/Jellyfin.Data/Entities/Library.cs @@ -25,7 +25,7 @@ namespace Jellyfin.Data.Entities } /// - /// Public constructor with required data + /// Public constructor with required data. /// /// public Library(string name) @@ -51,7 +51,7 @@ namespace Jellyfin.Data.Entities *************************************************************************/ /// - /// Backing field for Id + /// Backing field for Id. /// internal int _Id; /// @@ -64,7 +64,7 @@ namespace Jellyfin.Data.Entities partial void GetId(ref int result); /// - /// Identity, Indexed, Required + /// Identity, Indexed, Required. /// [Key] [Required] @@ -89,7 +89,7 @@ namespace Jellyfin.Data.Entities } /// - /// Backing field for Name + /// Backing field for Name. /// protected string _Name; /// @@ -127,7 +127,7 @@ namespace Jellyfin.Data.Entities } /// - /// Required, ConcurrenyToken + /// Required, ConcurrenyToken. /// [ConcurrencyCheck] [Required] diff --git a/Jellyfin.Data/Entities/LibraryItem.cs b/Jellyfin.Data/Entities/LibraryItem.cs index c2ba7059d..b7dad8d7c 100644 --- a/Jellyfin.Data/Entities/LibraryItem.cs +++ b/Jellyfin.Data/Entities/LibraryItem.cs @@ -17,7 +17,7 @@ namespace Jellyfin.Data.Entities } /// - /// Public constructor with required data + /// Public constructor with required data. /// /// This is whats gets displayed in the Urls and API requests. This could also be a string. protected LibraryItem(Guid urlid, DateTime dateadded) @@ -33,7 +33,7 @@ namespace Jellyfin.Data.Entities *************************************************************************/ /// - /// Backing field for Id + /// Backing field for Id. /// internal int _Id; /// @@ -46,7 +46,7 @@ namespace Jellyfin.Data.Entities partial void GetId(ref int result); /// - /// Identity, Indexed, Required + /// Identity, Indexed, Required. /// [Key] [Required] @@ -71,7 +71,7 @@ namespace Jellyfin.Data.Entities } /// - /// Backing field for UrlId + /// Backing field for UrlId. /// internal Guid _UrlId; /// @@ -108,7 +108,7 @@ namespace Jellyfin.Data.Entities } /// - /// Backing field for DateAdded + /// Backing field for DateAdded. /// protected DateTime _DateAdded; /// @@ -121,7 +121,7 @@ namespace Jellyfin.Data.Entities partial void GetDateAdded(ref DateTime result); /// - /// Required + /// Required. /// [Required] public DateTime DateAdded @@ -144,7 +144,7 @@ namespace Jellyfin.Data.Entities } /// - /// Required, ConcurrenyToken + /// Required, ConcurrenyToken. /// [ConcurrencyCheck] [Required] @@ -160,7 +160,7 @@ namespace Jellyfin.Data.Entities *************************************************************************/ /// - /// Required + /// Required. /// [ForeignKey("LibraryRoot_Id")] public virtual LibraryRoot LibraryRoot { get; set; } diff --git a/Jellyfin.Data/Entities/LibraryRoot.cs b/Jellyfin.Data/Entities/LibraryRoot.cs index 7823db02a..a84c7de4b 100644 --- a/Jellyfin.Data/Entities/LibraryRoot.cs +++ b/Jellyfin.Data/Entities/LibraryRoot.cs @@ -25,7 +25,7 @@ namespace Jellyfin.Data.Entities } /// - /// Public constructor with required data + /// Public constructor with required data. /// /// Absolute Path public LibraryRoot(string path) @@ -51,7 +51,7 @@ namespace Jellyfin.Data.Entities *************************************************************************/ /// - /// Backing field for Id + /// Backing field for Id. /// internal int _Id; /// @@ -64,7 +64,7 @@ namespace Jellyfin.Data.Entities partial void GetId(ref int result); /// - /// Identity, Indexed, Required + /// Identity, Indexed, Required. /// [Key] [Required] @@ -89,7 +89,7 @@ namespace Jellyfin.Data.Entities } /// - /// Backing field for Path + /// Backing field for Path. /// protected string _Path; /// @@ -103,7 +103,7 @@ namespace Jellyfin.Data.Entities /// /// Required, Max length = 65535 - /// Absolute Path + /// Absolute Path. /// [Required] [MaxLength(65535)] @@ -128,7 +128,7 @@ namespace Jellyfin.Data.Entities } /// - /// Backing field for NetworkPath + /// Backing field for NetworkPath. /// protected string _NetworkPath; /// @@ -166,7 +166,7 @@ namespace Jellyfin.Data.Entities } /// - /// Required, ConcurrenyToken + /// Required, ConcurrenyToken. /// [ConcurrencyCheck] [Required] @@ -182,7 +182,7 @@ namespace Jellyfin.Data.Entities *************************************************************************/ /// - /// Required + /// Required. /// [ForeignKey("Library_Id")] public virtual Library Library { get; set; } diff --git a/Jellyfin.Data/Entities/MediaFile.cs b/Jellyfin.Data/Entities/MediaFile.cs index 94c39a28a..d8781bcb2 100644 --- a/Jellyfin.Data/Entities/MediaFile.cs +++ b/Jellyfin.Data/Entities/MediaFile.cs @@ -28,7 +28,7 @@ namespace Jellyfin.Data.Entities } /// - /// Public constructor with required data + /// Public constructor with required data. /// /// Relative to the LibraryRoot /// @@ -64,7 +64,7 @@ namespace Jellyfin.Data.Entities *************************************************************************/ /// - /// Backing field for Id + /// Backing field for Id. /// internal int _Id; /// @@ -77,7 +77,7 @@ namespace Jellyfin.Data.Entities partial void GetId(ref int result); /// - /// Identity, Indexed, Required + /// Identity, Indexed, Required. /// [Key] [Required] @@ -102,7 +102,7 @@ namespace Jellyfin.Data.Entities } /// - /// Backing field for Path + /// Backing field for Path. /// protected string _Path; /// @@ -116,7 +116,7 @@ namespace Jellyfin.Data.Entities /// /// Required, Max length = 65535 - /// Relative to the LibraryRoot + /// Relative to the LibraryRoot. /// [Required] [MaxLength(65535)] @@ -141,7 +141,7 @@ namespace Jellyfin.Data.Entities } /// - /// Backing field for Kind + /// Backing field for Kind. /// protected Enums.MediaFileKind _Kind; /// @@ -154,7 +154,7 @@ namespace Jellyfin.Data.Entities partial void GetKind(ref Enums.MediaFileKind result); /// - /// Required + /// Required. /// [Required] public Enums.MediaFileKind Kind @@ -177,7 +177,7 @@ namespace Jellyfin.Data.Entities } /// - /// Required, ConcurrenyToken + /// Required, ConcurrenyToken. /// [ConcurrencyCheck] [Required] diff --git a/Jellyfin.Data/Entities/MediaFileStream.cs b/Jellyfin.Data/Entities/MediaFileStream.cs index 723977fdf..a7a33e255 100644 --- a/Jellyfin.Data/Entities/MediaFileStream.cs +++ b/Jellyfin.Data/Entities/MediaFileStream.cs @@ -25,7 +25,7 @@ namespace Jellyfin.Data.Entities } /// - /// Public constructor with required data + /// Public constructor with required data. /// /// /// @@ -55,7 +55,7 @@ namespace Jellyfin.Data.Entities *************************************************************************/ /// - /// Backing field for Id + /// Backing field for Id. /// internal int _Id; /// @@ -68,7 +68,7 @@ namespace Jellyfin.Data.Entities partial void GetId(ref int result); /// - /// Identity, Indexed, Required + /// Identity, Indexed, Required. /// [Key] [Required] @@ -93,7 +93,7 @@ namespace Jellyfin.Data.Entities } /// - /// Backing field for StreamNumber + /// Backing field for StreamNumber. /// protected int _StreamNumber; /// @@ -106,7 +106,7 @@ namespace Jellyfin.Data.Entities partial void GetStreamNumber(ref int result); /// - /// Required + /// Required. /// [Required] public int StreamNumber @@ -129,7 +129,7 @@ namespace Jellyfin.Data.Entities } /// - /// Required, ConcurrenyToken + /// Required, ConcurrenyToken. /// [ConcurrencyCheck] [Required] diff --git a/Jellyfin.Data/Entities/Metadata.cs b/Jellyfin.Data/Entities/Metadata.cs index 6558642cf..4282bb9f7 100644 --- a/Jellyfin.Data/Entities/Metadata.cs +++ b/Jellyfin.Data/Entities/Metadata.cs @@ -24,7 +24,7 @@ namespace Jellyfin.Data.Entities } /// - /// Public constructor with required data + /// Public constructor with required data. /// /// The title or name of the object /// ISO-639-3 3-character language codes @@ -50,7 +50,7 @@ namespace Jellyfin.Data.Entities *************************************************************************/ /// - /// Backing field for Id + /// Backing field for Id. /// internal int _Id; /// @@ -63,7 +63,7 @@ namespace Jellyfin.Data.Entities partial void GetId(ref int result); /// - /// Identity, Indexed, Required + /// Identity, Indexed, Required. /// [Key] [Required] @@ -88,7 +88,7 @@ namespace Jellyfin.Data.Entities } /// - /// Backing field for Title + /// Backing field for Title. /// protected string _Title; /// @@ -102,7 +102,7 @@ namespace Jellyfin.Data.Entities /// /// Required, Max length = 1024 - /// The title or name of the object + /// The title or name of the object. /// [Required] [MaxLength(1024)] @@ -127,7 +127,7 @@ namespace Jellyfin.Data.Entities } /// - /// Backing field for OriginalTitle + /// Backing field for OriginalTitle. /// protected string _OriginalTitle; /// @@ -164,7 +164,7 @@ namespace Jellyfin.Data.Entities } /// - /// Backing field for SortTitle + /// Backing field for SortTitle. /// protected string _SortTitle; /// @@ -201,7 +201,7 @@ namespace Jellyfin.Data.Entities } /// - /// Backing field for Language + /// Backing field for Language. /// protected string _Language; /// @@ -215,7 +215,7 @@ namespace Jellyfin.Data.Entities /// /// Required, Min length = 3, Max length = 3 - /// ISO-639-3 3-character language codes + /// ISO-639-3 3-character language codes. /// [Required] [MinLength(3)] @@ -241,7 +241,7 @@ namespace Jellyfin.Data.Entities } /// - /// Backing field for ReleaseDate + /// Backing field for ReleaseDate. /// protected DateTimeOffset? _ReleaseDate; /// @@ -273,7 +273,7 @@ namespace Jellyfin.Data.Entities } /// - /// Backing field for DateAdded + /// Backing field for DateAdded. /// protected DateTime _DateAdded; /// @@ -286,7 +286,7 @@ namespace Jellyfin.Data.Entities partial void GetDateAdded(ref DateTime result); /// - /// Required + /// Required. /// [Required] public DateTime DateAdded @@ -309,7 +309,7 @@ namespace Jellyfin.Data.Entities } /// - /// Backing field for DateModified + /// Backing field for DateModified. /// protected DateTime _DateModified; /// @@ -322,7 +322,7 @@ namespace Jellyfin.Data.Entities partial void GetDateModified(ref DateTime result); /// - /// Required + /// Required. /// [Required] public DateTime DateModified @@ -345,7 +345,7 @@ namespace Jellyfin.Data.Entities } /// - /// Required, ConcurrenyToken + /// Required, ConcurrenyToken. /// [ConcurrencyCheck] [Required] diff --git a/Jellyfin.Data/Entities/MetadataProvider.cs b/Jellyfin.Data/Entities/MetadataProvider.cs index bf9689709..9069d6ad6 100644 --- a/Jellyfin.Data/Entities/MetadataProvider.cs +++ b/Jellyfin.Data/Entities/MetadataProvider.cs @@ -25,7 +25,7 @@ namespace Jellyfin.Data.Entities } /// - /// Public constructor with required data + /// Public constructor with required data. /// /// public MetadataProvider(string name) @@ -51,7 +51,7 @@ namespace Jellyfin.Data.Entities *************************************************************************/ /// - /// Backing field for Id + /// Backing field for Id. /// internal int _Id; /// @@ -64,7 +64,7 @@ namespace Jellyfin.Data.Entities partial void GetId(ref int result); /// - /// Identity, Indexed, Required + /// Identity, Indexed, Required. /// [Key] [Required] @@ -89,7 +89,7 @@ namespace Jellyfin.Data.Entities } /// - /// Backing field for Name + /// Backing field for Name. /// protected string _Name; /// @@ -127,7 +127,7 @@ namespace Jellyfin.Data.Entities } /// - /// Required, ConcurrenyToken + /// Required, ConcurrenyToken. /// [ConcurrencyCheck] [Required] diff --git a/Jellyfin.Data/Entities/MetadataProviderId.cs b/Jellyfin.Data/Entities/MetadataProviderId.cs index c49c6f42e..5facf1188 100644 --- a/Jellyfin.Data/Entities/MetadataProviderId.cs +++ b/Jellyfin.Data/Entities/MetadataProviderId.cs @@ -28,7 +28,7 @@ namespace Jellyfin.Data.Entities } /// - /// Public constructor with required data + /// Public constructor with required data. /// /// /// @@ -77,7 +77,7 @@ namespace Jellyfin.Data.Entities *************************************************************************/ /// - /// Backing field for Id + /// Backing field for Id. /// internal int _Id; /// @@ -90,7 +90,7 @@ namespace Jellyfin.Data.Entities partial void GetId(ref int result); /// - /// Identity, Indexed, Required + /// Identity, Indexed, Required. /// [Key] [Required] @@ -115,7 +115,7 @@ namespace Jellyfin.Data.Entities } /// - /// Backing field for ProviderId + /// Backing field for ProviderId. /// protected string _ProviderId; /// @@ -153,7 +153,7 @@ namespace Jellyfin.Data.Entities } /// - /// Required, ConcurrenyToken + /// Required, ConcurrenyToken. /// [ConcurrencyCheck] [Required] @@ -169,7 +169,7 @@ namespace Jellyfin.Data.Entities *************************************************************************/ /// - /// Required + /// Required. /// [ForeignKey("MetadataProvider_Id")] public virtual MetadataProvider MetadataProvider { get; set; } diff --git a/Jellyfin.Data/Entities/Movie.cs b/Jellyfin.Data/Entities/Movie.cs index ad2504b0d..64326ca3a 100644 --- a/Jellyfin.Data/Entities/Movie.cs +++ b/Jellyfin.Data/Entities/Movie.cs @@ -28,7 +28,7 @@ namespace Jellyfin.Data.Entities } /// - /// Public constructor with required data + /// Public constructor with required data. /// /// This is whats gets displayed in the Urls and API requests. This could also be a string. public Movie(Guid urlid, DateTime dateadded) diff --git a/Jellyfin.Data/Entities/MovieMetadata.cs b/Jellyfin.Data/Entities/MovieMetadata.cs index 1f8f1c2a0..f01b208bc 100644 --- a/Jellyfin.Data/Entities/MovieMetadata.cs +++ b/Jellyfin.Data/Entities/MovieMetadata.cs @@ -28,7 +28,7 @@ namespace Jellyfin.Data.Entities } /// - /// Public constructor with required data + /// Public constructor with required data. /// /// The title or name of the object /// ISO-639-3 3-character language codes @@ -65,7 +65,7 @@ namespace Jellyfin.Data.Entities *************************************************************************/ /// - /// Backing field for Outline + /// Backing field for Outline. /// protected string _Outline; /// @@ -102,7 +102,7 @@ namespace Jellyfin.Data.Entities } /// - /// Backing field for Plot + /// Backing field for Plot. /// protected string _Plot; /// @@ -139,7 +139,7 @@ namespace Jellyfin.Data.Entities } /// - /// Backing field for Tagline + /// Backing field for Tagline. /// protected string _Tagline; /// @@ -176,7 +176,7 @@ namespace Jellyfin.Data.Entities } /// - /// Backing field for Country + /// Backing field for Country. /// protected string _Country; /// diff --git a/Jellyfin.Data/Entities/MusicAlbum.cs b/Jellyfin.Data/Entities/MusicAlbum.cs index e07f4357b..9afea1fb6 100644 --- a/Jellyfin.Data/Entities/MusicAlbum.cs +++ b/Jellyfin.Data/Entities/MusicAlbum.cs @@ -28,7 +28,7 @@ namespace Jellyfin.Data.Entities } /// - /// Public constructor with required data + /// Public constructor with required data. /// /// This is whats gets displayed in the Urls and API requests. This could also be a string. public MusicAlbum(Guid urlid, DateTime dateadded) diff --git a/Jellyfin.Data/Entities/MusicAlbumMetadata.cs b/Jellyfin.Data/Entities/MusicAlbumMetadata.cs index 7743890a6..0ba594654 100644 --- a/Jellyfin.Data/Entities/MusicAlbumMetadata.cs +++ b/Jellyfin.Data/Entities/MusicAlbumMetadata.cs @@ -28,7 +28,7 @@ namespace Jellyfin.Data.Entities } /// - /// Public constructor with required data + /// Public constructor with required data. /// /// The title or name of the object /// ISO-639-3 3-character language codes @@ -65,7 +65,7 @@ namespace Jellyfin.Data.Entities *************************************************************************/ /// - /// Backing field for Barcode + /// Backing field for Barcode. /// protected string _Barcode; /// @@ -102,7 +102,7 @@ namespace Jellyfin.Data.Entities } /// - /// Backing field for LabelNumber + /// Backing field for LabelNumber. /// protected string _LabelNumber; /// @@ -139,7 +139,7 @@ namespace Jellyfin.Data.Entities } /// - /// Backing field for Country + /// Backing field for Country. /// protected string _Country; /// diff --git a/Jellyfin.Data/Entities/Person.cs b/Jellyfin.Data/Entities/Person.cs index f71418819..8f6fb3a7d 100644 --- a/Jellyfin.Data/Entities/Person.cs +++ b/Jellyfin.Data/Entities/Person.cs @@ -28,7 +28,7 @@ namespace Jellyfin.Data.Entities } /// - /// Public constructor with required data + /// Public constructor with required data. /// /// /// @@ -59,7 +59,7 @@ namespace Jellyfin.Data.Entities *************************************************************************/ /// - /// Backing field for Id + /// Backing field for Id. /// internal int _Id; /// @@ -72,7 +72,7 @@ namespace Jellyfin.Data.Entities partial void GetId(ref int result); /// - /// Identity, Indexed, Required + /// Identity, Indexed, Required. /// [Key] [Required] @@ -97,7 +97,7 @@ namespace Jellyfin.Data.Entities } /// - /// Backing field for UrlId + /// Backing field for UrlId. /// protected Guid _UrlId; /// @@ -110,7 +110,7 @@ namespace Jellyfin.Data.Entities partial void GetUrlId(ref Guid result); /// - /// Required + /// Required. /// [Required] public Guid UrlId @@ -133,7 +133,7 @@ namespace Jellyfin.Data.Entities } /// - /// Backing field for Name + /// Backing field for Name. /// protected string _Name; /// @@ -171,7 +171,7 @@ namespace Jellyfin.Data.Entities } /// - /// Backing field for SourceId + /// Backing field for SourceId. /// protected string _SourceId; /// @@ -208,7 +208,7 @@ namespace Jellyfin.Data.Entities } /// - /// Backing field for DateAdded + /// Backing field for DateAdded. /// protected DateTime _DateAdded; /// @@ -221,7 +221,7 @@ namespace Jellyfin.Data.Entities partial void GetDateAdded(ref DateTime result); /// - /// Required + /// Required. /// [Required] public DateTime DateAdded @@ -244,7 +244,7 @@ namespace Jellyfin.Data.Entities } /// - /// Backing field for DateModified + /// Backing field for DateModified. /// protected DateTime _DateModified; /// @@ -257,7 +257,7 @@ namespace Jellyfin.Data.Entities partial void GetDateModified(ref DateTime result); /// - /// Required + /// Required. /// [Required] public DateTime DateModified @@ -280,7 +280,7 @@ namespace Jellyfin.Data.Entities } /// - /// Required, ConcurrenyToken + /// Required, ConcurrenyToken. /// [ConcurrencyCheck] [Required] diff --git a/Jellyfin.Data/Entities/PersonRole.cs b/Jellyfin.Data/Entities/PersonRole.cs index a3d047115..9bd477938 100644 --- a/Jellyfin.Data/Entities/PersonRole.cs +++ b/Jellyfin.Data/Entities/PersonRole.cs @@ -31,7 +31,7 @@ namespace Jellyfin.Data.Entities } /// - /// Public constructor with required data + /// Public constructor with required data. /// /// /// @@ -65,7 +65,7 @@ namespace Jellyfin.Data.Entities *************************************************************************/ /// - /// Backing field for Id + /// Backing field for Id. /// internal int _Id; /// @@ -78,7 +78,7 @@ namespace Jellyfin.Data.Entities partial void GetId(ref int result); /// - /// Identity, Indexed, Required + /// Identity, Indexed, Required. /// [Key] [Required] @@ -103,7 +103,7 @@ namespace Jellyfin.Data.Entities } /// - /// Backing field for Role + /// Backing field for Role. /// protected string _Role; /// @@ -140,7 +140,7 @@ namespace Jellyfin.Data.Entities } /// - /// Backing field for Type + /// Backing field for Type. /// protected Enums.PersonRoleType _Type; /// @@ -153,7 +153,7 @@ namespace Jellyfin.Data.Entities partial void GetType(ref Enums.PersonRoleType result); /// - /// Required + /// Required. /// [Required] public Enums.PersonRoleType Type @@ -176,7 +176,7 @@ namespace Jellyfin.Data.Entities } /// - /// Required, ConcurrenyToken + /// Required, ConcurrenyToken. /// [ConcurrencyCheck] [Required] @@ -192,7 +192,7 @@ namespace Jellyfin.Data.Entities *************************************************************************/ /// - /// Required + /// Required. /// [ForeignKey("Person_Id")] diff --git a/Jellyfin.Data/Entities/Photo.cs b/Jellyfin.Data/Entities/Photo.cs index 226730126..9da55fe43 100644 --- a/Jellyfin.Data/Entities/Photo.cs +++ b/Jellyfin.Data/Entities/Photo.cs @@ -28,7 +28,7 @@ namespace Jellyfin.Data.Entities } /// - /// Public constructor with required data + /// Public constructor with required data. /// /// This is whats gets displayed in the Urls and API requests. This could also be a string. public Photo(Guid urlid, DateTime dateadded) diff --git a/Jellyfin.Data/Entities/PhotoMetadata.cs b/Jellyfin.Data/Entities/PhotoMetadata.cs index 2bb239cdd..5a9cf5b66 100644 --- a/Jellyfin.Data/Entities/PhotoMetadata.cs +++ b/Jellyfin.Data/Entities/PhotoMetadata.cs @@ -24,7 +24,7 @@ namespace Jellyfin.Data.Entities } /// - /// Public constructor with required data + /// Public constructor with required data. /// /// The title or name of the object /// ISO-639-3 3-character language codes diff --git a/Jellyfin.Data/Entities/ProviderMapping.cs b/Jellyfin.Data/Entities/ProviderMapping.cs index e86d9737f..4125eabcd 100644 --- a/Jellyfin.Data/Entities/ProviderMapping.cs +++ b/Jellyfin.Data/Entities/ProviderMapping.cs @@ -25,7 +25,7 @@ namespace Jellyfin.Data.Entities } /// - /// Public constructor with required data + /// Public constructor with required data. /// /// /// @@ -65,7 +65,7 @@ namespace Jellyfin.Data.Entities *************************************************************************/ /// - /// Identity, Indexed, Required + /// Identity, Indexed, Required. /// [Key] [Required] @@ -97,7 +97,7 @@ namespace Jellyfin.Data.Entities public string ProviderData { get; set; } /// - /// Required, ConcurrenyToken + /// Required, ConcurrenyToken. /// [ConcurrencyCheck] [Required] diff --git a/Jellyfin.Data/Entities/Rating.cs b/Jellyfin.Data/Entities/Rating.cs index 0c8b99ca2..34f395a22 100644 --- a/Jellyfin.Data/Entities/Rating.cs +++ b/Jellyfin.Data/Entities/Rating.cs @@ -25,7 +25,7 @@ namespace Jellyfin.Data.Entities } /// - /// Public constructor with required data + /// Public constructor with required data. /// /// /// @@ -55,7 +55,7 @@ namespace Jellyfin.Data.Entities *************************************************************************/ /// - /// Backing field for Id + /// Backing field for Id. /// internal int _Id; /// @@ -68,7 +68,7 @@ namespace Jellyfin.Data.Entities partial void GetId(ref int result); /// - /// Identity, Indexed, Required + /// Identity, Indexed, Required. /// [Key] [Required] @@ -93,7 +93,7 @@ namespace Jellyfin.Data.Entities } /// - /// Backing field for Value + /// Backing field for Value. /// protected double _Value; /// @@ -106,7 +106,7 @@ namespace Jellyfin.Data.Entities partial void GetValue(ref double result); /// - /// Required + /// Required. /// [Required] public double Value @@ -129,7 +129,7 @@ namespace Jellyfin.Data.Entities } /// - /// Backing field for Votes + /// Backing field for Votes. /// protected int? _Votes; /// @@ -161,7 +161,7 @@ namespace Jellyfin.Data.Entities } /// - /// Required, ConcurrenyToken + /// Required, ConcurrenyToken. /// [ConcurrencyCheck] [Required] diff --git a/Jellyfin.Data/Entities/RatingSource.cs b/Jellyfin.Data/Entities/RatingSource.cs index c829042b5..5ea6069f9 100644 --- a/Jellyfin.Data/Entities/RatingSource.cs +++ b/Jellyfin.Data/Entities/RatingSource.cs @@ -5,7 +5,7 @@ using System.ComponentModel.DataAnnotations.Schema; namespace Jellyfin.Data.Entities { /// - /// This is the entity to store review ratings, not age ratings + /// This is the entity to store review ratings, not age ratings. /// public partial class RatingSource { @@ -28,7 +28,7 @@ namespace Jellyfin.Data.Entities } /// - /// Public constructor with required data + /// Public constructor with required data. /// /// /// @@ -62,7 +62,7 @@ namespace Jellyfin.Data.Entities *************************************************************************/ /// - /// Backing field for Id + /// Backing field for Id. /// internal int _Id; /// @@ -75,7 +75,7 @@ namespace Jellyfin.Data.Entities partial void GetId(ref int result); /// - /// Identity, Indexed, Required + /// Identity, Indexed, Required. /// [Key] [Required] @@ -100,7 +100,7 @@ namespace Jellyfin.Data.Entities } /// - /// Backing field for Name + /// Backing field for Name. /// protected string _Name; /// @@ -137,7 +137,7 @@ namespace Jellyfin.Data.Entities } /// - /// Backing field for MaximumValue + /// Backing field for MaximumValue. /// protected double _MaximumValue; /// @@ -150,7 +150,7 @@ namespace Jellyfin.Data.Entities partial void GetMaximumValue(ref double result); /// - /// Required + /// Required. /// [Required] public double MaximumValue @@ -173,7 +173,7 @@ namespace Jellyfin.Data.Entities } /// - /// Backing field for MinimumValue + /// Backing field for MinimumValue. /// protected double _MinimumValue; /// @@ -186,7 +186,7 @@ namespace Jellyfin.Data.Entities partial void GetMinimumValue(ref double result); /// - /// Required + /// Required. /// [Required] public double MinimumValue @@ -209,7 +209,7 @@ namespace Jellyfin.Data.Entities } /// - /// Required, ConcurrenyToken + /// Required, ConcurrenyToken. /// [ConcurrencyCheck] [Required] diff --git a/Jellyfin.Data/Entities/Release.cs b/Jellyfin.Data/Entities/Release.cs index 35fcbb4b7..fe0dbaa54 100644 --- a/Jellyfin.Data/Entities/Release.cs +++ b/Jellyfin.Data/Entities/Release.cs @@ -29,7 +29,7 @@ namespace Jellyfin.Data.Entities } /// - /// Public constructor with required data + /// Public constructor with required data. /// /// /// @@ -87,7 +87,7 @@ namespace Jellyfin.Data.Entities *************************************************************************/ /// - /// Backing field for Id + /// Backing field for Id. /// internal int _Id; /// @@ -100,7 +100,7 @@ namespace Jellyfin.Data.Entities partial void GetId(ref int result); /// - /// Identity, Indexed, Required + /// Identity, Indexed, Required. /// [Key] [Required] @@ -125,7 +125,7 @@ namespace Jellyfin.Data.Entities } /// - /// Backing field for Name + /// Backing field for Name. /// protected string _Name; /// @@ -163,7 +163,7 @@ namespace Jellyfin.Data.Entities } /// - /// Required, ConcurrenyToken + /// Required, ConcurrenyToken. /// [ConcurrencyCheck] [Required] diff --git a/Jellyfin.Data/Entities/Season.cs b/Jellyfin.Data/Entities/Season.cs index 2a861b660..81f413fa8 100644 --- a/Jellyfin.Data/Entities/Season.cs +++ b/Jellyfin.Data/Entities/Season.cs @@ -31,7 +31,7 @@ namespace Jellyfin.Data.Entities } /// - /// Public constructor with required data + /// Public constructor with required data. /// /// This is whats gets displayed in the Urls and API requests. This could also be a string. /// @@ -66,7 +66,7 @@ namespace Jellyfin.Data.Entities *************************************************************************/ /// - /// Backing field for SeasonNumber + /// Backing field for SeasonNumber. /// protected int? _SeasonNumber; /// diff --git a/Jellyfin.Data/Entities/SeasonMetadata.cs b/Jellyfin.Data/Entities/SeasonMetadata.cs index 10320c6bb..b323984f1 100644 --- a/Jellyfin.Data/Entities/SeasonMetadata.cs +++ b/Jellyfin.Data/Entities/SeasonMetadata.cs @@ -25,7 +25,7 @@ namespace Jellyfin.Data.Entities } /// - /// Public constructor with required data + /// Public constructor with required data. /// /// The title or name of the object /// ISO-639-3 3-character language codes @@ -61,7 +61,7 @@ namespace Jellyfin.Data.Entities *************************************************************************/ /// - /// Backing field for Outline + /// Backing field for Outline. /// protected string _Outline; /// diff --git a/Jellyfin.Data/Entities/Series.cs b/Jellyfin.Data/Entities/Series.cs index cf1d6b781..013c8385f 100644 --- a/Jellyfin.Data/Entities/Series.cs +++ b/Jellyfin.Data/Entities/Series.cs @@ -20,7 +20,7 @@ namespace Jellyfin.Data.Entities } /// - /// Public constructor with required data + /// Public constructor with required data. /// /// This is whats gets displayed in the Urls and API requests. This could also be a string. public Series(Guid urlid, DateTime dateadded) @@ -47,7 +47,7 @@ namespace Jellyfin.Data.Entities *************************************************************************/ /// - /// Backing field for AirsDayOfWeek + /// Backing field for AirsDayOfWeek. /// protected DayOfWeek? _AirsDayOfWeek; /// @@ -79,7 +79,7 @@ namespace Jellyfin.Data.Entities } /// - /// Backing field for AirsTime + /// Backing field for AirsTime. /// protected DateTimeOffset? _AirsTime; /// @@ -92,7 +92,7 @@ namespace Jellyfin.Data.Entities partial void GetAirsTime(ref DateTimeOffset? result); /// - /// The time the show airs, ignore the date portion + /// The time the show airs, ignore the date portion. /// public DateTimeOffset? AirsTime { @@ -114,7 +114,7 @@ namespace Jellyfin.Data.Entities } /// - /// Backing field for FirstAired + /// Backing field for FirstAired. /// protected DateTimeOffset? _FirstAired; /// diff --git a/Jellyfin.Data/Entities/SeriesMetadata.cs b/Jellyfin.Data/Entities/SeriesMetadata.cs index bb31c2e4e..4666d79ef 100644 --- a/Jellyfin.Data/Entities/SeriesMetadata.cs +++ b/Jellyfin.Data/Entities/SeriesMetadata.cs @@ -28,7 +28,7 @@ namespace Jellyfin.Data.Entities } /// - /// Public constructor with required data + /// Public constructor with required data. /// /// The title or name of the object /// ISO-639-3 3-character language codes @@ -65,7 +65,7 @@ namespace Jellyfin.Data.Entities *************************************************************************/ /// - /// Backing field for Outline + /// Backing field for Outline. /// protected string _Outline; /// @@ -102,7 +102,7 @@ namespace Jellyfin.Data.Entities } /// - /// Backing field for Plot + /// Backing field for Plot. /// protected string _Plot; /// @@ -139,7 +139,7 @@ namespace Jellyfin.Data.Entities } /// - /// Backing field for Tagline + /// Backing field for Tagline. /// protected string _Tagline; /// @@ -176,7 +176,7 @@ namespace Jellyfin.Data.Entities } /// - /// Backing field for Country + /// Backing field for Country. /// protected string _Country; /// diff --git a/Jellyfin.Data/Entities/Track.cs b/Jellyfin.Data/Entities/Track.cs index c9e8fd1c3..1c3562a65 100644 --- a/Jellyfin.Data/Entities/Track.cs +++ b/Jellyfin.Data/Entities/Track.cs @@ -31,7 +31,7 @@ namespace Jellyfin.Data.Entities } /// - /// Public constructor with required data + /// Public constructor with required data. /// /// This is whats gets displayed in the Urls and API requests. This could also be a string. /// @@ -66,7 +66,7 @@ namespace Jellyfin.Data.Entities *************************************************************************/ /// - /// Backing field for TrackNumber + /// Backing field for TrackNumber. /// protected int? _TrackNumber; /// diff --git a/Jellyfin.Data/Entities/TrackMetadata.cs b/Jellyfin.Data/Entities/TrackMetadata.cs index 7b99c0683..05bb953f8 100644 --- a/Jellyfin.Data/Entities/TrackMetadata.cs +++ b/Jellyfin.Data/Entities/TrackMetadata.cs @@ -24,7 +24,7 @@ namespace Jellyfin.Data.Entities } /// - /// Public constructor with required data + /// Public constructor with required data. /// /// The title or name of the object /// ISO-639-3 3-character language codes diff --git a/Jellyfin.Data/Enums/PreferenceKind.cs b/Jellyfin.Data/Enums/PreferenceKind.cs index de8eecc73..a54d789af 100644 --- a/Jellyfin.Data/Enums/PreferenceKind.cs +++ b/Jellyfin.Data/Enums/PreferenceKind.cs @@ -26,7 +26,7 @@ namespace Jellyfin.Data.Enums EnabledDevices = 3, /// - /// A list of enabled channels + /// A list of enabled channels. /// EnabledChannels = 4, diff --git a/Jellyfin.Server.Implementations/JellyfinDb.cs b/Jellyfin.Server.Implementations/JellyfinDb.cs index f574ebc66..a3fc6291f 100644 --- a/Jellyfin.Server.Implementations/JellyfinDb.cs +++ b/Jellyfin.Server.Implementations/JellyfinDb.cs @@ -69,7 +69,7 @@ namespace Jellyfin.Server.Implementations /// /// Repository for global::Jellyfin.Data.Entities.RatingSource - This is the entity to - /// store review ratings, not age ratings + /// store review ratings, not age ratings. /// public virtual DbSet RatingSources { get; set; } public virtual DbSet Releases { get; set; } diff --git a/MediaBrowser.Api/ApiEntryPoint.cs b/MediaBrowser.Api/ApiEntryPoint.cs index 9e651fb19..b041effb2 100644 --- a/MediaBrowser.Api/ApiEntryPoint.cs +++ b/MediaBrowser.Api/ApiEntryPoint.cs @@ -43,7 +43,7 @@ namespace MediaBrowser.Api private readonly IMediaSourceManager _mediaSourceManager; /// - /// The active transcoding jobs + /// The active transcoding jobs. /// private readonly List _activeTranscodingJobs = new List(); @@ -293,7 +293,7 @@ namespace MediaBrowser.Api /// /// - /// The progressive + /// The progressive. /// /// Called when [transcode failed to start]. /// diff --git a/MediaBrowser.Api/BaseApiService.cs b/MediaBrowser.Api/BaseApiService.cs index a91a9b580..63a31a745 100644 --- a/MediaBrowser.Api/BaseApiService.cs +++ b/MediaBrowser.Api/BaseApiService.cs @@ -17,7 +17,7 @@ using Microsoft.Extensions.Logging; namespace MediaBrowser.Api { /// - /// Class BaseApiService + /// Class BaseApiService. /// public abstract class BaseApiService : IService, IRequiresRequest { diff --git a/MediaBrowser.Api/ChannelService.cs b/MediaBrowser.Api/ChannelService.cs index 3cab9fb66..8c336b1c9 100644 --- a/MediaBrowser.Api/ChannelService.cs +++ b/MediaBrowser.Api/ChannelService.cs @@ -36,7 +36,7 @@ namespace MediaBrowser.Api public int? StartIndex { get; set; } /// - /// The maximum number of items to return + /// The maximum number of items to return. /// /// The limit. [ApiMember(Name = "Limit", Description = "Optional. The maximum number of records to return", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")] @@ -90,7 +90,7 @@ namespace MediaBrowser.Api public int? StartIndex { get; set; } /// - /// The maximum number of items to return + /// The maximum number of items to return. /// /// The limit. [ApiMember(Name = "Limit", Description = "Optional. The maximum number of records to return", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")] @@ -149,7 +149,7 @@ namespace MediaBrowser.Api public int? StartIndex { get; set; } /// - /// The maximum number of items to return + /// The maximum number of items to return. /// /// The limit. [ApiMember(Name = "Limit", Description = "Optional. The maximum number of records to return", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")] diff --git a/MediaBrowser.Api/ConfigurationService.cs b/MediaBrowser.Api/ConfigurationService.cs index 3ad51de8d..19369ccca 100644 --- a/MediaBrowser.Api/ConfigurationService.cs +++ b/MediaBrowser.Api/ConfigurationService.cs @@ -11,7 +11,7 @@ using Microsoft.Extensions.Logging; namespace MediaBrowser.Api { /// - /// Class GetConfiguration + /// Class GetConfiguration. /// [Route("/System/Configuration", "GET", Summary = "Gets application configuration")] [Authenticated] @@ -28,7 +28,7 @@ namespace MediaBrowser.Api } /// - /// Class UpdateConfiguration + /// Class UpdateConfiguration. /// [Route("/System/Configuration", "POST", Summary = "Updates application configuration")] [Authenticated(Roles = "Admin")] @@ -65,12 +65,12 @@ namespace MediaBrowser.Api public class ConfigurationService : BaseApiService { /// - /// The _json serializer + /// The _json serializer. /// private readonly IJsonSerializer _jsonSerializer; /// - /// The _configuration manager + /// The _configuration manager. /// private readonly IServerConfigurationManager _configurationManager; diff --git a/MediaBrowser.Api/DisplayPreferencesService.cs b/MediaBrowser.Api/DisplayPreferencesService.cs index 62c4ff43f..c3ed40ad3 100644 --- a/MediaBrowser.Api/DisplayPreferencesService.cs +++ b/MediaBrowser.Api/DisplayPreferencesService.cs @@ -10,7 +10,7 @@ using Microsoft.Extensions.Logging; namespace MediaBrowser.Api { /// - /// Class UpdateDisplayPreferences + /// Class UpdateDisplayPreferences. /// [Route("/DisplayPreferences/{DisplayPreferencesId}", "POST", Summary = "Updates a user's display preferences for an item")] public class UpdateDisplayPreferences : DisplayPreferences, IReturnVoid @@ -44,17 +44,17 @@ namespace MediaBrowser.Api } /// - /// Class DisplayPreferencesService + /// Class DisplayPreferencesService. /// [Authenticated] public class DisplayPreferencesService : BaseApiService { /// - /// The _display preferences manager + /// The _display preferences manager. /// private readonly IDisplayPreferencesRepository _displayPreferencesManager; /// - /// The _json serializer + /// The _json serializer. /// private readonly IJsonSerializer _jsonSerializer; diff --git a/MediaBrowser.Api/EnvironmentService.cs b/MediaBrowser.Api/EnvironmentService.cs index fddf78465..70acd069e 100644 --- a/MediaBrowser.Api/EnvironmentService.cs +++ b/MediaBrowser.Api/EnvironmentService.cs @@ -12,7 +12,7 @@ using Microsoft.Extensions.Logging; namespace MediaBrowser.Api { /// - /// Class GetDirectoryContents + /// Class GetDirectoryContents. /// [Route("/Environment/DirectoryContents", "GET", Summary = "Gets the contents of a given directory in the file system")] public class GetDirectoryContents : IReturn> @@ -66,7 +66,7 @@ namespace MediaBrowser.Api } /// - /// Class GetDrives + /// Class GetDrives. /// [Route("/Environment/Drives", "GET", Summary = "Gets available drives from the server's file system")] public class GetDrives : IReturn> @@ -74,7 +74,7 @@ namespace MediaBrowser.Api } /// - /// Class GetNetworkComputers + /// Class GetNetworkComputers. /// [Route("/Environment/NetworkDevices", "GET", Summary = "Gets a list of devices on the network")] public class GetNetworkDevices : IReturn> @@ -103,7 +103,7 @@ namespace MediaBrowser.Api } /// - /// Class EnvironmentService + /// Class EnvironmentService. /// [Authenticated(Roles = "Admin", AllowBeforeStartupWizard = true)] public class EnvironmentService : BaseApiService @@ -112,7 +112,7 @@ namespace MediaBrowser.Api private const string UncSeparatorString = "\\"; /// - /// The _network manager + /// The _network manager. /// private readonly INetworkManager _networkManager; private readonly IFileSystem _fileSystem; @@ -220,7 +220,7 @@ namespace MediaBrowser.Api } /// - /// Gets the list that is returned when an empty path is supplied + /// Gets the list that is returned when an empty path is supplied. /// /// IEnumerable{FileSystemEntryInfo}. private IEnumerable GetDrives() diff --git a/MediaBrowser.Api/IHasItemFields.cs b/MediaBrowser.Api/IHasItemFields.cs index 6359de77d..ad4f1b489 100644 --- a/MediaBrowser.Api/IHasItemFields.cs +++ b/MediaBrowser.Api/IHasItemFields.cs @@ -5,7 +5,7 @@ using MediaBrowser.Model.Querying; namespace MediaBrowser.Api { /// - /// Interface IHasItemFields + /// Interface IHasItemFields. /// public interface IHasItemFields { diff --git a/MediaBrowser.Api/Images/ImageByNameService.cs b/MediaBrowser.Api/Images/ImageByNameService.cs index 45b7d0c10..2d405ac3d 100644 --- a/MediaBrowser.Api/Images/ImageByNameService.cs +++ b/MediaBrowser.Api/Images/ImageByNameService.cs @@ -16,7 +16,7 @@ using Microsoft.Extensions.Logging; namespace MediaBrowser.Api.Images { /// - /// Class GetGeneralImage + /// Class GetGeneralImage. /// [Route("/Images/General/{Name}/{Type}", "GET", Summary = "Gets a general image by name")] public class GetGeneralImage @@ -33,7 +33,7 @@ namespace MediaBrowser.Api.Images } /// - /// Class GetRatingImage + /// Class GetRatingImage. /// [Route("/Images/Ratings/{Theme}/{Name}", "GET", Summary = "Gets a rating image by name")] public class GetRatingImage @@ -54,7 +54,7 @@ namespace MediaBrowser.Api.Images } /// - /// Class GetMediaInfoImage + /// Class GetMediaInfoImage. /// [Route("/Images/MediaInfo/{Theme}/{Name}", "GET", Summary = "Gets a media info image by name")] public class GetMediaInfoImage @@ -93,12 +93,12 @@ namespace MediaBrowser.Api.Images } /// - /// Class ImageByNameService + /// Class ImageByNameService. /// public class ImageByNameService : BaseApiService { /// - /// The _app paths + /// The _app paths. /// private readonly IServerApplicationPaths _appPaths; diff --git a/MediaBrowser.Api/Images/ImageRequest.cs b/MediaBrowser.Api/Images/ImageRequest.cs index 71ff09b63..0f3455548 100644 --- a/MediaBrowser.Api/Images/ImageRequest.cs +++ b/MediaBrowser.Api/Images/ImageRequest.cs @@ -4,30 +4,30 @@ using MediaBrowser.Model.Services; namespace MediaBrowser.Api.Images { /// - /// Class ImageRequest + /// Class ImageRequest. /// public class ImageRequest : DeleteImageRequest { /// - /// The max width + /// The max width. /// [ApiMember(Name = "MaxWidth", Description = "The maximum image width to return.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")] public int? MaxWidth { get; set; } /// - /// The max height + /// The max height. /// [ApiMember(Name = "MaxHeight", Description = "The maximum image height to return.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")] public int? MaxHeight { get; set; } /// - /// The width + /// The width. /// [ApiMember(Name = "Width", Description = "The fixed image width to return.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")] public int? Width { get; set; } /// - /// The height + /// The height. /// [ApiMember(Name = "Height", Description = "The fixed image height to return.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")] public int? Height { get; set; } @@ -79,7 +79,7 @@ namespace MediaBrowser.Api.Images } /// - /// Class DeleteImageRequest + /// Class DeleteImageRequest. /// public class DeleteImageRequest { diff --git a/MediaBrowser.Api/Images/ImageService.cs b/MediaBrowser.Api/Images/ImageService.cs index 6f2956c5d..8426a9a4f 100644 --- a/MediaBrowser.Api/Images/ImageService.cs +++ b/MediaBrowser.Api/Images/ImageService.cs @@ -58,7 +58,7 @@ namespace MediaBrowser.Api.Images } /// - /// Class UpdateItemImageIndex + /// Class UpdateItemImageIndex. /// [Route("/Items/{Id}/Images/{Type}/{Index}/Index", "POST", Summary = "Updates the index for an item image")] [Authenticated(Roles = "admin")] @@ -94,7 +94,7 @@ namespace MediaBrowser.Api.Images } /// - /// Class GetPersonImage + /// Class GetPersonImage. /// [Route("/Artists/{Name}/Images/{Type}", "GET")] [Route("/Artists/{Name}/Images/{Type}/{Index}", "GET")] @@ -131,7 +131,7 @@ namespace MediaBrowser.Api.Images } /// - /// Class GetUserImage + /// Class GetUserImage. /// [Route("/Users/{Id}/Images/{Type}", "GET")] [Route("/Users/{Id}/Images/{Type}/{Index}", "GET")] @@ -148,7 +148,7 @@ namespace MediaBrowser.Api.Images } /// - /// Class DeleteItemImage + /// Class DeleteItemImage. /// [Route("/Items/{Id}/Images/{Type}", "DELETE")] [Route("/Items/{Id}/Images/{Type}/{Index}", "DELETE")] @@ -164,7 +164,7 @@ namespace MediaBrowser.Api.Images } /// - /// Class DeleteUserImage + /// Class DeleteUserImage. /// [Route("/Users/{Id}/Images/{Type}", "DELETE")] [Route("/Users/{Id}/Images/{Type}/{Index}", "DELETE")] @@ -180,7 +180,7 @@ namespace MediaBrowser.Api.Images } /// - /// Class PostUserImage + /// Class PostUserImage. /// [Route("/Users/{Id}/Images/{Type}", "POST")] [Route("/Users/{Id}/Images/{Type}/{Index}", "POST")] @@ -195,14 +195,14 @@ namespace MediaBrowser.Api.Images public string Id { get; set; } /// - /// The raw Http Request Input Stream + /// The raw Http Request Input Stream. /// /// The request stream. public Stream RequestStream { get; set; } } /// - /// Class PostItemImage + /// Class PostItemImage. /// [Route("/Items/{Id}/Images/{Type}", "POST")] [Route("/Items/{Id}/Images/{Type}/{Index}", "POST")] @@ -217,14 +217,14 @@ namespace MediaBrowser.Api.Images public string Id { get; set; } /// - /// The raw Http Request Input Stream + /// The raw Http Request Input Stream. /// /// The request stream. public Stream RequestStream { get; set; } } /// - /// Class ImageService + /// Class ImageService. /// public class ImageService : BaseApiService { diff --git a/MediaBrowser.Api/Images/RemoteImageService.cs b/MediaBrowser.Api/Images/RemoteImageService.cs index 2633a5d3c..86464b4b9 100644 --- a/MediaBrowser.Api/Images/RemoteImageService.cs +++ b/MediaBrowser.Api/Images/RemoteImageService.cs @@ -33,7 +33,7 @@ namespace MediaBrowser.Api.Images public int? StartIndex { get; set; } /// - /// The maximum number of items to return + /// The maximum number of items to return. /// /// The limit. [ApiMember(Name = "Limit", Description = "Optional. The maximum number of records to return", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")] diff --git a/MediaBrowser.Api/Library/LibraryService.cs b/MediaBrowser.Api/Library/LibraryService.cs index eb64abb4d..1ab820680 100644 --- a/MediaBrowser.Api/Library/LibraryService.cs +++ b/MediaBrowser.Api/Library/LibraryService.cs @@ -49,7 +49,7 @@ namespace MediaBrowser.Api.Library } /// - /// Class GetCriticReviews + /// Class GetCriticReviews. /// [Route("/Items/{Id}/CriticReviews", "GET", Summary = "Gets critic reviews for an item")] [Authenticated] @@ -70,7 +70,7 @@ namespace MediaBrowser.Api.Library public int? StartIndex { get; set; } /// - /// The maximum number of items to return + /// The maximum number of items to return. /// /// The limit. [ApiMember(Name = "Limit", Description = "Optional. The maximum number of records to return", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")] @@ -78,7 +78,7 @@ namespace MediaBrowser.Api.Library } /// - /// Class GetThemeSongs + /// Class GetThemeSongs. /// [Route("/Items/{Id}/ThemeSongs", "GET", Summary = "Gets theme songs for an item")] [Authenticated] @@ -103,7 +103,7 @@ namespace MediaBrowser.Api.Library } /// - /// Class GetThemeVideos + /// Class GetThemeVideos. /// [Route("/Items/{Id}/ThemeVideos", "GET", Summary = "Gets theme videos for an item")] [Authenticated] @@ -128,7 +128,7 @@ namespace MediaBrowser.Api.Library } /// - /// Class GetThemeVideos + /// Class GetThemeVideos. /// [Route("/Items/{Id}/ThemeMedia", "GET", Summary = "Gets theme videos and songs for an item")] [Authenticated] @@ -205,7 +205,7 @@ namespace MediaBrowser.Api.Library } /// - /// Class GetPhyscialPaths + /// Class GetPhyscialPaths. /// [Route("/Library/PhysicalPaths", "GET", Summary = "Gets a list of physical paths from virtual folders")] [Authenticated(Roles = "Admin")] @@ -312,7 +312,7 @@ namespace MediaBrowser.Api.Library } /// - /// Class LibraryService + /// Class LibraryService. /// public class LibraryService : BaseApiService { diff --git a/MediaBrowser.Api/Library/LibraryStructureService.cs b/MediaBrowser.Api/Library/LibraryStructureService.cs index 1e300814f..b69550ed1 100644 --- a/MediaBrowser.Api/Library/LibraryStructureService.cs +++ b/MediaBrowser.Api/Library/LibraryStructureService.cs @@ -19,7 +19,7 @@ using Microsoft.Extensions.Logging; namespace MediaBrowser.Api.Library { /// - /// Class GetDefaultVirtualFolders + /// Class GetDefaultVirtualFolders. /// [Route("/Library/VirtualFolders", "GET")] public class GetVirtualFolders : IReturn> @@ -166,18 +166,18 @@ namespace MediaBrowser.Api.Library } /// - /// Class LibraryStructureService + /// Class LibraryStructureService. /// [Authenticated(Roles = "Admin", AllowBeforeStartupWizard = true)] public class LibraryStructureService : BaseApiService { /// - /// The _app paths + /// The _app paths. /// private readonly IServerApplicationPaths _appPaths; /// - /// The _library manager + /// The _library manager. /// private readonly ILibraryManager _libraryManager; private readonly ILibraryMonitor _libraryMonitor; diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs index b00a5fec8..8e13744c4 100644 --- a/MediaBrowser.Api/LiveTv/LiveTvService.cs +++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs @@ -31,7 +31,7 @@ using Microsoft.Net.Http.Headers; namespace MediaBrowser.Api.LiveTv { /// - /// This is insecure right now to avoid windows phone refactoring + /// This is insecure right now to avoid windows phone refactoring. /// [Route("/LiveTv/Info", "GET", Summary = "Gets available live tv services.")] [Authenticated] @@ -72,7 +72,7 @@ namespace MediaBrowser.Api.LiveTv public bool? IsSports { get; set; } /// - /// The maximum number of items to return + /// The maximum number of items to return. /// /// The limit. [ApiMember(Name = "Limit", Description = "Optional. The maximum number of records to return", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")] @@ -100,7 +100,7 @@ namespace MediaBrowser.Api.LiveTv public string EnableImageTypes { get; set; } /// - /// Fields to return within the items, in addition to basic information + /// Fields to return within the items, in addition to basic information. /// /// The fields. [ApiMember(Name = "Fields", Description = "Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimeted. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)] @@ -188,7 +188,7 @@ namespace MediaBrowser.Api.LiveTv public string EnableImageTypes { get; set; } /// - /// Fields to return within the items, in addition to basic information + /// Fields to return within the items, in addition to basic information. /// /// The fields. [ApiMember(Name = "Fields", Description = "Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimeted. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)] @@ -250,7 +250,7 @@ namespace MediaBrowser.Api.LiveTv public string EnableImageTypes { get; set; } /// - /// Fields to return within the items, in addition to basic information + /// Fields to return within the items, in addition to basic information. /// /// The fields. [ApiMember(Name = "Fields", Description = "Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimeted. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)] @@ -410,7 +410,7 @@ namespace MediaBrowser.Api.LiveTv public Guid LibrarySeriesId { get; set; } /// - /// Fields to return within the items, in addition to basic information + /// Fields to return within the items, in addition to basic information. /// /// The fields. [ApiMember(Name = "Fields", Description = "Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimeted. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)] @@ -473,7 +473,7 @@ namespace MediaBrowser.Api.LiveTv public string GenreIds { get; set; } /// - /// Fields to return within the items, in addition to basic information + /// Fields to return within the items, in addition to basic information. /// /// The fields. [ApiMember(Name = "Fields", Description = "Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimeted. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)] diff --git a/MediaBrowser.Api/LocalizationService.cs b/MediaBrowser.Api/LocalizationService.cs index 6a69d2656..d6b5f5195 100644 --- a/MediaBrowser.Api/LocalizationService.cs +++ b/MediaBrowser.Api/LocalizationService.cs @@ -8,7 +8,7 @@ using Microsoft.Extensions.Logging; namespace MediaBrowser.Api { /// - /// Class GetCultures + /// Class GetCultures. /// [Route("/Localization/Cultures", "GET", Summary = "Gets known cultures")] public class GetCultures : IReturn @@ -16,7 +16,7 @@ namespace MediaBrowser.Api } /// - /// Class GetCountries + /// Class GetCountries. /// [Route("/Localization/Countries", "GET", Summary = "Gets known countries")] public class GetCountries : IReturn @@ -24,7 +24,7 @@ namespace MediaBrowser.Api } /// - /// Class ParentalRatings + /// Class ParentalRatings. /// [Route("/Localization/ParentalRatings", "GET", Summary = "Gets known parental ratings")] public class GetParentalRatings : IReturn @@ -32,7 +32,7 @@ namespace MediaBrowser.Api } /// - /// Class ParentalRatings + /// Class ParentalRatings. /// [Route("/Localization/Options", "GET", Summary = "Gets localization options")] public class GetLocalizationOptions : IReturn @@ -40,13 +40,13 @@ namespace MediaBrowser.Api } /// - /// Class CulturesService + /// Class CulturesService. /// [Authenticated(AllowBeforeStartupWizard = true)] public class LocalizationService : BaseApiService { /// - /// The _localization + /// The _localization. /// private readonly ILocalizationManager _localization; diff --git a/MediaBrowser.Api/Movies/MoviesService.cs b/MediaBrowser.Api/Movies/MoviesService.cs index 88ca0aa23..34cccffa3 100644 --- a/MediaBrowser.Api/Movies/MoviesService.cs +++ b/MediaBrowser.Api/Movies/MoviesService.cs @@ -65,13 +65,13 @@ namespace MediaBrowser.Api.Movies } /// - /// Class MoviesService + /// Class MoviesService. /// [Authenticated] public class MoviesService : BaseApiService { /// - /// The _user manager + /// The _user manager. /// private readonly IUserManager _userManager; diff --git a/MediaBrowser.Api/Movies/TrailersService.cs b/MediaBrowser.Api/Movies/TrailersService.cs index a7758b100..ca9f9d03b 100644 --- a/MediaBrowser.Api/Movies/TrailersService.cs +++ b/MediaBrowser.Api/Movies/TrailersService.cs @@ -18,18 +18,18 @@ namespace MediaBrowser.Api.Movies } /// - /// Class TrailersService + /// Class TrailersService. /// [Authenticated] public class TrailersService : BaseApiService { /// - /// The _user manager + /// The _user manager. /// private readonly IUserManager _userManager; /// - /// The _library manager + /// The _library manager. /// private readonly ILibraryManager _libraryManager; diff --git a/MediaBrowser.Api/Music/AlbumsService.cs b/MediaBrowser.Api/Music/AlbumsService.cs index f257d1014..74d3cce12 100644 --- a/MediaBrowser.Api/Music/AlbumsService.cs +++ b/MediaBrowser.Api/Music/AlbumsService.cs @@ -27,16 +27,16 @@ namespace MediaBrowser.Api.Music public class AlbumsService : BaseApiService { /// - /// The _user manager + /// The _user manager. /// private readonly IUserManager _userManager; /// - /// The _user data repository + /// The _user data repository. /// private readonly IUserDataManager _userDataRepository; /// - /// The _library manager + /// The _library manager. /// private readonly ILibraryManager _libraryManager; private readonly IItemRepository _itemRepo; diff --git a/MediaBrowser.Api/PackageService.cs b/MediaBrowser.Api/PackageService.cs index 444354a99..a63d06ad5 100644 --- a/MediaBrowser.Api/PackageService.cs +++ b/MediaBrowser.Api/PackageService.cs @@ -14,7 +14,7 @@ using Microsoft.Extensions.Logging; namespace MediaBrowser.Api { /// - /// Class GetPackage + /// Class GetPackage. /// [Route("/Packages/{Name}", "GET", Summary = "Gets a package, by name or assembly guid")] [Authenticated] @@ -36,7 +36,7 @@ namespace MediaBrowser.Api } /// - /// Class GetPackages + /// Class GetPackages. /// [Route("/Packages", "GET", Summary = "Gets available packages")] [Authenticated] @@ -45,7 +45,7 @@ namespace MediaBrowser.Api } /// - /// Class InstallPackage + /// Class InstallPackage. /// [Route("/Packages/Installed/{Name}", "POST", Summary = "Installs a package")] [Authenticated(Roles = "Admin")] @@ -74,7 +74,7 @@ namespace MediaBrowser.Api } /// - /// Class CancelPackageInstallation + /// Class CancelPackageInstallation. /// [Route("/Packages/Installing/{Id}", "DELETE", Summary = "Cancels a package installation")] [Authenticated(Roles = "Admin")] @@ -89,7 +89,7 @@ namespace MediaBrowser.Api } /// - /// Class PackageService + /// Class PackageService. /// public class PackageService : BaseApiService { diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index 2eb6198c0..afbafa9d3 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -28,7 +28,7 @@ using Microsoft.Extensions.Logging; namespace MediaBrowser.Api.Playback { /// - /// Class BaseStreamingService + /// Class BaseStreamingService. /// public abstract class BaseStreamingService : BaseApiService { diff --git a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs b/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs index c2d49a93b..f41f006fa 100644 --- a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs +++ b/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs @@ -20,7 +20,7 @@ using Microsoft.Extensions.Logging; namespace MediaBrowser.Api.Playback.Hls { /// - /// Class BaseHlsService + /// Class BaseHlsService. /// public abstract class BaseHlsService : BaseStreamingService { diff --git a/MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs b/MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs index 87ccde2e0..8a3d00283 100644 --- a/MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs +++ b/MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs @@ -13,7 +13,7 @@ using Microsoft.Extensions.Logging; namespace MediaBrowser.Api.Playback.Hls { /// - /// Class GetHlsAudioSegment + /// Class GetHlsAudioSegment. /// // Can't require authentication just yet due to seeing some requests come from Chrome without full query string //[Authenticated] @@ -37,7 +37,7 @@ namespace MediaBrowser.Api.Playback.Hls } /// - /// Class GetHlsVideoSegment + /// Class GetHlsVideoSegment. /// [Route("/Videos/{Id}/hls/{PlaylistId}/stream.m3u8", "GET")] [Authenticated] @@ -66,7 +66,7 @@ namespace MediaBrowser.Api.Playback.Hls } /// - /// Class GetHlsVideoSegment + /// Class GetHlsVideoSegment. /// // Can't require authentication just yet due to seeing some requests come from Chrome without full query string //[Authenticated] diff --git a/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs b/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs index aefb3f019..9562f9953 100644 --- a/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs +++ b/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs @@ -22,7 +22,7 @@ namespace MediaBrowser.Api.Playback.Hls } /// - /// Class VideoHlsService + /// Class VideoHlsService. /// [Authenticated] public class VideoHlsService : BaseHlsService diff --git a/MediaBrowser.Api/Playback/Progressive/AudioService.cs b/MediaBrowser.Api/Playback/Progressive/AudioService.cs index 34c7986ca..d51787df2 100644 --- a/MediaBrowser.Api/Playback/Progressive/AudioService.cs +++ b/MediaBrowser.Api/Playback/Progressive/AudioService.cs @@ -15,7 +15,7 @@ using Microsoft.Extensions.Logging; namespace MediaBrowser.Api.Playback.Progressive { /// - /// Class GetAudioStream + /// Class GetAudioStream. /// [Route("/Audio/{Id}/stream.{Container}", "GET", Summary = "Gets an audio stream")] [Route("/Audio/{Id}/stream", "GET", Summary = "Gets an audio stream")] @@ -26,7 +26,7 @@ namespace MediaBrowser.Api.Playback.Progressive } /// - /// Class AudioService + /// Class AudioService. /// // TODO: In order to autheneticate this in the future, Dlna playback will require updating //[Authenticated] diff --git a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs index 43cde440c..4820cbd92 100644 --- a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs +++ b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs @@ -21,7 +21,7 @@ using Microsoft.Net.Http.Headers; namespace MediaBrowser.Api.Playback.Progressive { /// - /// Class BaseProgressiveStreamingService + /// Class BaseProgressiveStreamingService. /// public abstract class BaseProgressiveStreamingService : BaseStreamingService { diff --git a/MediaBrowser.Api/Playback/Progressive/VideoService.cs b/MediaBrowser.Api/Playback/Progressive/VideoService.cs index a35e6c201..c3f6b905c 100644 --- a/MediaBrowser.Api/Playback/Progressive/VideoService.cs +++ b/MediaBrowser.Api/Playback/Progressive/VideoService.cs @@ -15,7 +15,7 @@ using Microsoft.Extensions.Logging; namespace MediaBrowser.Api.Playback.Progressive { /// - /// Class GetVideoStream + /// Class GetVideoStream. /// [Route("/Videos/{Id}/stream.mpegts", "GET")] [Route("/Videos/{Id}/stream.ts", "GET")] @@ -62,7 +62,7 @@ namespace MediaBrowser.Api.Playback.Progressive } /// - /// Class VideoService + /// Class VideoService. /// // TODO: In order to autheneticate this in the future, Dlna playback will require updating //[Authenticated] diff --git a/MediaBrowser.Api/Playback/StaticRemoteStreamWriter.cs b/MediaBrowser.Api/Playback/StaticRemoteStreamWriter.cs index 3b8b29995..7e2e337ad 100644 --- a/MediaBrowser.Api/Playback/StaticRemoteStreamWriter.cs +++ b/MediaBrowser.Api/Playback/StaticRemoteStreamWriter.cs @@ -8,17 +8,17 @@ using MediaBrowser.Model.Services; namespace MediaBrowser.Api.Playback { /// - /// Class StaticRemoteStreamWriter + /// Class StaticRemoteStreamWriter. /// public class StaticRemoteStreamWriter : IAsyncStreamWriter, IHasHeaders { /// - /// The _input stream + /// The _input stream. /// private readonly HttpResponseInfo _response; /// - /// The _options + /// The _options. /// private readonly IDictionary _options = new Dictionary(); diff --git a/MediaBrowser.Api/Playback/StreamRequest.cs b/MediaBrowser.Api/Playback/StreamRequest.cs index 9ba8eda91..cfcc98035 100644 --- a/MediaBrowser.Api/Playback/StreamRequest.cs +++ b/MediaBrowser.Api/Playback/StreamRequest.cs @@ -4,7 +4,7 @@ using MediaBrowser.Model.Services; namespace MediaBrowser.Api.Playback { /// - /// Class StreamRequest + /// Class StreamRequest. /// public class StreamRequest : BaseEncodingJobOptions { diff --git a/MediaBrowser.Api/PlaylistService.cs b/MediaBrowser.Api/PlaylistService.cs index d5def03be..5513c0892 100644 --- a/MediaBrowser.Api/PlaylistService.cs +++ b/MediaBrowser.Api/PlaylistService.cs @@ -95,14 +95,14 @@ namespace MediaBrowser.Api public int? StartIndex { get; set; } /// - /// The maximum number of items to return + /// The maximum number of items to return. /// /// The limit. [ApiMember(Name = "Limit", Description = "Optional. The maximum number of records to return", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")] public int? Limit { get; set; } /// - /// Fields to return within the items, in addition to basic information + /// Fields to return within the items, in addition to basic information. /// /// The fields. [ApiMember(Name = "Fields", Description = "Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimeted. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)] diff --git a/MediaBrowser.Api/PluginService.cs b/MediaBrowser.Api/PluginService.cs index fd1075727..e9d5b2bc4 100644 --- a/MediaBrowser.Api/PluginService.cs +++ b/MediaBrowser.Api/PluginService.cs @@ -15,7 +15,7 @@ using Microsoft.Extensions.Logging; namespace MediaBrowser.Api { /// - /// Class Plugins + /// Class Plugins. /// [Route("/Plugins", "GET", Summary = "Gets a list of currently installed plugins")] [Authenticated] @@ -25,7 +25,7 @@ namespace MediaBrowser.Api } /// - /// Class UninstallPlugin + /// Class UninstallPlugin. /// [Route("/Plugins/{Id}", "DELETE", Summary = "Uninstalls a plugin")] [Authenticated(Roles = "Admin")] @@ -40,7 +40,7 @@ namespace MediaBrowser.Api } /// - /// Class GetPluginConfiguration + /// Class GetPluginConfiguration. /// [Route("/Plugins/{Id}/Configuration", "GET", Summary = "Gets a plugin's configuration")] [Authenticated] @@ -55,7 +55,7 @@ namespace MediaBrowser.Api } /// - /// Class UpdatePluginConfiguration + /// Class UpdatePluginConfiguration. /// [Route("/Plugins/{Id}/Configuration", "POST", Summary = "Updates a plugin's configuration")] [Authenticated] @@ -69,7 +69,7 @@ namespace MediaBrowser.Api public string Id { get; set; } /// - /// The raw Http Request Input Stream + /// The raw Http Request Input Stream. /// /// The request stream. public Stream RequestStream { get; set; } @@ -86,7 +86,7 @@ namespace MediaBrowser.Api } /// - /// Class GetPluginSecurityInfo + /// Class GetPluginSecurityInfo. /// [Route("/Plugins/SecurityInfo", "GET", Summary = "Gets plugin registration information", IsHidden = true)] [Authenticated] @@ -95,7 +95,7 @@ namespace MediaBrowser.Api } /// - /// Class UpdatePluginSecurityInfo + /// Class UpdatePluginSecurityInfo. /// [Route("/Plugins/SecurityInfo", "POST", Summary = "Updates plugin registration information", IsHidden = true)] [Authenticated(Roles = "Admin")] @@ -136,17 +136,17 @@ namespace MediaBrowser.Api public bool IsMBSupporter { get; set; } } /// - /// Class PluginsService + /// Class PluginsService. /// public class PluginService : BaseApiService { /// - /// The _json serializer + /// The _json serializer. /// private readonly IJsonSerializer _jsonSerializer; /// - /// The _app host + /// The _app host. /// private readonly IApplicationHost _appHost; private readonly IInstallationManager _installationManager; diff --git a/MediaBrowser.Api/ScheduledTasks/ScheduledTaskService.cs b/MediaBrowser.Api/ScheduledTasks/ScheduledTaskService.cs index e08a8482e..86b00316a 100644 --- a/MediaBrowser.Api/ScheduledTasks/ScheduledTaskService.cs +++ b/MediaBrowser.Api/ScheduledTasks/ScheduledTaskService.cs @@ -11,7 +11,7 @@ using Microsoft.Extensions.Logging; namespace MediaBrowser.Api.ScheduledTasks { /// - /// Class GetScheduledTask + /// Class GetScheduledTask. /// [Route("/ScheduledTasks/{Id}", "GET", Summary = "Gets a scheduled task, by Id")] public class GetScheduledTask : IReturn @@ -25,7 +25,7 @@ namespace MediaBrowser.Api.ScheduledTasks } /// - /// Class GetScheduledTasks + /// Class GetScheduledTasks. /// [Route("/ScheduledTasks", "GET", Summary = "Gets scheduled tasks")] public class GetScheduledTasks : IReturn @@ -38,7 +38,7 @@ namespace MediaBrowser.Api.ScheduledTasks } /// - /// Class StartScheduledTask + /// Class StartScheduledTask. /// [Route("/ScheduledTasks/Running/{Id}", "POST", Summary = "Starts a scheduled task")] public class StartScheduledTask : IReturnVoid @@ -52,7 +52,7 @@ namespace MediaBrowser.Api.ScheduledTasks } /// - /// Class StopScheduledTask + /// Class StopScheduledTask. /// [Route("/ScheduledTasks/Running/{Id}", "DELETE", Summary = "Stops a scheduled task")] public class StopScheduledTask : IReturnVoid @@ -66,7 +66,7 @@ namespace MediaBrowser.Api.ScheduledTasks } /// - /// Class UpdateScheduledTaskTriggers + /// Class UpdateScheduledTaskTriggers. /// [Route("/ScheduledTasks/{Id}/Triggers", "POST", Summary = "Updates the triggers for a scheduled task")] public class UpdateScheduledTaskTriggers : List, IReturnVoid @@ -80,7 +80,7 @@ namespace MediaBrowser.Api.ScheduledTasks } /// - /// Class ScheduledTasksService + /// Class ScheduledTasksService. /// [Authenticated(Roles = "Admin")] public class ScheduledTaskService : BaseApiService diff --git a/MediaBrowser.Api/ScheduledTasks/ScheduledTasksWebSocketListener.cs b/MediaBrowser.Api/ScheduledTasks/ScheduledTasksWebSocketListener.cs index 14b9b3618..25dd39f2d 100644 --- a/MediaBrowser.Api/ScheduledTasks/ScheduledTasksWebSocketListener.cs +++ b/MediaBrowser.Api/ScheduledTasks/ScheduledTasksWebSocketListener.cs @@ -9,7 +9,7 @@ using Microsoft.Extensions.Logging; namespace MediaBrowser.Api.ScheduledTasks { /// - /// Class ScheduledTasksWebSocketListener + /// Class ScheduledTasksWebSocketListener. /// public class ScheduledTasksWebSocketListener : BasePeriodicWebSocketListener, WebSocketListenerState> { diff --git a/MediaBrowser.Api/SearchService.cs b/MediaBrowser.Api/SearchService.cs index 4a2f96ed8..64ee69300 100644 --- a/MediaBrowser.Api/SearchService.cs +++ b/MediaBrowser.Api/SearchService.cs @@ -18,7 +18,7 @@ using Microsoft.Extensions.Logging; namespace MediaBrowser.Api { /// - /// Class GetSearchHints + /// Class GetSearchHints. /// [Route("/Search/Hints", "GET", Summary = "Gets search hints based on a search term")] public class GetSearchHints : IReturn @@ -31,7 +31,7 @@ namespace MediaBrowser.Api public int? StartIndex { get; set; } /// - /// The maximum number of items to return + /// The maximum number of items to return. /// /// The limit. [ApiMember(Name = "Limit", Description = "Optional. The maximum number of records to return", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")] @@ -45,7 +45,7 @@ namespace MediaBrowser.Api public Guid UserId { get; set; } /// - /// Search characters used to find items + /// Search characters used to find items. /// /// The index by. [ApiMember(Name = "SearchTerm", Description = "The search term to filter on", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")] @@ -104,13 +104,13 @@ namespace MediaBrowser.Api } /// - /// Class SearchService + /// Class SearchService. /// [Authenticated] public class SearchService : BaseApiService { /// - /// The _search engine + /// The _search engine. /// private readonly ISearchEngine _searchEngine; private readonly ILibraryManager _libraryManager; diff --git a/MediaBrowser.Api/Sessions/SessionInfoWebSocketListener.cs b/MediaBrowser.Api/Sessions/SessionInfoWebSocketListener.cs index 175984575..2400d6def 100644 --- a/MediaBrowser.Api/Sessions/SessionInfoWebSocketListener.cs +++ b/MediaBrowser.Api/Sessions/SessionInfoWebSocketListener.cs @@ -8,7 +8,7 @@ using Microsoft.Extensions.Logging; namespace MediaBrowser.Api.Sessions { /// - /// Class SessionInfoWebSocketListener + /// Class SessionInfoWebSocketListener. /// public class SessionInfoWebSocketListener : BasePeriodicWebSocketListener, WebSocketListenerState> { @@ -19,7 +19,7 @@ namespace MediaBrowser.Api.Sessions protected override string Name => "Sessions"; /// - /// The _kernel + /// The _kernel. /// private readonly ISessionManager _sessionManager; diff --git a/MediaBrowser.Api/Sessions/SessionService.cs b/MediaBrowser.Api/Sessions/SessionService.cs index d986eea65..50adc5698 100644 --- a/MediaBrowser.Api/Sessions/SessionService.cs +++ b/MediaBrowser.Api/Sessions/SessionService.cs @@ -46,14 +46,14 @@ namespace MediaBrowser.Api.Sessions public string Id { get; set; } /// - /// Artist, Genre, Studio, Person, or any kind of BaseItem + /// Artist, Genre, Studio, Person, or any kind of BaseItem. /// /// The type of the item. [ApiMember(Name = "ItemType", Description = "The type of item to browse to.", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")] public string ItemType { get; set; } /// - /// Artist name, genre name, item Id, etc + /// Artist name, genre name, item Id, etc. /// /// The item identifier. [ApiMember(Name = "ItemId", Description = "The Id of the item.", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")] diff --git a/MediaBrowser.Api/SimilarItemsHelper.cs b/MediaBrowser.Api/SimilarItemsHelper.cs index 90c324ff3..7ed70f5d7 100644 --- a/MediaBrowser.Api/SimilarItemsHelper.cs +++ b/MediaBrowser.Api/SimilarItemsHelper.cs @@ -14,7 +14,7 @@ using Microsoft.Extensions.Logging; namespace MediaBrowser.Api { /// - /// Class BaseGetSimilarItemsFromItem + /// Class BaseGetSimilarItemsFromItem. /// public class BaseGetSimilarItemsFromItem : BaseGetSimilarItems { @@ -50,14 +50,14 @@ namespace MediaBrowser.Api public Guid UserId { get; set; } /// - /// The maximum number of items to return + /// The maximum number of items to return. /// /// The limit. [ApiMember(Name = "Limit", Description = "Optional. The maximum number of records to return", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")] public int? Limit { get; set; } /// - /// Fields to return within the items, in addition to basic information + /// Fields to return within the items, in addition to basic information. /// /// The fields. [ApiMember(Name = "Fields", Description = "Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimeted. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines, TrailerUrls", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)] @@ -65,7 +65,7 @@ namespace MediaBrowser.Api } /// - /// Class SimilarItemsHelper + /// Class SimilarItemsHelper. /// public static class SimilarItemsHelper { diff --git a/MediaBrowser.Api/System/ActivityLogService.cs b/MediaBrowser.Api/System/ActivityLogService.cs index a6bacad4f..7ca31c21a 100644 --- a/MediaBrowser.Api/System/ActivityLogService.cs +++ b/MediaBrowser.Api/System/ActivityLogService.cs @@ -22,7 +22,7 @@ namespace MediaBrowser.Api.System public int? StartIndex { get; set; } /// - /// The maximum number of items to return + /// The maximum number of items to return. /// /// The limit. [ApiMember(Name = "Limit", Description = "Optional. The maximum number of records to return", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")] diff --git a/MediaBrowser.Api/System/ActivityLogWebSocketListener.cs b/MediaBrowser.Api/System/ActivityLogWebSocketListener.cs index 8e4860be4..39976371a 100644 --- a/MediaBrowser.Api/System/ActivityLogWebSocketListener.cs +++ b/MediaBrowser.Api/System/ActivityLogWebSocketListener.cs @@ -8,7 +8,7 @@ using Microsoft.Extensions.Logging; namespace MediaBrowser.Api.System { /// - /// Class SessionInfoWebSocketListener + /// Class SessionInfoWebSocketListener. /// public class ActivityLogWebSocketListener : BasePeriodicWebSocketListener { @@ -19,7 +19,7 @@ namespace MediaBrowser.Api.System protected override string Name => "ActivityLogEntry"; /// - /// The _kernel + /// The _kernel. /// private readonly IActivityManager _activityManager; diff --git a/MediaBrowser.Api/System/SystemService.cs b/MediaBrowser.Api/System/SystemService.cs index 4f10a4ad2..e0e20d828 100644 --- a/MediaBrowser.Api/System/SystemService.cs +++ b/MediaBrowser.Api/System/SystemService.cs @@ -18,7 +18,7 @@ using Microsoft.Extensions.Logging; namespace MediaBrowser.Api.System { /// - /// Class GetSystemInfo + /// Class GetSystemInfo. /// [Route("/System/Info", "GET", Summary = "Gets information about the server")] [Authenticated(EscapeParentalControl = true, AllowBeforeStartupWizard = true)] @@ -38,7 +38,7 @@ namespace MediaBrowser.Api.System } /// - /// Class RestartApplication + /// Class RestartApplication. /// [Route("/System/Restart", "POST", Summary = "Restarts the application, if needed")] [Authenticated(Roles = "Admin", AllowLocal = true)] @@ -83,12 +83,12 @@ namespace MediaBrowser.Api.System } /// - /// Class SystemInfoService + /// Class SystemInfoService. /// public class SystemService : BaseApiService { /// - /// The _app host + /// The _app host. /// private readonly IServerApplicationHost _appHost; private readonly IApplicationPaths _appPaths; diff --git a/MediaBrowser.Api/TvShowsService.cs b/MediaBrowser.Api/TvShowsService.cs index 23062b67b..6177c2e2e 100644 --- a/MediaBrowser.Api/TvShowsService.cs +++ b/MediaBrowser.Api/TvShowsService.cs @@ -19,7 +19,7 @@ using Microsoft.Extensions.Logging; namespace MediaBrowser.Api { /// - /// Class GetNextUpEpisodes + /// Class GetNextUpEpisodes. /// [Route("/Shows/NextUp", "GET", Summary = "Gets a list of next up episodes")] public class GetNextUpEpisodes : IReturn>, IHasDtoOptions @@ -39,14 +39,14 @@ namespace MediaBrowser.Api public int? StartIndex { get; set; } /// - /// The maximum number of items to return + /// The maximum number of items to return. /// /// The limit. [ApiMember(Name = "Limit", Description = "Optional. The maximum number of records to return", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")] public int? Limit { get; set; } /// - /// Fields to return within the items, in addition to basic information + /// Fields to return within the items, in addition to basic information. /// /// The fields. [ApiMember(Name = "Fields", Description = "Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimeted. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines, TrailerUrls", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)] @@ -99,14 +99,14 @@ namespace MediaBrowser.Api public int? StartIndex { get; set; } /// - /// The maximum number of items to return + /// The maximum number of items to return. /// /// The limit. [ApiMember(Name = "Limit", Description = "Optional. The maximum number of records to return", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")] public int? Limit { get; set; } /// - /// Fields to return within the items, in addition to basic information + /// Fields to return within the items, in addition to basic information. /// /// The fields. [ApiMember(Name = "Fields", Description = "Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimeted. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines, TrailerUrls", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)] @@ -143,7 +143,7 @@ namespace MediaBrowser.Api public Guid UserId { get; set; } /// - /// Fields to return within the items, in addition to basic information + /// Fields to return within the items, in addition to basic information. /// /// The fields. [ApiMember(Name = "Fields", Description = "Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimeted. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines, TrailerUrls", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)] @@ -175,7 +175,7 @@ namespace MediaBrowser.Api public int? StartIndex { get; set; } /// - /// The maximum number of items to return + /// The maximum number of items to return. /// /// The limit. [ApiMember(Name = "Limit", Description = "Optional. The maximum number of records to return", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")] @@ -211,7 +211,7 @@ namespace MediaBrowser.Api public Guid UserId { get; set; } /// - /// Fields to return within the items, in addition to basic information + /// Fields to return within the items, in addition to basic information. /// /// The fields. [ApiMember(Name = "Fields", Description = "Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimeted. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines, TrailerUrls", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)] @@ -243,18 +243,18 @@ namespace MediaBrowser.Api } /// - /// Class TvShowsService + /// Class TvShowsService. /// [Authenticated] public class TvShowsService : BaseApiService { /// - /// The _user manager + /// The _user manager. /// private readonly IUserManager _userManager; /// - /// The _library manager + /// The _library manager. /// private readonly ILibraryManager _libraryManager; diff --git a/MediaBrowser.Api/UserLibrary/ArtistsService.cs b/MediaBrowser.Api/UserLibrary/ArtistsService.cs index bef91d54d..9875e0208 100644 --- a/MediaBrowser.Api/UserLibrary/ArtistsService.cs +++ b/MediaBrowser.Api/UserLibrary/ArtistsService.cs @@ -14,7 +14,7 @@ using Microsoft.Extensions.Logging; namespace MediaBrowser.Api.UserLibrary { /// - /// Class GetArtists + /// Class GetArtists. /// [Route("/Artists", "GET", Summary = "Gets all artists from a given item, folder, or the entire library")] public class GetArtists : GetItemsByName @@ -45,7 +45,7 @@ namespace MediaBrowser.Api.UserLibrary } /// - /// Class ArtistsService + /// Class ArtistsService. /// [Authenticated] public class ArtistsService : BaseItemsByNameService diff --git a/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs b/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs index 4802849f4..a68c6fb6d 100644 --- a/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs +++ b/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs @@ -15,7 +15,7 @@ using Microsoft.Extensions.Logging; namespace MediaBrowser.Api.UserLibrary { /// - /// Class BaseItemsByNameService + /// Class BaseItemsByNameService. /// /// The type of the T item type. public abstract class BaseItemsByNameService : BaseApiService @@ -52,7 +52,7 @@ namespace MediaBrowser.Api.UserLibrary protected IUserManager UserManager { get; } /// - /// Gets the library manager + /// Gets the library manager. /// protected ILibraryManager LibraryManager { get; } @@ -375,7 +375,7 @@ namespace MediaBrowser.Api.UserLibrary } /// - /// Class GetItemsByName + /// Class GetItemsByName. /// public class GetItemsByName : BaseItemsRequest, IReturn> { diff --git a/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs b/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs index 7561b5c89..5a4394425 100644 --- a/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs +++ b/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs @@ -111,14 +111,14 @@ namespace MediaBrowser.Api.UserLibrary public int? StartIndex { get; set; } /// - /// The maximum number of items to return + /// The maximum number of items to return. /// /// The limit. [ApiMember(Name = "Limit", Description = "Optional. The maximum number of records to return", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")] public int? Limit { get; set; } /// - /// Whether or not to perform the query recursively + /// Whether or not to perform the query recursively. /// /// true if recursive; otherwise, false. [ApiMember(Name = "Recursive", Description = "When searching within folders, this determines whether or not the search will be recursive. true/false", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")] @@ -141,7 +141,7 @@ namespace MediaBrowser.Api.UserLibrary public string ParentId { get; set; } /// - /// Fields to return within the items, in addition to basic information + /// Fields to return within the items, in addition to basic information. /// /// The fields. [ApiMember(Name = "Fields", Description = "Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimeted. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)] @@ -162,14 +162,14 @@ namespace MediaBrowser.Api.UserLibrary public string IncludeItemTypes { get; set; } /// - /// Filters to apply to the results + /// Filters to apply to the results. /// /// The filters. [ApiMember(Name = "Filters", Description = "Optional. Specify additional filters to apply. This allows multiple, comma delimeted. Options: IsFolder, IsNotFolder, IsUnplayed, IsPlayed, IsFavorite, IsResumable, Likes, Dislikes", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)] public string Filters { get; set; } /// - /// Gets or sets the Isfavorite option + /// Gets or sets the Isfavorite option. /// /// IsFavorite [ApiMember(Name = "IsFavorite", Description = "Optional filter by items that are marked as favorite, or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")] @@ -190,7 +190,7 @@ namespace MediaBrowser.Api.UserLibrary public string ImageTypes { get; set; } /// - /// What to sort the results by + /// What to sort the results by. /// /// The sort by. [ApiMember(Name = "SortBy", Description = "Optional. Specify one or more sort orders, comma delimeted. Options: Album, AlbumArtist, Artist, Budget, CommunityRating, CriticRating, DateCreated, DatePlayed, PlayCount, PremiereDate, ProductionYear, SortName, Random, Revenue, Runtime", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)] @@ -200,7 +200,7 @@ namespace MediaBrowser.Api.UserLibrary public bool? IsPlayed { get; set; } /// - /// Limit results to items containing specific genres + /// Limit results to items containing specific genres. /// /// The genres. [ApiMember(Name = "Genres", Description = "Optional. If specified, results will be filtered based on genre. This allows multiple, pipe delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)] @@ -215,7 +215,7 @@ namespace MediaBrowser.Api.UserLibrary public string Tags { get; set; } /// - /// Limit results to items containing specific years + /// Limit results to items containing specific years. /// /// The years. [ApiMember(Name = "Years", Description = "Optional. If specified, results will be filtered based on production year. This allows multiple, comma delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)] @@ -234,7 +234,7 @@ namespace MediaBrowser.Api.UserLibrary public string EnableImageTypes { get; set; } /// - /// Limit results to items containing a specific person + /// Limit results to items containing a specific person. /// /// The person. [ApiMember(Name = "Person", Description = "Optional. If specified, results will be filtered to include only those containing the specified person.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] @@ -244,14 +244,14 @@ namespace MediaBrowser.Api.UserLibrary public string PersonIds { get; set; } /// - /// If the Person filter is used, this can also be used to restrict to a specific person type + /// If the Person filter is used, this can also be used to restrict to a specific person type. /// /// The type of the person. [ApiMember(Name = "PersonTypes", Description = "Optional. If specified, along with Person, results will be filtered to include only those containing the specified person and PersonType. Allows multiple, comma-delimited", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] public string PersonTypes { get; set; } /// - /// Limit results to items containing specific studios + /// Limit results to items containing specific studios. /// /// The studios. [ApiMember(Name = "Studios", Description = "Optional. If specified, results will be filtered based on studio. This allows multiple, pipe delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)] diff --git a/MediaBrowser.Api/UserLibrary/GenresService.cs b/MediaBrowser.Api/UserLibrary/GenresService.cs index 1fa272a5f..7bdfbac98 100644 --- a/MediaBrowser.Api/UserLibrary/GenresService.cs +++ b/MediaBrowser.Api/UserLibrary/GenresService.cs @@ -14,7 +14,7 @@ using Microsoft.Extensions.Logging; namespace MediaBrowser.Api.UserLibrary { /// - /// Class GetGenres + /// Class GetGenres. /// [Route("/Genres", "GET", Summary = "Gets all genres from a given item, folder, or the entire library")] public class GetGenres : GetItemsByName @@ -22,7 +22,7 @@ namespace MediaBrowser.Api.UserLibrary } /// - /// Class GetGenre + /// Class GetGenre. /// [Route("/Genres/{Name}", "GET", Summary = "Gets a genre, by name")] public class GetGenre : IReturn @@ -43,7 +43,7 @@ namespace MediaBrowser.Api.UserLibrary } /// - /// Class GenresService + /// Class GenresService. /// [Authenticated] public class GenresService : BaseItemsByNameService diff --git a/MediaBrowser.Api/UserLibrary/ItemsService.cs b/MediaBrowser.Api/UserLibrary/ItemsService.cs index 49d534c36..7efe0552c 100644 --- a/MediaBrowser.Api/UserLibrary/ItemsService.cs +++ b/MediaBrowser.Api/UserLibrary/ItemsService.cs @@ -20,7 +20,7 @@ using MusicAlbum = MediaBrowser.Controller.Entities.Audio.MusicAlbum; namespace MediaBrowser.Api.UserLibrary { /// - /// Class GetItems + /// Class GetItems. /// [Route("/Items", "GET", Summary = "Gets items based on a query.")] [Route("/Users/{UserId}/Items", "GET", Summary = "Gets items based on a query.")] @@ -34,18 +34,18 @@ namespace MediaBrowser.Api.UserLibrary } /// - /// Class ItemsService + /// Class ItemsService. /// [Authenticated] public class ItemsService : BaseApiService { /// - /// The _user manager + /// The _user manager. /// private readonly IUserManager _userManager; /// - /// The _library manager + /// The _library manager. /// private readonly ILibraryManager _libraryManager; private readonly ILocalizationManager _localization; @@ -496,7 +496,7 @@ namespace MediaBrowser.Api.UserLibrary } /// - /// Class DateCreatedComparer + /// Class DateCreatedComparer. /// public class DateCreatedComparer : IComparer { diff --git a/MediaBrowser.Api/UserLibrary/PersonsService.cs b/MediaBrowser.Api/UserLibrary/PersonsService.cs index 3204e5219..7924339ed 100644 --- a/MediaBrowser.Api/UserLibrary/PersonsService.cs +++ b/MediaBrowser.Api/UserLibrary/PersonsService.cs @@ -14,7 +14,7 @@ using Microsoft.Extensions.Logging; namespace MediaBrowser.Api.UserLibrary { /// - /// Class GetPersons + /// Class GetPersons. /// [Route("/Persons", "GET", Summary = "Gets all persons from a given item, folder, or the entire library")] public class GetPersons : GetItemsByName @@ -22,7 +22,7 @@ namespace MediaBrowser.Api.UserLibrary } /// - /// Class GetPerson + /// Class GetPerson. /// [Route("/Persons/{Name}", "GET", Summary = "Gets a person, by name")] public class GetPerson : IReturn @@ -43,7 +43,7 @@ namespace MediaBrowser.Api.UserLibrary } /// - /// Class PersonsService + /// Class PersonsService. /// [Authenticated] public class PersonsService : BaseItemsByNameService diff --git a/MediaBrowser.Api/UserLibrary/PlaystateService.cs b/MediaBrowser.Api/UserLibrary/PlaystateService.cs index ab231626b..d809cc2e7 100644 --- a/MediaBrowser.Api/UserLibrary/PlaystateService.cs +++ b/MediaBrowser.Api/UserLibrary/PlaystateService.cs @@ -14,7 +14,7 @@ using Microsoft.Extensions.Logging; namespace MediaBrowser.Api.UserLibrary { /// - /// Class MarkPlayedItem + /// Class MarkPlayedItem. /// [Route("/Users/{UserId}/PlayedItems/{Id}", "POST", Summary = "Marks an item as played")] public class MarkPlayedItem : IReturn @@ -38,7 +38,7 @@ namespace MediaBrowser.Api.UserLibrary } /// - /// Class MarkUnplayedItem + /// Class MarkUnplayedItem. /// [Route("/Users/{UserId}/PlayedItems/{Id}", "DELETE", Summary = "Marks an item as unplayed")] public class MarkUnplayedItem : IReturn @@ -81,7 +81,7 @@ namespace MediaBrowser.Api.UserLibrary } /// - /// Class OnPlaybackStart + /// Class OnPlaybackStart. /// [Route("/Users/{UserId}/PlayingItems/{Id}", "POST", Summary = "Reports that a user has begun playing an item")] public class OnPlaybackStart : IReturnVoid @@ -123,7 +123,7 @@ namespace MediaBrowser.Api.UserLibrary } /// - /// Class OnPlaybackProgress + /// Class OnPlaybackProgress. /// [Route("/Users/{UserId}/PlayingItems/{Id}/Progress", "POST", Summary = "Reports a user's playback progress")] public class OnPlaybackProgress : IReturnVoid @@ -181,7 +181,7 @@ namespace MediaBrowser.Api.UserLibrary } /// - /// Class OnPlaybackStopped + /// Class OnPlaybackStopped. /// [Route("/Users/{UserId}/PlayingItems/{Id}", "DELETE", Summary = "Reports that a user has stopped playing an item")] public class OnPlaybackStopped : IReturnVoid diff --git a/MediaBrowser.Api/UserLibrary/StudiosService.cs b/MediaBrowser.Api/UserLibrary/StudiosService.cs index 683ce5d09..66350955f 100644 --- a/MediaBrowser.Api/UserLibrary/StudiosService.cs +++ b/MediaBrowser.Api/UserLibrary/StudiosService.cs @@ -13,7 +13,7 @@ using Microsoft.Extensions.Logging; namespace MediaBrowser.Api.UserLibrary { /// - /// Class GetStudios + /// Class GetStudios. /// [Route("/Studios", "GET", Summary = "Gets all studios from a given item, folder, or the entire library")] public class GetStudios : GetItemsByName @@ -21,7 +21,7 @@ namespace MediaBrowser.Api.UserLibrary } /// - /// Class GetStudio + /// Class GetStudio. /// [Route("/Studios/{Name}", "GET", Summary = "Gets a studio, by name")] public class GetStudio : IReturn @@ -42,7 +42,7 @@ namespace MediaBrowser.Api.UserLibrary } /// - /// Class StudiosService + /// Class StudiosService. /// [Authenticated] public class StudiosService : BaseItemsByNameService diff --git a/MediaBrowser.Api/UserLibrary/UserLibraryService.cs b/MediaBrowser.Api/UserLibrary/UserLibraryService.cs index f75852885..f9cbba410 100644 --- a/MediaBrowser.Api/UserLibrary/UserLibraryService.cs +++ b/MediaBrowser.Api/UserLibrary/UserLibraryService.cs @@ -20,7 +20,7 @@ using Microsoft.Extensions.Logging; namespace MediaBrowser.Api.UserLibrary { /// - /// Class GetItem + /// Class GetItem. /// [Route("/Users/{UserId}/Items/{Id}", "GET", Summary = "Gets an item from a user's library")] public class GetItem : IReturn @@ -41,7 +41,7 @@ namespace MediaBrowser.Api.UserLibrary } /// - /// Class GetItem + /// Class GetItem. /// [Route("/Users/{UserId}/Items/Root", "GET", Summary = "Gets the root folder from a user's library")] public class GetRootFolder : IReturn @@ -55,7 +55,7 @@ namespace MediaBrowser.Api.UserLibrary } /// - /// Class GetIntros + /// Class GetIntros. /// [Route("/Users/{UserId}/Items/{Id}/Intros", "GET", Summary = "Gets intros to play before the main media item plays")] public class GetIntros : IReturn> @@ -76,7 +76,7 @@ namespace MediaBrowser.Api.UserLibrary } /// - /// Class MarkFavoriteItem + /// Class MarkFavoriteItem. /// [Route("/Users/{UserId}/FavoriteItems/{Id}", "POST", Summary = "Marks an item as a favorite")] public class MarkFavoriteItem : IReturn @@ -97,7 +97,7 @@ namespace MediaBrowser.Api.UserLibrary } /// - /// Class UnmarkFavoriteItem + /// Class UnmarkFavoriteItem. /// [Route("/Users/{UserId}/FavoriteItems/{Id}", "DELETE", Summary = "Unmarks an item as a favorite")] public class UnmarkFavoriteItem : IReturn @@ -118,7 +118,7 @@ namespace MediaBrowser.Api.UserLibrary } /// - /// Class ClearUserItemRating + /// Class ClearUserItemRating. /// [Route("/Users/{UserId}/Items/{Id}/Rating", "DELETE", Summary = "Deletes a user's saved personal rating for an item")] public class DeleteUserItemRating : IReturn @@ -139,7 +139,7 @@ namespace MediaBrowser.Api.UserLibrary } /// - /// Class UpdateUserItemRating + /// Class UpdateUserItemRating. /// [Route("/Users/{UserId}/Items/{Id}/Rating", "POST", Summary = "Updates a user's rating for an item")] public class UpdateUserItemRating : IReturn @@ -167,7 +167,7 @@ namespace MediaBrowser.Api.UserLibrary } /// - /// Class GetLocalTrailers + /// Class GetLocalTrailers. /// [Route("/Users/{UserId}/Items/{Id}/LocalTrailers", "GET", Summary = "Gets local trailers for an item")] public class GetLocalTrailers : IReturn @@ -188,7 +188,7 @@ namespace MediaBrowser.Api.UserLibrary } /// - /// Class GetSpecialFeatures + /// Class GetSpecialFeatures. /// [Route("/Users/{UserId}/Items/{Id}/SpecialFeatures", "GET", Summary = "Gets special features for an item")] public class GetSpecialFeatures : IReturn @@ -259,7 +259,7 @@ namespace MediaBrowser.Api.UserLibrary } /// - /// Class UserLibraryService + /// Class UserLibraryService. /// [Authenticated] public class UserLibraryService : BaseApiService diff --git a/MediaBrowser.Api/UserLibrary/YearsService.cs b/MediaBrowser.Api/UserLibrary/YearsService.cs index d023ee90a..0523f89fa 100644 --- a/MediaBrowser.Api/UserLibrary/YearsService.cs +++ b/MediaBrowser.Api/UserLibrary/YearsService.cs @@ -13,7 +13,7 @@ using Microsoft.Extensions.Logging; namespace MediaBrowser.Api.UserLibrary { /// - /// Class GetYears + /// Class GetYears. /// [Route("/Years", "GET", Summary = "Gets all years from a given item, folder, or the entire library")] public class GetYears : GetItemsByName @@ -21,7 +21,7 @@ namespace MediaBrowser.Api.UserLibrary } /// - /// Class GetYear + /// Class GetYear. /// [Route("/Years/{Year}", "GET", Summary = "Gets a year")] public class GetYear : IReturn @@ -42,7 +42,7 @@ namespace MediaBrowser.Api.UserLibrary } /// - /// Class YearsService + /// Class YearsService. /// [Authenticated] public class YearsService : BaseItemsByNameService diff --git a/MediaBrowser.Api/UserService.cs b/MediaBrowser.Api/UserService.cs index 9cb9baf63..131def554 100644 --- a/MediaBrowser.Api/UserService.cs +++ b/MediaBrowser.Api/UserService.cs @@ -19,7 +19,7 @@ using Microsoft.Extensions.Logging; namespace MediaBrowser.Api { /// - /// Class GetUsers + /// Class GetUsers. /// [Route("/Users", "GET", Summary = "Gets a list of users")] [Authenticated] @@ -41,7 +41,7 @@ namespace MediaBrowser.Api } /// - /// Class GetUser + /// Class GetUser. /// [Route("/Users/{Id}", "GET", Summary = "Gets a user by Id")] [Authenticated(EscapeParentalControl = true)] @@ -56,7 +56,7 @@ namespace MediaBrowser.Api } /// - /// Class DeleteUser + /// Class DeleteUser. /// [Route("/Users/{Id}", "DELETE", Summary = "Deletes a user")] [Authenticated(Roles = "Admin")] @@ -71,7 +71,7 @@ namespace MediaBrowser.Api } /// - /// Class AuthenticateUser + /// Class AuthenticateUser. /// [Route("/Users/{Id}/Authenticate", "POST", Summary = "Authenticates a user")] public class AuthenticateUser : IReturn @@ -95,7 +95,7 @@ namespace MediaBrowser.Api } /// - /// Class AuthenticateUser + /// Class AuthenticateUser. /// [Route("/Users/AuthenticateByName", "POST", Summary = "Authenticates a user")] public class AuthenticateUserByName : IReturn @@ -119,7 +119,7 @@ namespace MediaBrowser.Api } /// - /// Class UpdateUserPassword + /// Class UpdateUserPassword. /// [Route("/Users/{Id}/Password", "POST", Summary = "Updates a user's password")] [Authenticated] @@ -149,7 +149,7 @@ namespace MediaBrowser.Api } /// - /// Class UpdateUserEasyPassword + /// Class UpdateUserEasyPassword. /// [Route("/Users/{Id}/EasyPassword", "POST", Summary = "Updates a user's easy password")] [Authenticated] @@ -177,7 +177,7 @@ namespace MediaBrowser.Api } /// - /// Class UpdateUser + /// Class UpdateUser. /// [Route("/Users/{Id}", "POST", Summary = "Updates a user")] [Authenticated] @@ -186,7 +186,7 @@ namespace MediaBrowser.Api } /// - /// Class UpdateUser + /// Class UpdateUser. /// [Route("/Users/{Id}/Policy", "POST", Summary = "Updates a user policy")] [Authenticated(Roles = "admin")] @@ -197,7 +197,7 @@ namespace MediaBrowser.Api } /// - /// Class UpdateUser + /// Class UpdateUser. /// [Route("/Users/{Id}/Configuration", "POST", Summary = "Updates a user configuration")] [Authenticated] @@ -208,7 +208,7 @@ namespace MediaBrowser.Api } /// - /// Class CreateUser + /// Class CreateUser. /// [Route("/Users/New", "POST", Summary = "Creates a user")] [Authenticated(Roles = "Admin")] @@ -236,7 +236,7 @@ namespace MediaBrowser.Api } /// - /// Class UsersService + /// Class UsersService. /// public class UserService : BaseApiService { diff --git a/MediaBrowser.Controller/Channels/InternalChannelFeatures.cs b/MediaBrowser.Controller/Channels/InternalChannelFeatures.cs index 60455e68a..1f4a26064 100644 --- a/MediaBrowser.Controller/Channels/InternalChannelFeatures.cs +++ b/MediaBrowser.Controller/Channels/InternalChannelFeatures.cs @@ -18,7 +18,7 @@ namespace MediaBrowser.Controller.Channels public List ContentTypes { get; set; } /// - /// Represents the maximum number of records the channel allows retrieving at a time + /// Represents the maximum number of records the channel allows retrieving at a time. /// public int? MaxPageSize { get; set; } diff --git a/MediaBrowser.Controller/Configuration/IServerConfigurationManager.cs b/MediaBrowser.Controller/Configuration/IServerConfigurationManager.cs index 6660743e6..a5c5e3bcc 100644 --- a/MediaBrowser.Controller/Configuration/IServerConfigurationManager.cs +++ b/MediaBrowser.Controller/Configuration/IServerConfigurationManager.cs @@ -4,7 +4,7 @@ using MediaBrowser.Model.Configuration; namespace MediaBrowser.Controller.Configuration { /// - /// Interface IServerConfigurationManager + /// Interface IServerConfigurationManager. /// public interface IServerConfigurationManager : IConfigurationManager { diff --git a/MediaBrowser.Controller/Drawing/IImageProcessor.cs b/MediaBrowser.Controller/Drawing/IImageProcessor.cs index f1873d539..488692c03 100644 --- a/MediaBrowser.Controller/Drawing/IImageProcessor.cs +++ b/MediaBrowser.Controller/Drawing/IImageProcessor.cs @@ -10,7 +10,7 @@ using MediaBrowser.Model.Entities; namespace MediaBrowser.Controller.Drawing { /// - /// Interface IImageProcessor + /// Interface IImageProcessor. /// public interface IImageProcessor { diff --git a/MediaBrowser.Controller/Dto/IDtoService.cs b/MediaBrowser.Controller/Dto/IDtoService.cs index 56e6c47c4..0dadc283e 100644 --- a/MediaBrowser.Controller/Dto/IDtoService.cs +++ b/MediaBrowser.Controller/Dto/IDtoService.cs @@ -7,7 +7,7 @@ using MediaBrowser.Model.Querying; namespace MediaBrowser.Controller.Dto { /// - /// Interface IDtoService + /// Interface IDtoService. /// public interface IDtoService { diff --git a/MediaBrowser.Controller/Entities/AggregateFolder.cs b/MediaBrowser.Controller/Entities/AggregateFolder.cs index 54540e892..67858b844 100644 --- a/MediaBrowser.Controller/Entities/AggregateFolder.cs +++ b/MediaBrowser.Controller/Entities/AggregateFolder.cs @@ -35,7 +35,7 @@ namespace MediaBrowser.Controller.Entities public override bool SupportsPlayedStatus => false; /// - /// The _virtual children + /// The _virtual children. /// private readonly ConcurrentBag _virtualChildren = new ConcurrentBag(); diff --git a/MediaBrowser.Controller/Entities/Audio/Audio.cs b/MediaBrowser.Controller/Entities/Audio/Audio.cs index a8ea2157d..b3e241a15 100644 --- a/MediaBrowser.Controller/Entities/Audio/Audio.cs +++ b/MediaBrowser.Controller/Entities/Audio/Audio.cs @@ -11,7 +11,7 @@ using MediaBrowser.Model.Entities; namespace MediaBrowser.Controller.Entities.Audio { /// - /// Class Audio + /// Class Audio. /// public class Audio : BaseItem, IHasAlbumArtist, diff --git a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs index f7b2f9549..e563f398b 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs @@ -15,7 +15,7 @@ using MetadataProvider = MediaBrowser.Model.Entities.MetadataProvider; namespace MediaBrowser.Controller.Entities.Audio { /// - /// Class MusicAlbum + /// Class MusicAlbum. /// public class MusicAlbum : Folder, IHasAlbumArtist, IHasArtist, IHasMusicGenres, IHasLookupInfo, IMetadataContainer { diff --git a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs index 63db3cfab..56c3c38dc 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs @@ -15,7 +15,7 @@ using MetadataProvider = MediaBrowser.Model.Entities.MetadataProvider; namespace MediaBrowser.Controller.Entities.Audio { /// - /// Class MusicArtist + /// Class MusicArtist. /// public class MusicArtist : Folder, IItemByName, IHasMusicGenres, IHasDualAccess, IHasLookupInfo { @@ -111,7 +111,7 @@ namespace MediaBrowser.Controller.Entities.Audio /// /// Returns the folder containing the item. - /// If the item is a folder, it returns the folder itself + /// If the item is a folder, it returns the folder itself. /// /// The containing folder path. [JsonIgnore] @@ -201,7 +201,7 @@ namespace MediaBrowser.Controller.Entities.Audio } /// - /// This is called before any metadata refresh and returns true or false indicating if changes were made + /// This is called before any metadata refresh and returns true or false indicating if changes were made. /// public override bool BeforeMetadataRefresh(bool replaceAllMetdata) { diff --git a/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs b/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs index 537e9630b..49a4cbae2 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs @@ -7,7 +7,7 @@ using Microsoft.Extensions.Logging; namespace MediaBrowser.Controller.Entities.Audio { /// - /// Class MusicGenre + /// Class MusicGenre. /// public class MusicGenre : BaseItem, IItemByName { @@ -34,7 +34,7 @@ namespace MediaBrowser.Controller.Entities.Audio /// /// Returns the folder containing the item. - /// If the item is a folder, it returns the folder itself + /// If the item is a folder, it returns the folder itself. /// /// The containing folder path. [JsonIgnore] @@ -98,7 +98,7 @@ namespace MediaBrowser.Controller.Entities.Audio } /// - /// This is called before any metadata refresh and returns true or false indicating if changes were made + /// This is called before any metadata refresh and returns true or false indicating if changes were made. /// public override bool BeforeMetadataRefresh(bool replaceAllMetdata) { diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index f2de1f2b1..ecbb83d07 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -31,12 +31,12 @@ using Microsoft.Extensions.Logging; namespace MediaBrowser.Controller.Entities { /// - /// Class BaseItem + /// Class BaseItem. /// public abstract class BaseItem : IHasProviderIds, IHasLookupInfo, IEquatable { /// - /// The supported image extensions + /// The supported image extensions. /// public static readonly string[] SupportedImageExtensions = new[] { ".png", ".jpg", ".jpeg", ".tbn", ".gif" }; @@ -75,7 +75,7 @@ namespace MediaBrowser.Controller.Entities public static char SlugChar = '-'; /// - /// The trailer folder name + /// The trailer folder name. /// public const string TrailerFolderName = "trailers"; public const string ThemeSongsFolderName = "theme-music"; @@ -243,7 +243,7 @@ namespace MediaBrowser.Controller.Entities /// /// Returns the folder containing the item. - /// If the item is a folder, it returns the folder itself + /// If the item is a folder, it returns the folder itself. /// [JsonIgnore] public virtual string ContainingFolderPath @@ -267,7 +267,7 @@ namespace MediaBrowser.Controller.Entities public string ServiceName { get; set; } /// - /// If this content came from an external service, the id of the content on that service + /// If this content came from an external service, the id of the content on that service. /// [JsonIgnore] public string ExternalId { get; set; } @@ -411,7 +411,7 @@ namespace MediaBrowser.Controller.Entities } /// - /// This is just a helper for convenience + /// This is just a helper for convenience. /// /// The primary image path. [JsonIgnore] @@ -556,7 +556,7 @@ namespace MediaBrowser.Controller.Entities public DateTime DateLastRefreshed { get; set; } /// - /// The logger + /// The logger. /// public static ILoggerFactory LoggerFactory { get; set; } public static ILogger Logger { get; set; } @@ -799,7 +799,7 @@ namespace MediaBrowser.Controller.Entities } /// - /// Finds a parent of a given type + /// Finds a parent of a given type. /// /// /// ``0. @@ -1351,7 +1351,7 @@ namespace MediaBrowser.Controller.Entities } /// - /// Overrides the base implementation to refresh metadata for local trailers + /// Overrides the base implementation to refresh metadata for local trailers. /// /// The options. /// The cancellation token. @@ -1753,7 +1753,7 @@ namespace MediaBrowser.Controller.Entities } /// - /// Determines if a given user has access to this item + /// Determines if a given user has access to this item. /// /// The user. /// true if [is parental allowed] [the specified user]; otherwise, false. @@ -2059,7 +2059,7 @@ namespace MediaBrowser.Controller.Entities public virtual bool EnableRememberingTrackSelections => true; /// - /// Adds a studio to the item + /// Adds a studio to the item. /// /// The name. /// @@ -2095,7 +2095,7 @@ namespace MediaBrowser.Controller.Entities } /// - /// Adds a genre to the item + /// Adds a genre to the item. /// /// The name. /// @@ -2190,7 +2190,7 @@ namespace MediaBrowser.Controller.Entities } /// - /// Gets an image + /// Gets an image. /// /// The type. /// Index of the image. @@ -2506,7 +2506,7 @@ namespace MediaBrowser.Controller.Entities } /// - /// Gets the file system path to delete when the item is to be deleted + /// Gets the file system path to delete when the item is to be deleted. /// /// public virtual IEnumerable GetDeletePaths() diff --git a/MediaBrowser.Controller/Entities/CollectionFolder.cs b/MediaBrowser.Controller/Entities/CollectionFolder.cs index e5adf88d1..35a6cef95 100644 --- a/MediaBrowser.Controller/Entities/CollectionFolder.cs +++ b/MediaBrowser.Controller/Entities/CollectionFolder.cs @@ -18,7 +18,7 @@ namespace MediaBrowser.Controller.Entities { /// /// Specialized Folder class that points to a subset of the physical folders in the system. - /// It is created from the user-specific folders within the system root + /// It is created from the user-specific folders within the system root. /// public class CollectionFolder : Folder, ICollectionFolder { @@ -140,7 +140,7 @@ namespace MediaBrowser.Controller.Entities } /// - /// Allow different display preferences for each collection folder + /// Allow different display preferences for each collection folder. /// /// The display prefs id. [JsonIgnore] diff --git a/MediaBrowser.Controller/Entities/Extensions.cs b/MediaBrowser.Controller/Entities/Extensions.cs index d2ca11740..3a34c668c 100644 --- a/MediaBrowser.Controller/Entities/Extensions.cs +++ b/MediaBrowser.Controller/Entities/Extensions.cs @@ -6,7 +6,7 @@ using MediaBrowser.Model.Entities; namespace MediaBrowser.Controller.Entities { /// - /// Class Extensions + /// Class Extensions. /// public static class Extensions { diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index 3a01b4379..34e5d78e7 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -31,7 +31,7 @@ using Series = MediaBrowser.Controller.Entities.TV.Series; namespace MediaBrowser.Controller.Entities { /// - /// Class Folder + /// Class Folder. /// public class Folder : BaseItem { @@ -172,7 +172,7 @@ namespace MediaBrowser.Controller.Entities public virtual IEnumerable Children => LoadChildren(); /// - /// thread-safe access to all recursive children of this folder - without regard to user + /// thread-safe access to all recursive children of this folder - without regard to user. /// /// The recursive children. [JsonIgnore] @@ -229,7 +229,7 @@ namespace MediaBrowser.Controller.Entities } /// - /// Validates that the children of the folder still exist + /// Validates that the children of the folder still exist. /// /// The progress. /// The cancellation token. @@ -570,7 +570,7 @@ namespace MediaBrowser.Controller.Entities } /// - /// Get the children of this folder from the actual file system + /// Get the children of this folder from the actual file system. /// /// IEnumerable{BaseItem}. protected virtual IEnumerable GetNonCachedChildren(IDirectoryService directoryService) @@ -582,7 +582,7 @@ namespace MediaBrowser.Controller.Entities } /// - /// Get our children from the repo - stubbed for now + /// Get our children from the repo - stubbed for now. /// /// IEnumerable{BaseItem}. protected List GetCachedChildren() @@ -1286,7 +1286,7 @@ namespace MediaBrowser.Controller.Entities } /// - /// Gets allowed recursive children of an item + /// Gets allowed recursive children of an item. /// /// The user. /// if set to true [include linked children]. diff --git a/MediaBrowser.Controller/Entities/Genre.cs b/MediaBrowser.Controller/Entities/Genre.cs index 773c7df34..852cf4684 100644 --- a/MediaBrowser.Controller/Entities/Genre.cs +++ b/MediaBrowser.Controller/Entities/Genre.cs @@ -8,7 +8,7 @@ using Microsoft.Extensions.Logging; namespace MediaBrowser.Controller.Entities { /// - /// Class Genre + /// Class Genre. /// public class Genre : BaseItem, IItemByName { @@ -31,7 +31,7 @@ namespace MediaBrowser.Controller.Entities /// /// Returns the folder containing the item. - /// If the item is a folder, it returns the folder itself + /// If the item is a folder, it returns the folder itself. /// /// The containing folder path. [JsonIgnore] @@ -96,7 +96,7 @@ namespace MediaBrowser.Controller.Entities } /// - /// This is called before any metadata refresh and returns true or false indicating if changes were made + /// This is called before any metadata refresh and returns true or false indicating if changes were made. /// public override bool BeforeMetadataRefresh(bool replaceAllMetdata) { diff --git a/MediaBrowser.Controller/Entities/ICollectionFolder.cs b/MediaBrowser.Controller/Entities/ICollectionFolder.cs index 4f0760746..245b23ff0 100644 --- a/MediaBrowser.Controller/Entities/ICollectionFolder.cs +++ b/MediaBrowser.Controller/Entities/ICollectionFolder.cs @@ -3,7 +3,7 @@ using System; namespace MediaBrowser.Controller.Entities { /// - /// This is just a marker interface to denote top level folders + /// This is just a marker interface to denote top level folders. /// public interface ICollectionFolder : IHasCollectionType { diff --git a/MediaBrowser.Controller/Entities/IHasAspectRatio.cs b/MediaBrowser.Controller/Entities/IHasAspectRatio.cs index 149c1e5ab..d7d007668 100644 --- a/MediaBrowser.Controller/Entities/IHasAspectRatio.cs +++ b/MediaBrowser.Controller/Entities/IHasAspectRatio.cs @@ -1,7 +1,7 @@ namespace MediaBrowser.Controller.Entities { /// - /// Interface IHasAspectRatio + /// Interface IHasAspectRatio. /// public interface IHasAspectRatio { diff --git a/MediaBrowser.Controller/Entities/IHasDisplayOrder.cs b/MediaBrowser.Controller/Entities/IHasDisplayOrder.cs index abee75a28..13226b234 100644 --- a/MediaBrowser.Controller/Entities/IHasDisplayOrder.cs +++ b/MediaBrowser.Controller/Entities/IHasDisplayOrder.cs @@ -1,7 +1,7 @@ namespace MediaBrowser.Controller.Entities { /// - /// Interface IHasDisplayOrder + /// Interface IHasDisplayOrder. /// public interface IHasDisplayOrder { diff --git a/MediaBrowser.Controller/Entities/IHasScreenshots.cs b/MediaBrowser.Controller/Entities/IHasScreenshots.cs index 0975242f5..b027a0cb1 100644 --- a/MediaBrowser.Controller/Entities/IHasScreenshots.cs +++ b/MediaBrowser.Controller/Entities/IHasScreenshots.cs @@ -1,7 +1,7 @@ namespace MediaBrowser.Controller.Entities { /// - /// Interface IHasScreenshots + /// Interface IHasScreenshots. /// public interface IHasScreenshots { diff --git a/MediaBrowser.Controller/Entities/LinkedChild.cs b/MediaBrowser.Controller/Entities/LinkedChild.cs index d88c31007..fbce74aab 100644 --- a/MediaBrowser.Controller/Entities/LinkedChild.cs +++ b/MediaBrowser.Controller/Entities/LinkedChild.cs @@ -16,7 +16,7 @@ namespace MediaBrowser.Controller.Entities public string Id { get; set; } /// - /// Serves as a cache + /// Serves as a cache. /// public Guid? ItemId { get; set; } diff --git a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs index be71bcc3c..70c48b6f1 100644 --- a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs +++ b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs @@ -11,7 +11,7 @@ using MediaBrowser.Model.Querying; namespace MediaBrowser.Controller.Entities.Movies { /// - /// Class BoxSet + /// Class BoxSet. /// public class BoxSet : Folder, IHasTrailers, IHasDisplayOrder, IHasLookupInfo { diff --git a/MediaBrowser.Controller/Entities/Movies/Movie.cs b/MediaBrowser.Controller/Entities/Movies/Movie.cs index 26a165025..53badac4d 100644 --- a/MediaBrowser.Controller/Entities/Movies/Movie.cs +++ b/MediaBrowser.Controller/Entities/Movies/Movie.cs @@ -13,7 +13,7 @@ using MediaBrowser.Model.Providers; namespace MediaBrowser.Controller.Entities.Movies { /// - /// Class Movie + /// Class Movie. /// public class Movie : Video, IHasSpecialFeatures, IHasTrailers, IHasLookupInfo, ISupportsBoxSetGrouping { diff --git a/MediaBrowser.Controller/Entities/Person.cs b/MediaBrowser.Controller/Entities/Person.cs index 9e4f9d47e..69bd7659c 100644 --- a/MediaBrowser.Controller/Entities/Person.cs +++ b/MediaBrowser.Controller/Entities/Person.cs @@ -46,7 +46,7 @@ namespace MediaBrowser.Controller.Entities /// /// Returns the folder containing the item. - /// If the item is a folder, it returns the folder itself + /// If the item is a folder, it returns the folder itself. /// /// The containing folder path. [JsonIgnore] @@ -118,7 +118,7 @@ namespace MediaBrowser.Controller.Entities } /// - /// This is called before any metadata refresh and returns true or false indicating if changes were made + /// This is called before any metadata refresh and returns true or false indicating if changes were made. /// public override bool BeforeMetadataRefresh(bool replaceAllMetdata) { diff --git a/MediaBrowser.Controller/Entities/Studio.cs b/MediaBrowser.Controller/Entities/Studio.cs index 068032317..f81b6f194 100644 --- a/MediaBrowser.Controller/Entities/Studio.cs +++ b/MediaBrowser.Controller/Entities/Studio.cs @@ -7,7 +7,7 @@ using Microsoft.Extensions.Logging; namespace MediaBrowser.Controller.Entities { /// - /// Class Studio + /// Class Studio. /// public class Studio : BaseItem, IItemByName { @@ -25,7 +25,7 @@ namespace MediaBrowser.Controller.Entities /// /// Returns the folder containing the item. - /// If the item is a folder, it returns the folder itself + /// If the item is a folder, it returns the folder itself. /// /// The containing folder path. [JsonIgnore] @@ -97,7 +97,7 @@ namespace MediaBrowser.Controller.Entities } /// - /// This is called before any metadata refresh and returns true or false indicating if changes were made + /// This is called before any metadata refresh and returns true or false indicating if changes were made. /// public override bool BeforeMetadataRefresh(bool replaceAllMetdata) { diff --git a/MediaBrowser.Controller/Entities/TV/Episode.cs b/MediaBrowser.Controller/Entities/TV/Episode.cs index 4ec60e7cd..82e7d49fb 100644 --- a/MediaBrowser.Controller/Entities/TV/Episode.cs +++ b/MediaBrowser.Controller/Entities/TV/Episode.cs @@ -12,7 +12,7 @@ using Microsoft.Extensions.Logging; namespace MediaBrowser.Controller.Entities.TV { /// - /// Class Episode + /// Class Episode. /// public class Episode : Video, IHasTrailers, IHasLookupInfo, IHasSeries { @@ -101,7 +101,7 @@ namespace MediaBrowser.Controller.Entities.TV } /// - /// This Episode's Series Instance + /// This Episode's Series Instance. /// /// The series. [JsonIgnore] diff --git a/MediaBrowser.Controller/Entities/TV/Season.cs b/MediaBrowser.Controller/Entities/TV/Season.cs index 7dfd1a759..9f0658776 100644 --- a/MediaBrowser.Controller/Entities/TV/Season.cs +++ b/MediaBrowser.Controller/Entities/TV/Season.cs @@ -11,7 +11,7 @@ using MediaBrowser.Model.Querying; namespace MediaBrowser.Controller.Entities.TV { /// - /// Class Season + /// Class Season. /// public class Season : Folder, IHasSeries, IHasLookupInfo { @@ -68,7 +68,7 @@ namespace MediaBrowser.Controller.Entities.TV } /// - /// This Episode's Series Instance + /// This Episode's Series Instance. /// /// The series. [JsonIgnore] @@ -225,7 +225,7 @@ namespace MediaBrowser.Controller.Entities.TV } /// - /// This is called before any metadata refresh and returns true or false indicating if changes were made + /// This is called before any metadata refresh and returns true or false indicating if changes were made. /// /// true if XXXX, false otherwise. public override bool BeforeMetadataRefresh(bool replaceAllMetdata) diff --git a/MediaBrowser.Controller/Entities/TV/Series.cs b/MediaBrowser.Controller/Entities/TV/Series.cs index a519089b3..9263a156a 100644 --- a/MediaBrowser.Controller/Entities/TV/Series.cs +++ b/MediaBrowser.Controller/Entities/TV/Series.cs @@ -17,7 +17,7 @@ using MetadataProvider = MediaBrowser.Model.Entities.MetadataProvider; namespace MediaBrowser.Controller.Entities.TV { /// - /// Class Series + /// Class Series. /// public class Series : Folder, IHasTrailers, IHasDisplayOrder, IHasLookupInfo, IMetadataContainer { @@ -54,7 +54,7 @@ namespace MediaBrowser.Controller.Entities.TV public IReadOnlyList RemoteTrailerIds { get; set; } /// - /// airdate, dvd or absolute + /// airdate, dvd or absolute. /// public string DisplayOrder { get; set; } diff --git a/MediaBrowser.Controller/Entities/Trailer.cs b/MediaBrowser.Controller/Entities/Trailer.cs index c327d17c9..6b544afc6 100644 --- a/MediaBrowser.Controller/Entities/Trailer.cs +++ b/MediaBrowser.Controller/Entities/Trailer.cs @@ -9,7 +9,7 @@ using MediaBrowser.Model.Providers; namespace MediaBrowser.Controller.Entities { /// - /// Class Trailer + /// Class Trailer. /// public class Trailer : Video, IHasLookupInfo { diff --git a/MediaBrowser.Controller/Entities/UserItemData.cs b/MediaBrowser.Controller/Entities/UserItemData.cs index ab425ee0f..81f4850a5 100644 --- a/MediaBrowser.Controller/Entities/UserItemData.cs +++ b/MediaBrowser.Controller/Entities/UserItemData.cs @@ -4,7 +4,7 @@ using System.Text.Json.Serialization; namespace MediaBrowser.Controller.Entities { /// - /// Class UserItemData + /// Class UserItemData. /// public class UserItemData { @@ -21,11 +21,11 @@ namespace MediaBrowser.Controller.Entities public string Key { get; set; } /// - /// The _rating + /// The _rating. /// private double? _rating; /// - /// Gets or sets the users 0-10 rating + /// Gets or sets the users 0-10 rating. /// /// The rating. /// Rating;A 0 to 10 rating is required for UserItemData. diff --git a/MediaBrowser.Controller/Entities/Video.cs b/MediaBrowser.Controller/Entities/Video.cs index 4cfa0e74d..4efeede19 100644 --- a/MediaBrowser.Controller/Entities/Video.cs +++ b/MediaBrowser.Controller/Entities/Video.cs @@ -17,7 +17,7 @@ using MediaBrowser.Model.MediaInfo; namespace MediaBrowser.Controller.Entities { /// - /// Class Video + /// Class Video. /// public class Video : BaseItem, IHasAspectRatio, diff --git a/MediaBrowser.Controller/Entities/Year.cs b/MediaBrowser.Controller/Entities/Year.cs index a01ef5c31..c961da643 100644 --- a/MediaBrowser.Controller/Entities/Year.cs +++ b/MediaBrowser.Controller/Entities/Year.cs @@ -7,7 +7,7 @@ using Microsoft.Extensions.Logging; namespace MediaBrowser.Controller.Entities { /// - /// Class Year + /// Class Year. /// public class Year : BaseItem, IItemByName { @@ -21,7 +21,7 @@ namespace MediaBrowser.Controller.Entities /// /// Returns the folder containing the item. - /// If the item is a folder, it returns the folder itself + /// If the item is a folder, it returns the folder itself. /// /// The containing folder path. [JsonIgnore] @@ -107,7 +107,7 @@ namespace MediaBrowser.Controller.Entities } /// - /// This is called before any metadata refresh and returns true or false indicating if changes were made + /// This is called before any metadata refresh and returns true or false indicating if changes were made. /// public override bool BeforeMetadataRefresh(bool replaceAllMetdata) { diff --git a/MediaBrowser.Controller/Extensions/StringExtensions.cs b/MediaBrowser.Controller/Extensions/StringExtensions.cs index b1aaf6534..e09543e14 100644 --- a/MediaBrowser.Controller/Extensions/StringExtensions.cs +++ b/MediaBrowser.Controller/Extensions/StringExtensions.cs @@ -7,7 +7,7 @@ using System.Text.RegularExpressions; namespace MediaBrowser.Controller.Extensions { /// - /// Class BaseExtensions + /// Class BaseExtensions. /// public static class StringExtensions { diff --git a/MediaBrowser.Controller/IServerApplicationHost.cs b/MediaBrowser.Controller/IServerApplicationHost.cs index d1d6c74b8..abdb0f695 100644 --- a/MediaBrowser.Controller/IServerApplicationHost.cs +++ b/MediaBrowser.Controller/IServerApplicationHost.cs @@ -10,7 +10,7 @@ using Microsoft.AspNetCore.Http; namespace MediaBrowser.Controller { /// - /// Interface IServerApplicationHost + /// Interface IServerApplicationHost. /// public interface IServerApplicationHost : IApplicationHost { diff --git a/MediaBrowser.Controller/IServerApplicationPaths.cs b/MediaBrowser.Controller/IServerApplicationPaths.cs index c35a22ac7..155bf9177 100644 --- a/MediaBrowser.Controller/IServerApplicationPaths.cs +++ b/MediaBrowser.Controller/IServerApplicationPaths.cs @@ -5,7 +5,7 @@ namespace MediaBrowser.Controller public interface IServerApplicationPaths : IApplicationPaths { /// - /// Gets the path to the base root media directory + /// Gets the path to the base root media directory. /// /// The root folder path. string RootFolderPath { get; } @@ -17,13 +17,13 @@ namespace MediaBrowser.Controller string DefaultUserViewsPath { get; } /// - /// Gets the path to the People directory + /// Gets the path to the People directory. /// /// The people path. string PeoplePath { get; } /// - /// Gets the path to the Genre directory + /// Gets the path to the Genre directory. /// /// The genre path. string GenrePath { get; } @@ -35,25 +35,25 @@ namespace MediaBrowser.Controller string MusicGenrePath { get; } /// - /// Gets the path to the Studio directory + /// Gets the path to the Studio directory. /// /// The studio path. string StudioPath { get; } /// - /// Gets the path to the Year directory + /// Gets the path to the Year directory. /// /// The year path. string YearPath { get; } /// - /// Gets the path to the General IBN directory + /// Gets the path to the General IBN directory. /// /// The general path. string GeneralPath { get; } /// - /// Gets the path to the Ratings IBN directory + /// Gets the path to the Ratings IBN directory. /// /// The ratings path. string RatingsPath { get; } @@ -65,7 +65,7 @@ namespace MediaBrowser.Controller string MediaInfoImagesPath { get; } /// - /// Gets the path to the user configuration directory + /// Gets the path to the user configuration directory. /// /// The user configuration directory path. string UserConfigurationDirectoryPath { get; } diff --git a/MediaBrowser.Controller/Library/IIntroProvider.cs b/MediaBrowser.Controller/Library/IIntroProvider.cs index aa7001611..d45493d40 100644 --- a/MediaBrowser.Controller/Library/IIntroProvider.cs +++ b/MediaBrowser.Controller/Library/IIntroProvider.cs @@ -5,7 +5,7 @@ using MediaBrowser.Controller.Entities; namespace MediaBrowser.Controller.Library { /// - /// Class BaseIntroProvider + /// Class BaseIntroProvider. /// public interface IIntroProvider { diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs index d7237039e..47c080ebd 100644 --- a/MediaBrowser.Controller/Library/ILibraryManager.cs +++ b/MediaBrowser.Controller/Library/ILibraryManager.cs @@ -21,7 +21,7 @@ using Person = MediaBrowser.Controller.Entities.Person; namespace MediaBrowser.Controller.Library { /// - /// Interface ILibraryManager + /// Interface ILibraryManager. /// public interface ILibraryManager { @@ -38,7 +38,7 @@ namespace MediaBrowser.Controller.Library bool allowIgnorePath = true); /// - /// Resolves a set of files into a list of BaseItem + /// Resolves a set of files into a list of BaseItem. /// IEnumerable ResolvePaths( IEnumerable files, @@ -54,7 +54,7 @@ namespace MediaBrowser.Controller.Library AggregateFolder RootFolder { get; } /// - /// Gets a Person + /// Gets a Person. /// /// The name. /// Task{Person}. @@ -75,14 +75,14 @@ namespace MediaBrowser.Controller.Library MusicArtist GetArtist(string name); MusicArtist GetArtist(string name, DtoOptions options); /// - /// Gets a Studio + /// Gets a Studio. /// /// The name. /// Task{Studio}. Studio GetStudio(string name); /// - /// Gets a Genre + /// Gets a Genre. /// /// The name. /// Task{Genre}. @@ -96,7 +96,7 @@ namespace MediaBrowser.Controller.Library MusicGenre GetMusicGenre(string name); /// - /// Gets a Year + /// Gets a Year. /// /// The value. /// Task{Year}. @@ -113,7 +113,7 @@ namespace MediaBrowser.Controller.Library Task ValidatePeople(CancellationToken cancellationToken, IProgress progress); /// - /// Reloads the root media folder + /// Reloads the root media folder. /// /// The progress. /// The cancellation token. diff --git a/MediaBrowser.Controller/Library/ILibraryPostScanTask.cs b/MediaBrowser.Controller/Library/ILibraryPostScanTask.cs index cba5e8fd7..4032e9d83 100644 --- a/MediaBrowser.Controller/Library/ILibraryPostScanTask.cs +++ b/MediaBrowser.Controller/Library/ILibraryPostScanTask.cs @@ -5,7 +5,7 @@ using System.Threading.Tasks; namespace MediaBrowser.Controller.Library { /// - /// An interface for tasks that run after the media library scan + /// An interface for tasks that run after the media library scan. /// public interface ILibraryPostScanTask { diff --git a/MediaBrowser.Controller/Library/IMetadataSaver.cs b/MediaBrowser.Controller/Library/IMetadataSaver.cs index dd119984e..027cc5b40 100644 --- a/MediaBrowser.Controller/Library/IMetadataSaver.cs +++ b/MediaBrowser.Controller/Library/IMetadataSaver.cs @@ -4,7 +4,7 @@ using MediaBrowser.Controller.Entities; namespace MediaBrowser.Controller.Library { /// - /// Interface IMetadataSaver + /// Interface IMetadataSaver. /// public interface IMetadataSaver { diff --git a/MediaBrowser.Controller/Library/ISearchEngine.cs b/MediaBrowser.Controller/Library/ISearchEngine.cs index 8498b92ae..31dcbba5b 100644 --- a/MediaBrowser.Controller/Library/ISearchEngine.cs +++ b/MediaBrowser.Controller/Library/ISearchEngine.cs @@ -4,7 +4,7 @@ using MediaBrowser.Model.Search; namespace MediaBrowser.Controller.Library { /// - /// Interface ILibrarySearchEngine + /// Interface ILibrarySearchEngine. /// public interface ISearchEngine { diff --git a/MediaBrowser.Controller/Library/IUserDataManager.cs b/MediaBrowser.Controller/Library/IUserDataManager.cs index f5ccad671..d08ad4cac 100644 --- a/MediaBrowser.Controller/Library/IUserDataManager.cs +++ b/MediaBrowser.Controller/Library/IUserDataManager.cs @@ -42,14 +42,14 @@ namespace MediaBrowser.Controller.Library UserItemDataDto GetUserDataDto(BaseItem item, BaseItemDto itemDto, User user, DtoOptions dto_options); /// - /// Get all user data for the given user + /// Get all user data for the given user. /// /// /// List GetAllUserData(Guid userId); /// - /// Save the all provided user data for the given user + /// Save the all provided user data for the given user. /// /// /// @@ -58,7 +58,7 @@ namespace MediaBrowser.Controller.Library void SaveAllUserData(Guid userId, UserItemData[] userData, CancellationToken cancellationToken); /// - /// Updates playstate for an item and returns true or false indicating if it was played to completion + /// Updates playstate for an item and returns true or false indicating if it was played to completion. /// bool UpdatePlayState(BaseItem item, UserItemData data, long? positionTicks); } diff --git a/MediaBrowser.Controller/Library/IUserManager.cs b/MediaBrowser.Controller/Library/IUserManager.cs index b5b2e4729..fe3e4f9e6 100644 --- a/MediaBrowser.Controller/Library/IUserManager.cs +++ b/MediaBrowser.Controller/Library/IUserManager.cs @@ -11,7 +11,7 @@ using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.Library { /// - /// Interface IUserManager + /// Interface IUserManager. /// public interface IUserManager { diff --git a/MediaBrowser.Controller/Library/ItemChangeEventArgs.cs b/MediaBrowser.Controller/Library/ItemChangeEventArgs.cs index c9671de47..b5c48321b 100644 --- a/MediaBrowser.Controller/Library/ItemChangeEventArgs.cs +++ b/MediaBrowser.Controller/Library/ItemChangeEventArgs.cs @@ -3,7 +3,7 @@ using MediaBrowser.Controller.Entities; namespace MediaBrowser.Controller.Library { /// - /// Class ItemChangeEventArgs + /// Class ItemChangeEventArgs. /// public class ItemChangeEventArgs { diff --git a/MediaBrowser.Controller/Library/ItemResolveArgs.cs b/MediaBrowser.Controller/Library/ItemResolveArgs.cs index cca85cd3b..7c1463862 100644 --- a/MediaBrowser.Controller/Library/ItemResolveArgs.cs +++ b/MediaBrowser.Controller/Library/ItemResolveArgs.cs @@ -15,7 +15,7 @@ namespace MediaBrowser.Controller.Library public class ItemResolveArgs : EventArgs { /// - /// The _app paths + /// The _app paths. /// private readonly IServerApplicationPaths _appPaths; diff --git a/MediaBrowser.Controller/Library/PlaybackProgressEventArgs.cs b/MediaBrowser.Controller/Library/PlaybackProgressEventArgs.cs index b4e205184..abe129484 100644 --- a/MediaBrowser.Controller/Library/PlaybackProgressEventArgs.cs +++ b/MediaBrowser.Controller/Library/PlaybackProgressEventArgs.cs @@ -8,7 +8,7 @@ using MediaBrowser.Model.Dto; namespace MediaBrowser.Controller.Library { /// - /// Holds information about a playback progress event + /// Holds information about a playback progress event. /// public class PlaybackProgressEventArgs : EventArgs { diff --git a/MediaBrowser.Controller/Library/Profiler.cs b/MediaBrowser.Controller/Library/Profiler.cs index 0febef3d3..a566de338 100644 --- a/MediaBrowser.Controller/Library/Profiler.cs +++ b/MediaBrowser.Controller/Library/Profiler.cs @@ -5,21 +5,21 @@ using Microsoft.Extensions.Logging; namespace MediaBrowser.Controller.Library { /// - /// Class Profiler + /// Class Profiler. /// public class Profiler : IDisposable { /// - /// The name + /// The name. /// readonly string _name; /// - /// The stopwatch + /// The stopwatch. /// readonly Stopwatch _stopwatch; /// - /// The _logger + /// The _logger. /// private readonly ILogger _logger; diff --git a/MediaBrowser.Controller/Library/SearchHintInfo.cs b/MediaBrowser.Controller/Library/SearchHintInfo.cs index 692431e34..897c2b7f4 100644 --- a/MediaBrowser.Controller/Library/SearchHintInfo.cs +++ b/MediaBrowser.Controller/Library/SearchHintInfo.cs @@ -3,7 +3,7 @@ using MediaBrowser.Controller.Entities; namespace MediaBrowser.Controller.Library { /// - /// Class SearchHintInfo + /// Class SearchHintInfo. /// public class SearchHintInfo { diff --git a/MediaBrowser.Controller/Library/TVUtils.cs b/MediaBrowser.Controller/Library/TVUtils.cs index fd5fb6748..ebdcfbdb3 100644 --- a/MediaBrowser.Controller/Library/TVUtils.cs +++ b/MediaBrowser.Controller/Library/TVUtils.cs @@ -3,7 +3,7 @@ using System; namespace MediaBrowser.Controller.Library { /// - /// Class TVUtils + /// Class TVUtils. /// public static class TVUtils { diff --git a/MediaBrowser.Controller/Library/UserDataSaveEventArgs.cs b/MediaBrowser.Controller/Library/UserDataSaveEventArgs.cs index 3e7351b8b..fa0192784 100644 --- a/MediaBrowser.Controller/Library/UserDataSaveEventArgs.cs +++ b/MediaBrowser.Controller/Library/UserDataSaveEventArgs.cs @@ -6,7 +6,7 @@ using MediaBrowser.Model.Entities; namespace MediaBrowser.Controller.Library { /// - /// Class UserDataSaveEventArgs + /// Class UserDataSaveEventArgs. /// public class UserDataSaveEventArgs : EventArgs { diff --git a/MediaBrowser.Controller/LiveTv/ChannelInfo.cs b/MediaBrowser.Controller/LiveTv/ChannelInfo.cs index 70477fce7..1b7095c7b 100644 --- a/MediaBrowser.Controller/LiveTv/ChannelInfo.cs +++ b/MediaBrowser.Controller/LiveTv/ChannelInfo.cs @@ -3,7 +3,7 @@ using MediaBrowser.Model.LiveTv; namespace MediaBrowser.Controller.LiveTv { /// - /// Class ChannelInfo + /// Class ChannelInfo. /// public class ChannelInfo { @@ -44,13 +44,13 @@ namespace MediaBrowser.Controller.LiveTv public ChannelType ChannelType { get; set; } /// - /// Supply the image path if it can be accessed directly from the file system + /// Supply the image path if it can be accessed directly from the file system. /// /// The image path. public string ImagePath { get; set; } /// - /// Supply the image url if it can be downloaded + /// Supply the image url if it can be downloaded. /// /// The image URL. public string ImageUrl { get; set; } diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs index bc3bf78f0..aa24d5ab8 100644 --- a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs +++ b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs @@ -14,7 +14,7 @@ using MediaBrowser.Model.Querying; namespace MediaBrowser.Controller.LiveTv { /// - /// Manages all live tv services installed on the server + /// Manages all live tv services installed on the server. /// public interface ILiveTvManager { diff --git a/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs b/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs index e17db34c6..472b061e6 100644 --- a/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs +++ b/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs @@ -140,7 +140,7 @@ namespace MediaBrowser.Controller.LiveTv /// /// Returns the folder containing the item. - /// If the item is a folder, it returns the folder itself + /// If the item is a folder, it returns the folder itself. /// /// The containing folder path. [JsonIgnore] diff --git a/MediaBrowser.Controller/LiveTv/ProgramInfo.cs b/MediaBrowser.Controller/LiveTv/ProgramInfo.cs index 5d0f13192..b847140f5 100644 --- a/MediaBrowser.Controller/LiveTv/ProgramInfo.cs +++ b/MediaBrowser.Controller/LiveTv/ProgramInfo.cs @@ -18,7 +18,7 @@ namespace MediaBrowser.Controller.LiveTv public string ChannelId { get; set; } /// - /// Name of the program + /// Name of the program. /// public string Name { get; set; } @@ -95,13 +95,13 @@ namespace MediaBrowser.Controller.LiveTv public string EpisodeTitle { get; set; } /// - /// Supply the image path if it can be accessed directly from the file system + /// Supply the image path if it can be accessed directly from the file system. /// /// The image path. public string ImagePath { get; set; } /// - /// Supply the image url if it can be downloaded + /// Supply the image url if it can be downloaded. /// /// The image URL. public string ImageUrl { get; set; } diff --git a/MediaBrowser.Controller/LiveTv/RecordingInfo.cs b/MediaBrowser.Controller/LiveTv/RecordingInfo.cs index 432388d6b..b9e0218ab 100644 --- a/MediaBrowser.Controller/LiveTv/RecordingInfo.cs +++ b/MediaBrowser.Controller/LiveTv/RecordingInfo.cs @@ -169,13 +169,13 @@ namespace MediaBrowser.Controller.LiveTv public float? CommunityRating { get; set; } /// - /// Supply the image path if it can be accessed directly from the file system + /// Supply the image path if it can be accessed directly from the file system. /// /// The image path. public string ImagePath { get; set; } /// - /// Supply the image url if it can be downloaded + /// Supply the image url if it can be downloaded. /// /// The image URL. public string ImageUrl { get; set; } diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 0ca42c0e0..680d92c2d 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -108,7 +108,7 @@ namespace MediaBrowser.Controller.MediaEncoding } /// - /// Gets the name of the output video codec + /// Gets the name of the output video codec. /// public string GetVideoEncoder(EncodingJobInfo state, EncodingOptions encodingOptions) { @@ -285,7 +285,7 @@ namespace MediaBrowser.Controller.MediaEncoding } /// - /// Infers the audio codec based on the url + /// Infers the audio codec based on the url. /// public string InferAudioCodec(string container) { @@ -703,7 +703,7 @@ namespace MediaBrowser.Controller.MediaEncoding } /// - /// Gets the video bitrate to specify on the command line + /// Gets the video bitrate to specify on the command line. /// public string GetVideoQualityParam(EncodingJobInfo state, string videoEncoder, EncodingOptions encodingOptions, string defaultPreset) { @@ -1300,7 +1300,7 @@ namespace MediaBrowser.Controller.MediaEncoding } /// - /// Gets the number of audio channels to specify on the command line + /// Gets the number of audio channels to specify on the command line. /// /// The state. /// The audio stream. @@ -1486,7 +1486,7 @@ namespace MediaBrowser.Controller.MediaEncoding } /// - /// Determines which stream will be used for playback + /// Determines which stream will be used for playback. /// /// All stream. /// Index of the desired. @@ -1961,7 +1961,7 @@ namespace MediaBrowser.Controller.MediaEncoding } /// - /// If we're going to put a fixed size on the command line, this will calculate it + /// If we're going to put a fixed size on the command line, this will calculate it. /// public string GetOutputSizeParam( EncodingJobInfo state, @@ -2505,7 +2505,7 @@ namespace MediaBrowser.Controller.MediaEncoding } /// - /// Gets the name of the output video codec + /// Gets the name of the output video codec. /// protected string GetHardwareAcceleratedVideoDecoder(EncodingJobInfo state, EncodingOptions encodingOptions) { diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs b/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs index acf1aae89..32973619d 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs @@ -418,7 +418,7 @@ namespace MediaBrowser.Controller.MediaEncoding } /// - /// Predicts the audio sample rate that will be in the output stream + /// Predicts the audio sample rate that will be in the output stream. /// public double? TargetVideoLevel { @@ -441,7 +441,7 @@ namespace MediaBrowser.Controller.MediaEncoding } /// - /// Predicts the audio sample rate that will be in the output stream + /// Predicts the audio sample rate that will be in the output stream. /// public int? TargetVideoBitDepth { @@ -476,7 +476,7 @@ namespace MediaBrowser.Controller.MediaEncoding } /// - /// Predicts the audio sample rate that will be in the output stream + /// Predicts the audio sample rate that will be in the output stream. /// public float? TargetFramerate { @@ -508,7 +508,7 @@ namespace MediaBrowser.Controller.MediaEncoding } /// - /// Predicts the audio sample rate that will be in the output stream + /// Predicts the audio sample rate that will be in the output stream. /// public int? TargetPacketLength { @@ -524,7 +524,7 @@ namespace MediaBrowser.Controller.MediaEncoding } /// - /// Predicts the audio sample rate that will be in the output stream + /// Predicts the audio sample rate that will be in the output stream. /// public string TargetVideoProfile { @@ -679,20 +679,20 @@ namespace MediaBrowser.Controller.MediaEncoding } /// - /// Enum TranscodingJobType + /// Enum TranscodingJobType. /// public enum TranscodingJobType { /// - /// The progressive + /// The progressive. /// Progressive, /// - /// The HLS + /// The HLS. /// Hls, /// - /// The dash + /// The dash. /// Dash } diff --git a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs index 37f0b11a7..e33c4ad0b 100644 --- a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs +++ b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs @@ -11,7 +11,7 @@ using MediaBrowser.Model.System; namespace MediaBrowser.Controller.MediaEncoding { /// - /// Interface IMediaEncoder + /// Interface IMediaEncoder. /// public interface IMediaEncoder : ITranscoderSupport { diff --git a/MediaBrowser.Controller/MediaEncoding/MediaEncoderHelpers.cs b/MediaBrowser.Controller/MediaEncoding/MediaEncoderHelpers.cs index 5cedc3d57..6c9bbb043 100644 --- a/MediaBrowser.Controller/MediaEncoding/MediaEncoderHelpers.cs +++ b/MediaBrowser.Controller/MediaEncoding/MediaEncoderHelpers.cs @@ -7,7 +7,7 @@ using MediaBrowser.Model.IO; namespace MediaBrowser.Controller.MediaEncoding { /// - /// Class MediaEncoderHelpers + /// Class MediaEncoderHelpers. /// public static class MediaEncoderHelpers { diff --git a/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs b/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs index df90c399b..9e262d31e 100644 --- a/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs +++ b/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs @@ -11,7 +11,7 @@ using Microsoft.Extensions.Logging; namespace MediaBrowser.Controller.Net { /// - /// Starts sending data over a web socket periodically when a message is received, and then stops when a corresponding stop message is received + /// Starts sending data over a web socket periodically when a message is received, and then stops when a corresponding stop message is received. /// /// The type of the T return data type. /// The type of the T state type. @@ -20,7 +20,7 @@ namespace MediaBrowser.Controller.Net where TReturnDataType : class { /// - /// The _active connections + /// The _active connections. /// private readonly List> _activeConnections = new List>(); @@ -38,7 +38,7 @@ namespace MediaBrowser.Controller.Net protected abstract Task GetDataToSend(); /// - /// The logger + /// The logger. /// protected ILogger> Logger; @@ -78,7 +78,7 @@ namespace MediaBrowser.Controller.Net } /// - /// Starts sending messages over a web socket + /// Starts sending messages over a web socket. /// /// The message. private void Start(WebSocketMessageInfo message) @@ -180,7 +180,7 @@ namespace MediaBrowser.Controller.Net } /// - /// Stops sending messages over a web socket + /// Stops sending messages over a web socket. /// /// The message. private void Stop(WebSocketMessageInfo message) diff --git a/MediaBrowser.Controller/Net/IHttpResultFactory.cs b/MediaBrowser.Controller/Net/IHttpResultFactory.cs index 25404fa78..609bd5f59 100644 --- a/MediaBrowser.Controller/Net/IHttpResultFactory.cs +++ b/MediaBrowser.Controller/Net/IHttpResultFactory.cs @@ -7,7 +7,7 @@ using MediaBrowser.Model.Services; namespace MediaBrowser.Controller.Net { /// - /// Interface IHttpResultFactory + /// Interface IHttpResultFactory. /// public interface IHttpResultFactory { diff --git a/MediaBrowser.Controller/Net/IHttpServer.cs b/MediaBrowser.Controller/Net/IHttpServer.cs index efb5f4ac3..e6609fae3 100644 --- a/MediaBrowser.Controller/Net/IHttpServer.cs +++ b/MediaBrowser.Controller/Net/IHttpServer.cs @@ -29,19 +29,19 @@ namespace MediaBrowser.Controller.Net void Init(IEnumerable serviceTypes, IEnumerable listener, IEnumerable urlPrefixes); /// - /// If set, all requests will respond with this message + /// If set, all requests will respond with this message. /// string GlobalResponse { get; set; } /// - /// The HTTP request handler + /// The HTTP request handler. /// /// /// Task RequestHandler(HttpContext context); /// - /// Get the default CORS headers + /// Get the default CORS headers. /// /// /// diff --git a/MediaBrowser.Controller/Net/IWebSocketListener.cs b/MediaBrowser.Controller/Net/IWebSocketListener.cs index 0f472a2bc..7250a57b0 100644 --- a/MediaBrowser.Controller/Net/IWebSocketListener.cs +++ b/MediaBrowser.Controller/Net/IWebSocketListener.cs @@ -3,7 +3,7 @@ using System.Threading.Tasks; namespace MediaBrowser.Controller.Net { /// - ///This is an interface for listening to messages coming through a web socket connection + ///This is an interface for listening to messages coming through a web socket connection. /// public interface IWebSocketListener { diff --git a/MediaBrowser.Controller/Net/WebSocketMessageInfo.cs b/MediaBrowser.Controller/Net/WebSocketMessageInfo.cs index 5bf39cae6..be0b3ddc3 100644 --- a/MediaBrowser.Controller/Net/WebSocketMessageInfo.cs +++ b/MediaBrowser.Controller/Net/WebSocketMessageInfo.cs @@ -3,7 +3,7 @@ using MediaBrowser.Model.Net; namespace MediaBrowser.Controller.Net { /// - /// Class WebSocketMessageInfo + /// Class WebSocketMessageInfo. /// public class WebSocketMessageInfo : WebSocketMessage { diff --git a/MediaBrowser.Controller/Persistence/IItemRepository.cs b/MediaBrowser.Controller/Persistence/IItemRepository.cs index 75fc43a04..0ae1b8bbf 100644 --- a/MediaBrowser.Controller/Persistence/IItemRepository.cs +++ b/MediaBrowser.Controller/Persistence/IItemRepository.cs @@ -9,12 +9,12 @@ using MediaBrowser.Model.Querying; namespace MediaBrowser.Controller.Persistence { /// - /// Provides an interface to implement an Item repository + /// Provides an interface to implement an Item repository. /// public interface IItemRepository : IRepository { /// - /// Saves an item + /// Saves an item. /// /// The item. /// The cancellation token. @@ -43,14 +43,14 @@ namespace MediaBrowser.Controller.Persistence BaseItem RetrieveItem(Guid id); /// - /// Gets chapters for an item + /// Gets chapters for an item. /// /// /// List GetChapters(BaseItem id); /// - /// Gets a single chapter for an item + /// Gets a single chapter for an item. /// /// /// diff --git a/MediaBrowser.Controller/Persistence/IRepository.cs b/MediaBrowser.Controller/Persistence/IRepository.cs index 56bf1dd5a..42f285076 100644 --- a/MediaBrowser.Controller/Persistence/IRepository.cs +++ b/MediaBrowser.Controller/Persistence/IRepository.cs @@ -3,12 +3,12 @@ using System; namespace MediaBrowser.Controller.Persistence { /// - /// Provides a base interface for all the repository interfaces + /// Provides a base interface for all the repository interfaces. /// public interface IRepository : IDisposable { /// - /// Gets the name of the repository + /// Gets the name of the repository. /// /// The name. string Name { get; } diff --git a/MediaBrowser.Controller/Persistence/IUserDataRepository.cs b/MediaBrowser.Controller/Persistence/IUserDataRepository.cs index 4c327eeef..ba7c9fd50 100644 --- a/MediaBrowser.Controller/Persistence/IUserDataRepository.cs +++ b/MediaBrowser.Controller/Persistence/IUserDataRepository.cs @@ -5,7 +5,7 @@ using MediaBrowser.Controller.Entities; namespace MediaBrowser.Controller.Persistence { /// - /// Provides an interface to implement a UserData repository + /// Provides an interface to implement a UserData repository. /// public interface IUserDataRepository : IRepository { @@ -30,14 +30,14 @@ namespace MediaBrowser.Controller.Persistence UserItemData GetUserData(long userId, List keys); /// - /// Return all user data associated with the given user + /// Return all user data associated with the given user. /// /// /// List GetAllUserData(long userId); /// - /// Save all user data associated with the given user + /// Save all user data associated with the given user. /// /// /// diff --git a/MediaBrowser.Controller/Plugins/IPluginConfigurationPage.cs b/MediaBrowser.Controller/Plugins/IPluginConfigurationPage.cs index c156da924..077f5ab63 100644 --- a/MediaBrowser.Controller/Plugins/IPluginConfigurationPage.cs +++ b/MediaBrowser.Controller/Plugins/IPluginConfigurationPage.cs @@ -4,7 +4,7 @@ using MediaBrowser.Common.Plugins; namespace MediaBrowser.Controller.Plugins { /// - /// Interface IConfigurationPage + /// Interface IConfigurationPage. /// public interface IPluginConfigurationPage { @@ -34,16 +34,16 @@ namespace MediaBrowser.Controller.Plugins } /// - /// Enum ConfigurationPageType + /// Enum ConfigurationPageType. /// public enum ConfigurationPageType { /// - /// The plugin configuration + /// The plugin configuration. /// PluginConfiguration, /// - /// The none + /// The none. /// None } diff --git a/MediaBrowser.Controller/Providers/IMetadataProvider.cs b/MediaBrowser.Controller/Providers/IMetadataProvider.cs index 3e595ff93..62b16dadd 100644 --- a/MediaBrowser.Controller/Providers/IMetadataProvider.cs +++ b/MediaBrowser.Controller/Providers/IMetadataProvider.cs @@ -3,7 +3,7 @@ using MediaBrowser.Controller.Entities; namespace MediaBrowser.Controller.Providers { /// - /// Marker interface + /// Marker interface. /// public interface IMetadataProvider { diff --git a/MediaBrowser.Controller/Providers/MetadataRefreshMode.cs b/MediaBrowser.Controller/Providers/MetadataRefreshMode.cs index 02152ee33..6d49b5510 100644 --- a/MediaBrowser.Controller/Providers/MetadataRefreshMode.cs +++ b/MediaBrowser.Controller/Providers/MetadataRefreshMode.cs @@ -3,22 +3,22 @@ namespace MediaBrowser.Controller.Providers public enum MetadataRefreshMode { /// - /// The none + /// The none. /// None = 0, /// - /// The validation only + /// The validation only. /// ValidationOnly = 1, /// - /// Providers will be executed based on default rules + /// Providers will be executed based on default rules. /// Default = 2, /// - /// All providers will be executed to search for new metadata + /// All providers will be executed to search for new metadata. /// FullRefresh = 3 } diff --git a/MediaBrowser.Controller/Providers/MetadataResult.cs b/MediaBrowser.Controller/Providers/MetadataResult.cs index 59adaedfa..83efed2a1 100644 --- a/MediaBrowser.Controller/Providers/MetadataResult.cs +++ b/MediaBrowser.Controller/Providers/MetadataResult.cs @@ -40,7 +40,7 @@ namespace MediaBrowser.Controller.Providers } /// - /// Not only does this clear, but initializes the list so that services can differentiate between a null list and zero people + /// Not only does this clear, but initializes the list so that services can differentiate between a null list and zero people. /// public void ResetPeople() { diff --git a/MediaBrowser.Controller/Providers/VideoContentType.cs b/MediaBrowser.Controller/Providers/VideoContentType.cs index c3b8964a3..49d587f6c 100644 --- a/MediaBrowser.Controller/Providers/VideoContentType.cs +++ b/MediaBrowser.Controller/Providers/VideoContentType.cs @@ -1,17 +1,17 @@ namespace MediaBrowser.Controller.Providers { /// - /// Enum VideoContentType + /// Enum VideoContentType. /// public enum VideoContentType { /// - /// The episode + /// The episode. /// Episode = 0, /// - /// The movie + /// The movie. /// Movie = 1 } diff --git a/MediaBrowser.Controller/Resolvers/BaseItemResolver.cs b/MediaBrowser.Controller/Resolvers/BaseItemResolver.cs index 637a7e3f0..67acdd9a3 100644 --- a/MediaBrowser.Controller/Resolvers/BaseItemResolver.cs +++ b/MediaBrowser.Controller/Resolvers/BaseItemResolver.cs @@ -4,7 +4,7 @@ using MediaBrowser.Controller.Library; namespace MediaBrowser.Controller.Resolvers { /// - /// Class ItemResolver + /// Class ItemResolver. /// /// public abstract class ItemResolver : IItemResolver @@ -27,7 +27,7 @@ namespace MediaBrowser.Controller.Resolvers public virtual ResolverPriority Priority => ResolverPriority.First; /// - /// Sets initial values on the newly resolved item + /// Sets initial values on the newly resolved item. /// /// The item. /// The args. diff --git a/MediaBrowser.Controller/Resolvers/IItemResolver.cs b/MediaBrowser.Controller/Resolvers/IItemResolver.cs index 16e37d249..2e82b51f1 100644 --- a/MediaBrowser.Controller/Resolvers/IItemResolver.cs +++ b/MediaBrowser.Controller/Resolvers/IItemResolver.cs @@ -7,7 +7,7 @@ using MediaBrowser.Model.IO; namespace MediaBrowser.Controller.Resolvers { /// - /// Interface IItemResolver + /// Interface IItemResolver. /// public interface IItemResolver { diff --git a/MediaBrowser.Controller/Resolvers/ResolverPriority.cs b/MediaBrowser.Controller/Resolvers/ResolverPriority.cs index e39310095..1911e5c1d 100644 --- a/MediaBrowser.Controller/Resolvers/ResolverPriority.cs +++ b/MediaBrowser.Controller/Resolvers/ResolverPriority.cs @@ -1,25 +1,25 @@ namespace MediaBrowser.Controller.Resolvers { /// - /// Enum ResolverPriority + /// Enum ResolverPriority. /// public enum ResolverPriority { /// - /// The first + /// The first. /// First = 1, /// - /// The second + /// The second. /// Second = 2, /// - /// The third + /// The third. /// Third = 3, Fourth = 4, /// - /// The last + /// The last. /// Last = 5 } diff --git a/MediaBrowser.Controller/Session/ISessionManager.cs b/MediaBrowser.Controller/Session/ISessionManager.cs index 1fdb588eb..e54f21050 100644 --- a/MediaBrowser.Controller/Session/ISessionManager.cs +++ b/MediaBrowser.Controller/Session/ISessionManager.cs @@ -13,7 +13,7 @@ using MediaBrowser.Model.SyncPlay; namespace MediaBrowser.Controller.Session { /// - /// Interface ISessionManager + /// Interface ISessionManager. /// public interface ISessionManager { @@ -79,14 +79,14 @@ namespace MediaBrowser.Controller.Session void UpdateDeviceName(string sessionId, string reportedDeviceName); /// - /// Used to report that playback has started for an item + /// Used to report that playback has started for an item. /// /// The info. /// Task. Task OnPlaybackStart(PlaybackStartInfo info); /// - /// Used to report playback progress for an item + /// Used to report playback progress for an item. /// /// The info. /// Task. @@ -96,7 +96,7 @@ namespace MediaBrowser.Controller.Session Task OnPlaybackProgress(PlaybackProgressInfo info, bool isAutomated); /// - /// Used to report that playback has ended for an item + /// Used to report that playback has ended for an item. /// /// The info. /// Task. diff --git a/MediaBrowser.Controller/Sorting/IBaseItemComparer.cs b/MediaBrowser.Controller/Sorting/IBaseItemComparer.cs index 31087edec..727cbe639 100644 --- a/MediaBrowser.Controller/Sorting/IBaseItemComparer.cs +++ b/MediaBrowser.Controller/Sorting/IBaseItemComparer.cs @@ -4,7 +4,7 @@ using MediaBrowser.Controller.Entities; namespace MediaBrowser.Controller.Sorting { /// - /// Interface IBaseItemComparer + /// Interface IBaseItemComparer. /// public interface IBaseItemComparer : IComparer { diff --git a/MediaBrowser.Controller/Sorting/IUserBaseItemComparer.cs b/MediaBrowser.Controller/Sorting/IUserBaseItemComparer.cs index 6f75d16de..6d03d97ae 100644 --- a/MediaBrowser.Controller/Sorting/IUserBaseItemComparer.cs +++ b/MediaBrowser.Controller/Sorting/IUserBaseItemComparer.cs @@ -3,7 +3,7 @@ using MediaBrowser.Controller.Library; namespace MediaBrowser.Controller.Sorting { /// - /// Represents a BaseItem comparer that requires a User to perform it's comparison + /// Represents a BaseItem comparer that requires a User to perform it's comparison. /// public interface IUserBaseItemComparer : IBaseItemComparer { diff --git a/MediaBrowser.Controller/Sync/IRemoteSyncProvider.cs b/MediaBrowser.Controller/Sync/IRemoteSyncProvider.cs index c0b62b753..b2c53365c 100644 --- a/MediaBrowser.Controller/Sync/IRemoteSyncProvider.cs +++ b/MediaBrowser.Controller/Sync/IRemoteSyncProvider.cs @@ -1,7 +1,7 @@ namespace MediaBrowser.Controller.Sync { /// - /// A marker interface + /// A marker interface. /// public interface IRemoteSyncProvider { diff --git a/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs b/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs index 0ceb55c57..da5a3d5bc 100644 --- a/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs +++ b/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs @@ -14,14 +14,14 @@ using Microsoft.Extensions.Logging; namespace MediaBrowser.LocalMetadata.Parsers { /// - /// Provides a base class for parsing metadata xml + /// Provides a base class for parsing metadata xml. /// /// public class BaseItemXmlParser where T : BaseItem { /// - /// The logger + /// The logger. /// protected ILogger> Logger { get; private set; } protected IProviderManager ProviderManager { get; private set; } @@ -39,7 +39,7 @@ namespace MediaBrowser.LocalMetadata.Parsers } /// - /// Fetches metadata for an item from one xml file + /// Fetches metadata for an item from one xml file. /// /// The item. /// The metadata file. @@ -124,7 +124,7 @@ namespace MediaBrowser.LocalMetadata.Parsers private readonly CultureInfo _usCulture = new CultureInfo("en-US"); /// - /// Fetches metadata from one Xml Element + /// Fetches metadata from one Xml Element. /// /// The reader. /// The item result. @@ -1230,7 +1230,7 @@ namespace MediaBrowser.LocalMetadata.Parsers /// - /// Used to split names of comma or pipe delimeted genres and people + /// Used to split names of comma or pipe delimeted genres and people. /// /// The value. /// IEnumerable{System.String}. diff --git a/MediaBrowser.MediaEncoding/BdInfo/BdInfoExaminer.cs b/MediaBrowser.MediaEncoding/BdInfo/BdInfoExaminer.cs index 3260f3051..e6359f4fb 100644 --- a/MediaBrowser.MediaEncoding/BdInfo/BdInfoExaminer.cs +++ b/MediaBrowser.MediaEncoding/BdInfo/BdInfoExaminer.cs @@ -9,7 +9,7 @@ using MediaBrowser.Model.MediaInfo; namespace MediaBrowser.MediaEncoding.BdInfo { /// - /// Class BdInfoExaminer + /// Class BdInfoExaminer. /// public class BdInfoExaminer : IBlurayExaminer { diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index a4896d5f9..59fd6b848 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -25,7 +25,7 @@ using System.Diagnostics; namespace MediaBrowser.MediaEncoding.Encoder { /// - /// Class MediaEncoder + /// Class MediaEncoder. /// public class MediaEncoder : IMediaEncoder, IDisposable { @@ -425,7 +425,7 @@ namespace MediaBrowser.MediaEncoding.Encoder } /// - /// The us culture + /// The us culture. /// protected readonly CultureInfo UsCulture = new CultureInfo("en-US"); diff --git a/MediaBrowser.MediaEncoding/Probing/FFProbeHelpers.cs b/MediaBrowser.MediaEncoding/Probing/FFProbeHelpers.cs index 78dc7b607..3aa296f7f 100644 --- a/MediaBrowser.MediaEncoding/Probing/FFProbeHelpers.cs +++ b/MediaBrowser.MediaEncoding/Probing/FFProbeHelpers.cs @@ -35,7 +35,7 @@ namespace MediaBrowser.MediaEncoding.Probing } /// - /// Gets a string from an FFProbeResult tags dictionary + /// Gets a string from an FFProbeResult tags dictionary. /// /// The tags. /// The key. @@ -52,7 +52,7 @@ namespace MediaBrowser.MediaEncoding.Probing } /// - /// Gets an int from an FFProbeResult tags dictionary + /// Gets an int from an FFProbeResult tags dictionary. /// /// The tags. /// The key. @@ -73,7 +73,7 @@ namespace MediaBrowser.MediaEncoding.Probing } /// - /// Gets a DateTime from an FFProbeResult tags dictionary + /// Gets a DateTime from an FFProbeResult tags dictionary. /// /// The tags. /// The key. @@ -94,7 +94,7 @@ namespace MediaBrowser.MediaEncoding.Probing } /// - /// Converts a dictionary to case insensitive + /// Converts a dictionary to case insensitive. /// /// The dict. /// Dictionary{System.StringSystem.String}. diff --git a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs index 7d57a691e..4c48c038f 100644 --- a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs +++ b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs @@ -515,7 +515,7 @@ namespace MediaBrowser.MediaEncoding.Probing } /// - /// Converts ffprobe stream info to our MediaAttachment class + /// Converts ffprobe stream info to our MediaAttachment class. /// /// The stream info. /// MediaAttachments. @@ -548,7 +548,7 @@ namespace MediaBrowser.MediaEncoding.Probing } /// - /// Converts ffprobe stream info to our MediaStream class + /// Converts ffprobe stream info to our MediaStream class. /// /// if set to true [is info]. /// The stream info. @@ -767,7 +767,7 @@ namespace MediaBrowser.MediaEncoding.Probing } /// - /// Gets a string from an FFProbeResult tags dictionary + /// Gets a string from an FFProbeResult tags dictionary. /// /// The tags. /// The key. @@ -1154,7 +1154,7 @@ namespace MediaBrowser.MediaEncoding.Probing } /// - /// Gets the studios from the tags collection + /// Gets the studios from the tags collection. /// /// The info. /// The tags. @@ -1191,7 +1191,7 @@ namespace MediaBrowser.MediaEncoding.Probing } /// - /// Gets the genres from the tags collection + /// Gets the genres from the tags collection. /// /// The information. /// The tags. diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs index 7e9894f0a..763d7f641 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs @@ -344,7 +344,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles } /// - /// The _semaphoreLocks + /// The _semaphoreLocks. /// private readonly ConcurrentDictionary _semaphoreLocks = new ConcurrentDictionary(); diff --git a/MediaBrowser.Model/Channels/ChannelFeatures.cs b/MediaBrowser.Model/Channels/ChannelFeatures.cs index 496102d83..a55754edd 100644 --- a/MediaBrowser.Model/Channels/ChannelFeatures.cs +++ b/MediaBrowser.Model/Channels/ChannelFeatures.cs @@ -38,7 +38,7 @@ namespace MediaBrowser.Model.Channels public ChannelMediaContentType[] ContentTypes { get; set; } /// - /// Represents the maximum number of records the channel allows retrieving at a time + /// Represents the maximum number of records the channel allows retrieving at a time. /// public int? MaxPageSize { get; set; } diff --git a/MediaBrowser.Model/Channels/ChannelQuery.cs b/MediaBrowser.Model/Channels/ChannelQuery.cs index d11260039..fd90e7f06 100644 --- a/MediaBrowser.Model/Channels/ChannelQuery.cs +++ b/MediaBrowser.Model/Channels/ChannelQuery.cs @@ -10,7 +10,7 @@ namespace MediaBrowser.Model.Channels public class ChannelQuery { /// - /// Fields to return within the items, in addition to basic information + /// Fields to return within the items, in addition to basic information. /// /// The fields. public ItemFields[] Fields { get; set; } @@ -34,7 +34,7 @@ namespace MediaBrowser.Model.Channels public int? StartIndex { get; set; } /// - /// The maximum number of items to return + /// The maximum number of items to return. /// /// The limit. public int? Limit { get; set; } diff --git a/MediaBrowser.Model/Configuration/BaseApplicationConfiguration.cs b/MediaBrowser.Model/Configuration/BaseApplicationConfiguration.cs index cdd322c94..54f4fb293 100644 --- a/MediaBrowser.Model/Configuration/BaseApplicationConfiguration.cs +++ b/MediaBrowser.Model/Configuration/BaseApplicationConfiguration.cs @@ -12,7 +12,7 @@ namespace MediaBrowser.Model.Configuration public class BaseApplicationConfiguration { /// - /// The number of days we should retain log files + /// The number of days we should retain log files. /// /// The log file retention days. public int LogFileRetentionDays { get; set; } diff --git a/MediaBrowser.Model/Configuration/MetadataPluginType.cs b/MediaBrowser.Model/Configuration/MetadataPluginType.cs index bff12799f..4c5e95266 100644 --- a/MediaBrowser.Model/Configuration/MetadataPluginType.cs +++ b/MediaBrowser.Model/Configuration/MetadataPluginType.cs @@ -3,7 +3,7 @@ namespace MediaBrowser.Model.Configuration { /// - /// Enum MetadataPluginType + /// Enum MetadataPluginType. /// public enum MetadataPluginType { diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs index afbe02dd3..742887620 100644 --- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs +++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs @@ -111,19 +111,19 @@ namespace MediaBrowser.Model.Configuration public string MetadataCountryCode { get; set; } /// - /// Characters to be replaced with a ' ' in strings to create a sort name + /// Characters to be replaced with a ' ' in strings to create a sort name. /// /// The sort replace characters. public string[] SortReplaceCharacters { get; set; } /// - /// Characters to be removed from strings to create a sort name + /// Characters to be removed from strings to create a sort name. /// /// The sort remove characters. public string[] SortRemoveCharacters { get; set; } /// - /// Words to be removed from strings to create a sort name + /// Words to be removed from strings to create a sort name. /// /// The sort remove words. public string[] SortRemoveWords { get; set; } diff --git a/MediaBrowser.Model/Configuration/UserConfiguration.cs b/MediaBrowser.Model/Configuration/UserConfiguration.cs index 85d864eec..d236ac215 100644 --- a/MediaBrowser.Model/Configuration/UserConfiguration.cs +++ b/MediaBrowser.Model/Configuration/UserConfiguration.cs @@ -7,7 +7,7 @@ using Jellyfin.Data.Enums; namespace MediaBrowser.Model.Configuration { /// - /// Class UserConfiguration + /// Class UserConfiguration. /// public class UserConfiguration { diff --git a/MediaBrowser.Model/Dlna/AudioOptions.cs b/MediaBrowser.Model/Dlna/AudioOptions.cs index fc555c5f7..baa99b903 100644 --- a/MediaBrowser.Model/Dlna/AudioOptions.cs +++ b/MediaBrowser.Model/Dlna/AudioOptions.cs @@ -47,7 +47,7 @@ namespace MediaBrowser.Model.Dlna public int? MaxAudioChannels { get; set; } /// - /// The application's configured quality setting + /// The application's configured quality setting. /// public long? MaxBitrate { get; set; } diff --git a/MediaBrowser.Model/Dlna/StreamInfo.cs b/MediaBrowser.Model/Dlna/StreamInfo.cs index 244463803..28d8a6439 100644 --- a/MediaBrowser.Model/Dlna/StreamInfo.cs +++ b/MediaBrowser.Model/Dlna/StreamInfo.cs @@ -465,7 +465,7 @@ namespace MediaBrowser.Model.Dlna } /// - /// Returns the audio stream that will be used + /// Returns the audio stream that will be used. /// public MediaStream TargetAudioStream { @@ -481,7 +481,7 @@ namespace MediaBrowser.Model.Dlna } /// - /// Returns the video stream that will be used + /// Returns the video stream that will be used. /// public MediaStream TargetVideoStream { @@ -497,7 +497,7 @@ namespace MediaBrowser.Model.Dlna } /// - /// Predicts the audio sample rate that will be in the output stream + /// Predicts the audio sample rate that will be in the output stream. /// public int? TargetAudioSampleRate { @@ -509,7 +509,7 @@ namespace MediaBrowser.Model.Dlna } /// - /// Predicts the audio sample rate that will be in the output stream + /// Predicts the audio sample rate that will be in the output stream. /// public int? TargetAudioBitDepth { @@ -532,7 +532,7 @@ namespace MediaBrowser.Model.Dlna } /// - /// Predicts the audio sample rate that will be in the output stream + /// Predicts the audio sample rate that will be in the output stream. /// public int? TargetVideoBitDepth { @@ -579,7 +579,7 @@ namespace MediaBrowser.Model.Dlna } /// - /// Predicts the audio sample rate that will be in the output stream + /// Predicts the audio sample rate that will be in the output stream. /// public float? TargetFramerate { @@ -593,7 +593,7 @@ namespace MediaBrowser.Model.Dlna } /// - /// Predicts the audio sample rate that will be in the output stream + /// Predicts the audio sample rate that will be in the output stream. /// public double? TargetVideoLevel { @@ -680,7 +680,7 @@ namespace MediaBrowser.Model.Dlna } /// - /// Predicts the audio sample rate that will be in the output stream + /// Predicts the audio sample rate that will be in the output stream. /// public int? TargetPacketLength { @@ -694,7 +694,7 @@ namespace MediaBrowser.Model.Dlna } /// - /// Predicts the audio sample rate that will be in the output stream + /// Predicts the audio sample rate that will be in the output stream. /// public string TargetVideoProfile { @@ -732,7 +732,7 @@ namespace MediaBrowser.Model.Dlna } /// - /// Predicts the audio bitrate that will be in the output stream + /// Predicts the audio bitrate that will be in the output stream. /// public int? TargetAudioBitrate { @@ -746,7 +746,7 @@ namespace MediaBrowser.Model.Dlna } /// - /// Predicts the audio channels that will be in the output stream + /// Predicts the audio channels that will be in the output stream. /// public int? TargetAudioChannels { @@ -787,7 +787,7 @@ namespace MediaBrowser.Model.Dlna } /// - /// Predicts the audio codec that will be in the output stream + /// Predicts the audio codec that will be in the output stream. /// public string[] TargetAudioCodec { @@ -840,7 +840,7 @@ namespace MediaBrowser.Model.Dlna } /// - /// Predicts the audio channels that will be in the output stream + /// Predicts the audio channels that will be in the output stream. /// public long? TargetSize { diff --git a/MediaBrowser.Model/Dlna/SubtitleDeliveryMethod.cs b/MediaBrowser.Model/Dlna/SubtitleDeliveryMethod.cs index 7b0204590..e7fe8d6af 100644 --- a/MediaBrowser.Model/Dlna/SubtitleDeliveryMethod.cs +++ b/MediaBrowser.Model/Dlna/SubtitleDeliveryMethod.cs @@ -5,22 +5,22 @@ namespace MediaBrowser.Model.Dlna public enum SubtitleDeliveryMethod { /// - /// The encode + /// The encode. /// Encode = 0, /// - /// The embed + /// The embed. /// Embed = 1, /// - /// The external + /// The external. /// External = 2, /// - /// The HLS + /// The HLS. /// Hls = 3 } diff --git a/MediaBrowser.Model/Dto/BaseItemDto.cs b/MediaBrowser.Model/Dto/BaseItemDto.cs index c7f8f0584..cad18b5c8 100644 --- a/MediaBrowser.Model/Dto/BaseItemDto.cs +++ b/MediaBrowser.Model/Dto/BaseItemDto.cs @@ -308,7 +308,7 @@ namespace MediaBrowser.Model.Dto public int? LocalTrailerCount { get; set; } /// - /// User data for this item based on the user it's being requested for + /// User data for this item based on the user it's being requested for. /// /// The user data. public UserItemDataDto UserData { get; set; } diff --git a/MediaBrowser.Model/Dto/ImageOptions.cs b/MediaBrowser.Model/Dto/ImageOptions.cs index 158e622a8..3f4405f1e 100644 --- a/MediaBrowser.Model/Dto/ImageOptions.cs +++ b/MediaBrowser.Model/Dto/ImageOptions.cs @@ -61,7 +61,7 @@ namespace MediaBrowser.Model.Dto /// /// Gets or sets the image tag. - /// If set this will result in strong, unconditional response caching + /// If set this will result in strong, unconditional response caching. /// /// The hash. public string Tag { get; set; } diff --git a/MediaBrowser.Model/Dto/MediaSourceInfo.cs b/MediaBrowser.Model/Dto/MediaSourceInfo.cs index 74c2cb4f4..e78e60d52 100644 --- a/MediaBrowser.Model/Dto/MediaSourceInfo.cs +++ b/MediaBrowser.Model/Dto/MediaSourceInfo.cs @@ -28,7 +28,7 @@ namespace MediaBrowser.Model.Dto public string Name { get; set; } /// - /// Differentiate internet url vs local network + /// Differentiate internet url vs local network. /// public bool IsRemote { get; set; } diff --git a/MediaBrowser.Model/Entities/DisplayPreferences.cs b/MediaBrowser.Model/Entities/DisplayPreferences.cs index 0e5db01dd..7e5c5be3b 100644 --- a/MediaBrowser.Model/Entities/DisplayPreferences.cs +++ b/MediaBrowser.Model/Entities/DisplayPreferences.cs @@ -104,7 +104,7 @@ namespace MediaBrowser.Model.Entities public bool ShowSidebar { get; set; } /// - /// Gets or sets the client + /// Gets or sets the client. /// public string Client { get; set; } } diff --git a/MediaBrowser.Model/Entities/MediaStream.cs b/MediaBrowser.Model/Entities/MediaStream.cs index 3db72f78a..33c14ec1b 100644 --- a/MediaBrowser.Model/Entities/MediaStream.cs +++ b/MediaBrowser.Model/Entities/MediaStream.cs @@ -13,7 +13,7 @@ using MediaBrowser.Model.MediaInfo; namespace MediaBrowser.Model.Entities { /// - /// Class MediaStream + /// Class MediaStream. /// public class MediaStream { diff --git a/MediaBrowser.Model/Entities/MetadataProvider.cs b/MediaBrowser.Model/Entities/MetadataProvider.cs index bcc2b48e7..7fecf67b8 100644 --- a/MediaBrowser.Model/Entities/MetadataProvider.cs +++ b/MediaBrowser.Model/Entities/MetadataProvider.cs @@ -3,28 +3,28 @@ namespace MediaBrowser.Model.Entities { /// - /// Enum MetadataProviders + /// Enum MetadataProviders. /// public enum MetadataProvider { /// - /// The imdb + /// The imdb. /// Imdb = 2, /// - /// The TMDB + /// The TMDB. /// Tmdb = 3, /// - /// The TVDB + /// The TVDB. /// Tvdb = 4, /// - /// The tvcom + /// The tvcom. /// Tvcom = 5, /// - /// Tmdb Collection Id + /// Tmdb Collection Id. /// TmdbCollection = 7, MusicBrainzAlbum = 8, diff --git a/MediaBrowser.Model/Entities/VirtualFolderInfo.cs b/MediaBrowser.Model/Entities/VirtualFolderInfo.cs index 2de02e403..662fa1f78 100644 --- a/MediaBrowser.Model/Entities/VirtualFolderInfo.cs +++ b/MediaBrowser.Model/Entities/VirtualFolderInfo.cs @@ -7,7 +7,7 @@ using MediaBrowser.Model.Configuration; namespace MediaBrowser.Model.Entities { /// - /// Used to hold information about a user's list of configured virtual folders + /// Used to hold information about a user's list of configured virtual folders. /// public class VirtualFolderInfo { diff --git a/MediaBrowser.Model/IO/IZipClient.cs b/MediaBrowser.Model/IO/IZipClient.cs index 83e8a018d..2daa54f22 100644 --- a/MediaBrowser.Model/IO/IZipClient.cs +++ b/MediaBrowser.Model/IO/IZipClient.cs @@ -5,7 +5,7 @@ using System.IO; namespace MediaBrowser.Model.IO { /// - /// Interface IZipClient + /// Interface IZipClient. /// public interface IZipClient { diff --git a/MediaBrowser.Model/LiveTv/ChannelType.cs b/MediaBrowser.Model/LiveTv/ChannelType.cs index b6974cb08..f4c55cb6d 100644 --- a/MediaBrowser.Model/LiveTv/ChannelType.cs +++ b/MediaBrowser.Model/LiveTv/ChannelType.cs @@ -6,7 +6,7 @@ namespace MediaBrowser.Model.LiveTv public enum ChannelType { /// - /// The TV + /// The TV. /// TV, diff --git a/MediaBrowser.Model/LiveTv/LiveTvChannelQuery.cs b/MediaBrowser.Model/LiveTv/LiveTvChannelQuery.cs index d1a94d8b3..3c5c39a16 100644 --- a/MediaBrowser.Model/LiveTv/LiveTvChannelQuery.cs +++ b/MediaBrowser.Model/LiveTv/LiveTvChannelQuery.cs @@ -54,7 +54,7 @@ namespace MediaBrowser.Model.LiveTv public int? StartIndex { get; set; } /// - /// The maximum number of items to return + /// The maximum number of items to return. /// /// The limit. public int? Limit { get; set; } @@ -67,13 +67,13 @@ namespace MediaBrowser.Model.LiveTv public bool EnableUserData { get; set; } /// - /// Used to specific whether to return news or not + /// Used to specific whether to return news or not. /// /// If set to null, all programs will be returned public bool? IsNews { get; set; } /// - /// Used to specific whether to return movies or not + /// Used to specific whether to return movies or not. /// /// If set to null, all programs will be returned public bool? IsMovie { get; set; } @@ -93,7 +93,7 @@ namespace MediaBrowser.Model.LiveTv public string[] SortBy { get; set; } /// - /// The sort order to return results with + /// The sort order to return results with. /// /// The sort order. public SortOrder? SortOrder { get; set; } diff --git a/MediaBrowser.Model/LiveTv/RecordingQuery.cs b/MediaBrowser.Model/LiveTv/RecordingQuery.cs index 264982930..de50adcec 100644 --- a/MediaBrowser.Model/LiveTv/RecordingQuery.cs +++ b/MediaBrowser.Model/LiveTv/RecordingQuery.cs @@ -37,7 +37,7 @@ namespace MediaBrowser.Model.LiveTv public int? StartIndex { get; set; } /// - /// The maximum number of items to return + /// The maximum number of items to return. /// /// The limit. public int? Limit { get; set; } @@ -61,7 +61,7 @@ namespace MediaBrowser.Model.LiveTv public string SeriesTimerId { get; set; } /// - /// Fields to return within the items, in addition to basic information + /// Fields to return within the items, in addition to basic information. /// /// The fields. public ItemFields[] Fields { get; set; } diff --git a/MediaBrowser.Model/LiveTv/SeriesTimerQuery.cs b/MediaBrowser.Model/LiveTv/SeriesTimerQuery.cs index bda46dd2b..b899a464b 100644 --- a/MediaBrowser.Model/LiveTv/SeriesTimerQuery.cs +++ b/MediaBrowser.Model/LiveTv/SeriesTimerQuery.cs @@ -7,7 +7,7 @@ namespace MediaBrowser.Model.LiveTv public class SeriesTimerQuery { /// - /// Gets or sets the sort by - SortName, Priority + /// Gets or sets the sort by - SortName, Priority. /// /// The sort by. public string? SortBy { get; set; } diff --git a/MediaBrowser.Model/Net/NetworkShare.cs b/MediaBrowser.Model/Net/NetworkShare.cs index a40cf73e4..6344cbe21 100644 --- a/MediaBrowser.Model/Net/NetworkShare.cs +++ b/MediaBrowser.Model/Net/NetworkShare.cs @@ -6,27 +6,27 @@ namespace MediaBrowser.Model.Net public class NetworkShare { /// - /// The name of the computer that this share belongs to + /// The name of the computer that this share belongs to. /// public string Server { get; set; } /// - /// Share name + /// Share name. /// public string Name { get; set; } /// - /// Local path + /// Local path. /// public string Path { get; set; } /// - /// Share type + /// Share type. /// public NetworkShareType ShareType { get; set; } /// - /// Comment + /// Comment. /// public string Remark { get; set; } } diff --git a/MediaBrowser.Model/Notifications/NotificationOption.cs b/MediaBrowser.Model/Notifications/NotificationOption.cs index 144949a3b..ea363d9b1 100644 --- a/MediaBrowser.Model/Notifications/NotificationOption.cs +++ b/MediaBrowser.Model/Notifications/NotificationOption.cs @@ -18,7 +18,7 @@ namespace MediaBrowser.Model.Notifications public string Type { get; set; } /// - /// User Ids to not monitor (it's opt out) + /// User Ids to not monitor (it's opt out). /// public string[] DisabledMonitorUsers { get; set; } diff --git a/MediaBrowser.Model/Querying/ItemFields.cs b/MediaBrowser.Model/Querying/ItemFields.cs index d7cc5ebbe..731d22aaf 100644 --- a/MediaBrowser.Model/Querying/ItemFields.cs +++ b/MediaBrowser.Model/Querying/ItemFields.cs @@ -8,198 +8,198 @@ namespace MediaBrowser.Model.Querying public enum ItemFields { /// - /// The air time + /// The air time. /// AirTime, /// - /// The can delete + /// The can delete. /// CanDelete, /// - /// The can download + /// The can download. /// CanDownload, /// - /// The channel information + /// The channel information. /// ChannelInfo, /// - /// The chapters + /// The chapters. /// Chapters, ChildCount, /// - /// The cumulative run time ticks + /// The cumulative run time ticks. /// CumulativeRunTimeTicks, /// - /// The custom rating + /// The custom rating. /// CustomRating, /// - /// The date created of the item + /// The date created of the item. /// DateCreated, /// - /// The date last media added + /// The date last media added. /// DateLastMediaAdded, /// - /// Item display preferences + /// Item display preferences. /// DisplayPreferencesId, /// - /// The etag + /// The etag. /// Etag, /// - /// The external urls + /// The external urls. /// ExternalUrls, /// - /// Genres + /// Genres. /// Genres, /// - /// The home page URL + /// The home page URL. /// HomePageUrl, /// - /// The item counts + /// The item counts. /// ItemCounts, /// - /// The media source count + /// The media source count. /// MediaSourceCount, /// - /// The media versions + /// The media versions. /// MediaSources, OriginalTitle, /// - /// The item overview + /// The item overview. /// Overview, /// - /// The id of the item's parent + /// The id of the item's parent. /// ParentId, /// - /// The physical path of the item + /// The physical path of the item. /// Path, /// - /// The list of people for the item + /// The list of people for the item. /// People, PlayAccess, /// - /// The production locations + /// The production locations. /// ProductionLocations, /// - /// Imdb, tmdb, etc + /// Imdb, tmdb, etc. /// ProviderIds, /// - /// The aspect ratio of the primary image + /// The aspect ratio of the primary image. /// PrimaryImageAspectRatio, RecursiveItemCount, /// - /// The settings + /// The settings. /// Settings, /// - /// The screenshot image tags + /// The screenshot image tags. /// ScreenshotImageTags, SeriesPrimaryImage, /// - /// The series studio + /// The series studio. /// SeriesStudio, /// - /// The sort name of the item + /// The sort name of the item. /// SortName, /// - /// The special episode numbers + /// The special episode numbers. /// SpecialEpisodeNumbers, /// - /// The studios of the item + /// The studios of the item. /// Studios, BasicSyncInfo, /// - /// The synchronize information + /// The synchronize information. /// SyncInfo, /// - /// The taglines of the item + /// The taglines of the item. /// Taglines, /// - /// The tags + /// The tags. /// Tags, /// - /// The trailer url of the item + /// The trailer url of the item. /// RemoteTrailers, /// - /// The media streams + /// The media streams. /// MediaStreams, /// - /// The season user data + /// The season user data. /// SeasonUserData, /// - /// The service name + /// The service name. /// ServiceName, ThemeSongIds, diff --git a/MediaBrowser.Model/Querying/ItemSortBy.cs b/MediaBrowser.Model/Querying/ItemSortBy.cs index edf71c1a7..0b846bb96 100644 --- a/MediaBrowser.Model/Querying/ItemSortBy.cs +++ b/MediaBrowser.Model/Querying/ItemSortBy.cs @@ -3,7 +3,7 @@ namespace MediaBrowser.Model.Querying { /// - /// These represent sort orders that are known by the core + /// These represent sort orders that are known by the core. /// public static class ItemSortBy { diff --git a/MediaBrowser.Model/Querying/NextUpQuery.cs b/MediaBrowser.Model/Querying/NextUpQuery.cs index 0df86cb22..ee13ffc16 100644 --- a/MediaBrowser.Model/Querying/NextUpQuery.cs +++ b/MediaBrowser.Model/Querying/NextUpQuery.cs @@ -33,13 +33,13 @@ namespace MediaBrowser.Model.Querying public int? StartIndex { get; set; } /// - /// The maximum number of items to return + /// The maximum number of items to return. /// /// The limit. public int? Limit { get; set; } /// - /// Fields to return within the items, in addition to basic information + /// Fields to return within the items, in addition to basic information. /// /// The fields. public ItemFields[] Fields { get; set; } diff --git a/MediaBrowser.Model/Querying/QueryResult.cs b/MediaBrowser.Model/Querying/QueryResult.cs index 42586243d..490f48b84 100644 --- a/MediaBrowser.Model/Querying/QueryResult.cs +++ b/MediaBrowser.Model/Querying/QueryResult.cs @@ -15,7 +15,7 @@ namespace MediaBrowser.Model.Querying public IReadOnlyList Items { get; set; } /// - /// The total number of records available + /// The total number of records available. /// /// The total record count. public int TotalRecordCount { get; set; } diff --git a/MediaBrowser.Model/Querying/UpcomingEpisodesQuery.cs b/MediaBrowser.Model/Querying/UpcomingEpisodesQuery.cs index ed1aa7ac6..12d537492 100644 --- a/MediaBrowser.Model/Querying/UpcomingEpisodesQuery.cs +++ b/MediaBrowser.Model/Querying/UpcomingEpisodesQuery.cs @@ -26,13 +26,13 @@ namespace MediaBrowser.Model.Querying public int? StartIndex { get; set; } /// - /// The maximum number of items to return + /// The maximum number of items to return. /// /// The limit. public int? Limit { get; set; } /// - /// Fields to return within the items, in addition to basic information + /// Fields to return within the items, in addition to basic information. /// /// The fields. public ItemFields[] Fields { get; set; } diff --git a/MediaBrowser.Model/Search/SearchQuery.cs b/MediaBrowser.Model/Search/SearchQuery.cs index 4470f1ad9..c58b13c35 100644 --- a/MediaBrowser.Model/Search/SearchQuery.cs +++ b/MediaBrowser.Model/Search/SearchQuery.cs @@ -8,7 +8,7 @@ namespace MediaBrowser.Model.Search public class SearchQuery { /// - /// The user to localize search results for + /// The user to localize search results for. /// /// The user id. public Guid UserId { get; set; } @@ -26,7 +26,7 @@ namespace MediaBrowser.Model.Search public int? StartIndex { get; set; } /// - /// The maximum number of items to return + /// The maximum number of items to return. /// /// The limit. public int? Limit { get; set; } diff --git a/MediaBrowser.Model/Services/ApiMemberAttribute.cs b/MediaBrowser.Model/Services/ApiMemberAttribute.cs index 7c23eee44..63f3ecd55 100644 --- a/MediaBrowser.Model/Services/ApiMemberAttribute.cs +++ b/MediaBrowser.Model/Services/ApiMemberAttribute.cs @@ -58,7 +58,7 @@ namespace MediaBrowser.Model.Services public string Route { get; set; } /// - /// Whether to exclude this property from being included in the ModelSchema + /// Whether to exclude this property from being included in the ModelSchema. /// public bool ExcludeInSchema { get; set; } } diff --git a/MediaBrowser.Model/Services/IRequest.cs b/MediaBrowser.Model/Services/IRequest.cs index f413f1e17..d8eddf27c 100644 --- a/MediaBrowser.Model/Services/IRequest.cs +++ b/MediaBrowser.Model/Services/IRequest.cs @@ -23,7 +23,7 @@ namespace MediaBrowser.Model.Services string Verb { get; } /// - /// The request ContentType + /// The request ContentType. /// string ContentType { get; } @@ -32,7 +32,7 @@ namespace MediaBrowser.Model.Services string UserAgent { get; } /// - /// The expected Response ContentType for this request + /// The expected Response ContentType for this request. /// string ResponseContentType { get; set; } @@ -55,7 +55,7 @@ namespace MediaBrowser.Model.Services string RemoteIp { get; } /// - /// The value of the Authorization Header used to send the Api Key, null if not available + /// The value of the Authorization Header used to send the Api Key, null if not available. /// string Authorization { get; } @@ -68,7 +68,7 @@ namespace MediaBrowser.Model.Services long ContentLength { get; } /// - /// The value of the Referrer, null if not available + /// The value of the Referrer, null if not available. /// Uri UrlReferrer { get; } } diff --git a/MediaBrowser.Model/Services/IRequiresRequestStream.cs b/MediaBrowser.Model/Services/IRequiresRequestStream.cs index 622626edc..3e5f2da42 100644 --- a/MediaBrowser.Model/Services/IRequiresRequestStream.cs +++ b/MediaBrowser.Model/Services/IRequiresRequestStream.cs @@ -7,7 +7,7 @@ namespace MediaBrowser.Model.Services public interface IRequiresRequestStream { /// - /// The raw Http Request Input Stream + /// The raw Http Request Input Stream. /// Stream RequestStream { get; set; } } diff --git a/MediaBrowser.Model/Session/PlayRequest.cs b/MediaBrowser.Model/Session/PlayRequest.cs index 62b68b49e..66775e735 100644 --- a/MediaBrowser.Model/Session/PlayRequest.cs +++ b/MediaBrowser.Model/Session/PlayRequest.cs @@ -7,7 +7,7 @@ using MediaBrowser.Model.Services; namespace MediaBrowser.Model.Session { /// - /// Class PlayRequest + /// Class PlayRequest. /// public class PlayRequest { @@ -19,7 +19,7 @@ namespace MediaBrowser.Model.Session public Guid[] ItemIds { get; set; } /// - /// Gets or sets the start position ticks that the first item should be played at + /// Gets or sets the start position ticks that the first item should be played at. /// /// The start position ticks. [ApiMember(Name = "StartPositionTicks", Description = "The starting position of the first item.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")] diff --git a/MediaBrowser.Model/Sync/SyncCategory.cs b/MediaBrowser.Model/Sync/SyncCategory.cs index 215ac301e..80ad5f56e 100644 --- a/MediaBrowser.Model/Sync/SyncCategory.cs +++ b/MediaBrowser.Model/Sync/SyncCategory.cs @@ -5,15 +5,15 @@ namespace MediaBrowser.Model.Sync public enum SyncCategory { /// - /// The latest + /// The latest. /// Latest = 0, /// - /// The next up + /// The next up. /// NextUp = 1, /// - /// The resume + /// The resume. /// Resume = 2 } diff --git a/MediaBrowser.Model/System/SystemInfo.cs b/MediaBrowser.Model/System/SystemInfo.cs index a67c38c3a..18ca74ee3 100644 --- a/MediaBrowser.Model/System/SystemInfo.cs +++ b/MediaBrowser.Model/System/SystemInfo.cs @@ -23,7 +23,7 @@ namespace MediaBrowser.Model.System }; /// - /// Class SystemInfo + /// Class SystemInfo. /// public class SystemInfo : PublicSystemInfo { diff --git a/MediaBrowser.Model/Tasks/IScheduledTaskWorker.cs b/MediaBrowser.Model/Tasks/IScheduledTaskWorker.cs index c79d7fe75..b08acba2c 100644 --- a/MediaBrowser.Model/Tasks/IScheduledTaskWorker.cs +++ b/MediaBrowser.Model/Tasks/IScheduledTaskWorker.cs @@ -57,7 +57,7 @@ namespace MediaBrowser.Model.Tasks double? CurrentProgress { get; } /// - /// Gets the triggers that define when the task will run + /// Gets the triggers that define when the task will run. /// /// The triggers. /// value diff --git a/MediaBrowser.Model/Tasks/ITaskManager.cs b/MediaBrowser.Model/Tasks/ITaskManager.cs index 4a7f579ec..363773ff7 100644 --- a/MediaBrowser.Model/Tasks/ITaskManager.cs +++ b/MediaBrowser.Model/Tasks/ITaskManager.cs @@ -10,7 +10,7 @@ namespace MediaBrowser.Model.Tasks public interface ITaskManager : IDisposable { /// - /// Gets the list of Scheduled Tasks + /// Gets the list of Scheduled Tasks. /// /// The scheduled tasks. IScheduledTaskWorker[] ScheduledTasks { get; } diff --git a/MediaBrowser.Providers/Manager/ImageSaver.cs b/MediaBrowser.Providers/Manager/ImageSaver.cs index 3c94f6215..b16462936 100644 --- a/MediaBrowser.Providers/Manager/ImageSaver.cs +++ b/MediaBrowser.Providers/Manager/ImageSaver.cs @@ -24,19 +24,19 @@ using Season = MediaBrowser.Controller.Entities.TV.Season; namespace MediaBrowser.Providers.Manager { /// - /// Class ImageSaver + /// Class ImageSaver. /// public class ImageSaver { private static readonly CultureInfo UsCulture = new CultureInfo("en-US"); /// - /// The _config + /// The _config. /// private readonly IServerConfigurationManager _config; /// - /// The _directory watchers + /// The _directory watchers. /// private readonly ILibraryMonitor _libraryMonitor; private readonly IFileSystem _fileSystem; diff --git a/MediaBrowser.Providers/Manager/ItemImageProvider.cs b/MediaBrowser.Providers/Manager/ItemImageProvider.cs index 7901503d3..1091c3326 100644 --- a/MediaBrowser.Providers/Manager/ItemImageProvider.cs +++ b/MediaBrowser.Providers/Manager/ItemImageProvider.cs @@ -168,7 +168,7 @@ namespace MediaBrowser.Providers.Manager } /// - /// Image types that are only one per item + /// Image types that are only one per item. /// private readonly ImageType[] _singularImages = { @@ -189,7 +189,7 @@ namespace MediaBrowser.Providers.Manager } /// - /// Determines if an item already contains the given images + /// Determines if an item already contains the given images. /// /// The item. /// The images. diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs index 5853c7714..989a4b5d1 100644 --- a/MediaBrowser.Providers/Manager/ProviderManager.cs +++ b/MediaBrowser.Providers/Manager/ProviderManager.cs @@ -38,7 +38,7 @@ using Series = MediaBrowser.Controller.Entities.TV.Series; namespace MediaBrowser.Providers.Manager { /// - /// Class ProviderManager + /// Class ProviderManager. /// public class ProviderManager : IProviderManager, IDisposable { diff --git a/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs b/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs index ba87e0570..8f3df2760 100644 --- a/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs +++ b/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs @@ -17,7 +17,7 @@ using MediaBrowser.Model.IO; namespace MediaBrowser.Providers.MediaInfo { /// - /// Uses ffmpeg to create video images + /// Uses ffmpeg to create video images. /// public class AudioImageProvider : IDynamicImageProvider { diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs b/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs index 73c89e815..de377086a 100644 --- a/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs +++ b/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs @@ -99,7 +99,7 @@ namespace MediaBrowser.Providers.MediaInfo } /// - /// Fetches data from the tags dictionary + /// Fetches data from the tags dictionary. /// /// The audio. /// The data. diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs index ccbe27c1f..29e6d7854 100644 --- a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs +++ b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs @@ -342,7 +342,7 @@ namespace MediaBrowser.Providers.MediaInfo } /// - /// Gets information about the longest playlist on a bdrom + /// Gets information about the longest playlist on a bdrom. /// /// The path. /// VideoStream. diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Models/Search/MovieResult.cs b/MediaBrowser.Providers/Plugins/Tmdb/Models/Search/MovieResult.cs index 51c26a61c..c0a880bc9 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/Models/Search/MovieResult.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/Models/Search/MovieResult.cs @@ -53,7 +53,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Models.Search /// The vote_average. public double Vote_Average { get; set; } /// - /// For collection search results + /// For collection search results. /// public string Name { get; set; } /// diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieProvider.cs index faeb48b12..3c0922f39 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieProvider.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieProvider.cs @@ -25,7 +25,7 @@ using Microsoft.Extensions.Logging; namespace MediaBrowser.Providers.Plugins.Tmdb.Movies { /// - /// Class MovieDbProvider + /// Class MovieDbProvider. /// public class TmdbMovieProvider : IRemoteMetadataProvider, IHasOrder { @@ -129,7 +129,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Movies public string Name => TmdbUtils.ProviderName; /// - /// The _TMDB settings task + /// The _TMDB settings task. /// private TmdbSettingsResult _tmdbSettings; diff --git a/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs b/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs index aabad3ada..26259f1aa 100644 --- a/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs +++ b/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs @@ -108,7 +108,7 @@ namespace MediaBrowser.Providers.TV /// /// Returns true if a series has any seasons or episodes without season or episode numbers - /// If this data is missing no virtual items will be added in order to prevent possible duplicates + /// If this data is missing no virtual items will be added in order to prevent possible duplicates. /// private bool HasInvalidContent(IList allItems) { @@ -171,7 +171,7 @@ namespace MediaBrowser.Providers.TV } /// - /// Removes the virtual entry after a corresponding physical version has been added + /// Removes the virtual entry after a corresponding physical version has been added. /// private bool RemoveObsoleteOrMissingEpisodes( IEnumerable allRecursiveChildren, diff --git a/RSSDP/DiscoveredSsdpDevice.cs b/RSSDP/DiscoveredSsdpDevice.cs index 1244ce523..d7561fc93 100644 --- a/RSSDP/DiscoveredSsdpDevice.cs +++ b/RSSDP/DiscoveredSsdpDevice.cs @@ -55,7 +55,7 @@ namespace Rssdp } /// - /// Returns the headers from the SSDP device response message + /// Returns the headers from the SSDP device response message. /// public HttpHeaders ResponseHeaders { get; set; } -- cgit v1.2.3 From 247f9c61e60ef774675cb4d6d1734d2ccdc6ee7a Mon Sep 17 00:00:00 2001 From: telans Date: Tue, 16 Jun 2020 09:43:52 +1200 Subject: fix SA1513/SA1516 --- DvdLib/Ifo/Cell.cs | 1 + DvdLib/Ifo/Chapter.cs | 2 + DvdLib/Ifo/Dvd.cs | 1 + DvdLib/Ifo/ProgramChain.cs | 4 + DvdLib/Ifo/Title.cs | 4 + Emby.Dlna/ContentDirectory/ControlHandler.cs | 1 + Emby.Dlna/Didl/DidlBuilder.cs | 3 + Emby.Dlna/DlnaManager.cs | 3 + Emby.Dlna/Eventing/EventManager.cs | 1 + Emby.Dlna/Eventing/EventSubscription.cs | 3 + Emby.Dlna/Main/DlnaEntryPoint.cs | 2 + Emby.Dlna/PlayTo/Device.cs | 2 + Emby.Dlna/PlayTo/PlayToController.cs | 5 + Emby.Dlna/PlayTo/PlayToManager.cs | 1 + Emby.Dlna/PlayTo/PlaybackStoppedEventArgs.cs | 1 + Emby.Dlna/PlayTo/uBaseObject.cs | 2 + Emby.Dlna/Server/DescriptionXmlBuilder.cs | 5 + Emby.Dlna/Service/BaseControlHandler.cs | 4 + Emby.Dlna/Service/ServiceXmlBuilder.cs | 1 + Emby.Naming/AudioBook/AudioBookFilePathParser.cs | 1 + .../Data/SqliteItemRepository.cs | 115 ++++++++++++++++++++ .../Data/SqliteUserDataRepository.cs | 3 + .../Devices/DeviceManager.cs | 1 + Emby.Server.Implementations/Dto/DtoService.cs | 11 ++ .../HttpServer/HttpListenerHost.cs | 1 + .../HttpServer/RangeRequestWriter.cs | 7 ++ .../HttpServer/Security/AuthService.cs | 1 + .../HttpServer/Security/AuthorizationContext.cs | 2 + .../IO/ManagedFileSystem.cs | 2 + .../Library/ExclusiveLiveStream.cs | 2 + .../Library/LibraryManager.cs | 2 + .../Library/MediaSourceManager.cs | 5 + .../Library/Resolvers/SpecialFolderResolver.cs | 2 + .../Library/Resolvers/TV/EpisodeResolver.cs | 1 + .../Library/SearchEngine.cs | 1 + .../LiveTv/Listings/SchedulesDirect.cs | 118 +++++++++++++++++++++ .../LiveTv/Listings/XmlTvListingsProvider.cs | 1 + .../LiveTv/LiveTvManager.cs | 12 +++ .../LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs | 19 ++++ .../LiveTv/TunerHosts/LiveStream.cs | 3 + .../Playlists/PlaylistManager.cs | 1 + .../ScheduledTasks/ScheduledTaskWorker.cs | 5 + .../Services/ServiceMethod.cs | 1 + .../Services/ServicePath.cs | 3 + .../Services/StringMapTypeDeserializer.cs | 2 + .../Services/SwaggerService.cs | 34 ++++++ .../Session/SessionWebSocketListener.cs | 1 + .../Sorting/PremiereDateComparer.cs | 1 + Emby.Server.Implementations/TV/TVSeriesManager.cs | 1 + Jellyfin.Data/Entities/Artwork.cs | 3 + Jellyfin.Data/Entities/BookMetadata.cs | 1 + Jellyfin.Data/Entities/Chapter.cs | 5 + Jellyfin.Data/Entities/Collection.cs | 2 + Jellyfin.Data/Entities/CollectionItem.cs | 1 + Jellyfin.Data/Entities/Company.cs | 1 + Jellyfin.Data/Entities/CompanyMetadata.cs | 4 + Jellyfin.Data/Entities/Episode.cs | 1 + Jellyfin.Data/Entities/EpisodeMetadata.cs | 3 + Jellyfin.Data/Entities/Genre.cs | 2 + Jellyfin.Data/Entities/Library.cs | 2 + Jellyfin.Data/Entities/LibraryItem.cs | 3 + Jellyfin.Data/Entities/LibraryRoot.cs | 3 + Jellyfin.Data/Entities/MediaFile.cs | 3 + Jellyfin.Data/Entities/MediaFileStream.cs | 2 + Jellyfin.Data/Entities/Metadata.cs | 8 ++ Jellyfin.Data/Entities/MetadataProvider.cs | 2 + Jellyfin.Data/Entities/MetadataProviderId.cs | 2 + Jellyfin.Data/Entities/MovieMetadata.cs | 4 + Jellyfin.Data/Entities/MusicAlbumMetadata.cs | 3 + Jellyfin.Data/Entities/Person.cs | 6 ++ Jellyfin.Data/Entities/PersonRole.cs | 3 + Jellyfin.Data/Entities/Rating.cs | 3 + Jellyfin.Data/Entities/RatingSource.cs | 4 + Jellyfin.Data/Entities/Release.cs | 2 + Jellyfin.Data/Entities/Season.cs | 1 + Jellyfin.Data/Entities/SeasonMetadata.cs | 1 + Jellyfin.Data/Entities/Series.cs | 3 + Jellyfin.Data/Entities/SeriesMetadata.cs | 4 + Jellyfin.Data/Entities/Track.cs | 1 + Jellyfin.Server.Implementations/JellyfinDb.cs | 39 +++++++ MediaBrowser.Api/EnvironmentService.cs | 1 + MediaBrowser.Api/FilterService.cs | 6 ++ MediaBrowser.Api/IHasDtoOptions.cs | 1 + MediaBrowser.Api/Library/LibraryService.cs | 11 ++ MediaBrowser.Api/LiveTv/LiveTvService.cs | 15 +++ MediaBrowser.Api/Playback/BaseStreamingService.cs | 4 + MediaBrowser.Api/Playback/Hls/BaseHlsService.cs | 1 + MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs | 2 + MediaBrowser.Api/Playback/MediaInfoService.cs | 2 + .../Progressive/BaseProgressiveStreamingService.cs | 6 ++ .../Progressive/ProgressiveStreamWriter.cs | 2 + MediaBrowser.Api/Playback/StreamRequest.cs | 4 + MediaBrowser.Api/Playback/UniversalAudioService.cs | 20 ++++ MediaBrowser.Api/PluginService.cs | 9 ++ MediaBrowser.Api/SimilarItemsHelper.cs | 4 + MediaBrowser.Api/Subtitles/SubtitleService.cs | 2 + MediaBrowser.Api/SuggestionsService.cs | 5 + MediaBrowser.Api/TranscodingJob.cs | 8 ++ MediaBrowser.Api/TvShowsService.cs | 1 + .../UserLibrary/BaseItemsByNameService.cs | 1 + MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs | 3 + MediaBrowser.Api/UserLibrary/UserViewsService.cs | 3 + .../Authentication/IAuthenticationProvider.cs | 3 + .../Authentication/IPasswordResetProvider.cs | 3 + .../Channels/ChannelItemInfo.cs | 11 ++ .../Collections/CollectionCreationOptions.cs | 1 + MediaBrowser.Controller/Drawing/ImageHelper.cs | 1 + .../Drawing/ImageProcessingOptions.cs | 7 ++ MediaBrowser.Controller/Dto/DtoOptions.cs | 6 ++ .../Entities/AggregateFolder.cs | 1 + MediaBrowser.Controller/Entities/Audio/Audio.cs | 2 + .../Entities/Audio/MusicAlbum.cs | 1 + .../Entities/Audio/MusicArtist.cs | 1 + .../Entities/Audio/MusicGenre.cs | 2 + MediaBrowser.Controller/Entities/AudioBook.cs | 2 + MediaBrowser.Controller/Entities/BaseItem.cs | 16 +++ .../Entities/CollectionFolder.cs | 3 + MediaBrowser.Controller/Entities/Folder.cs | 21 ++++ MediaBrowser.Controller/Entities/Genre.cs | 2 + .../Entities/IHasMediaSources.cs | 2 + .../Entities/IHasProgramAttributes.cs | 8 ++ MediaBrowser.Controller/Entities/IHasSeries.cs | 3 + .../Entities/InternalItemsQuery.cs | 103 ++++++++++++++++++ MediaBrowser.Controller/Entities/LinkedChild.cs | 3 + MediaBrowser.Controller/Entities/PeopleHelper.cs | 1 + MediaBrowser.Controller/Entities/Person.cs | 2 + MediaBrowser.Controller/Entities/Photo.cs | 11 ++ MediaBrowser.Controller/Entities/Share.cs | 1 + MediaBrowser.Controller/Entities/Studio.cs | 2 + MediaBrowser.Controller/Entities/TV/Episode.cs | 6 ++ MediaBrowser.Controller/Entities/TV/Season.cs | 1 + MediaBrowser.Controller/Entities/TV/Series.cs | 2 + MediaBrowser.Controller/Entities/UserItemData.cs | 1 + .../Entities/UserViewBuilder.cs | 2 + MediaBrowser.Controller/Entities/Video.cs | 10 ++ MediaBrowser.Controller/Entities/Year.cs | 1 + MediaBrowser.Controller/IO/FileData.cs | 3 + MediaBrowser.Controller/Library/DeleteOptions.cs | 1 + MediaBrowser.Controller/Library/ILiveStream.cs | 5 + MediaBrowser.Controller/Library/ItemResolveArgs.cs | 2 + .../Library/PlaybackProgressEventArgs.cs | 9 ++ MediaBrowser.Controller/Library/Profiler.cs | 1 + MediaBrowser.Controller/Library/TVUtils.cs | 1 + MediaBrowser.Controller/LiveTv/ChannelInfo.cs | 3 + MediaBrowser.Controller/LiveTv/ILiveTvManager.cs | 3 + MediaBrowser.Controller/LiveTv/ITunerHost.cs | 1 + .../LiveTv/LiveTvConflictException.cs | 1 + MediaBrowser.Controller/LiveTv/ProgramInfo.cs | 1 + MediaBrowser.Controller/LiveTv/SeriesTimerInfo.cs | 1 + MediaBrowser.Controller/LiveTv/TimerInfo.cs | 7 ++ .../LiveTv/TunerChannelMapping.cs | 3 + .../MediaEncoding/EncodingHelper.cs | 28 +++++ .../MediaEncoding/EncodingJobInfo.cs | 8 ++ .../MediaEncoding/EncodingJobOptions.cs | 10 ++ .../MediaEncoding/MediaInfoRequest.cs | 4 + .../Net/AuthenticatedAttribute.cs | 3 + .../Net/BasePeriodicWebSocketListener.cs | 2 + MediaBrowser.Controller/Net/StaticResultOptions.cs | 5 + .../Providers/ImageRefreshOptions.cs | 2 + .../Providers/MetadataResult.cs | 1 + MediaBrowser.Controller/Resolvers/IItemResolver.cs | 1 + .../Security/AuthenticationInfo.cs | 1 + .../Session/AuthenticationRequest.cs | 8 ++ MediaBrowser.Controller/Session/SessionInfo.cs | 5 + .../Subtitles/SubtitleResponse.cs | 3 + .../Subtitles/SubtitleSearchRequest.cs | 12 +++ MediaBrowser.Controller/Sync/SyncedFileInfo.cs | 1 + MediaBrowser.Controller/SyncPlay/GroupInfo.cs | 1 + .../Images/EpisodeLocalImageProvider.cs | 1 + .../Parsers/BaseItemXmlParser.cs | 48 +++++++++ .../Parsers/BoxSetXmlParser.cs | 2 + .../Parsers/PlaylistXmlParser.cs | 2 + MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs | 7 ++ MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 1 + .../Probing/ProbeResultNormalizer.cs | 13 +++ MediaBrowser.MediaEncoding/Subtitles/AssParser.cs | 4 + MediaBrowser.MediaEncoding/Subtitles/SrtParser.cs | 5 + MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs | 4 + .../Subtitles/SubtitleEncoder.cs | 9 ++ MediaBrowser.Model/Configuration/LibraryOptions.cs | 23 ++++ .../Configuration/UserConfiguration.cs | 4 + .../Configuration/XbmcMetadataOptions.cs | 1 + MediaBrowser.Model/Dlna/AudioOptions.cs | 1 + MediaBrowser.Model/Dlna/DeviceProfile.cs | 21 ++++ .../Dlna/MediaFormatProfileResolver.cs | 13 +++ MediaBrowser.Model/Dlna/StreamBuilder.cs | 21 ++++ MediaBrowser.Model/Dlna/StreamInfo.cs | 20 ++++ MediaBrowser.Model/Dto/BaseItemDto.cs | 25 +++++ MediaBrowser.Model/Dto/MediaSourceInfo.cs | 21 ++++ MediaBrowser.Model/Dto/MetadataEditorInfo.cs | 4 + MediaBrowser.Model/Dto/NameIdPair.cs | 1 + MediaBrowser.Model/Entities/MediaStream.cs | 13 +++ MediaBrowser.Model/Entities/MediaUrl.cs | 1 + MediaBrowser.Model/Entities/VirtualFolderInfo.cs | 1 + MediaBrowser.Model/LiveTv/BaseTimerInfoDto.cs | 1 + MediaBrowser.Model/LiveTv/LiveTvChannelQuery.cs | 2 + MediaBrowser.Model/LiveTv/LiveTvOptions.cs | 34 ++++++ MediaBrowser.Model/LiveTv/RecordingQuery.cs | 9 ++ MediaBrowser.Model/MediaInfo/LiveStreamRequest.cs | 11 ++ MediaBrowser.Model/MediaInfo/MediaInfo.cs | 8 ++ .../MediaInfo/PlaybackInfoRequest.cs | 6 ++ MediaBrowser.Model/Providers/RemoteSubtitleInfo.cs | 10 ++ MediaBrowser.Model/Providers/SubtitleOptions.cs | 6 ++ .../Providers/SubtitleProviderInfo.cs | 1 + MediaBrowser.Model/Querying/QueryFilters.cs | 5 + MediaBrowser.Model/Search/SearchHint.cs | 1 + MediaBrowser.Model/Search/SearchQuery.cs | 7 ++ MediaBrowser.Model/Services/IRequest.cs | 4 + MediaBrowser.Model/Services/IService.cs | 2 + MediaBrowser.Model/Session/ClientCapabilities.cs | 4 + MediaBrowser.Model/Session/PlayRequest.cs | 3 + MediaBrowser.Model/Session/PlaybackProgressInfo.cs | 2 + MediaBrowser.Model/Session/PlaybackStopInfo.cs | 1 + MediaBrowser.Model/Session/TranscodingInfo.cs | 8 ++ MediaBrowser.Model/Sync/SyncJob.cs | 2 + MediaBrowser.Model/Users/UserAction.cs | 6 ++ MediaBrowser.Model/Users/UserPolicy.cs | 20 ++++ MediaBrowser.Providers/Manager/ImageSaver.cs | 5 + .../Manager/ItemImageProvider.cs | 3 + MediaBrowser.Providers/Manager/MetadataService.cs | 7 ++ MediaBrowser.Providers/Manager/ProviderManager.cs | 1 + MediaBrowser.Providers/Manager/ProviderUtils.cs | 1 + .../MediaInfo/AudioImageProvider.cs | 1 + .../MediaInfo/FFProbeVideoInfo.cs | 3 + .../MediaInfo/VideoImageProvider.cs | 2 + .../Movies/MovieMetadataService.cs | 2 + .../Movies/TrailerMetadataService.cs | 2 + .../Playlists/PlaylistItemsProvider.cs | 4 + .../Plugins/AudioDb/AlbumProvider.cs | 37 +++++++ .../Plugins/AudioDb/ArtistProvider.cs | 40 +++++++ .../Plugins/MusicBrainz/AlbumProvider.cs | 13 +++ .../Plugins/MusicBrainz/ArtistProvider.cs | 6 ++ .../Plugins/Omdb/OmdbItemProvider.cs | 22 ++++ .../Tmdb/Models/Collections/CollectionImages.cs | 1 + .../Tmdb/Models/Collections/CollectionResult.cs | 6 ++ .../Plugins/Tmdb/Models/Collections/Part.cs | 4 + .../Plugins/Tmdb/Models/General/Backdrop.cs | 6 ++ .../Plugins/Tmdb/Models/General/Crew.cs | 5 + .../Plugins/Tmdb/Models/General/ExternalIds.cs | 4 + .../Plugins/Tmdb/Models/General/Genre.cs | 1 + .../Plugins/Tmdb/Models/General/Images.cs | 1 + .../Plugins/Tmdb/Models/General/Keyword.cs | 1 + .../Plugins/Tmdb/Models/General/Poster.cs | 6 ++ .../Plugins/Tmdb/Models/General/Profile.cs | 4 + .../Plugins/Tmdb/Models/General/Still.cs | 7 ++ .../Plugins/Tmdb/Models/General/Video.cs | 7 ++ .../Tmdb/Models/Movies/BelongsToCollection.cs | 3 + .../Plugins/Tmdb/Models/Movies/Cast.cs | 5 + .../Plugins/Tmdb/Models/Movies/Casts.cs | 1 + .../Plugins/Tmdb/Models/Movies/Country.cs | 2 + .../Plugins/Tmdb/Models/Movies/MovieResult.cs | 29 +++++ .../Tmdb/Models/Movies/ProductionCompany.cs | 1 + .../Tmdb/Models/Movies/ProductionCountry.cs | 1 + .../Plugins/Tmdb/Models/Movies/SpokenLanguage.cs | 1 + .../Plugins/Tmdb/Models/Movies/Youtube.cs | 2 + .../Plugins/Tmdb/Models/People/PersonResult.cs | 13 +++ .../Plugins/Tmdb/Models/Search/TvResult.cs | 8 ++ .../Plugins/Tmdb/Models/TV/Cast.cs | 5 + .../Plugins/Tmdb/Models/TV/ContentRating.cs | 1 + .../Plugins/Tmdb/Models/TV/CreatedBy.cs | 2 + .../Plugins/Tmdb/Models/TV/Credits.cs | 1 + .../Plugins/Tmdb/Models/TV/Episode.cs | 7 ++ .../Plugins/Tmdb/Models/TV/EpisodeCredits.cs | 2 + .../Plugins/Tmdb/Models/TV/EpisodeResult.cs | 13 +++ .../Plugins/Tmdb/Models/TV/GuestStar.cs | 5 + .../Plugins/Tmdb/Models/TV/Network.cs | 1 + .../Plugins/Tmdb/Models/TV/Season.cs | 4 + .../Plugins/Tmdb/Models/TV/SeasonResult.cs | 10 ++ .../Plugins/Tmdb/Models/TV/SeriesResult.cs | 29 +++++ .../Plugins/Tmdb/Movies/TmdbImageProvider.cs | 3 + .../Plugins/Tmdb/Movies/TmdbSettings.cs | 3 + .../Plugins/Tmdb/People/TmdbPersonImageProvider.cs | 3 + .../Plugins/Tmdb/People/TmdbPersonProvider.cs | 1 + .../Subtitles/SubtitleManager.cs | 1 + MediaBrowser.Providers/TV/DummySeasonProvider.cs | 1 + MediaBrowser.Providers/TV/SeriesMetadataService.cs | 2 + RSSDP/DiscoveredSsdpDevice.cs | 1 + RSSDP/HttpParserBase.cs | 1 + RSSDP/SsdpCommunicationsServer.cs | 1 + RSSDP/SsdpDevice.cs | 4 + RSSDP/SsdpDeviceLocator.cs | 1 + RSSDP/SsdpDevicePublisher.cs | 3 + RSSDP/SsdpEmbeddedDevice.cs | 1 + 283 files changed, 1810 insertions(+) (limited to 'MediaBrowser.Controller') diff --git a/DvdLib/Ifo/Cell.cs b/DvdLib/Ifo/Cell.cs index 2eab400f7..ea0b50e43 100644 --- a/DvdLib/Ifo/Cell.cs +++ b/DvdLib/Ifo/Cell.cs @@ -7,6 +7,7 @@ namespace DvdLib.Ifo public class Cell { public CellPlaybackInfo PlaybackInfo { get; private set; } + public CellPositionInfo PositionInfo { get; private set; } internal void ParsePlayback(BinaryReader br) diff --git a/DvdLib/Ifo/Chapter.cs b/DvdLib/Ifo/Chapter.cs index 1e69429f8..e786cb553 100644 --- a/DvdLib/Ifo/Chapter.cs +++ b/DvdLib/Ifo/Chapter.cs @@ -5,7 +5,9 @@ namespace DvdLib.Ifo public class Chapter { public ushort ProgramChainNumber { get; private set; } + public ushort ProgramNumber { get; private set; } + public uint ChapterNumber { get; private set; } public Chapter(ushort pgcNum, ushort programNum, uint chapterNum) diff --git a/DvdLib/Ifo/Dvd.cs b/DvdLib/Ifo/Dvd.cs index ca20baa73..1252bab50 100644 --- a/DvdLib/Ifo/Dvd.cs +++ b/DvdLib/Ifo/Dvd.cs @@ -125,6 +125,7 @@ namespace DvdLib.Ifo if (titleNum + 1 < numTitles && vtsFs.Position == (baseAddr + offsets[titleNum + 1])) break; chapNum++; } + while (vtsFs.Position < (baseAddr + endaddr)); } diff --git a/DvdLib/Ifo/ProgramChain.cs b/DvdLib/Ifo/ProgramChain.cs index 4860360af..8048f4bbd 100644 --- a/DvdLib/Ifo/ProgramChain.cs +++ b/DvdLib/Ifo/ProgramChain.cs @@ -22,7 +22,9 @@ namespace DvdLib.Ifo public readonly List Cells; public DvdTime PlaybackTime { get; private set; } + public UserOperation ProhibitedUserOperations { get; private set; } + public byte[] AudioStreamControl { get; private set; } // 8*2 entries public byte[] SubpictureStreamControl { get; private set; } // 32*4 entries @@ -33,9 +35,11 @@ namespace DvdLib.Ifo private ushort _goupProgramNumber; public ProgramPlaybackMode PlaybackMode { get; private set; } + public uint ProgramCount { get; private set; } public byte StillTime { get; private set; } + public byte[] Palette { get; private set; } // 16*4 entries private ushort _commandTableOffset; diff --git a/DvdLib/Ifo/Title.cs b/DvdLib/Ifo/Title.cs index abf806d2c..4af3af754 100644 --- a/DvdLib/Ifo/Title.cs +++ b/DvdLib/Ifo/Title.cs @@ -8,8 +8,11 @@ namespace DvdLib.Ifo public class Title { public uint TitleNumber { get; private set; } + public uint AngleCount { get; private set; } + public ushort ChapterCount { get; private set; } + public byte VideoTitleSetNumber { get; private set; } private ushort _parentalManagementMask; @@ -17,6 +20,7 @@ namespace DvdLib.Ifo private uint _vtsStartSector; // relative to start of entire disk public ProgramChain EntryProgramChain { get; private set; } + public readonly List ProgramChains; public readonly List Chapters; diff --git a/Emby.Dlna/ContentDirectory/ControlHandler.cs b/Emby.Dlna/ContentDirectory/ControlHandler.cs index de6b619ba..291de5245 100644 --- a/Emby.Dlna/ContentDirectory/ControlHandler.cs +++ b/Emby.Dlna/ContentDirectory/ControlHandler.cs @@ -1357,6 +1357,7 @@ namespace Emby.Dlna.ContentDirectory internal class ServerItem { public BaseItem Item { get; set; } + public StubType? StubType { get; set; } public ServerItem(BaseItem item) diff --git a/Emby.Dlna/Didl/DidlBuilder.cs b/Emby.Dlna/Didl/DidlBuilder.cs index 6ded76f7d..aa7a11815 100644 --- a/Emby.Dlna/Didl/DidlBuilder.cs +++ b/Emby.Dlna/Didl/DidlBuilder.cs @@ -765,6 +765,7 @@ namespace Emby.Dlna.Didl { AddValue(writer, "dc", "rating", item.OfficialRating, NS_DC); } + if (filter.Contains("upnp:rating")) { AddValue(writer, "upnp", "rating", item.OfficialRating, NS_UPNP); @@ -1052,10 +1053,12 @@ namespace Emby.Dlna.Didl { return GetImageInfo(item, ImageType.Primary); } + if (item.HasImage(ImageType.Thumb)) { return GetImageInfo(item, ImageType.Thumb); } + if (item.HasImage(ImageType.Backdrop)) { if (item is Channel) diff --git a/Emby.Dlna/DlnaManager.cs b/Emby.Dlna/DlnaManager.cs index e5f483950..ef8df854b 100644 --- a/Emby.Dlna/DlnaManager.cs +++ b/Emby.Dlna/DlnaManager.cs @@ -438,6 +438,7 @@ namespace Emby.Dlna { throw new ArgumentException("Profile is missing Id"); } + if (string.IsNullOrEmpty(profile.Name)) { throw new ArgumentException("Profile is missing Name"); @@ -463,6 +464,7 @@ namespace Emby.Dlna { _profiles[path] = new Tuple(GetInternalProfileInfo(_fileSystem.GetFileInfo(path), type), profile); } + SerializeToXml(profile, path); } @@ -492,6 +494,7 @@ namespace Emby.Dlna class InternalProfileInfo { internal DeviceProfileInfo Info { get; set; } + internal string Path { get; set; } } diff --git a/Emby.Dlna/Eventing/EventManager.cs b/Emby.Dlna/Eventing/EventManager.cs index 5a51569e2..edccfd190 100644 --- a/Emby.Dlna/Eventing/EventManager.cs +++ b/Emby.Dlna/Eventing/EventManager.cs @@ -150,6 +150,7 @@ namespace Emby.Dlna.Eventing builder.Append(""); builder.Append(""); } + builder.Append(""); var options = new HttpRequestOptions diff --git a/Emby.Dlna/Eventing/EventSubscription.cs b/Emby.Dlna/Eventing/EventSubscription.cs index 51eaee9d7..40d73ee0e 100644 --- a/Emby.Dlna/Eventing/EventSubscription.cs +++ b/Emby.Dlna/Eventing/EventSubscription.cs @@ -7,10 +7,13 @@ namespace Emby.Dlna.Eventing public class EventSubscription { public string Id { get; set; } + public string CallbackUrl { get; set; } + public string NotificationType { get; set; } public DateTime SubscriptionTime { get; set; } + public int TimeoutSeconds { get; set; } public long TriggerCount { get; set; } diff --git a/Emby.Dlna/Main/DlnaEntryPoint.cs b/Emby.Dlna/Main/DlnaEntryPoint.cs index a7b1d384d..b965a09b9 100644 --- a/Emby.Dlna/Main/DlnaEntryPoint.cs +++ b/Emby.Dlna/Main/DlnaEntryPoint.cs @@ -320,6 +320,7 @@ namespace Emby.Dlna.Main { guid = text.GetMD5(); } + return guid.ToString("N", CultureInfo.InvariantCulture); } @@ -388,6 +389,7 @@ namespace Emby.Dlna.Main { _logger.LogError(ex, "Error disposing PlayTo manager"); } + _manager = null; } } diff --git a/Emby.Dlna/PlayTo/Device.cs b/Emby.Dlna/PlayTo/Device.cs index 86b72e264..12757a123 100644 --- a/Emby.Dlna/PlayTo/Device.cs +++ b/Emby.Dlna/PlayTo/Device.cs @@ -37,6 +37,7 @@ namespace Emby.Dlna.PlayTo RefreshVolumeIfNeeded().GetAwaiter().GetResult(); return _volume; } + set => _volume = value; } @@ -494,6 +495,7 @@ namespace Emby.Dlna.PlayTo return; } } + RestartTimerInactive(); } } diff --git a/Emby.Dlna/PlayTo/PlayToController.cs b/Emby.Dlna/PlayTo/PlayToController.cs index f1c69196a..92a93d434 100644 --- a/Emby.Dlna/PlayTo/PlayToController.cs +++ b/Emby.Dlna/PlayTo/PlayToController.cs @@ -425,6 +425,7 @@ namespace Emby.Dlna.PlayTo await _device.SetAvTransport(newItem.StreamUrl, GetDlnaHeaders(newItem), newItem.Didl, CancellationToken.None).ConfigureAwait(false); return; } + await SeekAfterTransportChange(newPosition, CancellationToken.None).ConfigureAwait(false); } } @@ -713,6 +714,7 @@ namespace Emby.Dlna.PlayTo throw new ArgumentException("Volume argument cannot be null"); } + default: return Task.CompletedTask; } @@ -798,12 +800,15 @@ namespace Emby.Dlna.PlayTo public int? SubtitleStreamIndex { get; set; } public string DeviceProfileId { get; set; } + public string DeviceId { get; set; } public string MediaSourceId { get; set; } + public string LiveStreamId { get; set; } public BaseItem Item { get; set; } + private MediaSourceInfo MediaSource; private IMediaSourceManager _mediaSourceManager; diff --git a/Emby.Dlna/PlayTo/PlayToManager.cs b/Emby.Dlna/PlayTo/PlayToManager.cs index c0500eb68..240c8a7d9 100644 --- a/Emby.Dlna/PlayTo/PlayToManager.cs +++ b/Emby.Dlna/PlayTo/PlayToManager.cs @@ -132,6 +132,7 @@ namespace Emby.Dlna.PlayTo usn = usn.Substring(index); found = true; } + index = usn.IndexOf("::", StringComparison.OrdinalIgnoreCase); if (index != -1) { diff --git a/Emby.Dlna/PlayTo/PlaybackStoppedEventArgs.cs b/Emby.Dlna/PlayTo/PlaybackStoppedEventArgs.cs index 3b169e599..fa42b80e8 100644 --- a/Emby.Dlna/PlayTo/PlaybackStoppedEventArgs.cs +++ b/Emby.Dlna/PlayTo/PlaybackStoppedEventArgs.cs @@ -12,6 +12,7 @@ namespace Emby.Dlna.PlayTo public class MediaChangedEventArgs : EventArgs { public uBaseObject OldMediaInfo { get; set; } + public uBaseObject NewMediaInfo { get; set; } } } diff --git a/Emby.Dlna/PlayTo/uBaseObject.cs b/Emby.Dlna/PlayTo/uBaseObject.cs index a8ed5692c..05c19299f 100644 --- a/Emby.Dlna/PlayTo/uBaseObject.cs +++ b/Emby.Dlna/PlayTo/uBaseObject.cs @@ -44,10 +44,12 @@ namespace Emby.Dlna.PlayTo { return MediaBrowser.Model.Entities.MediaType.Audio; } + if (classType.IndexOf(MediaBrowser.Model.Entities.MediaType.Video, StringComparison.Ordinal) != -1) { return MediaBrowser.Model.Entities.MediaType.Video; } + if (classType.IndexOf("image", StringComparison.Ordinal) != -1) { return MediaBrowser.Model.Entities.MediaType.Photo; diff --git a/Emby.Dlna/Server/DescriptionXmlBuilder.cs b/Emby.Dlna/Server/DescriptionXmlBuilder.cs index 5ecc81a2f..7143c3109 100644 --- a/Emby.Dlna/Server/DescriptionXmlBuilder.cs +++ b/Emby.Dlna/Server/DescriptionXmlBuilder.cs @@ -134,6 +134,7 @@ namespace Emby.Dlna.Server return result; } } + return c.ToString(CultureInfo.InvariantCulture); } @@ -157,18 +158,22 @@ namespace Emby.Dlna.Server { break; } + if (stringBuilder == null) { stringBuilder = new StringBuilder(); } + stringBuilder.Append(str, num, num2 - num); stringBuilder.Append(GetEscapeSequence(str[num2])); num = num2 + 1; } + if (stringBuilder == null) { return str; } + stringBuilder.Append(str, num, length - num); return stringBuilder.ToString(); } diff --git a/Emby.Dlna/Service/BaseControlHandler.cs b/Emby.Dlna/Service/BaseControlHandler.cs index 161a3434c..699d325ea 100644 --- a/Emby.Dlna/Service/BaseControlHandler.cs +++ b/Emby.Dlna/Service/BaseControlHandler.cs @@ -18,6 +18,7 @@ namespace Emby.Dlna.Service private const string NS_SOAPENV = "http://schemas.xmlsoap.org/soap/envelope/"; protected IServerConfigurationManager Config { get; } + protected ILogger Logger { get; } protected BaseControlHandler(IServerConfigurationManager config, ILogger logger) @@ -135,6 +136,7 @@ namespace Emby.Dlna.Service break; } + default: { await reader.SkipAsync().ConfigureAwait(false); @@ -211,7 +213,9 @@ namespace Emby.Dlna.Service private class ControlRequestInfo { public string LocalName { get; set; } + public string NamespaceURI { get; set; } + public Dictionary Headers { get; } = new Dictionary(StringComparer.OrdinalIgnoreCase); } diff --git a/Emby.Dlna/Service/ServiceXmlBuilder.cs b/Emby.Dlna/Service/ServiceXmlBuilder.cs index 62ffd9e42..af557aa14 100644 --- a/Emby.Dlna/Service/ServiceXmlBuilder.cs +++ b/Emby.Dlna/Service/ServiceXmlBuilder.cs @@ -80,6 +80,7 @@ namespace Emby.Dlna.Service { builder.Append("" + DescriptionXmlBuilder.Escape(allowedValue) + ""); } + builder.Append(""); } diff --git a/Emby.Naming/AudioBook/AudioBookFilePathParser.cs b/Emby.Naming/AudioBook/AudioBookFilePathParser.cs index 5494df9d6..3c874c62c 100644 --- a/Emby.Naming/AudioBook/AudioBookFilePathParser.cs +++ b/Emby.Naming/AudioBook/AudioBookFilePathParser.cs @@ -64,6 +64,7 @@ namespace Emby.Naming.AudioBook { result.ChapterNumber = int.Parse(matches[0].Groups[0].Value); } + if (matches.Count > 1) { result.PartNumber = int.Parse(matches[matches.Count - 1].Groups[0].Value); diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index d33125661..f09ecaa29 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -793,6 +793,7 @@ namespace Emby.Server.Implementations.Data { saveItemStatement.TryBindNull("@Width"); } + if (item.Height > 0) { saveItemStatement.TryBind("@Height", item.Height); @@ -932,6 +933,7 @@ namespace Emby.Server.Implementations.Data { saveItemStatement.TryBindNull("@SeriesName"); } + if (string.IsNullOrWhiteSpace(userDataKey)) { saveItemStatement.TryBindNull("@UserDataKey"); @@ -1007,6 +1009,7 @@ namespace Emby.Server.Implementations.Data { artists = string.Join("|", hasArtists.Artists); } + saveItemStatement.TryBind("@Artists", artists); string albumArtists = null; @@ -1106,6 +1109,7 @@ namespace Emby.Server.Implementations.Data { continue; } + str.Append(ToValueString(i) + "|"); } @@ -1366,6 +1370,7 @@ namespace Emby.Server.Implementations.Data hasStartDate.StartDate = reader[index].ReadDateTime(); } } + index++; } @@ -1373,12 +1378,14 @@ namespace Emby.Server.Implementations.Data { item.EndDate = reader[index].TryReadDateTime(); } + index++; if (!reader.IsDBNull(index)) { item.ChannelId = new Guid(reader.GetString(index)); } + index++; if (enableProgramAttributes) @@ -1389,24 +1396,28 @@ namespace Emby.Server.Implementations.Data { hasProgramAttributes.IsMovie = reader.GetBoolean(index); } + index++; if (!reader.IsDBNull(index)) { hasProgramAttributes.IsSeries = reader.GetBoolean(index); } + index++; if (!reader.IsDBNull(index)) { hasProgramAttributes.EpisodeTitle = reader.GetString(index); } + index++; if (!reader.IsDBNull(index)) { hasProgramAttributes.IsRepeat = reader.GetBoolean(index); } + index++; } else @@ -1419,6 +1430,7 @@ namespace Emby.Server.Implementations.Data { item.CommunityRating = reader.GetFloat(index); } + index++; if (HasField(query, ItemFields.CustomRating)) @@ -1427,6 +1439,7 @@ namespace Emby.Server.Implementations.Data { item.CustomRating = reader.GetString(index); } + index++; } @@ -1434,6 +1447,7 @@ namespace Emby.Server.Implementations.Data { item.IndexNumber = reader.GetInt32(index); } + index++; if (HasField(query, ItemFields.Settings)) @@ -1442,18 +1456,21 @@ namespace Emby.Server.Implementations.Data { item.IsLocked = reader.GetBoolean(index); } + index++; if (!reader.IsDBNull(index)) { item.PreferredMetadataLanguage = reader.GetString(index); } + index++; if (!reader.IsDBNull(index)) { item.PreferredMetadataCountryCode = reader.GetString(index); } + index++; } @@ -1463,6 +1480,7 @@ namespace Emby.Server.Implementations.Data { item.Width = reader.GetInt32(index); } + index++; } @@ -1472,6 +1490,7 @@ namespace Emby.Server.Implementations.Data { item.Height = reader.GetInt32(index); } + index++; } @@ -1481,6 +1500,7 @@ namespace Emby.Server.Implementations.Data { item.DateLastRefreshed = reader[index].ReadDateTime(); } + index++; } @@ -1488,18 +1508,21 @@ namespace Emby.Server.Implementations.Data { item.Name = reader.GetString(index); } + index++; if (!reader.IsDBNull(index)) { item.Path = RestorePath(reader.GetString(index)); } + index++; if (!reader.IsDBNull(index)) { item.PremiereDate = reader[index].TryReadDateTime(); } + index++; if (HasField(query, ItemFields.Overview)) @@ -1508,6 +1531,7 @@ namespace Emby.Server.Implementations.Data { item.Overview = reader.GetString(index); } + index++; } @@ -1515,18 +1539,21 @@ namespace Emby.Server.Implementations.Data { item.ParentIndexNumber = reader.GetInt32(index); } + index++; if (!reader.IsDBNull(index)) { item.ProductionYear = reader.GetInt32(index); } + index++; if (!reader.IsDBNull(index)) { item.OfficialRating = reader.GetString(index); } + index++; if (HasField(query, ItemFields.SortName)) @@ -1535,6 +1562,7 @@ namespace Emby.Server.Implementations.Data { item.ForcedSortName = reader.GetString(index); } + index++; } @@ -1542,12 +1570,14 @@ namespace Emby.Server.Implementations.Data { item.RunTimeTicks = reader.GetInt64(index); } + index++; if (!reader.IsDBNull(index)) { item.Size = reader.GetInt64(index); } + index++; if (HasField(query, ItemFields.DateCreated)) @@ -1556,6 +1586,7 @@ namespace Emby.Server.Implementations.Data { item.DateCreated = reader[index].ReadDateTime(); } + index++; } @@ -1563,6 +1594,7 @@ namespace Emby.Server.Implementations.Data { item.DateModified = reader[index].ReadDateTime(); } + index++; item.Id = reader.GetGuid(index); @@ -1574,6 +1606,7 @@ namespace Emby.Server.Implementations.Data { item.Genres = reader.GetString(index).Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries); } + index++; } @@ -1581,6 +1614,7 @@ namespace Emby.Server.Implementations.Data { item.ParentId = reader.GetGuid(index); } + index++; if (!reader.IsDBNull(index)) @@ -1590,6 +1624,7 @@ namespace Emby.Server.Implementations.Data item.Audio = audio; } } + index++; // TODO: Even if not needed by apps, the server needs it internally @@ -1603,6 +1638,7 @@ namespace Emby.Server.Implementations.Data liveTvChannel.ServiceName = reader.GetString(index); } } + index++; } @@ -1610,6 +1646,7 @@ namespace Emby.Server.Implementations.Data { item.IsInMixedFolder = reader.GetBoolean(index); } + index++; if (HasField(query, ItemFields.DateLastSaved)) @@ -1618,6 +1655,7 @@ namespace Emby.Server.Implementations.Data { item.DateLastSaved = reader[index].ReadDateTime(); } + index++; } @@ -1635,8 +1673,10 @@ namespace Emby.Server.Implementations.Data } } } + item.LockedFields = GetLockedFields(reader.GetString(index)).ToArray(); } + index++; } @@ -1646,6 +1686,7 @@ namespace Emby.Server.Implementations.Data { item.Studios = reader.GetString(index).Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries); } + index++; } @@ -1655,6 +1696,7 @@ namespace Emby.Server.Implementations.Data { item.Tags = reader.GetString(index).Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries); } + index++; } @@ -1674,9 +1716,11 @@ namespace Emby.Server.Implementations.Data } } } + trailer.TrailerTypes = GetTrailerTypes(reader.GetString(index)).ToArray(); } } + index++; } @@ -1686,6 +1730,7 @@ namespace Emby.Server.Implementations.Data { item.OriginalTitle = reader.GetString(index); } + index++; } @@ -1696,6 +1741,7 @@ namespace Emby.Server.Implementations.Data video.PrimaryVersionId = reader.GetString(index); } } + index++; if (HasField(query, ItemFields.DateLastMediaAdded)) @@ -1704,6 +1750,7 @@ namespace Emby.Server.Implementations.Data { folder.DateLastMediaAdded = reader[index].TryReadDateTime(); } + index++; } @@ -1711,18 +1758,21 @@ namespace Emby.Server.Implementations.Data { item.Album = reader.GetString(index); } + index++; if (!reader.IsDBNull(index)) { item.CriticRating = reader.GetFloat(index); } + index++; if (!reader.IsDBNull(index)) { item.IsVirtualItem = reader.GetBoolean(index); } + index++; if (item is IHasSeries hasSeriesName) @@ -1732,6 +1782,7 @@ namespace Emby.Server.Implementations.Data hasSeriesName.SeriesName = reader.GetString(index); } } + index++; if (hasEpisodeAttributes) @@ -1742,6 +1793,7 @@ namespace Emby.Server.Implementations.Data { episode.SeasonName = reader.GetString(index); } + index++; if (!reader.IsDBNull(index)) { @@ -1752,6 +1804,7 @@ namespace Emby.Server.Implementations.Data { index++; } + index++; } @@ -1765,6 +1818,7 @@ namespace Emby.Server.Implementations.Data hasSeries.SeriesId = reader.GetGuid(index); } } + index++; } @@ -1774,6 +1828,7 @@ namespace Emby.Server.Implementations.Data { item.PresentationUniqueKey = reader.GetString(index); } + index++; } @@ -1783,6 +1838,7 @@ namespace Emby.Server.Implementations.Data { item.InheritedParentalRatingValue = reader.GetInt32(index); } + index++; } @@ -1792,6 +1848,7 @@ namespace Emby.Server.Implementations.Data { item.ExternalSeriesId = reader.GetString(index); } + index++; } @@ -1801,6 +1858,7 @@ namespace Emby.Server.Implementations.Data { item.Tagline = reader.GetString(index); } + index++; } @@ -1808,6 +1866,7 @@ namespace Emby.Server.Implementations.Data { DeserializeProviderIds(reader.GetString(index), item); } + index++; if (query.DtoOptions.EnableImages) @@ -1816,6 +1875,7 @@ namespace Emby.Server.Implementations.Data { DeserializeImages(reader.GetString(index), item); } + index++; } @@ -1825,6 +1885,7 @@ namespace Emby.Server.Implementations.Data { item.ProductionLocations = reader.GetString(index).Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries).ToArray(); } + index++; } @@ -1834,6 +1895,7 @@ namespace Emby.Server.Implementations.Data { item.ExtraIds = SplitToGuids(reader.GetString(index)); } + index++; } @@ -1841,6 +1903,7 @@ namespace Emby.Server.Implementations.Data { item.TotalBitrate = reader.GetInt32(index); } + index++; if (!reader.IsDBNull(index)) @@ -1850,6 +1913,7 @@ namespace Emby.Server.Implementations.Data item.ExtraType = extraType; } } + index++; if (hasArtistFields) @@ -1858,12 +1922,14 @@ namespace Emby.Server.Implementations.Data { hasArtists.Artists = reader.GetString(index).Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries); } + index++; if (item is IHasAlbumArtist hasAlbumArtists && !reader.IsDBNull(index)) { hasAlbumArtists.AlbumArtists = reader.GetString(index).Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries); } + index++; } @@ -1871,6 +1937,7 @@ namespace Emby.Server.Implementations.Data { item.ExternalId = reader.GetString(index); } + index++; if (HasField(query, ItemFields.SeriesPresentationUniqueKey)) @@ -1882,6 +1949,7 @@ namespace Emby.Server.Implementations.Data hasSeries.SeriesPresentationUniqueKey = reader.GetString(index); } } + index++; } @@ -1891,6 +1959,7 @@ namespace Emby.Server.Implementations.Data { program.ShowId = reader.GetString(index); } + index++; } @@ -1898,6 +1967,7 @@ namespace Emby.Server.Implementations.Data { item.OwnerId = reader.GetGuid(index); } + index++; return item; @@ -2473,6 +2543,7 @@ namespace Emby.Server.Implementations.Data { statement.TryBind("@SearchTermStartsWith", searchTerm + "%"); } + if (commandText.IndexOf("@SearchTermContains", StringComparison.OrdinalIgnoreCase) != -1) { statement.TryBind("@SearchTermContains", "%" + searchTerm + "%"); @@ -2743,6 +2814,7 @@ namespace Emby.Server.Implementations.Data { items[i] = newItem; } + return; } } @@ -2835,6 +2907,7 @@ namespace Emby.Server.Implementations.Data { statementTexts.Add(commandText); } + if (query.EnableTotalRecordCount) { commandText = string.Empty; @@ -3239,6 +3312,7 @@ namespace Emby.Server.Implementations.Data { statementTexts.Add(commandText); } + if (query.EnableTotalRecordCount) { commandText = string.Empty; @@ -3592,11 +3666,13 @@ namespace Emby.Server.Implementations.Data whereClauses.Add("IndexNumber=@IndexNumber"); statement?.TryBind("@IndexNumber", query.IndexNumber.Value); } + if (query.ParentIndexNumber.HasValue) { whereClauses.Add("ParentIndexNumber=@ParentIndexNumber"); statement?.TryBind("@ParentIndexNumber", query.ParentIndexNumber.Value); } + if (query.ParentIndexNumberNotEquals.HasValue) { whereClauses.Add("(ParentIndexNumber<>@ParentIndexNumberNotEquals or ParentIndexNumber is null)"); @@ -3882,6 +3958,7 @@ namespace Emby.Server.Implementations.Data { statement.TryBind(paramName, artistId.ToByteArray()); } + index++; } @@ -3902,6 +3979,7 @@ namespace Emby.Server.Implementations.Data { statement.TryBind(paramName, artistId.ToByteArray()); } + index++; } @@ -3922,8 +4000,10 @@ namespace Emby.Server.Implementations.Data { statement.TryBind(paramName, artistId.ToByteArray()); } + index++; } + var clause = "(" + string.Join(" OR ", clauses) + ")"; whereClauses.Add(clause); } @@ -3941,8 +4021,10 @@ namespace Emby.Server.Implementations.Data { statement.TryBind(paramName, albumId.ToByteArray()); } + index++; } + var clause = "(" + string.Join(" OR ", clauses) + ")"; whereClauses.Add(clause); } @@ -3960,8 +4042,10 @@ namespace Emby.Server.Implementations.Data { statement.TryBind(paramName, artistId.ToByteArray()); } + index++; } + var clause = "(" + string.Join(" OR ", clauses) + ")"; whereClauses.Add(clause); } @@ -3979,8 +4063,10 @@ namespace Emby.Server.Implementations.Data { statement.TryBind(paramName, genreId.ToByteArray()); } + index++; } + var clause = "(" + string.Join(" OR ", clauses) + ")"; whereClauses.Add(clause); } @@ -3996,8 +4082,10 @@ namespace Emby.Server.Implementations.Data { statement.TryBind("@Genre" + index, GetCleanValue(item)); } + index++; } + var clause = "(" + string.Join(" OR ", clauses) + ")"; whereClauses.Add(clause); } @@ -4013,8 +4101,10 @@ namespace Emby.Server.Implementations.Data { statement.TryBind("@Tag" + index, GetCleanValue(item)); } + index++; } + var clause = "(" + string.Join(" OR ", clauses) + ")"; whereClauses.Add(clause); } @@ -4030,8 +4120,10 @@ namespace Emby.Server.Implementations.Data { statement.TryBind("@ExcludeTag" + index, GetCleanValue(item)); } + index++; } + var clause = "(" + string.Join(" OR ", clauses) + ")"; whereClauses.Add(clause); } @@ -4050,8 +4142,10 @@ namespace Emby.Server.Implementations.Data { statement.TryBind(paramName, studioId.ToByteArray()); } + index++; } + var clause = "(" + string.Join(" OR ", clauses) + ")"; whereClauses.Add(clause); } @@ -4067,8 +4161,10 @@ namespace Emby.Server.Implementations.Data { statement.TryBind("@OfficialRating" + index, item); } + index++; } + var clause = "(" + string.Join(" OR ", clauses) + ")"; whereClauses.Add(clause); } @@ -4243,6 +4339,7 @@ namespace Emby.Server.Implementations.Data statement.TryBind("@IsVirtualItem", isVirtualItem.Value); } } + if (query.IsSpecialSeason.HasValue) { if (query.IsSpecialSeason.Value) @@ -4254,6 +4351,7 @@ namespace Emby.Server.Implementations.Data whereClauses.Add("IndexNumber <> 0"); } } + if (query.IsUnaired.HasValue) { if (query.IsUnaired.Value) @@ -4265,6 +4363,7 @@ namespace Emby.Server.Implementations.Data whereClauses.Add("PremiereDate < DATETIME('now')"); } } + var queryMediaTypes = query.MediaTypes.Where(IsValidMediaType).ToArray(); if (queryMediaTypes.Length == 1) { @@ -4280,6 +4379,7 @@ namespace Emby.Server.Implementations.Data whereClauses.Add("MediaType in (" + val + ")"); } + if (query.ItemIds.Length > 0) { var includeIds = new List(); @@ -4292,11 +4392,13 @@ namespace Emby.Server.Implementations.Data { statement.TryBind("@IncludeId" + index, id); } + index++; } whereClauses.Add("(" + string.Join(" OR ", includeIds) + ")"); } + if (query.ExcludeItemIds.Length > 0) { var excludeIds = new List(); @@ -4309,6 +4411,7 @@ namespace Emby.Server.Implementations.Data { statement.TryBind("@ExcludeId" + index, id); } + index++; } @@ -4333,6 +4436,7 @@ namespace Emby.Server.Implementations.Data { statement.TryBind(paramName, "%" + pair.Key + "=" + pair.Value + "%"); } + index++; break; @@ -4375,6 +4479,7 @@ namespace Emby.Server.Implementations.Data { statement.TryBind(paramName, "%" + pair.Key + "=" + pair.Value + "%"); } + index++; break; @@ -4425,6 +4530,7 @@ namespace Emby.Server.Implementations.Data { whereClauses.Add("(TopParentId=@TopParentId)"); } + if (statement != null) { statement.TryBind("@TopParentId", queryTopParentIds[0].ToString("N", CultureInfo.InvariantCulture)); @@ -4462,11 +4568,13 @@ namespace Emby.Server.Implementations.Data statement.TryBind("@AncestorId", query.AncestorIds[0]); } } + if (query.AncestorIds.Length > 1) { var inClause = string.Join(",", query.AncestorIds.Select(i => "'" + i.ToString("N", CultureInfo.InvariantCulture) + "'")); whereClauses.Add(string.Format("Guid in (select itemId from AncestorIds where AncestorIdText in ({0}))", inClause)); } + if (!string.IsNullOrWhiteSpace(query.AncestorWithPresentationUniqueKey)) { var inClause = "select guid from TypedBaseItems where PresentationUniqueKey=@AncestorWithPresentationUniqueKey"; @@ -4495,6 +4603,7 @@ namespace Emby.Server.Implementations.Data statement.TryBind("@UnratedType", query.BlockUnratedItems[0].ToString()); } } + if (query.BlockUnratedItems.Length > 1) { var inClause = string.Join(",", query.BlockUnratedItems.Select(i => "'" + i.ToString() + "'")); @@ -4969,6 +5078,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type statement.TryBind("@ItemId", query.ItemId.ToByteArray()); } } + if (!query.AppearsInItemId.Equals(Guid.Empty)) { whereClauses.Add("Name in (Select Name from People where ItemId=@AppearsInItemId)"); @@ -4977,6 +5087,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type statement.TryBind("@AppearsInItemId", query.AppearsInItemId.ToByteArray()); } } + var queryPersonTypes = query.PersonTypes.Where(IsValidPersonType).ToList(); if (queryPersonTypes.Count == 1) @@ -4993,6 +5104,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type whereClauses.Add("PersonType in (" + val + ")"); } + var queryExcludePersonTypes = query.ExcludePersonTypes.Where(IsValidPersonType).ToList(); if (queryExcludePersonTypes.Count == 1) @@ -5009,6 +5121,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type whereClauses.Add("PersonType not in (" + val + ")"); } + if (query.MaxListOrder.HasValue) { whereClauses.Add("ListOrder<=@MaxListOrder"); @@ -5017,6 +5130,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type statement.TryBind("@MaxListOrder", query.MaxListOrder.Value); } } + if (!string.IsNullOrWhiteSpace(query.NameContains)) { whereClauses.Add("Name like @NameContains"); @@ -5156,6 +5270,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type var typeString = string.Join(",", withItemTypes.Select(i => "'" + i + "'")); commandText += " AND ItemId In (select guid from typedbaseitems where type in (" + typeString + "))"; } + if (excludeItemTypes.Count > 0) { var typeString = string.Join(",", excludeItemTypes.Select(i => "'" + i + "'")); diff --git a/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs b/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs index 7e66fa072..023125c92 100644 --- a/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs @@ -135,10 +135,12 @@ namespace Emby.Server.Implementations.Data { throw new ArgumentNullException(nameof(userData)); } + if (internalUserId <= 0) { throw new ArgumentNullException(nameof(internalUserId)); } + if (string.IsNullOrEmpty(key)) { throw new ArgumentNullException(nameof(key)); @@ -153,6 +155,7 @@ namespace Emby.Server.Implementations.Data { throw new ArgumentNullException(nameof(userData)); } + if (internalUserId <= 0) { throw new ArgumentNullException(nameof(internalUserId)); diff --git a/Emby.Server.Implementations/Devices/DeviceManager.cs b/Emby.Server.Implementations/Devices/DeviceManager.cs index 789cdfc11..e75745cc6 100644 --- a/Emby.Server.Implementations/Devices/DeviceManager.cs +++ b/Emby.Server.Implementations/Devices/DeviceManager.cs @@ -169,6 +169,7 @@ namespace Emby.Server.Implementations.Devices { throw new ArgumentException("user not found"); } + if (string.IsNullOrEmpty(deviceId)) { throw new ArgumentNullException(nameof(deviceId)); diff --git a/Emby.Server.Implementations/Dto/DtoService.cs b/Emby.Server.Implementations/Dto/DtoService.cs index 41ff7e3ab..f5a58cc6d 100644 --- a/Emby.Server.Implementations/Dto/DtoService.cs +++ b/Emby.Server.Implementations/Dto/DtoService.cs @@ -277,6 +277,7 @@ namespace Emby.Server.Implementations.Dto dto.EpisodeTitle = dto.Name; dto.Name = dto.SeriesName; } + liveTvManager.AddInfoToRecordingDto(item, dto, activeRecording, user); } @@ -292,6 +293,7 @@ namespace Emby.Server.Implementations.Dto { continue; } + var containers = container.Split(new[] { ',' }); if (containers.Length < 2) { @@ -456,6 +458,7 @@ namespace Emby.Server.Implementations.Dto { dto.SeriesName = item.SeriesName; } + private static void SetPhotoProperties(BaseItemDto dto, Photo item) { dto.CameraMake = item.CameraMake; @@ -554,22 +557,27 @@ namespace Emby.Server.Implementations.Dto { return 0; } + if (i.IsType(PersonType.GuestStar)) { return 1; } + if (i.IsType(PersonType.Director)) { return 2; } + if (i.IsType(PersonType.Writer)) { return 3; } + if (i.IsType(PersonType.Producer)) { return 4; } + if (i.IsType(PersonType.Composer)) { return 4; @@ -1346,6 +1354,7 @@ namespace Emby.Server.Implementations.Dto dto.ParentLogoImageTag = GetTagAndFillBlurhash(dto, parent, image); } } + if (artLimit > 0 && !(imageTags != null && imageTags.ContainsKey(ImageType.Art)) && dto.ParentArtItemId == null) { var image = allImages.FirstOrDefault(i => i.Type == ImageType.Art); @@ -1356,6 +1365,7 @@ namespace Emby.Server.Implementations.Dto dto.ParentArtImageTag = GetTagAndFillBlurhash(dto, parent, image); } } + if (thumbLimit > 0 && !(imageTags != null && imageTags.ContainsKey(ImageType.Thumb)) && (dto.ParentThumbItemId == null || parent is Series) && !(parent is ICollectionFolder) && !(parent is UserView)) { var image = allImages.FirstOrDefault(i => i.Type == ImageType.Thumb); @@ -1366,6 +1376,7 @@ namespace Emby.Server.Implementations.Dto dto.ParentThumbImageTag = GetTagAndFillBlurhash(dto, parent, image); } } + if (backdropLimit > 0 && !((dto.BackdropImageTags != null && dto.BackdropImageTags.Length > 0) || (dto.ParentBackdropImageTags != null && dto.ParentBackdropImageTags.Length > 0))) { var images = allImages.Where(i => i.Type == ImageType.Backdrop).Take(backdropLimit).ToList(); diff --git a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs index 1b6e4b554..e52acc548 100644 --- a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs +++ b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs @@ -453,6 +453,7 @@ namespace Emby.Server.Implementations.HttpServer { httpRes.Headers.Add(key, value); } + httpRes.ContentType = "text/plain"; await httpRes.WriteAsync(string.Empty, cancellationToken).ConfigureAwait(false); return; diff --git a/Emby.Server.Implementations/HttpServer/RangeRequestWriter.cs b/Emby.Server.Implementations/HttpServer/RangeRequestWriter.cs index 8b9028f6b..94cedb918 100644 --- a/Emby.Server.Implementations/HttpServer/RangeRequestWriter.cs +++ b/Emby.Server.Implementations/HttpServer/RangeRequestWriter.cs @@ -20,15 +20,21 @@ namespace Emby.Server.Implementations.HttpServer /// /// The source stream. private Stream SourceStream { get; set; } + private string RangeHeader { get; set; } + private bool IsHeadRequest { get; set; } private long RangeStart { get; set; } + private long RangeEnd { get; set; } + private long RangeLength { get; set; } + private long TotalContentLength { get; set; } public Action OnComplete { get; set; } + private readonly ILogger _logger; private const int BufferSize = 81920; @@ -139,6 +145,7 @@ namespace Emby.Server.Implementations.HttpServer { start = long.Parse(vals[0], UsCulture); } + if (!string.IsNullOrEmpty(vals[1])) { end = long.Parse(vals[1], UsCulture); diff --git a/Emby.Server.Implementations/HttpServer/Security/AuthService.cs b/Emby.Server.Implementations/HttpServer/Security/AuthService.cs index 72959003a..2e6ff65a6 100644 --- a/Emby.Server.Implementations/HttpServer/Security/AuthService.cs +++ b/Emby.Server.Implementations/HttpServer/Security/AuthService.cs @@ -140,6 +140,7 @@ namespace Emby.Server.Implementations.HttpServer.Security { return true; } + if (authAttribtues.AllowLocalOnly && request.IsLocal) { return true; diff --git a/Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs b/Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs index 4dffcd92d..bbade00ff 100644 --- a/Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs +++ b/Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs @@ -71,6 +71,7 @@ namespace Emby.Server.Implementations.HttpServer.Security { token = httpReq.Headers["X-MediaBrowser-Token"]; } + if (string.IsNullOrEmpty(token)) { token = httpReq.QueryString["api_key"]; @@ -160,6 +161,7 @@ namespace Emby.Server.Implementations.HttpServer.Security _authRepo.Update(tokenInfo); } } + httpReq.Items["OriginalAuthenticationInfo"] = tokenInfo; } diff --git a/Emby.Server.Implementations/IO/ManagedFileSystem.cs b/Emby.Server.Implementations/IO/ManagedFileSystem.cs index a7bbf6acc..a3a3f91b7 100644 --- a/Emby.Server.Implementations/IO/ManagedFileSystem.cs +++ b/Emby.Server.Implementations/IO/ManagedFileSystem.cs @@ -628,6 +628,7 @@ namespace Emby.Server.Implementations.IO { return false; } + return extensions.Contains(ext, StringComparer.OrdinalIgnoreCase); }); } @@ -682,6 +683,7 @@ namespace Emby.Server.Implementations.IO { return false; } + return extensions.Contains(ext, StringComparer.OrdinalIgnoreCase); }); } diff --git a/Emby.Server.Implementations/Library/ExclusiveLiveStream.cs b/Emby.Server.Implementations/Library/ExclusiveLiveStream.cs index 9a7186898..ab39a7223 100644 --- a/Emby.Server.Implementations/Library/ExclusiveLiveStream.cs +++ b/Emby.Server.Implementations/Library/ExclusiveLiveStream.cs @@ -12,11 +12,13 @@ namespace Emby.Server.Implementations.Library public class ExclusiveLiveStream : ILiveStream { public int ConsumerCount { get; set; } + public string OriginalStreamId { get; set; } public string TunerHostId => null; public bool EnableStreamSharing { get; set; } + public MediaSourceInfo MediaSource { get; set; } public string UniqueId { get; private set; } diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index 1d4651da2..46f433282 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -2784,10 +2784,12 @@ namespace Emby.Server.Implementations.Library { throw new ArgumentNullException(nameof(path)); } + if (string.IsNullOrWhiteSpace(from)) { throw new ArgumentNullException(nameof(from)); } + if (string.IsNullOrWhiteSpace(to)) { throw new ArgumentNullException(nameof(to)); diff --git a/Emby.Server.Implementations/Library/MediaSourceManager.cs b/Emby.Server.Implementations/Library/MediaSourceManager.cs index 919261027..ceb36b389 100644 --- a/Emby.Server.Implementations/Library/MediaSourceManager.cs +++ b/Emby.Server.Implementations/Library/MediaSourceManager.cs @@ -205,22 +205,27 @@ namespace Emby.Server.Implementations.Library { return MediaProtocol.Rtsp; } + if (path.StartsWith("Rtmp", StringComparison.OrdinalIgnoreCase)) { return MediaProtocol.Rtmp; } + if (path.StartsWith("Http", StringComparison.OrdinalIgnoreCase)) { return MediaProtocol.Http; } + if (path.StartsWith("rtp", StringComparison.OrdinalIgnoreCase)) { return MediaProtocol.Rtp; } + if (path.StartsWith("ftp", StringComparison.OrdinalIgnoreCase)) { return MediaProtocol.Ftp; } + if (path.StartsWith("udp", StringComparison.OrdinalIgnoreCase)) { return MediaProtocol.Udp; diff --git a/Emby.Server.Implementations/Library/Resolvers/SpecialFolderResolver.cs b/Emby.Server.Implementations/Library/Resolvers/SpecialFolderResolver.cs index 4819f2fc0..99f304190 100644 --- a/Emby.Server.Implementations/Library/Resolvers/SpecialFolderResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/SpecialFolderResolver.cs @@ -41,10 +41,12 @@ namespace Emby.Server.Implementations.Library.Resolvers { return new AggregateFolder(); } + if (string.Equals(args.Path, _appPaths.DefaultUserViewsPath, StringComparison.OrdinalIgnoreCase)) { return new UserRootFolder(); // if we got here and still a root - must be user root } + if (args.IsVf) { return new CollectionFolder diff --git a/Emby.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs b/Emby.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs index 7f477a0f0..2f7af60c0 100644 --- a/Emby.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs @@ -55,6 +55,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV episode.SeriesId = series.Id; episode.SeriesName = series.Name; } + if (season != null) { episode.SeasonId = season.Id; diff --git a/Emby.Server.Implementations/Library/SearchEngine.cs b/Emby.Server.Implementations/Library/SearchEngine.cs index b8c42cdf8..3df9cc06f 100644 --- a/Emby.Server.Implementations/Library/SearchEngine.cs +++ b/Emby.Server.Implementations/Library/SearchEngine.cs @@ -194,6 +194,7 @@ namespace Emby.Server.Implementations.Library { searchQuery.AncestorIds = new[] { searchQuery.ParentId }; } + searchQuery.ParentId = Guid.Empty; searchQuery.IncludeItemsByName = true; searchQuery.IncludeItemTypes = Array.Empty(); diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs index fdd305f86..3709f8fe4 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs @@ -212,6 +212,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings { channelNumber = map.channel; } + if (string.IsNullOrWhiteSpace(channelNumber)) { channelNumber = map.atscMajor + "." + map.atscMinor; @@ -400,6 +401,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings { date = DateTime.SpecifyKind(date, DateTimeKind.Utc); } + return date; } @@ -622,6 +624,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings _lastErrorResponse = DateTime.UtcNow; } } + throw; } finally @@ -805,11 +808,13 @@ namespace Emby.Server.Implementations.LiveTv.Listings { throw new ArgumentException("Username is required"); } + if (string.IsNullOrEmpty(info.Password)) { throw new ArgumentException("Password is required"); } } + if (validateListings) { if (string.IsNullOrEmpty(info.ListingsId)) @@ -932,24 +937,35 @@ namespace Emby.Server.Implementations.LiveTv.Listings public class Token { public int code { get; set; } + public string message { get; set; } + public string serverID { get; set; } + public string token { get; set; } } + public class Lineup { public string lineup { get; set; } + public string name { get; set; } + public string transport { get; set; } + public string location { get; set; } + public string uri { get; set; } } public class Lineups { public int code { get; set; } + public string serverID { get; set; } + public string datetime { get; set; } + public List lineups { get; set; } } @@ -957,8 +973,11 @@ namespace Emby.Server.Implementations.LiveTv.Listings public class Headends { public string headend { get; set; } + public string transport { get; set; } + public string location { get; set; } + public List lineups { get; set; } } @@ -967,59 +986,83 @@ namespace Emby.Server.Implementations.LiveTv.Listings public class Map { public string stationID { get; set; } + public string channel { get; set; } + public string logicalChannelNumber { get; set; } + public int uhfVhf { get; set; } + public int atscMajor { get; set; } + public int atscMinor { get; set; } } public class Broadcaster { public string city { get; set; } + public string state { get; set; } + public string postalcode { get; set; } + public string country { get; set; } } public class Logo { public string URL { get; set; } + public int height { get; set; } + public int width { get; set; } + public string md5 { get; set; } } public class Station { public string stationID { get; set; } + public string name { get; set; } + public string callsign { get; set; } + public List broadcastLanguage { get; set; } + public List descriptionLanguage { get; set; } + public Broadcaster broadcaster { get; set; } + public string affiliate { get; set; } + public Logo logo { get; set; } + public bool? isCommercialFree { get; set; } } public class Metadata { public string lineup { get; set; } + public string modified { get; set; } + public string transport { get; set; } } public class Channel { public List map { get; set; } + public List stations { get; set; } + public Metadata metadata { get; set; } } public class RequestScheduleForChannel { public string stationID { get; set; } + public List date { get; set; } } @@ -1029,29 +1072,43 @@ namespace Emby.Server.Implementations.LiveTv.Listings public class Rating { public string body { get; set; } + public string code { get; set; } } public class Multipart { public int partNumber { get; set; } + public int totalParts { get; set; } } public class Program { public string programID { get; set; } + public string airDateTime { get; set; } + public int duration { get; set; } + public string md5 { get; set; } + public List audioProperties { get; set; } + public List videoProperties { get; set; } + public List ratings { get; set; } + public bool? @new { get; set; } + public Multipart multipart { get; set; } + public string liveTapeDelay { get; set; } + public bool premiere { get; set; } + public bool repeat { get; set; } + public string isPremiereOrFinale { get; set; } } @@ -1060,16 +1117,22 @@ namespace Emby.Server.Implementations.LiveTv.Listings public class MetadataSchedule { public string modified { get; set; } + public string md5 { get; set; } + public string startDate { get; set; } + public string endDate { get; set; } + public int days { get; set; } } public class Day { public string stationID { get; set; } + public List programs { get; set; } + public MetadataSchedule metadata { get; set; } public Day() @@ -1092,24 +1155,28 @@ namespace Emby.Server.Implementations.LiveTv.Listings public class Description100 { public string descriptionLanguage { get; set; } + public string description { get; set; } } public class Description1000 { public string descriptionLanguage { get; set; } + public string description { get; set; } } public class DescriptionsProgram { public List description100 { get; set; } + public List description1000 { get; set; } } public class Gracenote { public int season { get; set; } + public int episode { get; set; } } @@ -1121,101 +1188,152 @@ namespace Emby.Server.Implementations.LiveTv.Listings public class ContentRating { public string body { get; set; } + public string code { get; set; } } public class Cast { public string billingOrder { get; set; } + public string role { get; set; } + public string nameId { get; set; } + public string personId { get; set; } + public string name { get; set; } + public string characterName { get; set; } } public class Crew { public string billingOrder { get; set; } + public string role { get; set; } + public string nameId { get; set; } + public string personId { get; set; } + public string name { get; set; } } public class QualityRating { public string ratingsBody { get; set; } + public string rating { get; set; } + public string minRating { get; set; } + public string maxRating { get; set; } + public string increment { get; set; } } public class Movie { public string year { get; set; } + public int duration { get; set; } + public List qualityRating { get; set; } } public class Recommendation { public string programID { get; set; } + public string title120 { get; set; } } public class ProgramDetails { public string audience { get; set; } + public string programID { get; set; } + public List titles { get; set; } + public EventDetails eventDetails { get; set; } + public DescriptionsProgram descriptions { get; set; } + public string originalAirDate { get; set; } + public List<string> genres { get; set; } + public string episodeTitle150 { get; set; } + public List<MetadataPrograms> metadata { get; set; } + public List<ContentRating> contentRating { get; set; } + public List<Cast> cast { get; set; } + public List<Crew> crew { get; set; } + public string entityType { get; set; } + public string showType { get; set; } + public bool hasImageArtwork { get; set; } + public string primaryImage { get; set; } + public string thumbImage { get; set; } + public string backdropImage { get; set; } + public string bannerImage { get; set; } + public string imageID { get; set; } + public string md5 { get; set; } + public List<string> contentAdvisory { get; set; } + public Movie movie { get; set; } + public List<Recommendation> recommendations { get; set; } } public class Caption { public string content { get; set; } + public string lang { get; set; } } public class ImageData { public string width { get; set; } + public string height { get; set; } + public string uri { get; set; } + public string size { get; set; } + public string aspect { get; set; } + public string category { get; set; } + public string text { get; set; } + public string primary { get; set; } + public string tier { get; set; } + public Caption caption { get; set; } } public class ShowImages { public string programID { get; set; } + public List<ImageData> data { get; set; } } } diff --git a/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs b/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs index 077b5c7e5..0a93c4674 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs @@ -224,6 +224,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings { uniqueString = "-" + programInfo.SeasonNumber.Value.ToString(CultureInfo.InvariantCulture); } + if (programInfo.EpisodeNumber.HasValue) { uniqueString = "-" + programInfo.EpisodeNumber.Value.ToString(CultureInfo.InvariantCulture); diff --git a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs index 42e93b7ff..4c1de3bcc 100644 --- a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs @@ -556,6 +556,7 @@ namespace Emby.Server.Implementations.LiveTv { forceUpdate = true; } + item.ParentId = channel.Id; // item.ChannelType = channelType; @@ -575,6 +576,7 @@ namespace Emby.Server.Implementations.LiveTv { forceUpdate = true; } + item.ExternalSeriesId = seriesId; var isSeries = info.IsSeries || !string.IsNullOrEmpty(info.EpisodeTitle); @@ -589,30 +591,37 @@ namespace Emby.Server.Implementations.LiveTv { tags.Add("Live"); } + if (info.IsPremiere) { tags.Add("Premiere"); } + if (info.IsNews) { tags.Add("News"); } + if (info.IsSports) { tags.Add("Sports"); } + if (info.IsKids) { tags.Add("Kids"); } + if (info.IsRepeat) { tags.Add("Repeat"); } + if (info.IsMovie) { tags.Add("Movie"); } + if (isSeries) { tags.Add("Series"); @@ -635,6 +644,7 @@ namespace Emby.Server.Implementations.LiveTv { forceUpdate = true; } + item.IsSeries = isSeries; item.Name = info.Name; @@ -652,12 +662,14 @@ namespace Emby.Server.Implementations.LiveTv { forceUpdate = true; } + item.StartDate = info.StartDate; if (item.EndDate != info.EndDate) { forceUpdate = true; } + item.EndDate = info.EndDate; item.ProductionYear = info.ProductionYear; diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs index f14fcde2a..dff113a2a 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs @@ -170,6 +170,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun _modelCache[cacheKey] = response; } } + return response; } @@ -201,6 +202,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun var name = line.Substring(0, index - 1); var currentChannel = line.Substring(index + 7); if (currentChannel != "none") { status = LiveTvTunerStatus.LiveTv; } else { status = LiveTvTunerStatus.Available; } + tuners.Add(new LiveTvTunerInfo { Name = name, @@ -229,11 +231,13 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun inside = true; continue; } + if (let == '>') { inside = false; continue; } + if (!inside) { buffer[bufferIndex] = let; @@ -331,12 +335,19 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun private class Channels { public string GuideNumber { get; set; } + public string GuideName { get; set; } + public string VideoCodec { get; set; } + public string AudioCodec { get; set; } + public string URL { get; set; } + public bool Favorite { get; set; } + public bool DRM { get; set; } + public int HD { get; set; } } @@ -657,13 +668,21 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun public class DiscoverResponse { public string FriendlyName { get; set; } + public string ModelNumber { get; set; } + public string FirmwareName { get; set; } + public string FirmwareVersion { get; set; } + public string DeviceID { get; set; } + public string DeviceAuth { get; set; } + public string BaseURL { get; set; } + public string LineupURL { get; set; } + public int TunerCount { get; set; } public bool SupportsTranscoding diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs index 4decdc24f..0333e723b 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs @@ -58,12 +58,15 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts protected virtual int EmptyReadLimit => 1000; public MediaSourceInfo OriginalMediaSource { get; set; } + public MediaSourceInfo MediaSource { get; set; } public int ConsumerCount { get; set; } public string OriginalStreamId { get; set; } + public bool EnableStreamSharing { get; set; } + public string UniqueId { get; } public string TunerHostId { get; } diff --git a/Emby.Server.Implementations/Playlists/PlaylistManager.cs b/Emby.Server.Implementations/Playlists/PlaylistManager.cs index 184d64e60..ac816ccd9 100644 --- a/Emby.Server.Implementations/Playlists/PlaylistManager.cs +++ b/Emby.Server.Implementations/Playlists/PlaylistManager.cs @@ -401,6 +401,7 @@ namespace Emby.Server.Implementations.Playlists { entry.Duration = TimeSpan.FromTicks(child.RunTimeTicks.Value); } + playlist.PlaylistEntries.Add(entry); } diff --git a/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs b/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs index e58c335a8..2031a1c6d 100644 --- a/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs +++ b/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs @@ -143,12 +143,14 @@ namespace Emby.Server.Implementations.ScheduledTasks Logger.LogError(ex, "Error deserializing {File}", path); } } + _readFromFile = true; } } return _lastExecutionResult; } + private set { _lastExecutionResult = value; @@ -261,6 +263,7 @@ namespace Emby.Server.Implementations.ScheduledTasks var triggers = InternalTriggers; return triggers.Select(i => i.Item1).ToArray(); } + set { if (value == null) @@ -640,6 +643,7 @@ namespace Emby.Server.Implementations.ScheduledTasks Logger.LogError(ex, "Error calling CancellationToken.Cancel();"); } } + var task = _currentTask; if (task != null) { @@ -675,6 +679,7 @@ namespace Emby.Server.Implementations.ScheduledTasks Logger.LogError(ex, "Error calling CancellationToken.Dispose();"); } } + if (wassRunning) { OnTaskCompleted(startTime, DateTime.UtcNow, TaskCompletionStatus.Aborted, null); diff --git a/Emby.Server.Implementations/Services/ServiceMethod.cs b/Emby.Server.Implementations/Services/ServiceMethod.cs index 59ee5908f..5116cc04f 100644 --- a/Emby.Server.Implementations/Services/ServiceMethod.cs +++ b/Emby.Server.Implementations/Services/ServiceMethod.cs @@ -9,6 +9,7 @@ namespace Emby.Server.Implementations.Services public string Id { get; set; } public ActionInvokerFn ServiceAction { get; set; } + public MediaBrowser.Model.Services.IHasRequestFilter[] RequestFilters { get; set; } public static string Key(Type serviceType, string method, string requestDtoName) diff --git a/Emby.Server.Implementations/Services/ServicePath.cs b/Emby.Server.Implementations/Services/ServicePath.cs index 43869f98a..3b7ffaf2c 100644 --- a/Emby.Server.Implementations/Services/ServicePath.cs +++ b/Emby.Server.Implementations/Services/ServicePath.cs @@ -62,7 +62,9 @@ namespace Emby.Server.Implementations.Services public string Path => this.restPath; public string Summary { get; private set; } + public string Description { get; private set; } + public bool IsHidden { get; private set; } public static string[] GetPathPartsForMatching(string pathInfo) @@ -159,6 +161,7 @@ namespace Emby.Server.Implementations.Services this.isWildcard[i] = true; variableName = variableName.Substring(0, variableName.Length - 1); } + this.variablesNames[i] = variableName; this.VariableArgsCount++; } diff --git a/Emby.Server.Implementations/Services/StringMapTypeDeserializer.cs b/Emby.Server.Implementations/Services/StringMapTypeDeserializer.cs index d3d27ae58..165bb0fc4 100644 --- a/Emby.Server.Implementations/Services/StringMapTypeDeserializer.cs +++ b/Emby.Server.Implementations/Services/StringMapTypeDeserializer.cs @@ -22,7 +22,9 @@ namespace Emby.Server.Implementations.Services } public Action<object, object> PropertySetFn { get; private set; } + public Func<string, object> PropertyParseStringFn { get; private set; } + public Type PropertyType { get; private set; } } diff --git a/Emby.Server.Implementations/Services/SwaggerService.cs b/Emby.Server.Implementations/Services/SwaggerService.cs index 16142a70d..4f011a678 100644 --- a/Emby.Server.Implementations/Services/SwaggerService.cs +++ b/Emby.Server.Implementations/Services/SwaggerService.cs @@ -18,13 +18,21 @@ namespace Emby.Server.Implementations.Services public class SwaggerSpec { public string swagger { get; set; } + public string[] schemes { get; set; } + public SwaggerInfo info { get; set; } + public string host { get; set; } + public string basePath { get; set; } + public SwaggerTag[] tags { get; set; } + public IDictionary<string, Dictionary<string, SwaggerMethod>> paths { get; set; } + public Dictionary<string, SwaggerDefinition> definitions { get; set; } + public SwaggerComponents components { get; set; } } @@ -36,15 +44,20 @@ namespace Emby.Server.Implementations.Services public class SwaggerSecurityScheme { public string name { get; set; } + public string type { get; set; } + public string @in { get; set; } } public class SwaggerInfo { public string description { get; set; } + public string version { get; set; } + public string title { get; set; } + public string termsOfService { get; set; } public SwaggerConcactInfo contact { get; set; } @@ -53,36 +66,52 @@ namespace Emby.Server.Implementations.Services public class SwaggerConcactInfo { public string email { get; set; } + public string name { get; set; } + public string url { get; set; } } public class SwaggerTag { public string description { get; set; } + public string name { get; set; } } public class SwaggerMethod { public string summary { get; set; } + public string description { get; set; } + public string[] tags { get; set; } + public string operationId { get; set; } + public string[] consumes { get; set; } + public string[] produces { get; set; } + public SwaggerParam[] parameters { get; set; } + public Dictionary<string, SwaggerResponse> responses { get; set; } + public Dictionary<string, string[]>[] security { get; set; } } public class SwaggerParam { public string @in { get; set; } + public string name { get; set; } + public string description { get; set; } + public bool required { get; set; } + public string type { get; set; } + public string collectionFormat { get; set; } } @@ -97,15 +126,20 @@ namespace Emby.Server.Implementations.Services public class SwaggerDefinition { public string type { get; set; } + public Dictionary<string, SwaggerProperty> properties { get; set; } } public class SwaggerProperty { public string type { get; set; } + public string format { get; set; } + public string description { get; set; } + public string[] @enum { get; set; } + public string @default { get; set; } } diff --git a/Emby.Server.Implementations/Session/SessionWebSocketListener.cs b/Emby.Server.Implementations/Session/SessionWebSocketListener.cs index ef32c692c..1e8b25e38 100644 --- a/Emby.Server.Implementations/Session/SessionWebSocketListener.cs +++ b/Emby.Server.Implementations/Session/SessionWebSocketListener.cs @@ -167,6 +167,7 @@ namespace Emby.Server.Implementations.Session _logger.LogWarning("Multiple attempts to keep alive single WebSocket {0}", webSocket); return; } + webSocket.Closed += OnWebSocketClosed; webSocket.LastKeepAliveDate = DateTime.UtcNow; diff --git a/Emby.Server.Implementations/Sorting/PremiereDateComparer.cs b/Emby.Server.Implementations/Sorting/PremiereDateComparer.cs index 0c944a7a0..491057a85 100644 --- a/Emby.Server.Implementations/Sorting/PremiereDateComparer.cs +++ b/Emby.Server.Implementations/Sorting/PremiereDateComparer.cs @@ -44,6 +44,7 @@ namespace Emby.Server.Implementations.Sorting // Don't blow up if the item has a bad ProductionYear, just return MinValue } } + return DateTime.MinValue; } diff --git a/Emby.Server.Implementations/TV/TVSeriesManager.cs b/Emby.Server.Implementations/TV/TVSeriesManager.cs index db056cc38..21c12ae79 100644 --- a/Emby.Server.Implementations/TV/TVSeriesManager.cs +++ b/Emby.Server.Implementations/TV/TVSeriesManager.cs @@ -256,6 +256,7 @@ namespace Emby.Server.Implementations.TV { items = items.Skip(query.StartIndex.Value); } + if (query.Limit.HasValue) { items = items.Take(query.Limit.Value); diff --git a/Jellyfin.Data/Entities/Artwork.cs b/Jellyfin.Data/Entities/Artwork.cs index 214fb4cb1..bebcc37d3 100644 --- a/Jellyfin.Data/Entities/Artwork.cs +++ b/Jellyfin.Data/Entities/Artwork.cs @@ -89,6 +89,7 @@ namespace Jellyfin.Data.Entities GetId(ref value); return (_Id = value); } + protected set { int oldValue = _Id; @@ -127,6 +128,7 @@ namespace Jellyfin.Data.Entities GetPath(ref value); return (_Path = value); } + set { string oldValue = _Path; @@ -163,6 +165,7 @@ namespace Jellyfin.Data.Entities GetKind(ref value); return (_Kind = value); } + set { Enums.ArtKind oldValue = _Kind; diff --git a/Jellyfin.Data/Entities/BookMetadata.cs b/Jellyfin.Data/Entities/BookMetadata.cs index dd389b64a..6c72c2732 100644 --- a/Jellyfin.Data/Entities/BookMetadata.cs +++ b/Jellyfin.Data/Entities/BookMetadata.cs @@ -84,6 +84,7 @@ namespace Jellyfin.Data.Entities GetISBN(ref value); return (_ISBN = value); } + set { long? oldValue = _ISBN; diff --git a/Jellyfin.Data/Entities/Chapter.cs b/Jellyfin.Data/Entities/Chapter.cs index 9b3a5e827..3d59fe6b8 100644 --- a/Jellyfin.Data/Entities/Chapter.cs +++ b/Jellyfin.Data/Entities/Chapter.cs @@ -86,6 +86,7 @@ namespace Jellyfin.Data.Entities GetId(ref value); return (_Id = value); } + protected set { int oldValue = _Id; @@ -123,6 +124,7 @@ namespace Jellyfin.Data.Entities GetName(ref value); return (_Name = value); } + set { string oldValue = _Name; @@ -163,6 +165,7 @@ namespace Jellyfin.Data.Entities GetLanguage(ref value); return (_Language = value); } + set { string oldValue = _Language; @@ -199,6 +202,7 @@ namespace Jellyfin.Data.Entities GetTimeStart(ref value); return (_TimeStart = value); } + set { long oldValue = _TimeStart; @@ -231,6 +235,7 @@ namespace Jellyfin.Data.Entities GetTimeEnd(ref value); return (_TimeEnd = value); } + set { long? oldValue = _TimeEnd; diff --git a/Jellyfin.Data/Entities/Collection.cs b/Jellyfin.Data/Entities/Collection.cs index c040cfe33..caf20f916 100644 --- a/Jellyfin.Data/Entities/Collection.cs +++ b/Jellyfin.Data/Entities/Collection.cs @@ -49,6 +49,7 @@ namespace Jellyfin.Data.Entities GetId(ref value); return (_Id = value); } + protected set { int oldValue = _Id; @@ -86,6 +87,7 @@ namespace Jellyfin.Data.Entities GetName(ref value); return (_Name = value); } + set { string oldValue = _Name; diff --git a/Jellyfin.Data/Entities/CollectionItem.cs b/Jellyfin.Data/Entities/CollectionItem.cs index c5e54c3a2..1a1078050 100644 --- a/Jellyfin.Data/Entities/CollectionItem.cs +++ b/Jellyfin.Data/Entities/CollectionItem.cs @@ -93,6 +93,7 @@ namespace Jellyfin.Data.Entities GetId(ref value); return (_Id = value); } + protected set { int oldValue = _Id; diff --git a/Jellyfin.Data/Entities/Company.cs b/Jellyfin.Data/Entities/Company.cs index 7d6f3b207..eefc581c6 100644 --- a/Jellyfin.Data/Entities/Company.cs +++ b/Jellyfin.Data/Entities/Company.cs @@ -101,6 +101,7 @@ namespace Jellyfin.Data.Entities GetId(ref value); return (_Id = value); } + protected set { int oldValue = _Id; diff --git a/Jellyfin.Data/Entities/CompanyMetadata.cs b/Jellyfin.Data/Entities/CompanyMetadata.cs index 1ad03b4f9..6a601c6e3 100644 --- a/Jellyfin.Data/Entities/CompanyMetadata.cs +++ b/Jellyfin.Data/Entities/CompanyMetadata.cs @@ -85,6 +85,7 @@ namespace Jellyfin.Data.Entities GetDescription(ref value); return (_Description = value); } + set { string oldValue = _Description; @@ -122,6 +123,7 @@ namespace Jellyfin.Data.Entities GetHeadquarters(ref value); return (_Headquarters = value); } + set { string oldValue = _Headquarters; @@ -159,6 +161,7 @@ namespace Jellyfin.Data.Entities GetCountry(ref value); return (_Country = value); } + set { string oldValue = _Country; @@ -196,6 +199,7 @@ namespace Jellyfin.Data.Entities GetHomepage(ref value); return (_Homepage = value); } + set { string oldValue = _Homepage; diff --git a/Jellyfin.Data/Entities/Episode.cs b/Jellyfin.Data/Entities/Episode.cs index 88531205f..6f4353a6f 100644 --- a/Jellyfin.Data/Entities/Episode.cs +++ b/Jellyfin.Data/Entities/Episode.cs @@ -86,6 +86,7 @@ namespace Jellyfin.Data.Entities GetEpisodeNumber(ref value); return (_EpisodeNumber = value); } + set { int? oldValue = _EpisodeNumber; diff --git a/Jellyfin.Data/Entities/EpisodeMetadata.cs b/Jellyfin.Data/Entities/EpisodeMetadata.cs index 0aa4b4270..17057cb1d 100644 --- a/Jellyfin.Data/Entities/EpisodeMetadata.cs +++ b/Jellyfin.Data/Entities/EpisodeMetadata.cs @@ -85,6 +85,7 @@ namespace Jellyfin.Data.Entities GetOutline(ref value); return (_Outline = value); } + set { string oldValue = _Outline; @@ -122,6 +123,7 @@ namespace Jellyfin.Data.Entities GetPlot(ref value); return (_Plot = value); } + set { string oldValue = _Plot; @@ -159,6 +161,7 @@ namespace Jellyfin.Data.Entities GetTagline(ref value); return (_Tagline = value); } + set { string oldValue = _Tagline; diff --git a/Jellyfin.Data/Entities/Genre.cs b/Jellyfin.Data/Entities/Genre.cs index ff0710671..b56e35667 100644 --- a/Jellyfin.Data/Entities/Genre.cs +++ b/Jellyfin.Data/Entities/Genre.cs @@ -82,6 +82,7 @@ namespace Jellyfin.Data.Entities GetId(ref value); return (_Id = value); } + protected set { int oldValue = _Id; @@ -120,6 +121,7 @@ namespace Jellyfin.Data.Entities GetName(ref value); return (_Name = value); } + set { string oldValue = _Name; diff --git a/Jellyfin.Data/Entities/Library.cs b/Jellyfin.Data/Entities/Library.cs index a5cc5c8da..4c7f7e7b7 100644 --- a/Jellyfin.Data/Entities/Library.cs +++ b/Jellyfin.Data/Entities/Library.cs @@ -77,6 +77,7 @@ namespace Jellyfin.Data.Entities GetId(ref value); return (_Id = value); } + protected set { int oldValue = _Id; @@ -115,6 +116,7 @@ namespace Jellyfin.Data.Entities GetName(ref value); return (_Name = value); } + set { string oldValue = _Name; diff --git a/Jellyfin.Data/Entities/LibraryItem.cs b/Jellyfin.Data/Entities/LibraryItem.cs index c2ba7059d..bfc2f7ddb 100644 --- a/Jellyfin.Data/Entities/LibraryItem.cs +++ b/Jellyfin.Data/Entities/LibraryItem.cs @@ -59,6 +59,7 @@ namespace Jellyfin.Data.Entities GetId(ref value); return (_Id = value); } + protected set { int oldValue = _Id; @@ -96,6 +97,7 @@ namespace Jellyfin.Data.Entities GetUrlId(ref value); return (_UrlId = value); } + set { Guid oldValue = _UrlId; @@ -132,6 +134,7 @@ namespace Jellyfin.Data.Entities GetDateAdded(ref value); return (_DateAdded = value); } + internal set { DateTime oldValue = _DateAdded; diff --git a/Jellyfin.Data/Entities/LibraryRoot.cs b/Jellyfin.Data/Entities/LibraryRoot.cs index 7823db02a..fa1e6f14c 100644 --- a/Jellyfin.Data/Entities/LibraryRoot.cs +++ b/Jellyfin.Data/Entities/LibraryRoot.cs @@ -77,6 +77,7 @@ namespace Jellyfin.Data.Entities GetId(ref value); return (_Id = value); } + protected set { int oldValue = _Id; @@ -116,6 +117,7 @@ namespace Jellyfin.Data.Entities GetPath(ref value); return (_Path = value); } + set { string oldValue = _Path; @@ -154,6 +156,7 @@ namespace Jellyfin.Data.Entities GetNetworkPath(ref value); return (_NetworkPath = value); } + set { string oldValue = _NetworkPath; diff --git a/Jellyfin.Data/Entities/MediaFile.cs b/Jellyfin.Data/Entities/MediaFile.cs index 94c39a28a..1c14c6c87 100644 --- a/Jellyfin.Data/Entities/MediaFile.cs +++ b/Jellyfin.Data/Entities/MediaFile.cs @@ -90,6 +90,7 @@ namespace Jellyfin.Data.Entities GetId(ref value); return (_Id = value); } + protected set { int oldValue = _Id; @@ -129,6 +130,7 @@ namespace Jellyfin.Data.Entities GetPath(ref value); return (_Path = value); } + set { string oldValue = _Path; @@ -165,6 +167,7 @@ namespace Jellyfin.Data.Entities GetKind(ref value); return (_Kind = value); } + set { Enums.MediaFileKind oldValue = _Kind; diff --git a/Jellyfin.Data/Entities/MediaFileStream.cs b/Jellyfin.Data/Entities/MediaFileStream.cs index 723977fdf..8819ddcd0 100644 --- a/Jellyfin.Data/Entities/MediaFileStream.cs +++ b/Jellyfin.Data/Entities/MediaFileStream.cs @@ -81,6 +81,7 @@ namespace Jellyfin.Data.Entities GetId(ref value); return (_Id = value); } + protected set { int oldValue = _Id; @@ -117,6 +118,7 @@ namespace Jellyfin.Data.Entities GetStreamNumber(ref value); return (_StreamNumber = value); } + set { int oldValue = _StreamNumber; diff --git a/Jellyfin.Data/Entities/Metadata.cs b/Jellyfin.Data/Entities/Metadata.cs index 6558642cf..4e5868e75 100644 --- a/Jellyfin.Data/Entities/Metadata.cs +++ b/Jellyfin.Data/Entities/Metadata.cs @@ -76,6 +76,7 @@ namespace Jellyfin.Data.Entities GetId(ref value); return (_Id = value); } + protected set { int oldValue = _Id; @@ -115,6 +116,7 @@ namespace Jellyfin.Data.Entities GetTitle(ref value); return (_Title = value); } + set { string oldValue = _Title; @@ -152,6 +154,7 @@ namespace Jellyfin.Data.Entities GetOriginalTitle(ref value); return (_OriginalTitle = value); } + set { string oldValue = _OriginalTitle; @@ -189,6 +192,7 @@ namespace Jellyfin.Data.Entities GetSortTitle(ref value); return (_SortTitle = value); } + set { string oldValue = _SortTitle; @@ -229,6 +233,7 @@ namespace Jellyfin.Data.Entities GetLanguage(ref value); return (_Language = value); } + set { string oldValue = _Language; @@ -261,6 +266,7 @@ namespace Jellyfin.Data.Entities GetReleaseDate(ref value); return (_ReleaseDate = value); } + set { DateTimeOffset? oldValue = _ReleaseDate; @@ -297,6 +303,7 @@ namespace Jellyfin.Data.Entities GetDateAdded(ref value); return (_DateAdded = value); } + internal set { DateTime oldValue = _DateAdded; @@ -333,6 +340,7 @@ namespace Jellyfin.Data.Entities GetDateModified(ref value); return (_DateModified = value); } + internal set { DateTime oldValue = _DateModified; diff --git a/Jellyfin.Data/Entities/MetadataProvider.cs b/Jellyfin.Data/Entities/MetadataProvider.cs index bf9689709..9b09fc5a6 100644 --- a/Jellyfin.Data/Entities/MetadataProvider.cs +++ b/Jellyfin.Data/Entities/MetadataProvider.cs @@ -77,6 +77,7 @@ namespace Jellyfin.Data.Entities GetId(ref value); return (_Id = value); } + protected set { int oldValue = _Id; @@ -115,6 +116,7 @@ namespace Jellyfin.Data.Entities GetName(ref value); return (_Name = value); } + set { string oldValue = _Name; diff --git a/Jellyfin.Data/Entities/MetadataProviderId.cs b/Jellyfin.Data/Entities/MetadataProviderId.cs index c49c6f42e..bcd2bad54 100644 --- a/Jellyfin.Data/Entities/MetadataProviderId.cs +++ b/Jellyfin.Data/Entities/MetadataProviderId.cs @@ -103,6 +103,7 @@ namespace Jellyfin.Data.Entities GetId(ref value); return (_Id = value); } + protected set { int oldValue = _Id; @@ -141,6 +142,7 @@ namespace Jellyfin.Data.Entities GetProviderId(ref value); return (_ProviderId = value); } + set { string oldValue = _ProviderId; diff --git a/Jellyfin.Data/Entities/MovieMetadata.cs b/Jellyfin.Data/Entities/MovieMetadata.cs index 1f8f1c2a0..6c9156a2d 100644 --- a/Jellyfin.Data/Entities/MovieMetadata.cs +++ b/Jellyfin.Data/Entities/MovieMetadata.cs @@ -90,6 +90,7 @@ namespace Jellyfin.Data.Entities GetOutline(ref value); return (_Outline = value); } + set { string oldValue = _Outline; @@ -127,6 +128,7 @@ namespace Jellyfin.Data.Entities GetPlot(ref value); return (_Plot = value); } + set { string oldValue = _Plot; @@ -164,6 +166,7 @@ namespace Jellyfin.Data.Entities GetTagline(ref value); return (_Tagline = value); } + set { string oldValue = _Tagline; @@ -201,6 +204,7 @@ namespace Jellyfin.Data.Entities GetCountry(ref value); return (_Country = value); } + set { string oldValue = _Country; diff --git a/Jellyfin.Data/Entities/MusicAlbumMetadata.cs b/Jellyfin.Data/Entities/MusicAlbumMetadata.cs index 7743890a6..cf0363b7d 100644 --- a/Jellyfin.Data/Entities/MusicAlbumMetadata.cs +++ b/Jellyfin.Data/Entities/MusicAlbumMetadata.cs @@ -90,6 +90,7 @@ namespace Jellyfin.Data.Entities GetBarcode(ref value); return (_Barcode = value); } + set { string oldValue = _Barcode; @@ -127,6 +128,7 @@ namespace Jellyfin.Data.Entities GetLabelNumber(ref value); return (_LabelNumber = value); } + set { string oldValue = _LabelNumber; @@ -164,6 +166,7 @@ namespace Jellyfin.Data.Entities GetCountry(ref value); return (_Country = value); } + set { string oldValue = _Country; diff --git a/Jellyfin.Data/Entities/Person.cs b/Jellyfin.Data/Entities/Person.cs index f71418819..9cc568e6e 100644 --- a/Jellyfin.Data/Entities/Person.cs +++ b/Jellyfin.Data/Entities/Person.cs @@ -85,6 +85,7 @@ namespace Jellyfin.Data.Entities GetId(ref value); return (_Id = value); } + protected set { int oldValue = _Id; @@ -121,6 +122,7 @@ namespace Jellyfin.Data.Entities GetUrlId(ref value); return (_UrlId = value); } + set { Guid oldValue = _UrlId; @@ -159,6 +161,7 @@ namespace Jellyfin.Data.Entities GetName(ref value); return (_Name = value); } + set { string oldValue = _Name; @@ -196,6 +199,7 @@ namespace Jellyfin.Data.Entities GetSourceId(ref value); return (_SourceId = value); } + set { string oldValue = _SourceId; @@ -232,6 +236,7 @@ namespace Jellyfin.Data.Entities GetDateAdded(ref value); return (_DateAdded = value); } + internal set { DateTime oldValue = _DateAdded; @@ -268,6 +273,7 @@ namespace Jellyfin.Data.Entities GetDateModified(ref value); return (_DateModified = value); } + internal set { DateTime oldValue = _DateModified; diff --git a/Jellyfin.Data/Entities/PersonRole.cs b/Jellyfin.Data/Entities/PersonRole.cs index a3d047115..e0492ea6a 100644 --- a/Jellyfin.Data/Entities/PersonRole.cs +++ b/Jellyfin.Data/Entities/PersonRole.cs @@ -91,6 +91,7 @@ namespace Jellyfin.Data.Entities GetId(ref value); return (_Id = value); } + protected set { int oldValue = _Id; @@ -128,6 +129,7 @@ namespace Jellyfin.Data.Entities GetRole(ref value); return (_Role = value); } + set { string oldValue = _Role; @@ -164,6 +166,7 @@ namespace Jellyfin.Data.Entities GetType(ref value); return (_Type = value); } + set { Enums.PersonRoleType oldValue = _Type; diff --git a/Jellyfin.Data/Entities/Rating.cs b/Jellyfin.Data/Entities/Rating.cs index 0c8b99ca2..490090bfa 100644 --- a/Jellyfin.Data/Entities/Rating.cs +++ b/Jellyfin.Data/Entities/Rating.cs @@ -81,6 +81,7 @@ namespace Jellyfin.Data.Entities GetId(ref value); return (_Id = value); } + protected set { int oldValue = _Id; @@ -117,6 +118,7 @@ namespace Jellyfin.Data.Entities GetValue(ref value); return (_Value = value); } + set { double oldValue = _Value; @@ -149,6 +151,7 @@ namespace Jellyfin.Data.Entities GetVotes(ref value); return (_Votes = value); } + set { int? oldValue = _Votes; diff --git a/Jellyfin.Data/Entities/RatingSource.cs b/Jellyfin.Data/Entities/RatingSource.cs index c829042b5..cf8af2270 100644 --- a/Jellyfin.Data/Entities/RatingSource.cs +++ b/Jellyfin.Data/Entities/RatingSource.cs @@ -88,6 +88,7 @@ namespace Jellyfin.Data.Entities GetId(ref value); return (_Id = value); } + protected set { int oldValue = _Id; @@ -125,6 +126,7 @@ namespace Jellyfin.Data.Entities GetName(ref value); return (_Name = value); } + set { string oldValue = _Name; @@ -161,6 +163,7 @@ namespace Jellyfin.Data.Entities GetMaximumValue(ref value); return (_MaximumValue = value); } + set { double oldValue = _MaximumValue; @@ -197,6 +200,7 @@ namespace Jellyfin.Data.Entities GetMinimumValue(ref value); return (_MinimumValue = value); } + set { double oldValue = _MinimumValue; diff --git a/Jellyfin.Data/Entities/Release.cs b/Jellyfin.Data/Entities/Release.cs index 35fcbb4b7..6be524a0f 100644 --- a/Jellyfin.Data/Entities/Release.cs +++ b/Jellyfin.Data/Entities/Release.cs @@ -113,6 +113,7 @@ namespace Jellyfin.Data.Entities GetId(ref value); return (_Id = value); } + protected set { int oldValue = _Id; @@ -151,6 +152,7 @@ namespace Jellyfin.Data.Entities GetName(ref value); return (_Name = value); } + set { string oldValue = _Name; diff --git a/Jellyfin.Data/Entities/Season.cs b/Jellyfin.Data/Entities/Season.cs index 2a861b660..631adb12c 100644 --- a/Jellyfin.Data/Entities/Season.cs +++ b/Jellyfin.Data/Entities/Season.cs @@ -86,6 +86,7 @@ namespace Jellyfin.Data.Entities GetSeasonNumber(ref value); return (_SeasonNumber = value); } + set { int? oldValue = _SeasonNumber; diff --git a/Jellyfin.Data/Entities/SeasonMetadata.cs b/Jellyfin.Data/Entities/SeasonMetadata.cs index 10320c6bb..2efbf6467 100644 --- a/Jellyfin.Data/Entities/SeasonMetadata.cs +++ b/Jellyfin.Data/Entities/SeasonMetadata.cs @@ -86,6 +86,7 @@ namespace Jellyfin.Data.Entities GetOutline(ref value); return (_Outline = value); } + set { string oldValue = _Outline; diff --git a/Jellyfin.Data/Entities/Series.cs b/Jellyfin.Data/Entities/Series.cs index cf1d6b781..386d3a8ac 100644 --- a/Jellyfin.Data/Entities/Series.cs +++ b/Jellyfin.Data/Entities/Series.cs @@ -67,6 +67,7 @@ namespace Jellyfin.Data.Entities GetAirsDayOfWeek(ref value); return (_AirsDayOfWeek = value); } + set { DayOfWeek? oldValue = _AirsDayOfWeek; @@ -102,6 +103,7 @@ namespace Jellyfin.Data.Entities GetAirsTime(ref value); return (_AirsTime = value); } + set { DateTimeOffset? oldValue = _AirsTime; @@ -134,6 +136,7 @@ namespace Jellyfin.Data.Entities GetFirstAired(ref value); return (_FirstAired = value); } + set { DateTimeOffset? oldValue = _FirstAired; diff --git a/Jellyfin.Data/Entities/SeriesMetadata.cs b/Jellyfin.Data/Entities/SeriesMetadata.cs index bb31c2e4e..f49c5a3b2 100644 --- a/Jellyfin.Data/Entities/SeriesMetadata.cs +++ b/Jellyfin.Data/Entities/SeriesMetadata.cs @@ -90,6 +90,7 @@ namespace Jellyfin.Data.Entities GetOutline(ref value); return (_Outline = value); } + set { string oldValue = _Outline; @@ -127,6 +128,7 @@ namespace Jellyfin.Data.Entities GetPlot(ref value); return (_Plot = value); } + set { string oldValue = _Plot; @@ -164,6 +166,7 @@ namespace Jellyfin.Data.Entities GetTagline(ref value); return (_Tagline = value); } + set { string oldValue = _Tagline; @@ -201,6 +204,7 @@ namespace Jellyfin.Data.Entities GetCountry(ref value); return (_Country = value); } + set { string oldValue = _Country; diff --git a/Jellyfin.Data/Entities/Track.cs b/Jellyfin.Data/Entities/Track.cs index c9e8fd1c3..fc9dfb370 100644 --- a/Jellyfin.Data/Entities/Track.cs +++ b/Jellyfin.Data/Entities/Track.cs @@ -86,6 +86,7 @@ namespace Jellyfin.Data.Entities GetTrackNumber(ref value); return (_TrackNumber = value); } + set { int? oldValue = _TrackNumber; diff --git a/Jellyfin.Server.Implementations/JellyfinDb.cs b/Jellyfin.Server.Implementations/JellyfinDb.cs index f574ebc66..d77cd432b 100644 --- a/Jellyfin.Server.Implementations/JellyfinDb.cs +++ b/Jellyfin.Server.Implementations/JellyfinDb.cs @@ -34,37 +34,69 @@ namespace Jellyfin.Server.Implementations public virtual DbSet<Preference> Preferences { get; set; } public virtual DbSet<User> Users { get; set; } + /*public virtual DbSet<Artwork> Artwork { get; set; } + public virtual DbSet<Book> Books { get; set; } + public virtual DbSet<BookMetadata> BookMetadata { get; set; } + public virtual DbSet<Chapter> Chapters { get; set; } + public virtual DbSet<Collection> Collections { get; set; } + public virtual DbSet<CollectionItem> CollectionItems { get; set; } + public virtual DbSet<Company> Companies { get; set; } + public virtual DbSet<CompanyMetadata> CompanyMetadata { get; set; } + public virtual DbSet<CustomItem> CustomItems { get; set; } + public virtual DbSet<CustomItemMetadata> CustomItemMetadata { get; set; } + public virtual DbSet<Episode> Episodes { get; set; } + public virtual DbSet<EpisodeMetadata> EpisodeMetadata { get; set; } + public virtual DbSet<Genre> Genres { get; set; } + public virtual DbSet<Group> Groups { get; set; } + public virtual DbSet<Library> Libraries { get; set; } + public virtual DbSet<LibraryItem> LibraryItems { get; set; } + public virtual DbSet<LibraryRoot> LibraryRoot { get; set; } + public virtual DbSet<MediaFile> MediaFiles { get; set; } + public virtual DbSet<MediaFileStream> MediaFileStream { get; set; } + public virtual DbSet<Metadata> Metadata { get; set; } + public virtual DbSet<MetadataProvider> MetadataProviders { get; set; } + public virtual DbSet<MetadataProviderId> MetadataProviderIds { get; set; } + public virtual DbSet<Movie> Movies { get; set; } + public virtual DbSet<MovieMetadata> MovieMetadata { get; set; } + public virtual DbSet<MusicAlbum> MusicAlbums { get; set; } + public virtual DbSet<MusicAlbumMetadata> MusicAlbumMetadata { get; set; } + public virtual DbSet<Person> People { get; set; } + public virtual DbSet<PersonRole> PersonRoles { get; set; } + public virtual DbSet<Photo> Photo { get; set; } + public virtual DbSet<PhotoMetadata> PhotoMetadata { get; set; } + public virtual DbSet<ProviderMapping> ProviderMappings { get; set; } + public virtual DbSet<Rating> Ratings { get; set; } /// <summary> @@ -72,12 +104,19 @@ namespace Jellyfin.Server.Implementations /// store review ratings, not age ratings /// </summary> public virtual DbSet<RatingSource> RatingSources { get; set; } + public virtual DbSet<Release> Releases { get; set; } + public virtual DbSet<Season> Seasons { get; set; } + public virtual DbSet<SeasonMetadata> SeasonMetadata { get; set; } + public virtual DbSet<Series> Series { get; set; } + public virtual DbSet<SeriesMetadata> SeriesMetadata { get; set; } + public virtual DbSet<Track> Tracks { get; set; } + public virtual DbSet<TrackMetadata> TrackMetadata { get; set; }*/ /// <inheritdoc/> diff --git a/MediaBrowser.Api/EnvironmentService.cs b/MediaBrowser.Api/EnvironmentService.cs index fddf78465..765774dee 100644 --- a/MediaBrowser.Api/EnvironmentService.cs +++ b/MediaBrowser.Api/EnvironmentService.cs @@ -50,6 +50,7 @@ namespace MediaBrowser.Api public string Path { get; set; } public bool ValidateWriteable { get; set; } + public bool? IsFile { get; set; } } diff --git a/MediaBrowser.Api/FilterService.cs b/MediaBrowser.Api/FilterService.cs index 833a684a5..1b736c77d 100644 --- a/MediaBrowser.Api/FilterService.cs +++ b/MediaBrowser.Api/FilterService.cs @@ -73,11 +73,17 @@ namespace MediaBrowser.Api } public bool? IsAiring { get; set; } + public bool? IsMovie { get; set; } + public bool? IsSports { get; set; } + public bool? IsKids { get; set; } + public bool? IsNews { get; set; } + public bool? IsSeries { get; set; } + public bool? Recursive { get; set; } } diff --git a/MediaBrowser.Api/IHasDtoOptions.cs b/MediaBrowser.Api/IHasDtoOptions.cs index 03d3b3692..33d498e8b 100644 --- a/MediaBrowser.Api/IHasDtoOptions.cs +++ b/MediaBrowser.Api/IHasDtoOptions.cs @@ -3,6 +3,7 @@ namespace MediaBrowser.Api public interface IHasDtoOptions : IHasItemFields { bool? EnableImages { get; set; } + bool? EnableUserData { get; set; } int? ImageTypeLimit { get; set; } diff --git a/MediaBrowser.Api/Library/LibraryService.cs b/MediaBrowser.Api/Library/LibraryService.cs index eb64abb4d..46bc43605 100644 --- a/MediaBrowser.Api/Library/LibraryService.cs +++ b/MediaBrowser.Api/Library/LibraryService.cs @@ -285,29 +285,38 @@ namespace MediaBrowser.Api.Library public class GetLibraryOptionsInfo : IReturn<LibraryOptionsResult> { public string LibraryContentType { get; set; } + public bool IsNewLibrary { get; set; } } public class LibraryOptionInfo { public string Name { get; set; } + public bool DefaultEnabled { get; set; } } public class LibraryOptionsResult { public LibraryOptionInfo[] MetadataSavers { get; set; } + public LibraryOptionInfo[] MetadataReaders { get; set; } + public LibraryOptionInfo[] SubtitleFetchers { get; set; } + public LibraryTypeOptions[] TypeOptions { get; set; } } public class LibraryTypeOptions { public string Type { get; set; } + public LibraryOptionInfo[] MetadataFetchers { get; set; } + public LibraryOptionInfo[] ImageFetchers { get; set; } + public ImageType[] SupportedImageTypes { get; set; } + public ImageOption[] DefaultImageOptions { get; set; } } @@ -1036,6 +1045,7 @@ namespace MediaBrowser.Api.Library { break; } + item = parent; } @@ -1093,6 +1103,7 @@ namespace MediaBrowser.Api.Library { break; } + item = parent; } diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs index b00a5fec8..84141e9ae 100644 --- a/MediaBrowser.Api/LiveTv/LiveTvService.cs +++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs @@ -200,10 +200,15 @@ namespace MediaBrowser.Api.LiveTv public bool? EnableUserData { get; set; } public bool? IsMovie { get; set; } + public bool? IsSeries { get; set; } + public bool? IsKids { get; set; } + public bool? IsSports { get; set; } + public bool? IsNews { get; set; } + public bool? IsLibraryItem { get; set; } public GetRecordings() @@ -348,6 +353,7 @@ namespace MediaBrowser.Api.LiveTv [ApiMember(Name = "HasAired", Description = "Optional. Filter by programs that have completed airing, or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")] public bool? HasAired { get; set; } + public bool? IsAiring { get; set; } [ApiMember(Name = "MaxStartDate", Description = "Optional. The maximum premiere date. Format = ISO", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET,POST")] @@ -407,6 +413,7 @@ namespace MediaBrowser.Api.LiveTv public bool? EnableUserData { get; set; } public string SeriesTimerId { get; set; } + public Guid LibrarySeriesId { get; set; } /// <summary> @@ -601,7 +608,9 @@ namespace MediaBrowser.Api.LiveTv public class AddListingProvider : ListingsProviderInfo, IReturn<ListingsProviderInfo> { public bool ValidateLogin { get; set; } + public bool ValidateListings { get; set; } + public string Pw { get; set; } } @@ -650,15 +659,20 @@ namespace MediaBrowser.Api.LiveTv { [ApiMember(Name = "Id", Description = "Provider id", IsRequired = true, DataType = "string", ParameterType = "query")] public string ProviderId { get; set; } + public string TunerChannelId { get; set; } + public string ProviderChannelId { get; set; } } public class ChannelMappingOptions { public List<TunerChannelMapping> TunerChannels { get; set; } + public List<NameIdPair> ProviderChannels { get; set; } + public NameValuePair[] Mappings { get; set; } + public string ProviderName { get; set; } } @@ -666,6 +680,7 @@ namespace MediaBrowser.Api.LiveTv public class GetLiveStreamFile { public string Id { get; set; } + public string Container { get; set; } } diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index 2eb6198c0..009a957b6 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -303,6 +303,7 @@ namespace MediaBrowser.Api.Playback { StartThrottler(state, transcodingJob); } + Logger.LogDebug("StartFfMpeg() finished successfully"); return transcodingJob; @@ -608,6 +609,7 @@ namespace MediaBrowser.Api.Playback { throw new ArgumentException("Invalid timeseek header"); } + int index = value.IndexOf('-'); value = index == -1 ? value.Substring(Npt.Length) @@ -639,8 +641,10 @@ namespace MediaBrowser.Api.Playback { throw new ArgumentException("Invalid timeseek header"); } + timeFactor /= 60; } + return TimeSpan.FromSeconds(secondsSum).Ticks; } diff --git a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs b/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs index c2d49a93b..5a2bf2ea3 100644 --- a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs +++ b/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs @@ -146,6 +146,7 @@ namespace MediaBrowser.Api.Playback.Hls { ApiEntryPoint.Instance.OnTranscodeEndRequest(job); } + return ResultFactory.GetResult(GetLivePlaylistText(playlist, state.SegmentLength), MimeTypes.GetMimeType("playlist.m3u8"), new Dictionary<string, string>()); } diff --git a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs index c0dfcf4c1..fe5f980b1 100644 --- a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs +++ b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs @@ -234,6 +234,7 @@ namespace MediaBrowser.Api.Playback.Hls Logger.LogDebug("Starting transcoding because segmentGap is {0} and max allowed gap is {1}. requestedIndex={2}", requestedIndex - currentTranscodingIndex.Value, segmentGapRequiringTranscodingChange, requestedIndex); startTranscoding = true; } + if (startTranscoding) { // If the playlist doesn't already exist, startup ffmpeg @@ -518,6 +519,7 @@ namespace MediaBrowser.Api.Playback.Hls { Logger.LogDebug("serving {0} as it's on disk and transcoding stopped", segmentPath); } + cancellationToken.ThrowIfCancellationRequested(); } else diff --git a/MediaBrowser.Api/Playback/MediaInfoService.cs b/MediaBrowser.Api/Playback/MediaInfoService.cs index 2dc62fda7..b7ca1a031 100644 --- a/MediaBrowser.Api/Playback/MediaInfoService.cs +++ b/MediaBrowser.Api/Playback/MediaInfoService.cs @@ -551,10 +551,12 @@ namespace MediaBrowser.Api.Playback { mediaSource.TranscodingUrl += "&allowVideoStreamCopy=false"; } + if (!allowAudioStreamCopy) { mediaSource.TranscodingUrl += "&allowAudioStreamCopy=false"; } + mediaSource.TranscodingContainer = streamInfo.Container; mediaSource.TranscodingSubProtocol = streamInfo.SubProtocol; } diff --git a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs index 43cde440c..85c7e0e7d 100644 --- a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs +++ b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs @@ -88,14 +88,17 @@ namespace MediaBrowser.Api.Playback.Progressive { return ".ts"; } + if (string.Equals(videoCodec, "theora", StringComparison.OrdinalIgnoreCase)) { return ".ogv"; } + if (string.Equals(videoCodec, "vpx", StringComparison.OrdinalIgnoreCase)) { return ".webm"; } + if (string.Equals(videoCodec, "wmv", StringComparison.OrdinalIgnoreCase)) { return ".asf"; @@ -111,14 +114,17 @@ namespace MediaBrowser.Api.Playback.Progressive { return ".aac"; } + if (string.Equals("mp3", audioCodec, StringComparison.OrdinalIgnoreCase)) { return ".mp3"; } + if (string.Equals("vorbis", audioCodec, StringComparison.OrdinalIgnoreCase)) { return ".ogg"; } + if (string.Equals("wma", audioCodec, StringComparison.OrdinalIgnoreCase)) { return ".wma"; diff --git a/MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs b/MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs index ffc5e1554..b70fff128 100644 --- a/MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs +++ b/MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs @@ -23,6 +23,7 @@ namespace MediaBrowser.Api.Playback.Progressive private long _bytesWritten = 0; public long StartPosition { get; set; } + public bool AllowEndOfFile = true; private readonly IDirectStreamProvider _directStreamProvider; @@ -105,6 +106,7 @@ namespace MediaBrowser.Api.Playback.Progressive { eofCount++; } + await Task.Delay(100, cancellationToken).ConfigureAwait(false); } else diff --git a/MediaBrowser.Api/Playback/StreamRequest.cs b/MediaBrowser.Api/Playback/StreamRequest.cs index 9ba8eda91..397898a7e 100644 --- a/MediaBrowser.Api/Playback/StreamRequest.cs +++ b/MediaBrowser.Api/Playback/StreamRequest.cs @@ -12,11 +12,15 @@ namespace MediaBrowser.Api.Playback public string DeviceProfileId { get; set; } public string Params { get; set; } + public string PlaySessionId { get; set; } + public string Tag { get; set; } + public string SegmentContainer { get; set; } public int? SegmentLength { get; set; } + public int? MinSegments { get; set; } } diff --git a/MediaBrowser.Api/Playback/UniversalAudioService.cs b/MediaBrowser.Api/Playback/UniversalAudioService.cs index b2d101a5b..d5d78cf37 100644 --- a/MediaBrowser.Api/Playback/UniversalAudioService.cs +++ b/MediaBrowser.Api/Playback/UniversalAudioService.cs @@ -37,10 +37,13 @@ namespace MediaBrowser.Api.Playback public string DeviceId { get; set; } public Guid UserId { get; set; } + public string AudioCodec { get; set; } + public string Container { get; set; } public int? MaxAudioChannels { get; set; } + public int? TranscodingAudioChannels { get; set; } public long? MaxStreamingBitrate { get; set; } @@ -49,12 +52,17 @@ namespace MediaBrowser.Api.Playback public long? StartTimeTicks { get; set; } public string TranscodingContainer { get; set; } + public string TranscodingProtocol { get; set; } + public int? MaxAudioSampleRate { get; set; } + public int? MaxAudioBitDepth { get; set; } public bool EnableRedirection { get; set; } + public bool EnableRemoteMedia { get; set; } + public bool BreakOnNonKeyFrames { get; set; } public BaseUniversalRequest() @@ -114,16 +122,27 @@ namespace MediaBrowser.Api.Playback } protected IHttpClient HttpClient { get; private set; } + protected IUserManager UserManager { get; private set; } + protected ILibraryManager LibraryManager { get; private set; } + protected IIsoManager IsoManager { get; private set; } + protected IMediaEncoder MediaEncoder { get; private set; } + protected IFileSystem FileSystem { get; private set; } + protected IDlnaManager DlnaManager { get; private set; } + protected IDeviceManager DeviceManager { get; private set; } + protected IMediaSourceManager MediaSourceManager { get; private set; } + protected IJsonSerializer JsonSerializer { get; private set; } + protected IAuthorizationContext AuthorizationContext { get; private set; } + protected INetworkManager NetworkManager { get; private set; } public Task<object> Get(GetUniversalAudioStream request) @@ -328,6 +347,7 @@ namespace MediaBrowser.Api.Playback { return await service.Head(newRequest).ConfigureAwait(false); } + return await service.Get(newRequest).ConfigureAwait(false); } else diff --git a/MediaBrowser.Api/PluginService.cs b/MediaBrowser.Api/PluginService.cs index fd1075727..1d092a5d4 100644 --- a/MediaBrowser.Api/PluginService.cs +++ b/MediaBrowser.Api/PluginService.cs @@ -115,24 +115,33 @@ namespace MediaBrowser.Api public class RegistrationInfo { public string Name { get; set; } + public DateTime ExpirationDate { get; set; } + public bool IsTrial { get; set; } + public bool IsRegistered { get; set; } } public class MBRegistrationRecord { public DateTime ExpirationDate { get; set; } + public bool IsRegistered { get; set; } + public bool RegChecked { get; set; } + public bool RegError { get; set; } + public bool TrialVersion { get; set; } + public bool IsValid { get; set; } } public class PluginSecurityInfo { public string SupporterKey { get; set; } + public bool IsMBSupporter { get; set; } } /// <summary> diff --git a/MediaBrowser.Api/SimilarItemsHelper.cs b/MediaBrowser.Api/SimilarItemsHelper.cs index 90c324ff3..c4df0a7ed 100644 --- a/MediaBrowser.Api/SimilarItemsHelper.cs +++ b/MediaBrowser.Api/SimilarItemsHelper.cs @@ -179,18 +179,22 @@ namespace MediaBrowser.Api { return 5; } + if (string.Equals(i.Type, PersonType.Actor, StringComparison.OrdinalIgnoreCase) || string.Equals(i.Role, PersonType.Actor, StringComparison.OrdinalIgnoreCase)) { return 3; } + if (string.Equals(i.Type, PersonType.Composer, StringComparison.OrdinalIgnoreCase) || string.Equals(i.Role, PersonType.Composer, StringComparison.OrdinalIgnoreCase)) { return 3; } + if (string.Equals(i.Type, PersonType.GuestStar, StringComparison.OrdinalIgnoreCase) || string.Equals(i.Role, PersonType.GuestStar, StringComparison.OrdinalIgnoreCase)) { return 3; } + if (string.Equals(i.Type, PersonType.Writer, StringComparison.OrdinalIgnoreCase) || string.Equals(i.Role, PersonType.Writer, StringComparison.OrdinalIgnoreCase)) { return 2; diff --git a/MediaBrowser.Api/Subtitles/SubtitleService.cs b/MediaBrowser.Api/Subtitles/SubtitleService.cs index f2968c6b5..a70da8e56 100644 --- a/MediaBrowser.Api/Subtitles/SubtitleService.cs +++ b/MediaBrowser.Api/Subtitles/SubtitleService.cs @@ -97,6 +97,7 @@ namespace MediaBrowser.Api.Subtitles [ApiMember(Name = "CopyTimestamps", Description = "CopyTimestamps", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")] public bool CopyTimestamps { get; set; } + public bool AddVttTimeMap { get; set; } } @@ -214,6 +215,7 @@ namespace MediaBrowser.Api.Subtitles { request.Format = "json"; } + if (string.IsNullOrEmpty(request.Format)) { var item = (Video)_libraryManager.GetItemById(request.Id); diff --git a/MediaBrowser.Api/SuggestionsService.cs b/MediaBrowser.Api/SuggestionsService.cs index 32d3bde5c..17afa8e79 100644 --- a/MediaBrowser.Api/SuggestionsService.cs +++ b/MediaBrowser.Api/SuggestionsService.cs @@ -18,10 +18,15 @@ namespace MediaBrowser.Api public class GetSuggestedItems : IReturn<QueryResult<BaseItemDto>> { public string MediaType { get; set; } + public string Type { get; set; } + public Guid UserId { get; set; } + public bool EnableTotalRecordCount { get; set; } + public int? StartIndex { get; set; } + public int? Limit { get; set; } public string[] GetMediaTypes() diff --git a/MediaBrowser.Api/TranscodingJob.cs b/MediaBrowser.Api/TranscodingJob.cs index 8c24e3ce1..bfc311a27 100644 --- a/MediaBrowser.Api/TranscodingJob.cs +++ b/MediaBrowser.Api/TranscodingJob.cs @@ -32,6 +32,7 @@ namespace MediaBrowser.Api /// </summary> /// <value>The path.</value> public MediaSourceInfo MediaSource { get; set; } + public string Path { get; set; } /// <summary> /// Gets or sets the type. @@ -43,6 +44,7 @@ namespace MediaBrowser.Api /// </summary> /// <value>The process.</value> public Process Process { get; set; } + public ILogger Logger { get; private set; } /// <summary> /// Gets or sets the active request count. @@ -62,18 +64,23 @@ namespace MediaBrowser.Api public object ProcessLock = new object(); public bool HasExited { get; set; } + public bool IsUserPaused { get; set; } public string Id { get; set; } public float? Framerate { get; set; } + public double? CompletionPercentage { get; set; } public long? BytesDownloaded { get; set; } + public long? BytesTranscoded { get; set; } + public int? BitRate { get; set; } public long? TranscodingPositionTicks { get; set; } + public long? DownloadPositionTicks { get; set; } public TranscodingThrottler TranscodingThrottler { get; set; } @@ -81,6 +88,7 @@ namespace MediaBrowser.Api private readonly object _timerLock = new object(); public DateTime LastPingDate { get; set; } + public int PingTimeout { get; set; } public TranscodingJob(ILogger logger) diff --git a/MediaBrowser.Api/TvShowsService.cs b/MediaBrowser.Api/TvShowsService.cs index 23062b67b..3e8daef03 100644 --- a/MediaBrowser.Api/TvShowsService.cs +++ b/MediaBrowser.Api/TvShowsService.cs @@ -73,6 +73,7 @@ namespace MediaBrowser.Api [ApiMember(Name = "EnableUserData", Description = "Optional, include user data", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")] public bool? EnableUserData { get; set; } + public bool EnableTotalRecordCount { get; set; } public GetNextUpEpisodes() diff --git a/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs b/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs index 4802849f4..3d9db90bd 100644 --- a/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs +++ b/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs @@ -210,6 +210,7 @@ namespace MediaBrowser.Api.UserLibrary { SetItemCounts(dto, i.Item2); } + return dto; }); diff --git a/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs b/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs index 7561b5c89..d9b52b10e 100644 --- a/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs +++ b/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs @@ -322,8 +322,11 @@ namespace MediaBrowser.Api.UserLibrary public bool? CollapseBoxSetItems { get; set; } public int? MinWidth { get; set; } + public int? MinHeight { get; set; } + public int? MaxWidth { get; set; } + public int? MaxHeight { get; set; } /// <summary> diff --git a/MediaBrowser.Api/UserLibrary/UserViewsService.cs b/MediaBrowser.Api/UserLibrary/UserViewsService.cs index 73d5ec6de..6f1620ddd 100644 --- a/MediaBrowser.Api/UserLibrary/UserViewsService.cs +++ b/MediaBrowser.Api/UserLibrary/UserViewsService.cs @@ -27,6 +27,7 @@ namespace MediaBrowser.Api.UserLibrary [ApiMember(Name = "IncludeExternalContent", Description = "Whether or not to include external views such as channels or live tv", IsRequired = true, DataType = "boolean", ParameterType = "query", Verb = "GET")] public bool? IncludeExternalContent { get; set; } + public bool IncludeHidden { get; set; } public string PresetViews { get; set; } @@ -80,6 +81,7 @@ namespace MediaBrowser.Api.UserLibrary { query.IncludeExternalContent = request.IncludeExternalContent.Value; } + query.IncludeHidden = request.IncludeHidden; if (!string.IsNullOrWhiteSpace(request.PresetViews)) @@ -140,6 +142,7 @@ namespace MediaBrowser.Api.UserLibrary class SpecialViewOption { public string Name { get; set; } + public string Id { get; set; } } } diff --git a/MediaBrowser.Controller/Authentication/IAuthenticationProvider.cs b/MediaBrowser.Controller/Authentication/IAuthenticationProvider.cs index c0324a384..b10233c71 100644 --- a/MediaBrowser.Controller/Authentication/IAuthenticationProvider.cs +++ b/MediaBrowser.Controller/Authentication/IAuthenticationProvider.cs @@ -7,7 +7,9 @@ namespace MediaBrowser.Controller.Authentication public interface IAuthenticationProvider { string Name { get; } + bool IsEnabled { get; } + Task<ProviderAuthenticationResult> Authenticate(string username, string password); bool HasPassword(User user); Task ChangePassword(User user, string newPassword); @@ -28,6 +30,7 @@ namespace MediaBrowser.Controller.Authentication public class ProviderAuthenticationResult { public string Username { get; set; } + public string DisplayName { get; set; } } } diff --git a/MediaBrowser.Controller/Authentication/IPasswordResetProvider.cs b/MediaBrowser.Controller/Authentication/IPasswordResetProvider.cs index d9b814f69..693df80ac 100644 --- a/MediaBrowser.Controller/Authentication/IPasswordResetProvider.cs +++ b/MediaBrowser.Controller/Authentication/IPasswordResetProvider.cs @@ -8,7 +8,9 @@ namespace MediaBrowser.Controller.Authentication public interface IPasswordResetProvider { string Name { get; } + bool IsEnabled { get; } + Task<ForgotPasswordResult> StartForgotPasswordProcess(User user, bool isInNetwork); Task<PinRedeemResult> RedeemPasswordResetPin(string pin); } @@ -16,6 +18,7 @@ namespace MediaBrowser.Controller.Authentication public class PasswordPinCreationResult { public string PinFile { get; set; } + public DateTime ExpirationDate { get; set; } } } diff --git a/MediaBrowser.Controller/Channels/ChannelItemInfo.cs b/MediaBrowser.Controller/Channels/ChannelItemInfo.cs index aff68883b..00d4d9cb3 100644 --- a/MediaBrowser.Controller/Channels/ChannelItemInfo.cs +++ b/MediaBrowser.Controller/Channels/ChannelItemInfo.cs @@ -24,7 +24,9 @@ namespace MediaBrowser.Controller.Channels public string Overview { get; set; } public List<string> Genres { get; set; } + public List<string> Studios { get; set; } + public List<string> Tags { get; set; } public List<PersonInfo> People { get; set; } @@ -34,26 +36,33 @@ namespace MediaBrowser.Controller.Channels public long? RunTimeTicks { get; set; } public string ImageUrl { get; set; } + public string OriginalTitle { get; set; } public ChannelMediaType MediaType { get; set; } + public ChannelFolderType FolderType { get; set; } public ChannelMediaContentType ContentType { get; set; } + public ExtraType ExtraType { get; set; } + public List<TrailerType> TrailerTypes { get; set; } public Dictionary<string, string> ProviderIds { get; set; } public DateTime? PremiereDate { get; set; } + public int? ProductionYear { get; set; } public DateTime? DateCreated { get; set; } public DateTime? StartDate { get; set; } + public DateTime? EndDate { get; set; } public int? IndexNumber { get; set; } + public int? ParentIndexNumber { get; set; } public List<MediaSourceInfo> MediaSources { get; set; } @@ -63,7 +72,9 @@ namespace MediaBrowser.Controller.Channels public List<string> Artists { get; set; } public List<string> AlbumArtists { get; set; } + public bool IsLiveStream { get; set; } + public string Etag { get; set; } public ChannelItemInfo() diff --git a/MediaBrowser.Controller/Collections/CollectionCreationOptions.cs b/MediaBrowser.Controller/Collections/CollectionCreationOptions.cs index 51fe4ce29..1e7549d2b 100644 --- a/MediaBrowser.Controller/Collections/CollectionCreationOptions.cs +++ b/MediaBrowser.Controller/Collections/CollectionCreationOptions.cs @@ -15,6 +15,7 @@ namespace MediaBrowser.Controller.Collections public Dictionary<string, string> ProviderIds { get; set; } public string[] ItemIdList { get; set; } + public Guid[] UserIds { get; set; } public CollectionCreationOptions() diff --git a/MediaBrowser.Controller/Drawing/ImageHelper.cs b/MediaBrowser.Controller/Drawing/ImageHelper.cs index c87a248b5..e1273fe7f 100644 --- a/MediaBrowser.Controller/Drawing/ImageHelper.cs +++ b/MediaBrowser.Controller/Drawing/ImageHelper.cs @@ -16,6 +16,7 @@ namespace MediaBrowser.Controller.Drawing return newSize; } + return GetSizeEstimate(options); } diff --git a/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs b/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs index 870e0278e..31d2c1bd4 100644 --- a/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs +++ b/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs @@ -15,6 +15,7 @@ namespace MediaBrowser.Controller.Drawing } public Guid ItemId { get; set; } + public BaseItem Item { get; set; } public ItemImageInfo Image { get; set; } @@ -38,12 +39,15 @@ namespace MediaBrowser.Controller.Drawing public bool AddPlayedIndicator { get; set; } public int? UnplayedCount { get; set; } + public int? Blur { get; set; } public double PercentPlayed { get; set; } public string BackgroundColor { get; set; } + public string ForegroundLayer { get; set; } + public bool RequiresAutoOrientation { get; set; } private bool HasDefaultOptions(string originalImagePath) @@ -73,14 +77,17 @@ namespace MediaBrowser.Controller.Drawing { return false; } + if (Height.HasValue && !sizeValue.Height.Equals(Height.Value)) { return false; } + if (MaxWidth.HasValue && sizeValue.Width > MaxWidth.Value) { return false; } + if (MaxHeight.HasValue && sizeValue.Height > MaxHeight.Value) { return false; diff --git a/MediaBrowser.Controller/Dto/DtoOptions.cs b/MediaBrowser.Controller/Dto/DtoOptions.cs index cdaf95f5c..cf301f1e4 100644 --- a/MediaBrowser.Controller/Dto/DtoOptions.cs +++ b/MediaBrowser.Controller/Dto/DtoOptions.cs @@ -14,11 +14,17 @@ namespace MediaBrowser.Controller.Dto }; public ItemFields[] Fields { get; set; } + public ImageType[] ImageTypes { get; set; } + public int ImageTypeLimit { get; set; } + public bool EnableImages { get; set; } + public bool AddProgramRecordingInfo { get; set; } + public bool EnableUserData { get; set; } + public bool AddCurrentProgram { get; set; } public DtoOptions() diff --git a/MediaBrowser.Controller/Entities/AggregateFolder.cs b/MediaBrowser.Controller/Entities/AggregateFolder.cs index 54540e892..fd0dc31cc 100644 --- a/MediaBrowser.Controller/Entities/AggregateFolder.cs +++ b/MediaBrowser.Controller/Entities/AggregateFolder.cs @@ -195,6 +195,7 @@ namespace MediaBrowser.Controller.Entities return child; } } + return null; } } diff --git a/MediaBrowser.Controller/Entities/Audio/Audio.cs b/MediaBrowser.Controller/Entities/Audio/Audio.cs index a8ea2157d..7d10e6831 100644 --- a/MediaBrowser.Controller/Entities/Audio/Audio.cs +++ b/MediaBrowser.Controller/Entities/Audio/Audio.cs @@ -93,6 +93,7 @@ namespace MediaBrowser.Controller.Entities.Audio { songKey = ParentIndexNumber.Value.ToString("0000") + "-" + songKey; } + songKey += Name; if (!string.IsNullOrEmpty(Album)) @@ -117,6 +118,7 @@ namespace MediaBrowser.Controller.Entities.Audio { return UnratedItem.Music; } + return base.GetBlockUnratedType(); } diff --git a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs index f7b2f9549..c3514e0f6 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs @@ -56,6 +56,7 @@ namespace MediaBrowser.Controller.Entities.Audio { return LibraryManager.GetArtist(name, options); } + return null; } diff --git a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs index 63db3cfab..cbba1914a 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs @@ -135,6 +135,7 @@ namespace MediaBrowser.Controller.Entities.Audio list.Add("Artist-" + (item.Name ?? string.Empty).RemoveDiacritics()); return list; } + public override string CreatePresentationUniqueKey() { return "Artist-" + (Name ?? string.Empty).RemoveDiacritics(); diff --git a/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs b/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs index 537e9630b..61f35b942 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs @@ -18,6 +18,7 @@ namespace MediaBrowser.Controller.Entities.Audio list.Insert(0, GetType().Name + "-" + (Name ?? string.Empty).RemoveDiacritics()); return list; } + public override string CreatePresentationUniqueKey() { return GetUserDataKeys()[0]; @@ -94,6 +95,7 @@ namespace MediaBrowser.Controller.Entities.Audio Logger.LogDebug("{0} path has changed from {1} to {2}", GetType().Name, Path, newPath); return true; } + return base.RequiresRefresh(); } diff --git a/MediaBrowser.Controller/Entities/AudioBook.cs b/MediaBrowser.Controller/Entities/AudioBook.cs index 4adaf4c6e..11ff8a257 100644 --- a/MediaBrowser.Controller/Entities/AudioBook.cs +++ b/MediaBrowser.Controller/Entities/AudioBook.cs @@ -24,10 +24,12 @@ namespace MediaBrowser.Controller.Entities { return SeriesName; } + public string FindSeriesName() { return SeriesName; } + public string FindSeriesPresentationUniqueKey() { return SeriesPresentationUniqueKey; diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index f2de1f2b1..d356cdfd6 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -108,6 +108,7 @@ namespace MediaBrowser.Controller.Entities public string PreferredMetadataLanguage { get; set; } public long? Size { get; set; } + public string Container { get; set; } [JsonIgnore] @@ -448,6 +449,7 @@ namespace MediaBrowser.Controller.Entities // hack alert return true; } + if (SourceType == SourceType.Channel) { // hack alert @@ -559,15 +561,25 @@ namespace MediaBrowser.Controller.Entities /// The logger /// </summary> public static ILoggerFactory LoggerFactory { get; set; } + public static ILogger<BaseItem> Logger { get; set; } + public static ILibraryManager LibraryManager { get; set; } + public static IServerConfigurationManager ConfigurationManager { get; set; } + public static IProviderManager ProviderManager { get; set; } + public static ILocalizationManager LocalizationManager { get; set; } + public static IItemRepository ItemRepository { get; set; } + public static IFileSystem FileSystem { get; set; } + public static IUserDataManager UserDataManager { get; set; } + public static IChannelManager ChannelManager { get; set; } + public static IMediaSourceManager MediaSourceManager { get; set; } /// <summary> @@ -644,8 +656,10 @@ namespace MediaBrowser.Controller.Entities _sortName = CreateSortName(); } } + return _sortName; } + set => _sortName = value; } @@ -814,6 +828,7 @@ namespace MediaBrowser.Controller.Entities return item; } } + return null; } @@ -837,6 +852,7 @@ namespace MediaBrowser.Controller.Entities { return null; } + return LibraryManager.GetItemById(id); } } diff --git a/MediaBrowser.Controller/Entities/CollectionFolder.cs b/MediaBrowser.Controller/Entities/CollectionFolder.cs index e5adf88d1..5023c1603 100644 --- a/MediaBrowser.Controller/Entities/CollectionFolder.cs +++ b/MediaBrowser.Controller/Entities/CollectionFolder.cs @@ -23,7 +23,9 @@ namespace MediaBrowser.Controller.Entities public class CollectionFolder : Folder, ICollectionFolder { public static IXmlSerializer XmlSerializer { get; set; } + public static IJsonSerializer JsonSerializer { get; set; } + public static IServerApplicationHost ApplicationHost { get; set; } public CollectionFolder() @@ -155,6 +157,7 @@ namespace MediaBrowser.Controller.Entities } public string[] PhysicalLocationsList { get; set; } + public Guid[] PhysicalFolderIds { get; set; } protected override FileSystemMetadata[] GetFileSystemChildren(IDirectoryService directoryService) diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index 3a01b4379..77551702a 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -126,10 +126,12 @@ namespace MediaBrowser.Controller.Entities { return false; } + if (this is UserView) { return false; } + return true; } @@ -156,6 +158,7 @@ namespace MediaBrowser.Controller.Entities { item.DateCreated = DateTime.UtcNow; } + if (item.DateModified == DateTime.MinValue) { item.DateModified = DateTime.UtcNow; @@ -501,6 +504,7 @@ namespace MediaBrowser.Controller.Entities { await series.RefreshMetadata(refreshOptions, cancellationToken).ConfigureAwait(false); } + await container.RefreshAllMetadata(refreshOptions, progress, cancellationToken).ConfigureAwait(false); } @@ -939,6 +943,7 @@ namespace MediaBrowser.Controller.Entities { items = items.Where(i => string.Compare(query.NameStartsWithOrGreater, i.SortName, StringComparison.CurrentCultureIgnoreCase) < 1); } + if (!string.IsNullOrEmpty(query.NameStartsWith)) { items = items.Where(i => i.SortName.StartsWith(query.NameStartsWith, StringComparison.OrdinalIgnoreCase)); @@ -989,18 +994,22 @@ namespace MediaBrowser.Controller.Entities { return false; } + if (queryParent is Series) { return false; } + if (queryParent is Season) { return false; } + if (queryParent is MusicAlbum) { return false; } + if (queryParent is MusicArtist) { return false; @@ -1030,22 +1039,27 @@ namespace MediaBrowser.Controller.Entities { return false; } + if (request.IsFavoriteOrLiked.HasValue) { return false; } + if (request.IsLiked.HasValue) { return false; } + if (request.IsPlayed.HasValue) { return false; } + if (request.IsResumable.HasValue) { return false; } + if (request.IsFolder.HasValue) { return false; @@ -1391,6 +1405,7 @@ namespace MediaBrowser.Controller.Entities list.Add(child); } } + return list; } @@ -1413,6 +1428,7 @@ namespace MediaBrowser.Controller.Entities return true; } } + return false; } @@ -1665,22 +1681,27 @@ namespace MediaBrowser.Controller.Entities { return false; } + if (this is UserView) { return false; } + if (this is UserRootFolder) { return false; } + if (this is Channel) { return false; } + if (SourceType != SourceType.Library) { return false; } + var iItemByName = this as IItemByName; if (iItemByName != null) { diff --git a/MediaBrowser.Controller/Entities/Genre.cs b/MediaBrowser.Controller/Entities/Genre.cs index 773c7df34..55634aa5e 100644 --- a/MediaBrowser.Controller/Entities/Genre.cs +++ b/MediaBrowser.Controller/Entities/Genre.cs @@ -19,6 +19,7 @@ namespace MediaBrowser.Controller.Entities list.Insert(0, GetType().Name + "-" + (Name ?? string.Empty).RemoveDiacritics()); return list; } + public override string CreatePresentationUniqueKey() { return GetUserDataKeys()[0]; @@ -92,6 +93,7 @@ namespace MediaBrowser.Controller.Entities Logger.LogDebug("{0} path has changed from {1} to {2}", GetType().Name, Path, newPath); return true; } + return base.RequiresRefresh(); } diff --git a/MediaBrowser.Controller/Entities/IHasMediaSources.cs b/MediaBrowser.Controller/Entities/IHasMediaSources.cs index 4635b9062..213c0a794 100644 --- a/MediaBrowser.Controller/Entities/IHasMediaSources.cs +++ b/MediaBrowser.Controller/Entities/IHasMediaSources.cs @@ -13,7 +13,9 @@ namespace MediaBrowser.Controller.Entities List<MediaSourceInfo> GetMediaSources(bool enablePathSubstitution); List<MediaStream> GetMediaStreams(); Guid Id { get; set; } + long? RunTimeTicks { get; set; } + string Path { get; } } } diff --git a/MediaBrowser.Controller/Entities/IHasProgramAttributes.cs b/MediaBrowser.Controller/Entities/IHasProgramAttributes.cs index 777b40828..fd1c19c97 100644 --- a/MediaBrowser.Controller/Entities/IHasProgramAttributes.cs +++ b/MediaBrowser.Controller/Entities/IHasProgramAttributes.cs @@ -5,13 +5,21 @@ namespace MediaBrowser.Controller.Entities public interface IHasProgramAttributes { bool IsMovie { get; set; } + bool IsSports { get; } + bool IsNews { get; } + bool IsKids { get; } + bool IsRepeat { get; set; } + bool IsSeries { get; set; } + ProgramAudio? Audio { get; set; } + string EpisodeTitle { get; set; } + string ServiceName { get; set; } } } diff --git a/MediaBrowser.Controller/Entities/IHasSeries.cs b/MediaBrowser.Controller/Entities/IHasSeries.cs index 7da53f730..475a2ab85 100644 --- a/MediaBrowser.Controller/Entities/IHasSeries.cs +++ b/MediaBrowser.Controller/Entities/IHasSeries.cs @@ -9,11 +9,14 @@ namespace MediaBrowser.Controller.Entities /// </summary> /// <value>The name of the series.</value> string SeriesName { get; set; } + string FindSeriesName(); string FindSeriesSortName(); Guid SeriesId { get; set; } + Guid FindSeriesId(); string SeriesPresentationUniqueKey { get; set; } + string FindSeriesPresentationUniqueKey(); } } diff --git a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs index 496bee857..466cda67c 100644 --- a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs +++ b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs @@ -21,100 +21,167 @@ namespace MediaBrowser.Controller.Entities public BaseItem SimilarTo { get; set; } public bool? IsFolder { get; set; } + public bool? IsFavorite { get; set; } + public bool? IsFavoriteOrLiked { get; set; } + public bool? IsLiked { get; set; } + public bool? IsPlayed { get; set; } + public bool? IsResumable { get; set; } + public bool? IncludeItemsByName { get; set; } public string[] MediaTypes { get; set; } + public string[] IncludeItemTypes { get; set; } + public string[] ExcludeItemTypes { get; set; } + public string[] ExcludeTags { get; set; } + public string[] ExcludeInheritedTags { get; set; } + public string[] Genres { get; set; } public bool? IsSpecialSeason { get; set; } + public bool? IsMissing { get; set; } + public bool? IsUnaired { get; set; } + public bool? CollapseBoxSetItems { get; set; } public string NameStartsWithOrGreater { get; set; } + public string NameStartsWith { get; set; } + public string NameLessThan { get; set; } + public string NameContains { get; set; } + public string MinSortName { get; set; } public string PresentationUniqueKey { get; set; } + public string Path { get; set; } + public string Name { get; set; } public string Person { get; set; } + public Guid[] PersonIds { get; set; } + public Guid[] ItemIds { get; set; } + public Guid[] ExcludeItemIds { get; set; } + public string AdjacentTo { get; set; } + public string[] PersonTypes { get; set; } public bool? Is3D { get; set; } + public bool? IsHD { get; set; } + public bool? IsLocked { get; set; } + public bool? IsPlaceHolder { get; set; } public bool? HasImdbId { get; set; } + public bool? HasOverview { get; set; } + public bool? HasTmdbId { get; set; } + public bool? HasOfficialRating { get; set; } + public bool? HasTvdbId { get; set; } + public bool? HasThemeSong { get; set; } + public bool? HasThemeVideo { get; set; } + public bool? HasSubtitles { get; set; } + public bool? HasSpecialFeature { get; set; } + public bool? HasTrailer { get; set; } + public bool? HasParentalRating { get; set; } public Guid[] StudioIds { get; set; } + public Guid[] GenreIds { get; set; } + public ImageType[] ImageTypes { get; set; } + public VideoType[] VideoTypes { get; set; } + public UnratedItem[] BlockUnratedItems { get; set; } + public int[] Years { get; set; } + public string[] Tags { get; set; } + public string[] OfficialRatings { get; set; } public DateTime? MinPremiereDate { get; set; } + public DateTime? MaxPremiereDate { get; set; } + public DateTime? MinStartDate { get; set; } + public DateTime? MaxStartDate { get; set; } + public DateTime? MinEndDate { get; set; } + public DateTime? MaxEndDate { get; set; } + public bool? IsAiring { get; set; } public bool? IsMovie { get; set; } + public bool? IsSports { get; set; } + public bool? IsKids { get; set; } + public bool? IsNews { get; set; } + public bool? IsSeries { get; set; } + public int? MinIndexNumber { get; set; } + public int? AiredDuringSeason { get; set; } + public double? MinCriticRating { get; set; } + public double? MinCommunityRating { get; set; } public Guid[] ChannelIds { get; set; } public int? ParentIndexNumber { get; set; } + public int? ParentIndexNumberNotEquals { get; set; } + public int? IndexNumber { get; set; } + public int? MinParentalRating { get; set; } + public int? MaxParentalRating { get; set; } public bool? HasDeadParentId { get; set; } + public bool? IsVirtualItem { get; set; } public Guid ParentId { get; set; } + public string ParentType { get; set; } + public Guid[] AncestorIds { get; set; } + public Guid[] TopParentIds { get; set; } public BaseItem Parent @@ -135,41 +202,65 @@ namespace MediaBrowser.Controller.Entities } public string[] PresetViews { get; set; } + public TrailerType[] TrailerTypes { get; set; } + public SourceType[] SourceTypes { get; set; } public SeriesStatus[] SeriesStatuses { get; set; } + public string ExternalSeriesId { get; set; } + public string ExternalId { get; set; } public Guid[] AlbumIds { get; set; } + public Guid[] ArtistIds { get; set; } + public Guid[] ExcludeArtistIds { get; set; } + public string AncestorWithPresentationUniqueKey { get; set; } + public string SeriesPresentationUniqueKey { get; set; } public bool GroupByPresentationUniqueKey { get; set; } + public bool GroupBySeriesPresentationUniqueKey { get; set; } + public bool EnableTotalRecordCount { get; set; } + public bool ForceDirect { get; set; } + public Dictionary<string, string> ExcludeProviderIds { get; set; } + public bool EnableGroupByMetadataKey { get; set; } + public bool? HasChapterImages { get; set; } public IReadOnlyList<(string, SortOrder)> OrderBy { get; set; } public DateTime? MinDateCreated { get; set; } + public DateTime? MinDateLastSaved { get; set; } + public DateTime? MinDateLastSavedForUser { get; set; } public DtoOptions DtoOptions { get; set; } + public int MinSimilarityScore { get; set; } + public string HasNoAudioTrackWithLanguage { get; set; } + public string HasNoInternalSubtitleTrackWithLanguage { get; set; } + public string HasNoExternalSubtitleTrackWithLanguage { get; set; } + public string HasNoSubtitleTrackWithLanguage { get; set; } + public bool? IsDeadArtist { get; set; } + public bool? IsDeadStudio { get; set; } + public bool? IsDeadPerson { get; set; } public InternalItemsQuery() @@ -240,17 +331,29 @@ namespace MediaBrowser.Controller.Entities } public Dictionary<string, string> HasAnyProviderId { get; set; } + public Guid[] AlbumArtistIds { get; set; } + public Guid[] BoxSetLibraryFolders { get; set; } + public Guid[] ContributingArtistIds { get; set; } + public bool? HasAired { get; set; } + public bool? HasOwnerId { get; set; } + public bool? Is4K { get; set; } + public int? MaxHeight { get; set; } + public int? MaxWidth { get; set; } + public int? MinHeight { get; set; } + public int? MinWidth { get; set; } + public string SearchTerm { get; set; } + public string SeriesTimerId { get; set; } } } diff --git a/MediaBrowser.Controller/Entities/LinkedChild.cs b/MediaBrowser.Controller/Entities/LinkedChild.cs index d88c31007..cb698794b 100644 --- a/MediaBrowser.Controller/Entities/LinkedChild.cs +++ b/MediaBrowser.Controller/Entities/LinkedChild.cs @@ -9,7 +9,9 @@ namespace MediaBrowser.Controller.Entities public class LinkedChild { public string Path { get; set; } + public LinkedChildType Type { get; set; } + public string LibraryItemId { get; set; } [JsonIgnore] @@ -63,6 +65,7 @@ namespace MediaBrowser.Controller.Entities { return _fileSystem.AreEqual(x.Path, y.Path); } + return false; } diff --git a/MediaBrowser.Controller/Entities/PeopleHelper.cs b/MediaBrowser.Controller/Entities/PeopleHelper.cs index 2fb613768..c39495759 100644 --- a/MediaBrowser.Controller/Entities/PeopleHelper.cs +++ b/MediaBrowser.Controller/Entities/PeopleHelper.cs @@ -113,6 +113,7 @@ namespace MediaBrowser.Controller.Entities return true; } } + return false; } } diff --git a/MediaBrowser.Controller/Entities/Person.cs b/MediaBrowser.Controller/Entities/Person.cs index 9e4f9d47e..56106a266 100644 --- a/MediaBrowser.Controller/Entities/Person.cs +++ b/MediaBrowser.Controller/Entities/Person.cs @@ -19,6 +19,7 @@ namespace MediaBrowser.Controller.Entities list.Insert(0, GetType().Name + "-" + (Name ?? string.Empty).RemoveDiacritics()); return list; } + public override string CreatePresentationUniqueKey() { return GetUserDataKeys()[0]; @@ -114,6 +115,7 @@ namespace MediaBrowser.Controller.Entities Logger.LogDebug("{0} path has changed from {1} to {2}", GetType().Name, Path, newPath); return true; } + return base.RequiresRefresh(); } diff --git a/MediaBrowser.Controller/Entities/Photo.cs b/MediaBrowser.Controller/Entities/Photo.cs index 5ebc9f16a..82d0826c5 100644 --- a/MediaBrowser.Controller/Entities/Photo.cs +++ b/MediaBrowser.Controller/Entities/Photo.cs @@ -29,6 +29,7 @@ namespace MediaBrowser.Controller.Entities return photoAlbum; } } + return null; } } @@ -68,17 +69,27 @@ namespace MediaBrowser.Controller.Entities } public string CameraMake { get; set; } + public string CameraModel { get; set; } + public string Software { get; set; } + public double? ExposureTime { get; set; } + public double? FocalLength { get; set; } + public ImageOrientation? Orientation { get; set; } + public double? Aperture { get; set; } + public double? ShutterSpeed { get; set; } public double? Latitude { get; set; } + public double? Longitude { get; set; } + public double? Altitude { get; set; } + public int? IsoSpeedRating { get; set; } } } diff --git a/MediaBrowser.Controller/Entities/Share.cs b/MediaBrowser.Controller/Entities/Share.cs index c17789ccc..a51f2b452 100644 --- a/MediaBrowser.Controller/Entities/Share.cs +++ b/MediaBrowser.Controller/Entities/Share.cs @@ -8,6 +8,7 @@ namespace MediaBrowser.Controller.Entities public class Share { public string UserId { get; set; } + public bool CanEdit { get; set; } } } diff --git a/MediaBrowser.Controller/Entities/Studio.cs b/MediaBrowser.Controller/Entities/Studio.cs index 068032317..b5ee1e952 100644 --- a/MediaBrowser.Controller/Entities/Studio.cs +++ b/MediaBrowser.Controller/Entities/Studio.cs @@ -18,6 +18,7 @@ namespace MediaBrowser.Controller.Entities list.Insert(0, GetType().Name + "-" + (Name ?? string.Empty).RemoveDiacritics()); return list; } + public override string CreatePresentationUniqueKey() { return GetUserDataKeys()[0]; @@ -93,6 +94,7 @@ namespace MediaBrowser.Controller.Entities Logger.LogDebug("{0} path has changed from {1} to {2}", GetType().Name, Path, newPath); return true; } + return base.RequiresRefresh(); } diff --git a/MediaBrowser.Controller/Entities/TV/Episode.cs b/MediaBrowser.Controller/Entities/TV/Episode.cs index 4ec60e7cd..ec95c0e66 100644 --- a/MediaBrowser.Controller/Entities/TV/Episode.cs +++ b/MediaBrowser.Controller/Entities/TV/Episode.cs @@ -34,7 +34,9 @@ namespace MediaBrowser.Controller.Entities.TV /// </summary> /// <value>The aired season.</value> public int? AirsBeforeSeasonNumber { get; set; } + public int? AirsAfterSeasonNumber { get; set; } + public int? AirsBeforeEpisodeNumber { get; set; } /// <summary> @@ -94,6 +96,7 @@ namespace MediaBrowser.Controller.Entities.TV { take--; } + list.InsertRange(0, seriesUserDataKeys.Take(take).Select(i => i + ParentIndexNumber.Value.ToString("000") + IndexNumber.Value.ToString("000"))); } @@ -114,6 +117,7 @@ namespace MediaBrowser.Controller.Entities.TV { seriesId = FindSeriesId(); } + return !seriesId.Equals(Guid.Empty) ? (LibraryManager.GetItemById(seriesId) as Series) : null; } } @@ -128,6 +132,7 @@ namespace MediaBrowser.Controller.Entities.TV { seasonId = FindSeasonId(); } + return !seasonId.Equals(Guid.Empty) ? (LibraryManager.GetItemById(seasonId) as Season) : null; } } @@ -160,6 +165,7 @@ namespace MediaBrowser.Controller.Entities.TV { return "Season " + ParentIndexNumber.Value.ToString(CultureInfo.InvariantCulture); } + return "Season Unknown"; } diff --git a/MediaBrowser.Controller/Entities/TV/Season.cs b/MediaBrowser.Controller/Entities/TV/Season.cs index 7dfd1a759..c96acf9ca 100644 --- a/MediaBrowser.Controller/Entities/TV/Season.cs +++ b/MediaBrowser.Controller/Entities/TV/Season.cs @@ -81,6 +81,7 @@ namespace MediaBrowser.Controller.Entities.TV { seriesId = FindSeriesId(); } + return seriesId == Guid.Empty ? null : (LibraryManager.GetItemById(seriesId) as Series); } } diff --git a/MediaBrowser.Controller/Entities/TV/Series.cs b/MediaBrowser.Controller/Entities/TV/Series.cs index a519089b3..315da7a3b 100644 --- a/MediaBrowser.Controller/Entities/TV/Series.cs +++ b/MediaBrowser.Controller/Entities/TV/Series.cs @@ -30,6 +30,7 @@ namespace MediaBrowser.Controller.Entities.TV } public DayOfWeek[] AirDays { get; set; } + public string AirTime { get; set; } [JsonIgnore] @@ -150,6 +151,7 @@ namespace MediaBrowser.Controller.Entities.TV { query.IncludeItemTypes = new[] { typeof(Episode).Name }; } + query.IsVirtualItem = false; query.Limit = 0; var totalRecordCount = LibraryManager.GetCount(query); diff --git a/MediaBrowser.Controller/Entities/UserItemData.cs b/MediaBrowser.Controller/Entities/UserItemData.cs index ab425ee0f..4d8db99c4 100644 --- a/MediaBrowser.Controller/Entities/UserItemData.cs +++ b/MediaBrowser.Controller/Entities/UserItemData.cs @@ -105,6 +105,7 @@ namespace MediaBrowser.Controller.Entities return null; } + set { if (value.HasValue) diff --git a/MediaBrowser.Controller/Entities/UserViewBuilder.cs b/MediaBrowser.Controller/Entities/UserViewBuilder.cs index dbfef0777..061e6001c 100644 --- a/MediaBrowser.Controller/Entities/UserViewBuilder.cs +++ b/MediaBrowser.Controller/Entities/UserViewBuilder.cs @@ -960,6 +960,7 @@ namespace MediaBrowser.Controller.Entities .OfType<Folder>() .Where(UserView.IsEligibleForGrouping); } + return _libraryManager.GetUserRootFolder() .GetChildren(user, true) .OfType<Folder>() @@ -978,6 +979,7 @@ namespace MediaBrowser.Controller.Entities return folder != null && viewTypes.Contains(folder.CollectionType ?? string.Empty, StringComparer.OrdinalIgnoreCase); }).ToArray(); } + return GetMediaFolders(user) .Where(i => { diff --git a/MediaBrowser.Controller/Entities/Video.cs b/MediaBrowser.Controller/Entities/Video.cs index 4cfa0e74d..8b534f05d 100644 --- a/MediaBrowser.Controller/Entities/Video.cs +++ b/MediaBrowser.Controller/Entities/Video.cs @@ -28,7 +28,9 @@ namespace MediaBrowser.Controller.Entities public string PrimaryVersionId { get; set; } public string[] AdditionalParts { get; set; } + public string[] LocalAlternateVersions { get; set; } + public LinkedChild[] LinkedAlternateVersions { get; set; } [JsonIgnore] @@ -52,15 +54,18 @@ namespace MediaBrowser.Controller.Entities { return false; } + if (extraType.Value == Model.Entities.ExtraType.ThemeVideo) { return false; } + if (extraType.Value == Model.Entities.ExtraType.Trailer) { return false; } } + return true; } } @@ -196,6 +201,7 @@ namespace MediaBrowser.Controller.Entities return video.MediaSourceCount; } } + return LinkedAlternateVersions.Length + LocalAlternateVersions.Length + 1; } } @@ -390,11 +396,13 @@ namespace MediaBrowser.Controller.Entities AdditionalParts = newVideo.AdditionalParts; updateType |= ItemUpdateType.MetadataImport; } + if (!LocalAlternateVersions.SequenceEqual(newVideo.LocalAlternateVersions, StringComparer.Ordinal)) { LocalAlternateVersions = newVideo.LocalAlternateVersions; updateType |= ItemUpdateType.MetadataImport; } + if (VideoType != newVideo.VideoType) { VideoType = newVideo.VideoType; @@ -416,6 +424,7 @@ namespace MediaBrowser.Controller.Entities .Select(i => i.FullName) .ToArray(); } + if (videoType == VideoType.BluRay) { return FileSystem.GetFiles(rootPath, new[] { ".m2ts" }, false, true) @@ -425,6 +434,7 @@ namespace MediaBrowser.Controller.Entities .Select(i => i.FullName) .ToArray(); } + return Array.Empty<string>(); } diff --git a/MediaBrowser.Controller/Entities/Year.cs b/MediaBrowser.Controller/Entities/Year.cs index a01ef5c31..d65b90c25 100644 --- a/MediaBrowser.Controller/Entities/Year.cs +++ b/MediaBrowser.Controller/Entities/Year.cs @@ -103,6 +103,7 @@ namespace MediaBrowser.Controller.Entities Logger.LogDebug("{0} path has changed from {1} to {2}", GetType().Name, Path, newPath); return true; } + return base.RequiresRefresh(); } diff --git a/MediaBrowser.Controller/IO/FileData.cs b/MediaBrowser.Controller/IO/FileData.cs index aa7373815..e655f50eb 100644 --- a/MediaBrowser.Controller/IO/FileData.cs +++ b/MediaBrowser.Controller/IO/FileData.cs @@ -20,6 +20,7 @@ namespace MediaBrowser.Controller.IO { dict[file.FullName] = file; } + return dict; } @@ -49,6 +50,7 @@ namespace MediaBrowser.Controller.IO { throw new ArgumentNullException(nameof(path)); } + if (args == null) { throw new ArgumentNullException(nameof(args)); @@ -116,6 +118,7 @@ namespace MediaBrowser.Controller.IO returnResult[index] = value; index++; } + return returnResult; } } diff --git a/MediaBrowser.Controller/Library/DeleteOptions.cs b/MediaBrowser.Controller/Library/DeleteOptions.cs index 751b90481..2944d8259 100644 --- a/MediaBrowser.Controller/Library/DeleteOptions.cs +++ b/MediaBrowser.Controller/Library/DeleteOptions.cs @@ -3,6 +3,7 @@ namespace MediaBrowser.Controller.Library public class DeleteOptions { public bool DeleteFileLocation { get; set; } + public bool DeleteFromExternalProvider { get; set; } public DeleteOptions() diff --git a/MediaBrowser.Controller/Library/ILiveStream.cs b/MediaBrowser.Controller/Library/ILiveStream.cs index 734932f17..7c9a9b20e 100644 --- a/MediaBrowser.Controller/Library/ILiveStream.cs +++ b/MediaBrowser.Controller/Library/ILiveStream.cs @@ -9,10 +9,15 @@ namespace MediaBrowser.Controller.Library Task Open(CancellationToken openCancellationToken); Task Close(); int ConsumerCount { get; set; } + string OriginalStreamId { get; set; } + string TunerHostId { get; } + bool EnableStreamSharing { get; } + MediaSourceInfo MediaSource { get; set; } + string UniqueId { get; } } } diff --git a/MediaBrowser.Controller/Library/ItemResolveArgs.cs b/MediaBrowser.Controller/Library/ItemResolveArgs.cs index cca85cd3b..096708ee3 100644 --- a/MediaBrowser.Controller/Library/ItemResolveArgs.cs +++ b/MediaBrowser.Controller/Library/ItemResolveArgs.cs @@ -129,6 +129,7 @@ namespace MediaBrowser.Controller.Library return item != null; } + return false; } @@ -256,6 +257,7 @@ namespace MediaBrowser.Controller.Library if (args.Path == null && Path == null) return true; return args.Path != null && BaseItem.FileSystem.AreEqual(args.Path, Path); } + return false; } diff --git a/MediaBrowser.Controller/Library/PlaybackProgressEventArgs.cs b/MediaBrowser.Controller/Library/PlaybackProgressEventArgs.cs index b4e205184..1ed69975c 100644 --- a/MediaBrowser.Controller/Library/PlaybackProgressEventArgs.cs +++ b/MediaBrowser.Controller/Library/PlaybackProgressEventArgs.cs @@ -13,18 +13,27 @@ namespace MediaBrowser.Controller.Library public class PlaybackProgressEventArgs : EventArgs { public List<User> Users { get; set; } + public long? PlaybackPositionTicks { get; set; } + public BaseItem Item { get; set; } + public BaseItemDto MediaInfo { get; set; } + public string MediaSourceId { get; set; } + public bool IsPaused { get; set; } + public bool IsAutomated { get; set; } public string DeviceId { get; set; } + public string DeviceName { get; set; } + public string ClientName { get; set; } public string PlaySessionId { get; set; } + public SessionInfo Session { get; set; } public PlaybackProgressEventArgs() diff --git a/MediaBrowser.Controller/Library/Profiler.cs b/MediaBrowser.Controller/Library/Profiler.cs index 0febef3d3..c4935868d 100644 --- a/MediaBrowser.Controller/Library/Profiler.cs +++ b/MediaBrowser.Controller/Library/Profiler.cs @@ -67,6 +67,7 @@ namespace MediaBrowser.Controller.Library message = string.Format("{0} took {1} seconds.", _name, ((float)_stopwatch.ElapsedMilliseconds / 1000).ToString("#0.000")); } + _logger.LogInformation(message); } } diff --git a/MediaBrowser.Controller/Library/TVUtils.cs b/MediaBrowser.Controller/Library/TVUtils.cs index fd5fb6748..885488851 100644 --- a/MediaBrowser.Controller/Library/TVUtils.cs +++ b/MediaBrowser.Controller/Library/TVUtils.cs @@ -40,6 +40,7 @@ namespace MediaBrowser.Controller.Library return new DayOfWeek[] { }; } + return null; } } diff --git a/MediaBrowser.Controller/LiveTv/ChannelInfo.cs b/MediaBrowser.Controller/LiveTv/ChannelInfo.cs index 70477fce7..384ca62aa 100644 --- a/MediaBrowser.Controller/LiveTv/ChannelInfo.cs +++ b/MediaBrowser.Controller/LiveTv/ChannelInfo.cs @@ -67,8 +67,11 @@ namespace MediaBrowser.Controller.LiveTv public bool? IsFavorite { get; set; } public bool? IsHD { get; set; } + public string AudioCodec { get; set; } + public string VideoCodec { get; set; } + public string[] Tags { get; set; } } } diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs index bc3bf78f0..4ac40fe88 100644 --- a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs +++ b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs @@ -286,8 +286,11 @@ namespace MediaBrowser.Controller.LiveTv public class ActiveRecordingInfo { public string Id { get; set; } + public string Path { get; set; } + public TimerInfo Timer { get; set; } + public CancellationTokenSource CancellationTokenSource { get; set; } } } diff --git a/MediaBrowser.Controller/LiveTv/ITunerHost.cs b/MediaBrowser.Controller/LiveTv/ITunerHost.cs index 240ba8c23..3679e4f78 100644 --- a/MediaBrowser.Controller/LiveTv/ITunerHost.cs +++ b/MediaBrowser.Controller/LiveTv/ITunerHost.cs @@ -50,6 +50,7 @@ namespace MediaBrowser.Controller.LiveTv get; } } + public interface IConfigurableTunerHost { /// <summary> diff --git a/MediaBrowser.Controller/LiveTv/LiveTvConflictException.cs b/MediaBrowser.Controller/LiveTv/LiveTvConflictException.cs index 92b8ee67c..0e09d1aeb 100644 --- a/MediaBrowser.Controller/LiveTv/LiveTvConflictException.cs +++ b/MediaBrowser.Controller/LiveTv/LiveTvConflictException.cs @@ -10,6 +10,7 @@ namespace MediaBrowser.Controller.LiveTv public LiveTvConflictException() { } + public LiveTvConflictException(string message) : base(message) { diff --git a/MediaBrowser.Controller/LiveTv/ProgramInfo.cs b/MediaBrowser.Controller/LiveTv/ProgramInfo.cs index 5d0f13192..aa7ad6ff7 100644 --- a/MediaBrowser.Controller/LiveTv/ProgramInfo.cs +++ b/MediaBrowser.Controller/LiveTv/ProgramInfo.cs @@ -199,6 +199,7 @@ namespace MediaBrowser.Controller.LiveTv public string Etag { get; set; } public Dictionary<string, string> ProviderIds { get; set; } + public Dictionary<string, string> SeriesProviderIds { get; set; } public ProgramInfo() diff --git a/MediaBrowser.Controller/LiveTv/SeriesTimerInfo.cs b/MediaBrowser.Controller/LiveTv/SeriesTimerInfo.cs index 4fbd496c5..6e7acaae3 100644 --- a/MediaBrowser.Controller/LiveTv/SeriesTimerInfo.cs +++ b/MediaBrowser.Controller/LiveTv/SeriesTimerInfo.cs @@ -57,6 +57,7 @@ namespace MediaBrowser.Controller.LiveTv public bool RecordAnyChannel { get; set; } public int KeepUpTo { get; set; } + public KeepUntil KeepUntil { get; set; } public bool SkipEpisodesInLibrary { get; set; } diff --git a/MediaBrowser.Controller/LiveTv/TimerInfo.cs b/MediaBrowser.Controller/LiveTv/TimerInfo.cs index 46774b2b7..df98bb6af 100644 --- a/MediaBrowser.Controller/LiveTv/TimerInfo.cs +++ b/MediaBrowser.Controller/LiveTv/TimerInfo.cs @@ -18,7 +18,9 @@ namespace MediaBrowser.Controller.LiveTv } public Dictionary<string, string> ProviderIds { get; set; } + public Dictionary<string, string> SeriesProviderIds { get; set; } + public string[] Tags { get; set; } /// <summary> @@ -146,10 +148,15 @@ namespace MediaBrowser.Controller.LiveTv public bool IsRepeat { get; set; } public string HomePageUrl { get; set; } + public float? CommunityRating { get; set; } + public string OfficialRating { get; set; } + public string[] Genres { get; set; } + public string RecordingPath { get; set; } + public KeepUntil KeepUntil { get; set; } } } diff --git a/MediaBrowser.Controller/LiveTv/TunerChannelMapping.cs b/MediaBrowser.Controller/LiveTv/TunerChannelMapping.cs index cb02da635..df3f55c26 100644 --- a/MediaBrowser.Controller/LiveTv/TunerChannelMapping.cs +++ b/MediaBrowser.Controller/LiveTv/TunerChannelMapping.cs @@ -3,8 +3,11 @@ namespace MediaBrowser.Controller.LiveTv public class TunerChannelMapping { public string Name { get; set; } + public string ProviderChannelName { get; set; } + public string ProviderChannelId { get; set; } + public string Id { get; set; } } } diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index ec90d28f7..4fff46f4e 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -1699,6 +1699,7 @@ namespace MediaBrowser.Controller.MediaEncoding { return (null, null); } + if (!videoHeight.HasValue && !requestedHeight.HasValue) { return (null, null); @@ -2569,8 +2570,10 @@ namespace MediaBrowser.Controller.MediaEncoding encodingOptions.HardwareDecodingCodecs = Array.Empty<string>(); return null; } + return "-c:v h264_qsv"; } + break; case "hevc": case "h265": @@ -2579,18 +2582,21 @@ namespace MediaBrowser.Controller.MediaEncoding return (isColorDepth10 && !encodingOptions.EnableDecodingColorDepth10Hevc) ? null : "-c:v hevc_qsv"; } + break; case "mpeg2video": if (_mediaEncoder.SupportsDecoder("mpeg2_qsv") && encodingOptions.HardwareDecodingCodecs.Contains("mpeg2video", StringComparer.OrdinalIgnoreCase)) { return "-c:v mpeg2_qsv"; } + break; case "vc1": if (_mediaEncoder.SupportsDecoder("vc1_qsv") && encodingOptions.HardwareDecodingCodecs.Contains("vc1", StringComparer.OrdinalIgnoreCase)) { return "-c:v vc1_qsv"; } + break; case "vp8": if (_mediaEncoder.SupportsDecoder("vp8_qsv") && encodingOptions.HardwareDecodingCodecs.Contains("vp8", StringComparer.OrdinalIgnoreCase)) @@ -2615,8 +2621,16 @@ namespace MediaBrowser.Controller.MediaEncoding case "h264": if (_mediaEncoder.SupportsDecoder("h264_cuvid") && encodingOptions.HardwareDecodingCodecs.Contains("h264", StringComparer.OrdinalIgnoreCase)) { + // cuvid decoder does not support 10-bit input. + if ((videoStream.BitDepth ?? 8) > 8) + { + encodingOptions.HardwareDecodingCodecs = Array.Empty<string>(); + return null; + } + return "-c:v h264_cuvid"; } + break; case "hevc": case "h265": @@ -2625,24 +2639,28 @@ namespace MediaBrowser.Controller.MediaEncoding return (isColorDepth10 && !encodingOptions.EnableDecodingColorDepth10Hevc) ? null : "-c:v hevc_cuvid"; } + break; case "mpeg2video": if (_mediaEncoder.SupportsDecoder("mpeg2_cuvid") && encodingOptions.HardwareDecodingCodecs.Contains("mpeg2video", StringComparer.OrdinalIgnoreCase)) { return "-c:v mpeg2_cuvid"; } + break; case "vc1": if (_mediaEncoder.SupportsDecoder("vc1_cuvid") && encodingOptions.HardwareDecodingCodecs.Contains("vc1", StringComparer.OrdinalIgnoreCase)) { return "-c:v vc1_cuvid"; } + break; case "mpeg4": if (_mediaEncoder.SupportsDecoder("mpeg4_cuvid") && encodingOptions.HardwareDecodingCodecs.Contains("mpeg4", StringComparer.OrdinalIgnoreCase)) { return "-c:v mpeg4_cuvid"; } + break; case "vp8": if (_mediaEncoder.SupportsDecoder("vp8_cuvid") && encodingOptions.HardwareDecodingCodecs.Contains("vp8", StringComparer.OrdinalIgnoreCase)) @@ -2669,6 +2687,7 @@ namespace MediaBrowser.Controller.MediaEncoding { return "-c:v h264_mediacodec"; } + break; case "hevc": case "h265": @@ -2677,24 +2696,28 @@ namespace MediaBrowser.Controller.MediaEncoding return (isColorDepth10 && !encodingOptions.EnableDecodingColorDepth10Hevc) ? null : "-c:v hevc_mediacodec"; } + break; case "mpeg2video": if (_mediaEncoder.SupportsDecoder("mpeg2_mediacodec") && encodingOptions.HardwareDecodingCodecs.Contains("mpeg2video", StringComparer.OrdinalIgnoreCase)) { return "-c:v mpeg2_mediacodec"; } + break; case "mpeg4": if (_mediaEncoder.SupportsDecoder("mpeg4_mediacodec") && encodingOptions.HardwareDecodingCodecs.Contains("mpeg4", StringComparer.OrdinalIgnoreCase)) { return "-c:v mpeg4_mediacodec"; } + break; case "vp8": if (_mediaEncoder.SupportsDecoder("vp8_mediacodec") && encodingOptions.HardwareDecodingCodecs.Contains("vp8", StringComparer.OrdinalIgnoreCase)) { return "-c:v vp8_mediacodec"; } + break; case "vp9": if (_mediaEncoder.SupportsDecoder("vp9_mediacodec") && encodingOptions.HardwareDecodingCodecs.Contains("vp9", StringComparer.OrdinalIgnoreCase)) @@ -2702,6 +2725,7 @@ namespace MediaBrowser.Controller.MediaEncoding return (isColorDepth10 && !encodingOptions.EnableDecodingColorDepth10Vp9) ? null : "-c:v vp9_mediacodec"; } + break; } } @@ -2715,24 +2739,28 @@ namespace MediaBrowser.Controller.MediaEncoding { return "-c:v h264_mmal"; } + break; case "mpeg2video": if (_mediaEncoder.SupportsDecoder("mpeg2_mmal") && encodingOptions.HardwareDecodingCodecs.Contains("mpeg2video", StringComparer.OrdinalIgnoreCase)) { return "-c:v mpeg2_mmal"; } + break; case "mpeg4": if (_mediaEncoder.SupportsDecoder("mpeg4_mmal") && encodingOptions.HardwareDecodingCodecs.Contains("mpeg4", StringComparer.OrdinalIgnoreCase)) { return "-c:v mpeg4_mmal"; } + break; case "vc1": if (_mediaEncoder.SupportsDecoder("vc1_mmal") && encodingOptions.HardwareDecodingCodecs.Contains("vc1", StringComparer.OrdinalIgnoreCase)) { return "-c:v vc1_mmal"; } + break; } } diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs b/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs index acf1aae89..0d6654f85 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs @@ -127,13 +127,19 @@ namespace MediaBrowser.Controller.MediaEncoding public string AlbumCoverPath { get; set; } public string InputAudioSync { get; set; } + public string InputVideoSync { get; set; } + public TransportStreamTimestamp InputTimestamp { get; set; } public MediaStream AudioStream { get; set; } + public string[] SupportedAudioCodecs { get; set; } + public string[] SupportedVideoCodecs { get; set; } + public string InputContainer { get; set; } + public IsoType? IsoType { get; set; } public BaseEncodingJobOptions BaseRequest { get; set; } @@ -293,6 +299,7 @@ namespace MediaBrowser.Controller.MediaEncoding } public bool IsVideoRequest { get; set; } + public TranscodingJobType TranscodingType { get; set; } public EncodingJobInfo(TranscodingJobType jobType) @@ -672,6 +679,7 @@ namespace MediaBrowser.Controller.MediaEncoding } public IProgress<double> Progress { get; set; } + public virtual void ReportTranscodingProgress(TimeSpan? transcodingPosition, float? framerate, double? percentComplete, long? bytesTranscoded, int? bitRate) { Progress.Report(percentComplete.Value); diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs b/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs index addc88174..8f6fcb9ab 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs @@ -9,9 +9,11 @@ namespace MediaBrowser.Controller.MediaEncoding public class EncodingJobOptions : BaseEncodingJobOptions { public string OutputDirectory { get; set; } + public string ItemId { get; set; } public string TempDirectory { get; set; } + public bool ReadInputAtNativeFramerate { get; set; } /// <summary> @@ -47,6 +49,7 @@ namespace MediaBrowser.Controller.MediaEncoding { SubtitleStreamIndex = info.SubtitleStreamIndex; } + StreamOptions = info.StreamOptions; } } @@ -81,7 +84,9 @@ namespace MediaBrowser.Controller.MediaEncoding public bool EnableAutoStreamCopy { get; set; } public bool AllowVideoStreamCopy { get; set; } + public bool AllowAudioStreamCopy { get; set; } + public bool BreakOnNonKeyFrames { get; set; } /// <summary> @@ -197,10 +202,15 @@ namespace MediaBrowser.Controller.MediaEncoding [ApiMember(Name = "MaxVideoBitDepth", Description = "Optional.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")] public int? MaxVideoBitDepth { get; set; } + public bool RequireAvc { get; set; } + public bool DeInterlace { get; set; } + public bool RequireNonAnamorphic { get; set; } + public int? TranscodingMaxAudioChannels { get; set; } + public int? CpuCoreLimit { get; set; } public string LiveStreamId { get; set; } diff --git a/MediaBrowser.Controller/MediaEncoding/MediaInfoRequest.cs b/MediaBrowser.Controller/MediaEncoding/MediaInfoRequest.cs index b78ef0b80..39a47792a 100644 --- a/MediaBrowser.Controller/MediaEncoding/MediaInfoRequest.cs +++ b/MediaBrowser.Controller/MediaEncoding/MediaInfoRequest.cs @@ -8,9 +8,13 @@ namespace MediaBrowser.Controller.MediaEncoding public class MediaInfoRequest { public MediaSourceInfo MediaSource { get; set; } + public bool ExtractChapters { get; set; } + public DlnaProfileType MediaType { get; set; } + public IIsoMount MountedIso { get; set; } + public string[] PlayableStreamFileNames { get; set; } public MediaInfoRequest() diff --git a/MediaBrowser.Controller/Net/AuthenticatedAttribute.cs b/MediaBrowser.Controller/Net/AuthenticatedAttribute.cs index 29fb81e32..ba3c715b8 100644 --- a/MediaBrowser.Controller/Net/AuthenticatedAttribute.cs +++ b/MediaBrowser.Controller/Net/AuthenticatedAttribute.cs @@ -58,8 +58,11 @@ namespace MediaBrowser.Controller.Net public interface IAuthenticationAttributes { bool EscapeParentalControl { get; } + bool AllowBeforeStartupWizard { get; } + bool AllowLocal { get; } + bool AllowLocalOnly { get; } string[] GetRoles(); diff --git a/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs b/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs index df90c399b..43016e1c9 100644 --- a/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs +++ b/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs @@ -254,7 +254,9 @@ namespace MediaBrowser.Controller.Net public class WebSocketListenerState { public DateTime DateLastSendUtc { get; set; } + public long InitialDelayMs { get; set; } + public long IntervalMs { get; set; } } } diff --git a/MediaBrowser.Controller/Net/StaticResultOptions.cs b/MediaBrowser.Controller/Net/StaticResultOptions.cs index 071beaed1..85772e036 100644 --- a/MediaBrowser.Controller/Net/StaticResultOptions.cs +++ b/MediaBrowser.Controller/Net/StaticResultOptions.cs @@ -8,8 +8,11 @@ namespace MediaBrowser.Controller.Net public class StaticResultOptions { public string ContentType { get; set; } + public TimeSpan? CacheDuration { get; set; } + public DateTime? DateLastModified { get; set; } + public Func<Task<Stream>> ContentFactory { get; set; } public bool IsHeadRequest { get; set; } @@ -17,9 +20,11 @@ namespace MediaBrowser.Controller.Net public IDictionary<string, string> ResponseHeaders { get; set; } public Action OnComplete { get; set; } + public Action OnError { get; set; } public string Path { get; set; } + public long? ContentLength { get; set; } public FileShare FileShare { get; set; } diff --git a/MediaBrowser.Controller/Providers/ImageRefreshOptions.cs b/MediaBrowser.Controller/Providers/ImageRefreshOptions.cs index aac41369c..3f8c409f5 100644 --- a/MediaBrowser.Controller/Providers/ImageRefreshOptions.cs +++ b/MediaBrowser.Controller/Providers/ImageRefreshOptions.cs @@ -7,11 +7,13 @@ namespace MediaBrowser.Controller.Providers public class ImageRefreshOptions { public MetadataRefreshMode ImageRefreshMode { get; set; } + public IDirectoryService DirectoryService { get; private set; } public bool ReplaceAllImages { get; set; } public ImageType[] ReplaceImages { get; set; } + public bool IsAutomated { get; set; } public ImageRefreshOptions(IDirectoryService directoryService) diff --git a/MediaBrowser.Controller/Providers/MetadataResult.cs b/MediaBrowser.Controller/Providers/MetadataResult.cs index 59adaedfa..af955774f 100644 --- a/MediaBrowser.Controller/Providers/MetadataResult.cs +++ b/MediaBrowser.Controller/Providers/MetadataResult.cs @@ -48,6 +48,7 @@ namespace MediaBrowser.Controller.Providers { People = new List<PersonInfo>(); } + People.Clear(); } diff --git a/MediaBrowser.Controller/Resolvers/IItemResolver.cs b/MediaBrowser.Controller/Resolvers/IItemResolver.cs index 16e37d249..751ca8098 100644 --- a/MediaBrowser.Controller/Resolvers/IItemResolver.cs +++ b/MediaBrowser.Controller/Resolvers/IItemResolver.cs @@ -35,6 +35,7 @@ namespace MediaBrowser.Controller.Resolvers public class MultiItemResolverResult { public List<BaseItem> Items { get; set; } + public List<FileSystemMetadata> ExtraFiles { get; set; } public MultiItemResolverResult() diff --git a/MediaBrowser.Controller/Security/AuthenticationInfo.cs b/MediaBrowser.Controller/Security/AuthenticationInfo.cs index 828213588..1d0b959b7 100644 --- a/MediaBrowser.Controller/Security/AuthenticationInfo.cs +++ b/MediaBrowser.Controller/Security/AuthenticationInfo.cs @@ -65,6 +65,7 @@ namespace MediaBrowser.Controller.Security public DateTime? DateRevoked { get; set; } public DateTime DateLastActivity { get; set; } + public string UserName { get; set; } } } diff --git a/MediaBrowser.Controller/Session/AuthenticationRequest.cs b/MediaBrowser.Controller/Session/AuthenticationRequest.cs index a28f47a9c..685ca3bdd 100644 --- a/MediaBrowser.Controller/Session/AuthenticationRequest.cs +++ b/MediaBrowser.Controller/Session/AuthenticationRequest.cs @@ -5,13 +5,21 @@ namespace MediaBrowser.Controller.Session public class AuthenticationRequest { public string Username { get; set; } + public Guid UserId { get; set; } + public string Password { get; set; } + public string PasswordSha1 { get; set; } + public string App { get; set; } + public string AppVersion { get; set; } + public string DeviceId { get; set; } + public string DeviceName { get; set; } + public string RemoteEndPoint { get; set; } } } diff --git a/MediaBrowser.Controller/Session/SessionInfo.cs b/MediaBrowser.Controller/Session/SessionInfo.cs index 2ba7c9fec..36bc11be4 100644 --- a/MediaBrowser.Controller/Session/SessionInfo.cs +++ b/MediaBrowser.Controller/Session/SessionInfo.cs @@ -61,6 +61,7 @@ namespace MediaBrowser.Controller.Session { return Array.Empty<string>(); } + return Capabilities.PlayableMediaTypes; } } @@ -154,6 +155,7 @@ namespace MediaBrowser.Controller.Session return true; } } + if (controllers.Length > 0) { return false; @@ -255,6 +257,7 @@ namespace MediaBrowser.Controller.Session return true; } } + return false; } @@ -292,6 +295,7 @@ namespace MediaBrowser.Controller.Session { return; } + if (progressInfo.IsPaused) { return; @@ -334,6 +338,7 @@ namespace MediaBrowser.Controller.Session _progressTimer.Dispose(); _progressTimer = null; } + _lastProgressInfo = null; } } diff --git a/MediaBrowser.Controller/Subtitles/SubtitleResponse.cs b/MediaBrowser.Controller/Subtitles/SubtitleResponse.cs index b8ba35a5f..ad6025927 100644 --- a/MediaBrowser.Controller/Subtitles/SubtitleResponse.cs +++ b/MediaBrowser.Controller/Subtitles/SubtitleResponse.cs @@ -5,8 +5,11 @@ namespace MediaBrowser.Controller.Subtitles public class SubtitleResponse { public string Language { get; set; } + public string Format { get; set; } + public bool IsForced { get; set; } + public Stream Stream { get; set; } } } diff --git a/MediaBrowser.Controller/Subtitles/SubtitleSearchRequest.cs b/MediaBrowser.Controller/Subtitles/SubtitleSearchRequest.cs index 61dc72258..a202723b9 100644 --- a/MediaBrowser.Controller/Subtitles/SubtitleSearchRequest.cs +++ b/MediaBrowser.Controller/Subtitles/SubtitleSearchRequest.cs @@ -8,23 +8,35 @@ namespace MediaBrowser.Controller.Subtitles public class SubtitleSearchRequest : IHasProviderIds { public string Language { get; set; } + public string TwoLetterISOLanguageName { get; set; } public VideoContentType ContentType { get; set; } public string MediaPath { get; set; } + public string SeriesName { get; set; } + public string Name { get; set; } + public int? IndexNumber { get; set; } + public int? IndexNumberEnd { get; set; } + public int? ParentIndexNumber { get; set; } + public int? ProductionYear { get; set; } + public long? RuntimeTicks { get; set; } + public bool IsPerfectMatch { get; set; } + public Dictionary<string, string> ProviderIds { get; set; } public bool SearchAllProviders { get; set; } + public string[] DisabledSubtitleFetchers { get; set; } + public string[] SubtitleFetcherOrder { get; set; } public SubtitleSearchRequest() diff --git a/MediaBrowser.Controller/Sync/SyncedFileInfo.cs b/MediaBrowser.Controller/Sync/SyncedFileInfo.cs index 2ff40addb..687a46d78 100644 --- a/MediaBrowser.Controller/Sync/SyncedFileInfo.cs +++ b/MediaBrowser.Controller/Sync/SyncedFileInfo.cs @@ -10,6 +10,7 @@ namespace MediaBrowser.Controller.Sync /// </summary> /// <value>The path.</value> public string Path { get; set; } + public string[] PathParts { get; set; } /// <summary> /// Gets or sets the protocol. diff --git a/MediaBrowser.Controller/SyncPlay/GroupInfo.cs b/MediaBrowser.Controller/SyncPlay/GroupInfo.cs index ef8df7d02..d0fac1efa 100644 --- a/MediaBrowser.Controller/SyncPlay/GroupInfo.cs +++ b/MediaBrowser.Controller/SyncPlay/GroupInfo.cs @@ -122,6 +122,7 @@ namespace MediaBrowser.Controller.SyncPlay { max = Math.Max(max, session.Ping); } + return max; } diff --git a/MediaBrowser.LocalMetadata/Images/EpisodeLocalImageProvider.cs b/MediaBrowser.LocalMetadata/Images/EpisodeLocalImageProvider.cs index 2f4cca5ff..9d23d80b8 100644 --- a/MediaBrowser.LocalMetadata/Images/EpisodeLocalImageProvider.cs +++ b/MediaBrowser.LocalMetadata/Images/EpisodeLocalImageProvider.cs @@ -75,6 +75,7 @@ namespace MediaBrowser.LocalMetadata.Images } } } + return list; } } diff --git a/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs b/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs index 0ceb55c57..f954d4192 100644 --- a/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs +++ b/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs @@ -24,6 +24,7 @@ namespace MediaBrowser.LocalMetadata.Parsers /// The logger /// </summary> protected ILogger<BaseItemXmlParser<T>> Logger { get; private set; } + protected IProviderManager ProviderManager { get; private set; } private Dictionary<string, string> _validProviderIds; @@ -150,6 +151,7 @@ namespace MediaBrowser.LocalMetadata.Parsers Logger.LogWarning("Invalid Added value found: " + val); } } + break; } @@ -161,6 +163,7 @@ namespace MediaBrowser.LocalMetadata.Parsers { item.OriginalTitle = val; } + break; } @@ -191,6 +194,7 @@ namespace MediaBrowser.LocalMetadata.Parsers { item.ForcedSortName = val; } + break; } @@ -274,6 +278,7 @@ namespace MediaBrowser.LocalMetadata.Parsers { reader.Read(); } + break; } @@ -290,6 +295,7 @@ namespace MediaBrowser.LocalMetadata.Parsers { reader.Read(); } + break; } @@ -302,6 +308,7 @@ namespace MediaBrowser.LocalMetadata.Parsers { item.OfficialRating = rating; } + break; } @@ -313,6 +320,7 @@ namespace MediaBrowser.LocalMetadata.Parsers { item.CustomRating = val; } + break; } @@ -327,6 +335,7 @@ namespace MediaBrowser.LocalMetadata.Parsers item.RunTimeTicks = TimeSpan.FromMinutes(runtime).Ticks; } } + break; } @@ -339,6 +348,7 @@ namespace MediaBrowser.LocalMetadata.Parsers { hasAspectRatio.AspectRatio = val; } + break; } @@ -350,6 +360,7 @@ namespace MediaBrowser.LocalMetadata.Parsers { item.IsLocked = string.Equals("true", val, StringComparison.OrdinalIgnoreCase); } + break; } @@ -361,8 +372,10 @@ namespace MediaBrowser.LocalMetadata.Parsers { continue; } + item.AddStudio(name); } + break; } @@ -374,8 +387,10 @@ namespace MediaBrowser.LocalMetadata.Parsers { continue; } + itemResult.AddPerson(p); } + break; } case "Writer": @@ -386,8 +401,10 @@ namespace MediaBrowser.LocalMetadata.Parsers { continue; } + itemResult.AddPerson(p); } + break; } @@ -411,9 +428,11 @@ namespace MediaBrowser.LocalMetadata.Parsers { continue; } + itemResult.AddPerson(p); } } + break; } @@ -425,8 +444,10 @@ namespace MediaBrowser.LocalMetadata.Parsers { continue; } + itemResult.AddPerson(p); } + break; } @@ -438,6 +459,7 @@ namespace MediaBrowser.LocalMetadata.Parsers { item.AddTrailerUrl(val); } + break; } @@ -453,6 +475,7 @@ namespace MediaBrowser.LocalMetadata.Parsers hasDisplayOrder.DisplayOrder = val; } } + break; } @@ -469,6 +492,7 @@ namespace MediaBrowser.LocalMetadata.Parsers { reader.Read(); } + break; } @@ -501,6 +525,7 @@ namespace MediaBrowser.LocalMetadata.Parsers item.CommunityRating = val; } } + break; } @@ -544,6 +569,7 @@ namespace MediaBrowser.LocalMetadata.Parsers { item.SetProviderId(MetadataProvider.TmdbCollection, tmdbCollection); } + break; case "Genres": @@ -559,6 +585,7 @@ namespace MediaBrowser.LocalMetadata.Parsers { reader.Read(); } + break; } @@ -575,6 +602,7 @@ namespace MediaBrowser.LocalMetadata.Parsers { reader.Read(); } + break; } @@ -591,6 +619,7 @@ namespace MediaBrowser.LocalMetadata.Parsers { reader.Read(); } + break; } @@ -607,6 +636,7 @@ namespace MediaBrowser.LocalMetadata.Parsers { reader.Read(); } + break; } @@ -627,6 +657,7 @@ namespace MediaBrowser.LocalMetadata.Parsers { reader.Read(); } + break; } @@ -659,6 +690,7 @@ namespace MediaBrowser.LocalMetadata.Parsers video.Video3DFormat = Video3DFormat.MVC; } } + break; } @@ -682,6 +714,7 @@ namespace MediaBrowser.LocalMetadata.Parsers } } } + private void FetchFromSharesNode(XmlReader reader, IHasShares item) { var list = new List<Share>(); @@ -716,6 +749,7 @@ namespace MediaBrowser.LocalMetadata.Parsers break; } + default: { reader.Skip(); @@ -791,6 +825,7 @@ namespace MediaBrowser.LocalMetadata.Parsers if (!string.IsNullOrWhiteSpace(val)) { } + break; } @@ -831,8 +866,10 @@ namespace MediaBrowser.LocalMetadata.Parsers { item.Tagline = val; } + break; } + default: reader.Skip(); break; @@ -870,6 +907,7 @@ namespace MediaBrowser.LocalMetadata.Parsers { item.AddGenre(genre); } + break; } @@ -907,6 +945,7 @@ namespace MediaBrowser.LocalMetadata.Parsers { tags.Add(tag); } + break; } @@ -949,6 +988,7 @@ namespace MediaBrowser.LocalMetadata.Parsers reader.Read(); continue; } + using (var subtree = reader.ReadSubtree()) { foreach (var person in GetPersonsFromXmlNode(subtree)) @@ -957,9 +997,11 @@ namespace MediaBrowser.LocalMetadata.Parsers { continue; } + item.AddPerson(person); } } + break; } @@ -995,6 +1037,7 @@ namespace MediaBrowser.LocalMetadata.Parsers { item.AddTrailerUrl(val); } + break; } @@ -1035,6 +1078,7 @@ namespace MediaBrowser.LocalMetadata.Parsers { item.AddStudio(studio); } + break; } @@ -1084,6 +1128,7 @@ namespace MediaBrowser.LocalMetadata.Parsers { type = val; } + break; } @@ -1095,6 +1140,7 @@ namespace MediaBrowser.LocalMetadata.Parsers { role = val; } + break; } case "SortOrder": @@ -1108,6 +1154,7 @@ namespace MediaBrowser.LocalMetadata.Parsers sortOrder = intVal; } } + break; } @@ -1206,6 +1253,7 @@ namespace MediaBrowser.LocalMetadata.Parsers item.CanEdit = string.Equals(reader.ReadElementContentAsString(), "true", StringComparison.OrdinalIgnoreCase); break; } + default: { reader.Skip(); diff --git a/MediaBrowser.LocalMetadata/Parsers/BoxSetXmlParser.cs b/MediaBrowser.LocalMetadata/Parsers/BoxSetXmlParser.cs index ca11a079d..dd4eefa50 100644 --- a/MediaBrowser.LocalMetadata/Parsers/BoxSetXmlParser.cs +++ b/MediaBrowser.LocalMetadata/Parsers/BoxSetXmlParser.cs @@ -26,6 +26,7 @@ namespace MediaBrowser.LocalMetadata.Parsers { reader.Read(); } + break; default: @@ -69,6 +70,7 @@ namespace MediaBrowser.LocalMetadata.Parsers break; } + default: { reader.Skip(); diff --git a/MediaBrowser.LocalMetadata/Parsers/PlaylistXmlParser.cs b/MediaBrowser.LocalMetadata/Parsers/PlaylistXmlParser.cs index 54710cd82..941ed1b95 100644 --- a/MediaBrowser.LocalMetadata/Parsers/PlaylistXmlParser.cs +++ b/MediaBrowser.LocalMetadata/Parsers/PlaylistXmlParser.cs @@ -35,6 +35,7 @@ namespace MediaBrowser.LocalMetadata.Parsers { reader.Read(); } + break; default: @@ -77,6 +78,7 @@ namespace MediaBrowser.LocalMetadata.Parsers break; } + default: { reader.Skip(); diff --git a/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs index 071902393..70fd63ff3 100644 --- a/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs +++ b/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs @@ -32,10 +32,15 @@ namespace MediaBrowser.LocalMetadata.Savers } protected IFileSystem FileSystem { get; private set; } + protected IServerConfigurationManager ConfigurationManager { get; private set; } + protected ILibraryManager LibraryManager { get; private set; } + protected IUserManager UserManager { get; private set; } + protected IUserDataManager UserDataManager { get; private set; } + protected ILogger<BaseXmlSaver> Logger { get; private set; } public string Name => XmlProviderUtils.Name; @@ -185,6 +190,7 @@ namespace MediaBrowser.LocalMetadata.Savers { writer.WriteElementString("OriginalTitle", item.OriginalTitle); } + if (!string.IsNullOrEmpty(item.CustomRating)) { writer.WriteElementString("CustomRating", item.CustomRating); @@ -278,6 +284,7 @@ namespace MediaBrowser.LocalMetadata.Savers { writer.WriteElementString("Language", item.PreferredMetadataLanguage); } + if (!string.IsNullOrEmpty(item.PreferredMetadataCountryCode)) { writer.WriteElementString("CountryCode", item.PreferredMetadataCountryCode); diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index 82f6ce15e..a8df27d38 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -229,6 +229,7 @@ namespace MediaBrowser.MediaEncoding.Encoder { return inJellyfinPath; } + var values = Environment.GetEnvironmentVariable("PATH"); foreach (var path in values.Split(Path.PathSeparator)) diff --git a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs index 7d57a691e..918694e66 100644 --- a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs +++ b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs @@ -93,6 +93,7 @@ namespace MediaBrowser.MediaEncoding.Probing { overview = FFProbeHelpers.GetDictionaryValue(tags, "description"); } + if (string.IsNullOrWhiteSpace(overview)) { overview = FFProbeHelpers.GetDictionaryValue(tags, "desc"); @@ -274,10 +275,12 @@ namespace MediaBrowser.MediaEncoding.Probing reader.Read(); continue; } + using (var subtree = reader.ReadSubtree()) { ReadFromDictNode(subtree, info); } + break; default: reader.Skip(); @@ -319,6 +322,7 @@ namespace MediaBrowser.MediaEncoding.Probing { ProcessPairs(currentKey, pairs, info); } + currentKey = reader.ReadElementContentAsString(); pairs = new List<NameValuePair>(); break; @@ -332,6 +336,7 @@ namespace MediaBrowser.MediaEncoding.Probing Value = value }); } + break; case "array": if (reader.IsEmptyElement) @@ -339,6 +344,7 @@ namespace MediaBrowser.MediaEncoding.Probing reader.Read(); continue; } + using (var subtree = reader.ReadSubtree()) { if (!string.IsNullOrWhiteSpace(currentKey)) @@ -346,6 +352,7 @@ namespace MediaBrowser.MediaEncoding.Probing pairs.AddRange(ReadValueArray(subtree)); } } + break; default: reader.Skip(); @@ -381,6 +388,7 @@ namespace MediaBrowser.MediaEncoding.Probing reader.Read(); continue; } + using (var subtree = reader.ReadSubtree()) { var dict = GetNameValuePair(subtree); @@ -389,6 +397,7 @@ namespace MediaBrowser.MediaEncoding.Probing pairs.Add(dict); } } + break; default: reader.Skip(); @@ -948,6 +957,7 @@ namespace MediaBrowser.MediaEncoding.Probing { peoples.Add(new BaseItemPerson { Name = person, Type = PersonType.Composer }); } + audio.People = peoples.ToArray(); } @@ -979,6 +989,7 @@ namespace MediaBrowser.MediaEncoding.Probing { peoples.Add(new BaseItemPerson { Name = person, Type = PersonType.Writer }); } + audio.People = peoples.ToArray(); } @@ -1012,6 +1023,7 @@ namespace MediaBrowser.MediaEncoding.Probing { albumArtist = FFProbeHelpers.GetDictionaryValue(tags, "album artist"); } + if (string.IsNullOrWhiteSpace(albumArtist)) { albumArtist = FFProbeHelpers.GetDictionaryValue(tags, "album_artist"); @@ -1175,6 +1187,7 @@ namespace MediaBrowser.MediaEncoding.Probing { continue; } + if (info.AlbumArtists.Contains(studio, StringComparer.OrdinalIgnoreCase)) { continue; diff --git a/MediaBrowser.MediaEncoding/Subtitles/AssParser.cs b/MediaBrowser.MediaEncoding/Subtitles/AssParser.cs index f44cf1452..0e2d70017 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/AssParser.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/AssParser.cs @@ -23,6 +23,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles string line; while (reader.ReadLine() != "[Events]") { } + var headers = ParseFieldHeaders(reader.ReadLine()); while ((line = reader.ReadLine()) != null) @@ -56,6 +57,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles trackEvents.Add(subEvent); } } + trackInfo.TrackEvents = trackEvents.ToArray(); return trackInfo; } @@ -112,11 +114,13 @@ namespace MediaBrowser.MediaEncoding.Subtitles { pre = s.Substring(0, 5) + "}"; } + int indexOfEnd = p.Text.IndexOf('}'); p.Text = p.Text.Remove(indexOfBegin, (indexOfEnd - indexOfBegin) + 1); indexOfBegin = p.Text.IndexOf('{'); } + p.Text = pre + p.Text; } } diff --git a/MediaBrowser.MediaEncoding/Subtitles/SrtParser.cs b/MediaBrowser.MediaEncoding/Subtitles/SrtParser.cs index c98dd1502..a8d383a2a 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SrtParser.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SrtParser.cs @@ -35,6 +35,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles { continue; } + var subEvent = new SubtitleTrackEvent { Id = line }; line = reader.ReadLine(); @@ -52,6 +53,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles _logger.LogWarning("Unrecognized line in srt: {0}", line); continue; } + subEvent.StartPositionTicks = GetTicks(time[0]); var endTime = time[1]; var idx = endTime.IndexOf(" ", StringComparison.Ordinal); @@ -65,8 +67,10 @@ namespace MediaBrowser.MediaEncoding.Subtitles { break; } + multiline.Add(line); } + subEvent.Text = string.Join(ParserValues.NewLine, multiline); subEvent.Text = subEvent.Text.Replace(@"\N", ParserValues.NewLine, StringComparison.OrdinalIgnoreCase); subEvent.Text = Regex.Replace(subEvent.Text, @"\{(?:\\\d?[\w.-]+(?:\([^\)]*\)|&H?[0-9A-Fa-f]+&|))+\}", string.Empty, RegexOptions.IgnoreCase); @@ -76,6 +80,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles trackEvents.Add(subEvent); } } + trackInfo.TrackEvents = trackEvents.ToArray(); return trackInfo; } diff --git a/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs b/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs index bae2f5417..9a8fcc431 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs @@ -135,6 +135,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles // subtitle.Renumber(1); } + trackInfo.TrackEvents = trackEvents.ToArray(); return trackInfo; } @@ -302,6 +303,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles return count; index = text.IndexOf(tag, index + 1); } + return count; } @@ -329,6 +331,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles { rest = string.Empty; } + extraTags += " size=\"" + fontSize.Substring(2) + "\""; } else if (rest.StartsWith("fn") && rest.Length > 2) @@ -344,6 +347,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles { rest = string.Empty; } + extraTags += " face=\"" + fontName.Substring(2) + "\""; } else if (rest.StartsWith("c") && rest.Length > 2) diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs index e35a626d8..b9d526a22 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs @@ -115,6 +115,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles { throw new ArgumentNullException(nameof(item)); } + if (string.IsNullOrWhiteSpace(mediaSourceId)) { throw new ArgumentNullException(nameof(mediaSourceId)); @@ -271,8 +272,11 @@ namespace MediaBrowser.MediaEncoding.Subtitles } public string Path { get; set; } + public MediaProtocol Protocol { get; set; } + public string Format { get; set; } + public bool IsExternal { get; set; } } @@ -287,10 +291,12 @@ namespace MediaBrowser.MediaEncoding.Subtitles { return new SrtParser(_logger); } + if (string.Equals(format, SubtitleFormat.SSA, StringComparison.OrdinalIgnoreCase)) { return new SsaParser(); } + if (string.Equals(format, SubtitleFormat.ASS, StringComparison.OrdinalIgnoreCase)) { return new AssParser(); @@ -315,14 +321,17 @@ namespace MediaBrowser.MediaEncoding.Subtitles { return new JsonWriter(); } + if (string.Equals(format, SubtitleFormat.SRT, StringComparison.OrdinalIgnoreCase)) { return new SrtWriter(); } + if (string.Equals(format, SubtitleFormat.VTT, StringComparison.OrdinalIgnoreCase)) { return new VttWriter(); } + if (string.Equals(format, SubtitleFormat.TTML, StringComparison.OrdinalIgnoreCase)) { return new TtmlWriter(); diff --git a/MediaBrowser.Model/Configuration/LibraryOptions.cs b/MediaBrowser.Model/Configuration/LibraryOptions.cs index 4229a4335..890469d36 100644 --- a/MediaBrowser.Model/Configuration/LibraryOptions.cs +++ b/MediaBrowser.Model/Configuration/LibraryOptions.cs @@ -10,17 +10,27 @@ namespace MediaBrowser.Model.Configuration public class LibraryOptions { public bool EnablePhotos { get; set; } + public bool EnableRealtimeMonitor { get; set; } + public bool EnableChapterImageExtraction { get; set; } + public bool ExtractChapterImagesDuringLibraryScan { get; set; } + public bool DownloadImagesInAdvance { get; set; } + public MediaPathInfo[] PathInfos { get; set; } public bool SaveLocalMetadata { get; set; } + public bool EnableInternetProviders { get; set; } + public bool ImportMissingEpisodes { get; set; } + public bool EnableAutomaticSeriesGrouping { get; set; } + public bool EnableEmbeddedTitles { get; set; } + public bool EnableEmbeddedEpisodeInfos { get; set; } public int AutomaticRefreshIntervalDays { get; set; } @@ -38,17 +48,25 @@ namespace MediaBrowser.Model.Configuration public string MetadataCountryCode { get; set; } public string SeasonZeroDisplayName { get; set; } + public string[] MetadataSavers { get; set; } + public string[] DisabledLocalMetadataReaders { get; set; } + public string[] LocalMetadataReaderOrder { get; set; } public string[] DisabledSubtitleFetchers { get; set; } + public string[] SubtitleFetcherOrder { get; set; } public bool SkipSubtitlesIfEmbeddedSubtitlesPresent { get; set; } + public bool SkipSubtitlesIfAudioTrackMatches { get; set; } + public string[] SubtitleDownloadLanguages { get; set; } + public bool RequirePerfectSubtitleMatch { get; set; } + public bool SaveSubtitlesWithMedia { get; set; } public TypeOptions[] TypeOptions { get; set; } @@ -89,17 +107,22 @@ namespace MediaBrowser.Model.Configuration public class MediaPathInfo { public string Path { get; set; } + public string NetworkPath { get; set; } } public class TypeOptions { public string Type { get; set; } + public string[] MetadataFetchers { get; set; } + public string[] MetadataFetcherOrder { get; set; } public string[] ImageFetchers { get; set; } + public string[] ImageFetcherOrder { get; set; } + public ImageOption[] ImageOptions { get; set; } public ImageOption GetImageOptions(ImageType type) diff --git a/MediaBrowser.Model/Configuration/UserConfiguration.cs b/MediaBrowser.Model/Configuration/UserConfiguration.cs index 85d864eec..a5179f3ca 100644 --- a/MediaBrowser.Model/Configuration/UserConfiguration.cs +++ b/MediaBrowser.Model/Configuration/UserConfiguration.cs @@ -34,6 +34,7 @@ namespace MediaBrowser.Model.Configuration public string[] GroupedFolders { get; set; } public SubtitlePlaybackMode SubtitleMode { get; set; } + public bool DisplayCollectionsView { get; set; } public bool EnableLocalPassword { get; set; } @@ -41,12 +42,15 @@ namespace MediaBrowser.Model.Configuration public string[] OrderedViews { get; set; } public string[] LatestItemsExcludes { get; set; } + public string[] MyMediaExcludes { get; set; } public bool HidePlayedInLatest { get; set; } public bool RememberAudioSelections { get; set; } + public bool RememberSubtitleSelections { get; set; } + public bool EnableNextEpisodeAutoPlay { get; set; } /// <summary> diff --git a/MediaBrowser.Model/Configuration/XbmcMetadataOptions.cs b/MediaBrowser.Model/Configuration/XbmcMetadataOptions.cs index c48a38192..4d5f996f8 100644 --- a/MediaBrowser.Model/Configuration/XbmcMetadataOptions.cs +++ b/MediaBrowser.Model/Configuration/XbmcMetadataOptions.cs @@ -10,6 +10,7 @@ namespace MediaBrowser.Model.Configuration public string ReleaseDateFormat { get; set; } public bool SaveImagePathsInNfo { get; set; } + public bool EnablePathSubstitution { get; set; } public bool EnableExtraThumbsDuplication { get; set; } diff --git a/MediaBrowser.Model/Dlna/AudioOptions.cs b/MediaBrowser.Model/Dlna/AudioOptions.cs index fc555c5f7..1468b0414 100644 --- a/MediaBrowser.Model/Dlna/AudioOptions.cs +++ b/MediaBrowser.Model/Dlna/AudioOptions.cs @@ -85,6 +85,7 @@ namespace MediaBrowser.Model.Dlna { return Profile.MaxStaticMusicBitrate; } + return Profile.MaxStaticBitrate; } diff --git a/MediaBrowser.Model/Dlna/DeviceProfile.cs b/MediaBrowser.Model/Dlna/DeviceProfile.cs index 6462ffdc1..7e921b1fd 100644 --- a/MediaBrowser.Model/Dlna/DeviceProfile.cs +++ b/MediaBrowser.Model/Dlna/DeviceProfile.cs @@ -27,16 +27,25 @@ namespace MediaBrowser.Model.Dlna public DeviceIdentification Identification { get; set; } public string FriendlyName { get; set; } + public string Manufacturer { get; set; } + public string ManufacturerUrl { get; set; } + public string ModelName { get; set; } + public string ModelDescription { get; set; } + public string ModelNumber { get; set; } + public string ModelUrl { get; set; } + public string SerialNumber { get; set; } public bool EnableAlbumArtInDidl { get; set; } + public bool EnableSingleAlbumArtLimit { get; set; } + public bool EnableSingleSubtitleLimit { get; set; } public string SupportedMediaTypes { get; set; } @@ -46,15 +55,19 @@ namespace MediaBrowser.Model.Dlna public string AlbumArtPn { get; set; } public int MaxAlbumArtWidth { get; set; } + public int MaxAlbumArtHeight { get; set; } public int? MaxIconWidth { get; set; } + public int? MaxIconHeight { get; set; } public long? MaxStreamingBitrate { get; set; } + public long? MaxStaticBitrate { get; set; } public int? MusicStreamingTranscodingBitrate { get; set; } + public int? MaxStaticMusicBitrate { get; set; } /// <summary> @@ -65,10 +78,13 @@ namespace MediaBrowser.Model.Dlna public string ProtocolInfo { get; set; } public int TimelineOffsetSeconds { get; set; } + public bool RequiresPlainVideoItems { get; set; } + public bool RequiresPlainFolders { get; set; } public bool EnableMSMediaReceiverRegistrar { get; set; } + public bool IgnoreTranscodeByteRangeRequests { get; set; } public XmlAttribute[] XmlRootAttributes { get; set; } @@ -88,6 +104,7 @@ namespace MediaBrowser.Model.Dlna public ContainerProfile[] ContainerProfiles { get; set; } public CodecProfile[] CodecProfiles { get; set; } + public ResponseProfile[] ResponseProfiles { get; set; } public SubtitleProfile[] SubtitleProfiles { get; set; } @@ -169,6 +186,7 @@ namespace MediaBrowser.Model.Dlna return i; } + return null; } @@ -209,6 +227,7 @@ namespace MediaBrowser.Model.Dlna return i; } + return null; } @@ -254,6 +273,7 @@ namespace MediaBrowser.Model.Dlna return i; } + return null; } @@ -318,6 +338,7 @@ namespace MediaBrowser.Model.Dlna return i; } + return null; } } diff --git a/MediaBrowser.Model/Dlna/MediaFormatProfileResolver.cs b/MediaBrowser.Model/Dlna/MediaFormatProfileResolver.cs index c03a8060f..47cc89210 100644 --- a/MediaBrowser.Model/Dlna/MediaFormatProfileResolver.cs +++ b/MediaBrowser.Model/Dlna/MediaFormatProfileResolver.cs @@ -107,6 +107,7 @@ namespace MediaBrowser.Model.Dlna return list.ToArray(); } + if (string.Equals(videoCodec, "h264", StringComparison.OrdinalIgnoreCase)) { if (string.Equals(audioCodec, "lpcm", StringComparison.OrdinalIgnoreCase)) @@ -150,8 +151,10 @@ namespace MediaBrowser.Model.Dlna { return new MediaFormatProfile[] { MediaFormatProfile.VC1_TS_AP_L2_AC3_ISO }; } + return new MediaFormatProfile[] { MediaFormatProfile.VC1_TS_AP_L1_AC3_ISO }; } + if (string.Equals(audioCodec, "dts", StringComparison.OrdinalIgnoreCase)) { suffix = string.Equals(suffix, "_ISO", StringComparison.OrdinalIgnoreCase) ? suffix : "_T"; @@ -190,10 +193,12 @@ namespace MediaBrowser.Model.Dlna { return MediaFormatProfile.AVC_MP4_MP_SD_AC3; } + if (string.Equals(audioCodec, "mp3", StringComparison.OrdinalIgnoreCase)) { return MediaFormatProfile.AVC_MP4_MP_SD_MPEG1_L3; } + if (width.HasValue && height.HasValue) { if ((width.Value <= 720) && (height.Value <= 576)) @@ -277,6 +282,7 @@ namespace MediaBrowser.Model.Dlna { return MediaFormatProfile.WMVMED_FULL; } + return MediaFormatProfile.WMVMED_PRO; } } @@ -285,6 +291,7 @@ namespace MediaBrowser.Model.Dlna { return MediaFormatProfile.WMVHIGH_FULL; } + return MediaFormatProfile.WMVHIGH_PRO; } @@ -342,6 +349,7 @@ namespace MediaBrowser.Model.Dlna { return MediaFormatProfile.WMA_BASE; } + return MediaFormatProfile.WMA_FULL; } @@ -353,14 +361,17 @@ namespace MediaBrowser.Model.Dlna { return MediaFormatProfile.LPCM16_44_MONO; } + if (frequency.Value == 44100 && channels.Value == 2) { return MediaFormatProfile.LPCM16_44_STEREO; } + if (frequency.Value == 48000 && channels.Value == 1) { return MediaFormatProfile.LPCM16_48_MONO; } + if (frequency.Value == 48000 && channels.Value == 2) { return MediaFormatProfile.LPCM16_48_STEREO; @@ -378,6 +389,7 @@ namespace MediaBrowser.Model.Dlna { return MediaFormatProfile.AAC_ISO_320; } + return MediaFormatProfile.AAC_ISO; } @@ -387,6 +399,7 @@ namespace MediaBrowser.Model.Dlna { return MediaFormatProfile.AAC_ADTS_320; } + return MediaFormatProfile.AAC_ADTS; } diff --git a/MediaBrowser.Model/Dlna/StreamBuilder.cs b/MediaBrowser.Model/Dlna/StreamBuilder.cs index 3fe5cf774..06bd24476 100644 --- a/MediaBrowser.Model/Dlna/StreamBuilder.cs +++ b/MediaBrowser.Model/Dlna/StreamBuilder.cs @@ -627,10 +627,12 @@ namespace MediaBrowser.Model.Dlna { playlistItem.MinSegments = transcodingProfile.MinSegments; } + if (transcodingProfile.SegmentLength > 0) { playlistItem.SegmentLength = transcodingProfile.SegmentLength; } + playlistItem.SubProtocol = transcodingProfile.Protocol; if (!string.IsNullOrEmpty(transcodingProfile.MaxAudioChannels) @@ -947,6 +949,7 @@ namespace MediaBrowser.Model.Dlna { return (PlayMethod.DirectPlay, new List<TranscodeReason>()); } + if (options.ForceDirectStream) { return (PlayMethod.DirectStream, new List<TranscodeReason>()); @@ -1261,6 +1264,7 @@ namespace MediaBrowser.Model.Dlna return true; } } + return false; } @@ -1363,14 +1367,17 @@ namespace MediaBrowser.Model.Dlna { throw new ArgumentException("ItemId is required"); } + if (string.IsNullOrEmpty(options.DeviceId)) { throw new ArgumentException("DeviceId is required"); } + if (options.Profile == null) { throw new ArgumentException("Profile is required"); } + if (options.MediaSources == null) { throw new ArgumentException("MediaSources is required"); @@ -1418,6 +1425,7 @@ namespace MediaBrowser.Model.Dlna item.AudioBitrate = Math.Max(num, item.AudioBitrate ?? num); } } + break; } case ProfileConditionValue.AudioChannels: @@ -1452,6 +1460,7 @@ namespace MediaBrowser.Model.Dlna item.SetOption(qualifier, "audiochannels", Math.Max(num, item.GetTargetAudioChannels(qualifier) ?? num).ToString(CultureInfo.InvariantCulture)); } } + break; } case ProfileConditionValue.IsAvc: @@ -1472,6 +1481,7 @@ namespace MediaBrowser.Model.Dlna item.RequireAvc = true; } } + break; } case ProfileConditionValue.IsAnamorphic: @@ -1492,6 +1502,7 @@ namespace MediaBrowser.Model.Dlna item.RequireNonAnamorphic = true; } } + break; } case ProfileConditionValue.IsInterlaced: @@ -1522,6 +1533,7 @@ namespace MediaBrowser.Model.Dlna item.SetOption(qualifier, "deinterlace", "true"); } } + break; } case ProfileConditionValue.AudioProfile: @@ -1567,6 +1579,7 @@ namespace MediaBrowser.Model.Dlna item.SetOption(qualifier, "maxrefframes", Math.Max(num, item.GetTargetRefFrames(qualifier) ?? num).ToString(CultureInfo.InvariantCulture)); } } + break; } case ProfileConditionValue.VideoBitDepth: @@ -1601,6 +1614,7 @@ namespace MediaBrowser.Model.Dlna item.SetOption(qualifier, "videobitdepth", Math.Max(num, item.GetTargetVideoBitDepth(qualifier) ?? num).ToString(CultureInfo.InvariantCulture)); } } + break; } case ProfileConditionValue.VideoProfile: @@ -1623,6 +1637,7 @@ namespace MediaBrowser.Model.Dlna item.SetOption(qualifier, "profile", string.Join(",", values)); } } + break; } case ProfileConditionValue.Height: @@ -1647,6 +1662,7 @@ namespace MediaBrowser.Model.Dlna item.MaxHeight = Math.Max(num, item.MaxHeight ?? num); } } + break; } case ProfileConditionValue.VideoBitrate: @@ -1671,6 +1687,7 @@ namespace MediaBrowser.Model.Dlna item.VideoBitrate = Math.Max(num, item.VideoBitrate ?? num); } } + break; } case ProfileConditionValue.VideoFramerate: @@ -1695,6 +1712,7 @@ namespace MediaBrowser.Model.Dlna item.MaxFramerate = Math.Max(num, item.MaxFramerate ?? num); } } + break; } case ProfileConditionValue.VideoLevel: @@ -1719,6 +1737,7 @@ namespace MediaBrowser.Model.Dlna item.SetOption(qualifier, "level", Math.Max(num, item.GetTargetVideoLevel(qualifier) ?? num).ToString(CultureInfo.InvariantCulture)); } } + break; } case ProfileConditionValue.Width: @@ -1743,8 +1762,10 @@ namespace MediaBrowser.Model.Dlna item.MaxWidth = Math.Max(num, item.MaxWidth ?? num); } } + break; } + default: break; } diff --git a/MediaBrowser.Model/Dlna/StreamInfo.cs b/MediaBrowser.Model/Dlna/StreamInfo.cs index 244463803..9e9d0b7e1 100644 --- a/MediaBrowser.Model/Dlna/StreamInfo.cs +++ b/MediaBrowser.Model/Dlna/StreamInfo.cs @@ -69,6 +69,7 @@ namespace MediaBrowser.Model.Dlna public Guid ItemId { get; set; } public PlayMethod PlayMethod { get; set; } + public EncodingContext Context { get; set; } public DlnaProfileType MediaType { get; set; } @@ -80,15 +81,23 @@ namespace MediaBrowser.Model.Dlna public long StartPositionTicks { get; set; } public int? SegmentLength { get; set; } + public int? MinSegments { get; set; } + public bool BreakOnNonKeyFrames { get; set; } public bool RequireAvc { get; set; } + public bool RequireNonAnamorphic { get; set; } + public bool CopyTimestamps { get; set; } + public bool EnableMpegtsM2TsMode { get; set; } + public bool EnableSubtitlesInManifest { get; set; } + public string[] AudioCodecs { get; set; } + public string[] VideoCodecs { get; set; } public int? AudioStreamIndex { get; set; } @@ -96,6 +105,7 @@ namespace MediaBrowser.Model.Dlna public int? SubtitleStreamIndex { get; set; } public int? TranscodingMaxAudioChannels { get; set; } + public int? GlobalMaxAudioChannels { get; set; } public int? AudioBitrate { get; set; } @@ -103,12 +113,15 @@ namespace MediaBrowser.Model.Dlna public int? VideoBitrate { get; set; } public int? MaxWidth { get; set; } + public int? MaxHeight { get; set; } public float? MaxFramerate { get; set; } public DeviceProfile DeviceProfile { get; set; } + public string DeviceProfileId { get; set; } + public string DeviceId { get; set; } public long? RunTimeTicks { get; set; } @@ -120,10 +133,13 @@ namespace MediaBrowser.Model.Dlna public MediaSourceInfo MediaSource { get; set; } public string[] SubtitleCodecs { get; set; } + public SubtitleDeliveryMethod SubtitleDeliveryMethod { get; set; } + public string SubtitleFormat { get; set; } public string PlaySessionId { get; set; } + public TranscodeReason[] TranscodeReasons { get; set; } public Dictionary<string, string> StreamOptions { get; private set; } @@ -160,11 +176,13 @@ namespace MediaBrowser.Model.Dlna { continue; } + if (string.Equals(pair.Name, "SubtitleStreamIndex", StringComparison.OrdinalIgnoreCase) && string.Equals(pair.Value, "-1", StringComparison.OrdinalIgnoreCase)) { continue; } + if (string.Equals(pair.Name, "Static", StringComparison.OrdinalIgnoreCase) && string.Equals(pair.Value, "false", StringComparison.OrdinalIgnoreCase)) { @@ -993,6 +1011,7 @@ namespace MediaBrowser.Model.Dlna { return GetMediaStreamCount(MediaStreamType.Video, int.MaxValue); } + return GetMediaStreamCount(MediaStreamType.Video, 1); } } @@ -1005,6 +1024,7 @@ namespace MediaBrowser.Model.Dlna { return GetMediaStreamCount(MediaStreamType.Audio, int.MaxValue); } + return GetMediaStreamCount(MediaStreamType.Audio, 1); } } diff --git a/MediaBrowser.Model/Dto/BaseItemDto.cs b/MediaBrowser.Model/Dto/BaseItemDto.cs index c7f8f0584..62005b901 100644 --- a/MediaBrowser.Model/Dto/BaseItemDto.cs +++ b/MediaBrowser.Model/Dto/BaseItemDto.cs @@ -62,17 +62,23 @@ namespace MediaBrowser.Model.Dto public DateTime? DateCreated { get; set; } public DateTime? DateLastMediaAdded { get; set; } + public string ExtraType { get; set; } public int? AirsBeforeSeasonNumber { get; set; } + public int? AirsAfterSeasonNumber { get; set; } + public int? AirsBeforeEpisodeNumber { get; set; } + public bool? CanDelete { get; set; } + public bool? CanDownload { get; set; } public bool? HasSubtitles { get; set; } public string PreferredMetadataLanguage { get; set; } + public string PreferredMetadataCountryCode { get; set; } /// <summary> @@ -87,6 +93,7 @@ namespace MediaBrowser.Model.Dto /// </summary> /// <value>The name of the sort.</value> public string SortName { get; set; } + public string ForcedSortName { get; set; } /// <summary> @@ -146,6 +153,7 @@ namespace MediaBrowser.Model.Dto /// </summary> /// <value>The channel identifier.</value> public Guid ChannelId { get; set; } + public string ChannelName { get; set; } /// <summary> @@ -213,6 +221,7 @@ namespace MediaBrowser.Model.Dto /// </summary> /// <value>The number.</value> public string Number { get; set; } + public string ChannelNumber { get; set; } /// <summary> @@ -467,6 +476,7 @@ namespace MediaBrowser.Model.Dto /// </summary> /// <value>The part count.</value> public int? PartCount { get; set; } + public int? MediaSourceCount { get; set; } /// <summary> @@ -599,6 +609,7 @@ namespace MediaBrowser.Model.Dto /// </summary> /// <value>The series count.</value> public int? SeriesCount { get; set; } + public int? ProgramCount { get; set; } /// <summary> /// Gets or sets the episode count. @@ -615,6 +626,7 @@ namespace MediaBrowser.Model.Dto /// </summary> /// <value>The album count.</value> public int? AlbumCount { get; set; } + public int? ArtistCount { get; set; } /// <summary> /// Gets or sets the music video count. @@ -629,18 +641,31 @@ namespace MediaBrowser.Model.Dto public bool? LockData { get; set; } public int? Width { get; set; } + public int? Height { get; set; } + public string CameraMake { get; set; } + public string CameraModel { get; set; } + public string Software { get; set; } + public double? ExposureTime { get; set; } + public double? FocalLength { get; set; } + public ImageOrientation? ImageOrientation { get; set; } + public double? Aperture { get; set; } + public double? ShutterSpeed { get; set; } + public double? Latitude { get; set; } + public double? Longitude { get; set; } + public double? Altitude { get; set; } + public int? IsoSpeedRating { get; set; } /// <summary> diff --git a/MediaBrowser.Model/Dto/MediaSourceInfo.cs b/MediaBrowser.Model/Dto/MediaSourceInfo.cs index 74c2cb4f4..0c9e11f8f 100644 --- a/MediaBrowser.Model/Dto/MediaSourceInfo.cs +++ b/MediaBrowser.Model/Dto/MediaSourceInfo.cs @@ -13,16 +13,19 @@ namespace MediaBrowser.Model.Dto public class MediaSourceInfo { public MediaProtocol Protocol { get; set; } + public string Id { get; set; } public string Path { get; set; } public string EncoderPath { get; set; } + public MediaProtocol? EncoderProtocol { get; set; } public MediaSourceType Type { get; set; } public string Container { get; set; } + public long? Size { get; set; } public string Name { get; set; } @@ -33,19 +36,33 @@ namespace MediaBrowser.Model.Dto public bool IsRemote { get; set; } public string ETag { get; set; } + public long? RunTimeTicks { get; set; } + public bool ReadAtNativeFramerate { get; set; } + public bool IgnoreDts { get; set; } + public bool IgnoreIndex { get; set; } + public bool GenPtsInput { get; set; } + public bool SupportsTranscoding { get; set; } + public bool SupportsDirectStream { get; set; } + public bool SupportsDirectPlay { get; set; } + public bool IsInfiniteStream { get; set; } + public bool RequiresOpening { get; set; } + public string OpenToken { get; set; } + public bool RequiresClosing { get; set; } + public string LiveStreamId { get; set; } + public int? BufferMs { get; set; } public bool RequiresLooping { get; set; } @@ -67,10 +84,13 @@ namespace MediaBrowser.Model.Dto public int? Bitrate { get; set; } public TransportStreamTimestamp? Timestamp { get; set; } + public Dictionary<string, string> RequiredHttpHeaders { get; set; } public string TranscodingUrl { get; set; } + public string TranscodingSubProtocol { get; set; } + public string TranscodingContainer { get; set; } public int? AnalyzeDurationMs { get; set; } @@ -118,6 +138,7 @@ namespace MediaBrowser.Model.Dto public TranscodeReason[] TranscodeReasons { get; set; } public int? DefaultAudioStreamIndex { get; set; } + public int? DefaultSubtitleStreamIndex { get; set; } public MediaStream GetDefaultAudioStream(int? defaultIndex) diff --git a/MediaBrowser.Model/Dto/MetadataEditorInfo.cs b/MediaBrowser.Model/Dto/MetadataEditorInfo.cs index 1d840a300..e4f38d6af 100644 --- a/MediaBrowser.Model/Dto/MetadataEditorInfo.cs +++ b/MediaBrowser.Model/Dto/MetadataEditorInfo.cs @@ -11,11 +11,15 @@ namespace MediaBrowser.Model.Dto public class MetadataEditorInfo { public ParentalRating[] ParentalRatingOptions { get; set; } + public CountryInfo[] Countries { get; set; } + public CultureDto[] Cultures { get; set; } + public ExternalIdInfo[] ExternalIdInfos { get; set; } public string ContentType { get; set; } + public NameValuePair[] ContentTypeOptions { get; set; } public MetadataEditorInfo() diff --git a/MediaBrowser.Model/Dto/NameIdPair.cs b/MediaBrowser.Model/Dto/NameIdPair.cs index efb2c157c..45c2fb35d 100644 --- a/MediaBrowser.Model/Dto/NameIdPair.cs +++ b/MediaBrowser.Model/Dto/NameIdPair.cs @@ -23,6 +23,7 @@ namespace MediaBrowser.Model.Dto public class NameGuidPair { public string Name { get; set; } + public Guid Id { get; set; } } } diff --git a/MediaBrowser.Model/Entities/MediaStream.cs b/MediaBrowser.Model/Entities/MediaStream.cs index 3db72f78a..f0f7bf838 100644 --- a/MediaBrowser.Model/Entities/MediaStream.cs +++ b/MediaBrowser.Model/Entities/MediaStream.cs @@ -125,6 +125,7 @@ namespace MediaBrowser.Model.Entities { attributes.Add(StringHelper.FirstToUpper(Language)); } + if (!string.IsNullOrEmpty(Codec) && !string.Equals(Codec, "dca", StringComparison.OrdinalIgnoreCase)) { attributes.Add(AudioCodec.GetFriendlyName(Codec)); @@ -142,6 +143,7 @@ namespace MediaBrowser.Model.Entities { attributes.Add(Channels.Value.ToString(CultureInfo.InvariantCulture) + " ch"); } + if (IsDefault) { attributes.Add("Default"); @@ -227,30 +229,37 @@ namespace MediaBrowser.Model.Entities { return "4K"; } + if (width >= 2500) { if (i.IsInterlaced) { return "1440i"; } + return "1440p"; } + if (width >= 1900 || height >= 1000) { if (i.IsInterlaced) { return "1080i"; } + return "1080p"; } + if (width >= 1260 || height >= 700) { if (i.IsInterlaced) { return "720i"; } + return "720p"; } + if (width >= 700 || height >= 440) { @@ -258,11 +267,13 @@ namespace MediaBrowser.Model.Entities { return "480i"; } + return "480p"; } return "SD"; } + return null; } @@ -448,6 +459,7 @@ namespace MediaBrowser.Model.Entities { return false; } + if (string.Equals(fromCodec, "ssa", StringComparison.OrdinalIgnoreCase)) { return false; @@ -458,6 +470,7 @@ namespace MediaBrowser.Model.Entities { return false; } + if (string.Equals(toCodec, "ssa", StringComparison.OrdinalIgnoreCase)) { return false; diff --git a/MediaBrowser.Model/Entities/MediaUrl.cs b/MediaBrowser.Model/Entities/MediaUrl.cs index 74f982437..80ceaa765 100644 --- a/MediaBrowser.Model/Entities/MediaUrl.cs +++ b/MediaBrowser.Model/Entities/MediaUrl.cs @@ -6,6 +6,7 @@ namespace MediaBrowser.Model.Entities public class MediaUrl { public string Url { get; set; } + public string Name { get; set; } } } diff --git a/MediaBrowser.Model/Entities/VirtualFolderInfo.cs b/MediaBrowser.Model/Entities/VirtualFolderInfo.cs index 2de02e403..f8df05761 100644 --- a/MediaBrowser.Model/Entities/VirtualFolderInfo.cs +++ b/MediaBrowser.Model/Entities/VirtualFolderInfo.cs @@ -52,6 +52,7 @@ namespace MediaBrowser.Model.Entities public string PrimaryImageItemId { get; set; } public double? RefreshProgress { get; set; } + public string RefreshStatus { get; set; } } } diff --git a/MediaBrowser.Model/LiveTv/BaseTimerInfoDto.cs b/MediaBrowser.Model/LiveTv/BaseTimerInfoDto.cs index 45970cf6b..07e76d960 100644 --- a/MediaBrowser.Model/LiveTv/BaseTimerInfoDto.cs +++ b/MediaBrowser.Model/LiveTv/BaseTimerInfoDto.cs @@ -124,6 +124,7 @@ namespace MediaBrowser.Model.LiveTv /// </summary> /// <value><c>true</c> if this instance is post padding required; otherwise, <c>false</c>.</value> public bool IsPostPaddingRequired { get; set; } + public KeepUntil KeepUntil { get; set; } } } diff --git a/MediaBrowser.Model/LiveTv/LiveTvChannelQuery.cs b/MediaBrowser.Model/LiveTv/LiveTvChannelQuery.cs index d1a94d8b3..fe2390689 100644 --- a/MediaBrowser.Model/LiveTv/LiveTvChannelQuery.cs +++ b/MediaBrowser.Model/LiveTv/LiveTvChannelQuery.cs @@ -64,6 +64,7 @@ namespace MediaBrowser.Model.LiveTv /// </summary> /// <value><c>true</c> if [add current program]; otherwise, <c>false</c>.</value> public bool AddCurrentProgram { get; set; } + public bool EnableUserData { get; set; } /// <summary> @@ -88,6 +89,7 @@ namespace MediaBrowser.Model.LiveTv /// </summary> /// <value><c>null</c> if [is sports] contains no value, <c>true</c> if [is sports]; otherwise, <c>false</c>.</value> public bool? IsSports { get; set; } + public bool? IsSeries { get; set; } public string[] SortBy { get; set; } diff --git a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs index 69c43efd4..789de3198 100644 --- a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs +++ b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs @@ -9,21 +9,29 @@ namespace MediaBrowser.Model.LiveTv public class LiveTvOptions { public int? GuideDays { get; set; } + public string RecordingPath { get; set; } + public string MovieRecordingPath { get; set; } + public string SeriesRecordingPath { get; set; } + public bool EnableRecordingSubfolders { get; set; } + public bool EnableOriginalAudioWithEncodedRecordings { get; set; } public TunerHostInfo[] TunerHosts { get; set; } + public ListingsProviderInfo[] ListingProviders { get; set; } public int PrePaddingSeconds { get; set; } + public int PostPaddingSeconds { get; set; } public string[] MediaLocationsCreated { get; set; } public string RecordingPostProcessor { get; set; } + public string RecordingPostProcessorArguments { get; set; } public LiveTvOptions() @@ -38,15 +46,25 @@ namespace MediaBrowser.Model.LiveTv public class TunerHostInfo { public string Id { get; set; } + public string Url { get; set; } + public string Type { get; set; } + public string DeviceId { get; set; } + public string FriendlyName { get; set; } + public bool ImportFavoritesOnly { get; set; } + public bool AllowHWTranscoding { get; set; } + public bool EnableStreamLooping { get; set; } + public string Source { get; set; } + public int TunerCount { get; set; } + public string UserAgent { get; set; } public TunerHostInfo() @@ -58,23 +76,39 @@ namespace MediaBrowser.Model.LiveTv public class ListingsProviderInfo { public string Id { get; set; } + public string Type { get; set; } + public string Username { get; set; } + public string Password { get; set; } + public string ListingsId { get; set; } + public string ZipCode { get; set; } + public string Country { get; set; } + public string Path { get; set; } public string[] EnabledTuners { get; set; } + public bool EnableAllTuners { get; set; } + public string[] NewsCategories { get; set; } + public string[] SportsCategories { get; set; } + public string[] KidsCategories { get; set; } + public string[] MovieCategories { get; set; } + public NameValuePair[] ChannelMappings { get; set; } + public string MoviePrefix { get; set; } + public string PreferredLanguage { get; set; } + public string UserAgent { get; set; } public ListingsProviderInfo() diff --git a/MediaBrowser.Model/LiveTv/RecordingQuery.cs b/MediaBrowser.Model/LiveTv/RecordingQuery.cs index 264982930..25755483a 100644 --- a/MediaBrowser.Model/LiveTv/RecordingQuery.cs +++ b/MediaBrowser.Model/LiveTv/RecordingQuery.cs @@ -65,14 +65,23 @@ namespace MediaBrowser.Model.LiveTv /// </summary> /// <value>The fields.</value> public ItemFields[] Fields { get; set; } + public bool? EnableImages { get; set; } + public bool? IsLibraryItem { get; set; } + public bool? IsNews { get; set; } + public bool? IsMovie { get; set; } + public bool? IsSeries { get; set; } + public bool? IsKids { get; set; } + public bool? IsSports { get; set; } + public int? ImageTypeLimit { get; set; } + public ImageType[] EnableImageTypes { get; set; } public bool EnableTotalRecordCount { get; set; } diff --git a/MediaBrowser.Model/MediaInfo/LiveStreamRequest.cs b/MediaBrowser.Model/MediaInfo/LiveStreamRequest.cs index cce508809..83bda5d56 100644 --- a/MediaBrowser.Model/MediaInfo/LiveStreamRequest.cs +++ b/MediaBrowser.Model/MediaInfo/LiveStreamRequest.cs @@ -32,18 +32,29 @@ namespace MediaBrowser.Model.MediaInfo } public string OpenToken { get; set; } + public Guid UserId { get; set; } + public string PlaySessionId { get; set; } + public long? MaxStreamingBitrate { get; set; } + public long? StartTimeTicks { get; set; } + public int? AudioStreamIndex { get; set; } + public int? SubtitleStreamIndex { get; set; } + public int? MaxAudioChannels { get; set; } + public Guid ItemId { get; set; } + public DeviceProfile DeviceProfile { get; set; } public bool EnableDirectPlay { get; set; } + public bool EnableDirectStream { get; set; } + public MediaProtocol[] DirectPlayProtocols { get; set; } } } diff --git a/MediaBrowser.Model/MediaInfo/MediaInfo.cs b/MediaBrowser.Model/MediaInfo/MediaInfo.cs index 97b979935..472055c22 100644 --- a/MediaBrowser.Model/MediaInfo/MediaInfo.cs +++ b/MediaBrowser.Model/MediaInfo/MediaInfo.cs @@ -35,13 +35,21 @@ namespace MediaBrowser.Model.MediaInfo /// </summary> /// <value>The studios.</value> public string[] Studios { get; set; } + public string[] Genres { get; set; } + public string ShowName { get; set; } + public int? IndexNumber { get; set; } + public int? ParentIndexNumber { get; set; } + public int? ProductionYear { get; set; } + public DateTime? PremiereDate { get; set; } + public BaseItemPerson[] People { get; set; } + public Dictionary<string, string> ProviderIds { get; set; } /// <summary> diff --git a/MediaBrowser.Model/MediaInfo/PlaybackInfoRequest.cs b/MediaBrowser.Model/MediaInfo/PlaybackInfoRequest.cs index 82e13e0eb..321685677 100644 --- a/MediaBrowser.Model/MediaInfo/PlaybackInfoRequest.cs +++ b/MediaBrowser.Model/MediaInfo/PlaybackInfoRequest.cs @@ -29,11 +29,17 @@ namespace MediaBrowser.Model.MediaInfo public DeviceProfile DeviceProfile { get; set; } public bool EnableDirectPlay { get; set; } + public bool EnableDirectStream { get; set; } + public bool EnableTranscoding { get; set; } + public bool AllowVideoStreamCopy { get; set; } + public bool AllowAudioStreamCopy { get; set; } + public bool IsPlayback { get; set; } + public bool AutoOpenLiveStream { get; set; } public MediaProtocol[] DirectPlayProtocols { get; set; } diff --git a/MediaBrowser.Model/Providers/RemoteSubtitleInfo.cs b/MediaBrowser.Model/Providers/RemoteSubtitleInfo.cs index d9f7a852c..a8d88d8a1 100644 --- a/MediaBrowser.Model/Providers/RemoteSubtitleInfo.cs +++ b/MediaBrowser.Model/Providers/RemoteSubtitleInfo.cs @@ -8,15 +8,25 @@ namespace MediaBrowser.Model.Providers public class RemoteSubtitleInfo { public string ThreeLetterISOLanguageName { get; set; } + public string Id { get; set; } + public string ProviderName { get; set; } + public string Name { get; set; } + public string Format { get; set; } + public string Author { get; set; } + public string Comment { get; set; } + public DateTime? DateCreated { get; set; } + public float? CommunityRating { get; set; } + public int? DownloadCount { get; set; } + public bool? IsHashMatch { get; set; } } } diff --git a/MediaBrowser.Model/Providers/SubtitleOptions.cs b/MediaBrowser.Model/Providers/SubtitleOptions.cs index c07379570..5702c460b 100644 --- a/MediaBrowser.Model/Providers/SubtitleOptions.cs +++ b/MediaBrowser.Model/Providers/SubtitleOptions.cs @@ -8,13 +8,19 @@ namespace MediaBrowser.Model.Providers public class SubtitleOptions { public bool SkipIfEmbeddedSubtitlesPresent { get; set; } + public bool SkipIfAudioTrackMatches { get; set; } + public string[] DownloadLanguages { get; set; } + public bool DownloadMovieSubtitles { get; set; } + public bool DownloadEpisodeSubtitles { get; set; } public string OpenSubtitlesUsername { get; set; } + public string OpenSubtitlesPasswordHash { get; set; } + public bool IsOpenSubtitleVipAccount { get; set; } public bool RequirePerfectMatch { get; set; } diff --git a/MediaBrowser.Model/Providers/SubtitleProviderInfo.cs b/MediaBrowser.Model/Providers/SubtitleProviderInfo.cs index ee25be4b6..7a7e7b9ec 100644 --- a/MediaBrowser.Model/Providers/SubtitleProviderInfo.cs +++ b/MediaBrowser.Model/Providers/SubtitleProviderInfo.cs @@ -6,6 +6,7 @@ namespace MediaBrowser.Model.Providers public class SubtitleProviderInfo { public string Name { get; set; } + public string Id { get; set; } } } diff --git a/MediaBrowser.Model/Querying/QueryFilters.cs b/MediaBrowser.Model/Querying/QueryFilters.cs index e04208f76..6e4d25181 100644 --- a/MediaBrowser.Model/Querying/QueryFilters.cs +++ b/MediaBrowser.Model/Querying/QueryFilters.cs @@ -9,8 +9,11 @@ namespace MediaBrowser.Model.Querying public class QueryFiltersLegacy { public string[] Genres { get; set; } + public string[] Tags { get; set; } + public string[] OfficialRatings { get; set; } + public int[] Years { get; set; } public QueryFiltersLegacy() @@ -21,9 +24,11 @@ namespace MediaBrowser.Model.Querying Years = Array.Empty<int>(); } } + public class QueryFilters { public NameGuidPair[] Genres { get; set; } + public string[] Tags { get; set; } public QueryFilters() diff --git a/MediaBrowser.Model/Search/SearchHint.cs b/MediaBrowser.Model/Search/SearchHint.cs index c7a721df6..983dbd2bc 100644 --- a/MediaBrowser.Model/Search/SearchHint.cs +++ b/MediaBrowser.Model/Search/SearchHint.cs @@ -100,6 +100,7 @@ namespace MediaBrowser.Model.Search public string MediaType { get; set; } public DateTime? StartDate { get; set; } + public DateTime? EndDate { get; set; } /// <summary> diff --git a/MediaBrowser.Model/Search/SearchQuery.cs b/MediaBrowser.Model/Search/SearchQuery.cs index 4470f1ad9..297199f61 100644 --- a/MediaBrowser.Model/Search/SearchQuery.cs +++ b/MediaBrowser.Model/Search/SearchQuery.cs @@ -32,14 +32,21 @@ namespace MediaBrowser.Model.Search public int? Limit { get; set; } public bool IncludePeople { get; set; } + public bool IncludeMedia { get; set; } + public bool IncludeGenres { get; set; } + public bool IncludeStudios { get; set; } + public bool IncludeArtists { get; set; } public string[] MediaTypes { get; set; } + public string[] IncludeItemTypes { get; set; } + public string[] ExcludeItemTypes { get; set; } + public string ParentId { get; set; } public bool? IsMovie { get; set; } diff --git a/MediaBrowser.Model/Services/IRequest.cs b/MediaBrowser.Model/Services/IRequest.cs index f413f1e17..89622f311 100644 --- a/MediaBrowser.Model/Services/IRequest.cs +++ b/MediaBrowser.Model/Services/IRequest.cs @@ -76,9 +76,13 @@ namespace MediaBrowser.Model.Services public interface IHttpFile { string Name { get; } + string FileName { get; } + long ContentLength { get; } + string ContentType { get; } + Stream InputStream { get; } } diff --git a/MediaBrowser.Model/Services/IService.cs b/MediaBrowser.Model/Services/IService.cs index a26d39455..5233f57ab 100644 --- a/MediaBrowser.Model/Services/IService.cs +++ b/MediaBrowser.Model/Services/IService.cs @@ -8,6 +8,8 @@ namespace MediaBrowser.Model.Services } public interface IReturn { } + public interface IReturn<T> : IReturn { } + public interface IReturnVoid : IReturn { } } diff --git a/MediaBrowser.Model/Session/ClientCapabilities.cs b/MediaBrowser.Model/Session/ClientCapabilities.cs index 51db66d21..d3878ca30 100644 --- a/MediaBrowser.Model/Session/ClientCapabilities.cs +++ b/MediaBrowser.Model/Session/ClientCapabilities.cs @@ -13,15 +13,19 @@ namespace MediaBrowser.Model.Session public string[] SupportedCommands { get; set; } public bool SupportsMediaControl { get; set; } + public bool SupportsContentUploading { get; set; } + public string MessageCallbackUrl { get; set; } public bool SupportsPersistentIdentifier { get; set; } + public bool SupportsSync { get; set; } public DeviceProfile DeviceProfile { get; set; } public string AppStoreUrl { get; set; } + public string IconUrl { get; set; } public ClientCapabilities() diff --git a/MediaBrowser.Model/Session/PlayRequest.cs b/MediaBrowser.Model/Session/PlayRequest.cs index 62b68b49e..1a51e23c9 100644 --- a/MediaBrowser.Model/Session/PlayRequest.cs +++ b/MediaBrowser.Model/Session/PlayRequest.cs @@ -39,8 +39,11 @@ namespace MediaBrowser.Model.Session public Guid ControllingUserId { get; set; } public int? SubtitleStreamIndex { get; set; } + public int? AudioStreamIndex { get; set; } + public string MediaSourceId { get; set; } + public int? StartIndex { get; set; } } } diff --git a/MediaBrowser.Model/Session/PlaybackProgressInfo.cs b/MediaBrowser.Model/Session/PlaybackProgressInfo.cs index 6b4cfe4f0..21bcabf1d 100644 --- a/MediaBrowser.Model/Session/PlaybackProgressInfo.cs +++ b/MediaBrowser.Model/Session/PlaybackProgressInfo.cs @@ -105,6 +105,7 @@ namespace MediaBrowser.Model.Session public RepeatMode RepeatMode { get; set; } public QueueItem[] NowPlayingQueue { get; set; } + public string PlaylistItemId { get; set; } } @@ -118,6 +119,7 @@ namespace MediaBrowser.Model.Session public class QueueItem { public Guid Id { get; set; } + public string PlaylistItemId { get; set; } } } diff --git a/MediaBrowser.Model/Session/PlaybackStopInfo.cs b/MediaBrowser.Model/Session/PlaybackStopInfo.cs index b0827ac99..aa29bb249 100644 --- a/MediaBrowser.Model/Session/PlaybackStopInfo.cs +++ b/MediaBrowser.Model/Session/PlaybackStopInfo.cs @@ -62,6 +62,7 @@ namespace MediaBrowser.Model.Session public string NextMediaType { get; set; } public string PlaylistItemId { get; set; } + public QueueItem[] NowPlayingQueue { get; set; } } } diff --git a/MediaBrowser.Model/Session/TranscodingInfo.cs b/MediaBrowser.Model/Session/TranscodingInfo.cs index d6dc83413..e832c2f6f 100644 --- a/MediaBrowser.Model/Session/TranscodingInfo.cs +++ b/MediaBrowser.Model/Session/TranscodingInfo.cs @@ -8,17 +8,25 @@ namespace MediaBrowser.Model.Session public class TranscodingInfo { public string AudioCodec { get; set; } + public string VideoCodec { get; set; } + public string Container { get; set; } + public bool IsVideoDirect { get; set; } + public bool IsAudioDirect { get; set; } + public int? Bitrate { get; set; } public float? Framerate { get; set; } + public double? CompletionPercentage { get; set; } public int? Width { get; set; } + public int? Height { get; set; } + public int? AudioChannels { get; set; } public TranscodeReason[] TranscodeReasons { get; set; } diff --git a/MediaBrowser.Model/Sync/SyncJob.cs b/MediaBrowser.Model/Sync/SyncJob.cs index 3cc9ff726..b9290b6e8 100644 --- a/MediaBrowser.Model/Sync/SyncJob.cs +++ b/MediaBrowser.Model/Sync/SyncJob.cs @@ -122,7 +122,9 @@ namespace MediaBrowser.Model.Sync public int ItemCount { get; set; } public string ParentName { get; set; } + public string PrimaryImageItemId { get; set; } + public string PrimaryImageTag { get; set; } public SyncJob() diff --git a/MediaBrowser.Model/Users/UserAction.cs b/MediaBrowser.Model/Users/UserAction.cs index 36b8e6ee5..7646db4a8 100644 --- a/MediaBrowser.Model/Users/UserAction.cs +++ b/MediaBrowser.Model/Users/UserAction.cs @@ -8,11 +8,17 @@ namespace MediaBrowser.Model.Users public class UserAction { public string Id { get; set; } + public string ServerId { get; set; } + public Guid UserId { get; set; } + public Guid ItemId { get; set; } + public UserActionType Type { get; set; } + public DateTime Date { get; set; } + public long? PositionTicks { get; set; } } } diff --git a/MediaBrowser.Model/Users/UserPolicy.cs b/MediaBrowser.Model/Users/UserPolicy.cs index 2fd27d3b9..caf2e0f54 100644 --- a/MediaBrowser.Model/Users/UserPolicy.cs +++ b/MediaBrowser.Model/Users/UserPolicy.cs @@ -35,24 +35,37 @@ namespace MediaBrowser.Model.Users public int? MaxParentalRating { get; set; } public string[] BlockedTags { get; set; } + public bool EnableUserPreferenceAccess { get; set; } + public AccessSchedule[] AccessSchedules { get; set; } + public UnratedItem[] BlockUnratedItems { get; set; } + public bool EnableRemoteControlOfOtherUsers { get; set; } + public bool EnableSharedDeviceControl { get; set; } + public bool EnableRemoteAccess { get; set; } public bool EnableLiveTvManagement { get; set; } + public bool EnableLiveTvAccess { get; set; } public bool EnableMediaPlayback { get; set; } + public bool EnableAudioPlaybackTranscoding { get; set; } + public bool EnableVideoPlaybackTranscoding { get; set; } + public bool EnablePlaybackRemuxing { get; set; } + public bool ForceRemoteSourceTranscoding { get; set; } public bool EnableContentDeletion { get; set; } + public string[] EnableContentDeletionFromFolders { get; set; } + public bool EnableContentDownloading { get; set; } /// <summary> @@ -60,29 +73,36 @@ namespace MediaBrowser.Model.Users /// </summary> /// <value><c>true</c> if [enable synchronize]; otherwise, <c>false</c>.</value> public bool EnableSyncTranscoding { get; set; } + public bool EnableMediaConversion { get; set; } public string[] EnabledDevices { get; set; } + public bool EnableAllDevices { get; set; } public string[] EnabledChannels { get; set; } + public bool EnableAllChannels { get; set; } public string[] EnabledFolders { get; set; } + public bool EnableAllFolders { get; set; } public int InvalidLoginAttemptCount { get; set; } + public int LoginAttemptsBeforeLockout { get; set; } public bool EnablePublicSharing { get; set; } public string[] BlockedMediaFolders { get; set; } + public string[] BlockedChannels { get; set; } public int RemoteClientBitrateLimit { get; set; } [XmlElement(ElementName = "AuthenticationProviderId")] public string AuthenticationProviderId { get; set; } + public string PasswordResetProviderId { get; set; } /// <summary> diff --git a/MediaBrowser.Providers/Manager/ImageSaver.cs b/MediaBrowser.Providers/Manager/ImageSaver.cs index 3c94f6215..2f5aa1819 100644 --- a/MediaBrowser.Providers/Manager/ImageSaver.cs +++ b/MediaBrowser.Providers/Manager/ImageSaver.cs @@ -104,6 +104,7 @@ namespace MediaBrowser.Providers.Manager } } } + if (saveLocallyWithMedia.HasValue && !saveLocallyWithMedia.Value) { saveLocally = saveLocallyWithMedia.Value; @@ -147,6 +148,7 @@ namespace MediaBrowser.Providers.Manager { retryPath = retryPaths[currentPathIndex]; } + var savedPath = await SaveImageToLocation(source, path, retryPath, cancellationToken).ConfigureAwait(false); savedPaths.Add(savedPath); currentPathIndex++; @@ -460,6 +462,7 @@ namespace MediaBrowser.Providers.Manager { filename = folderName; } + path = Path.Combine(item.GetInternalMetadataPath(), filename + extension); } @@ -551,6 +554,7 @@ namespace MediaBrowser.Providers.Manager { list.Add(Path.Combine(item.ContainingFolderPath, "extrathumbs", "thumb" + outputIndex.ToString(UsCulture) + extension)); } + return list.ToArray(); } @@ -619,6 +623,7 @@ namespace MediaBrowser.Providers.Manager { imageFilename = "poster"; } + var folder = Path.GetDirectoryName(item.Path); return Path.Combine(folder, Path.GetFileNameWithoutExtension(item.Path) + "-" + imageFilename + extension); diff --git a/MediaBrowser.Providers/Manager/ItemImageProvider.cs b/MediaBrowser.Providers/Manager/ItemImageProvider.cs index 7901503d3..3d60979f3 100644 --- a/MediaBrowser.Providers/Manager/ItemImageProvider.cs +++ b/MediaBrowser.Providers/Manager/ItemImageProvider.cs @@ -58,6 +58,7 @@ namespace MediaBrowser.Providers.Manager { ClearImages(item, ImageType.Backdrop); } + if (refreshOptions.IsReplacingImage(ImageType.Screenshot)) { ClearImages(item, ImageType.Screenshot); @@ -472,6 +473,7 @@ namespace MediaBrowser.Providers.Manager { continue; } + break; } } @@ -585,6 +587,7 @@ namespace MediaBrowser.Providers.Manager { continue; } + break; } } diff --git a/MediaBrowser.Providers/Manager/MetadataService.cs b/MediaBrowser.Providers/Manager/MetadataService.cs index 73fb63743..a3920d26f 100644 --- a/MediaBrowser.Providers/Manager/MetadataService.cs +++ b/MediaBrowser.Providers/Manager/MetadataService.cs @@ -210,6 +210,7 @@ namespace MediaBrowser.Providers.Manager LibraryManager.UpdatePeople(baseItem, result.People); SavePeopleMetadata(result.People, libraryOptions, cancellationToken); } + result.Item.UpdateToRepository(reason, cancellationToken); } @@ -324,6 +325,7 @@ namespace MediaBrowser.Providers.Manager { return true; } + var folder = item as Folder; if (folder != null) { @@ -422,6 +424,7 @@ namespace MediaBrowser.Providers.Manager { dateLastMediaAdded = childDateCreated; } + any = true; } } @@ -726,6 +729,7 @@ namespace MediaBrowser.Providers.Manager { hasLocalMetadata = true; } + break; } @@ -874,6 +878,7 @@ namespace MediaBrowser.Providers.Manager { return "en"; } + return language; } @@ -924,7 +929,9 @@ namespace MediaBrowser.Providers.Manager public class RefreshResult { public ItemUpdateType UpdateType { get; set; } + public string ErrorMessage { get; set; } + public int Failures { get; set; } } } diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs index 5853c7714..5b1192c30 100644 --- a/MediaBrowser.Providers/Manager/ProviderManager.cs +++ b/MediaBrowser.Providers/Manager/ProviderManager.cs @@ -787,6 +787,7 @@ namespace MediaBrowser.Providers.Manager { searchInfo.SearchInfo.MetadataLanguage = _configurationManager.Configuration.PreferredMetadataLanguage; } + if (string.IsNullOrWhiteSpace(searchInfo.SearchInfo.MetadataCountryCode)) { searchInfo.SearchInfo.MetadataCountryCode = _configurationManager.Configuration.MetadataCountryCode; diff --git a/MediaBrowser.Providers/Manager/ProviderUtils.cs b/MediaBrowser.Providers/Manager/ProviderUtils.cs index 60410032e..4f49dc1c9 100644 --- a/MediaBrowser.Providers/Manager/ProviderUtils.cs +++ b/MediaBrowser.Providers/Manager/ProviderUtils.cs @@ -26,6 +26,7 @@ namespace MediaBrowser.Providers.Manager { throw new ArgumentNullException(nameof(source)); } + if (target == null) { throw new ArgumentNullException(nameof(target)); diff --git a/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs b/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs index ba87e0570..ef4e1dde9 100644 --- a/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs +++ b/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs @@ -129,6 +129,7 @@ namespace MediaBrowser.Providers.MediaInfo { return false; } + if (!item.IsFileProtocol) { return false; diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs index ccbe27c1f..54847c8a9 100644 --- a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs +++ b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs @@ -404,6 +404,7 @@ namespace MediaBrowser.Providers.MediaInfo video.ProductionYear = data.ProductionYear; } } + if (data.PremiereDate.HasValue) { if (!video.PremiereDate.HasValue || isFullRefresh) @@ -411,6 +412,7 @@ namespace MediaBrowser.Providers.MediaInfo video.PremiereDate = data.PremiereDate; } } + if (data.IndexNumber.HasValue) { if (!video.IndexNumber.HasValue || isFullRefresh) @@ -418,6 +420,7 @@ namespace MediaBrowser.Providers.MediaInfo video.IndexNumber = data.IndexNumber; } } + if (data.ParentIndexNumber.HasValue) { if (!video.ParentIndexNumber.HasValue || isFullRefresh) diff --git a/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs b/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs index 08e503a71..7f4a8a372 100644 --- a/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs +++ b/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs @@ -93,6 +93,7 @@ namespace MediaBrowser.Providers.MediaInfo { videoIndex++; } + if (mediaStream == imageStream) { break; @@ -132,6 +133,7 @@ namespace MediaBrowser.Providers.MediaInfo { return false; } + if (!item.IsFileProtocol) { return false; diff --git a/MediaBrowser.Providers/Movies/MovieMetadataService.cs b/MediaBrowser.Providers/Movies/MovieMetadataService.cs index 9faba4798..61d8c8263 100644 --- a/MediaBrowser.Providers/Movies/MovieMetadataService.cs +++ b/MediaBrowser.Providers/Movies/MovieMetadataService.cs @@ -28,10 +28,12 @@ namespace MediaBrowser.Providers.Movies { return false; } + if (!item.ProductionYear.HasValue) { return false; } + return base.IsFullLocalMetadata(item); } diff --git a/MediaBrowser.Providers/Movies/TrailerMetadataService.cs b/MediaBrowser.Providers/Movies/TrailerMetadataService.cs index b45d2b745..09519c7a3 100644 --- a/MediaBrowser.Providers/Movies/TrailerMetadataService.cs +++ b/MediaBrowser.Providers/Movies/TrailerMetadataService.cs @@ -28,10 +28,12 @@ namespace MediaBrowser.Providers.Movies { return false; } + if (!item.ProductionYear.HasValue) { return false; } + return base.IsFullLocalMetadata(item); } diff --git a/MediaBrowser.Providers/Playlists/PlaylistItemsProvider.cs b/MediaBrowser.Providers/Playlists/PlaylistItemsProvider.cs index ed0601c00..4ad4f890a 100644 --- a/MediaBrowser.Providers/Playlists/PlaylistItemsProvider.cs +++ b/MediaBrowser.Providers/Playlists/PlaylistItemsProvider.cs @@ -61,18 +61,22 @@ namespace MediaBrowser.Providers.Playlists { return GetWplItems(stream); } + if (string.Equals(".zpl", extension, StringComparison.OrdinalIgnoreCase)) { return GetZplItems(stream); } + if (string.Equals(".m3u", extension, StringComparison.OrdinalIgnoreCase)) { return GetM3uItems(stream); } + if (string.Equals(".m3u8", extension, StringComparison.OrdinalIgnoreCase)) { return GetM3u8Items(stream); } + if (string.Equals(".pls", extension, StringComparison.OrdinalIgnoreCase)) { return GetPlsItems(stream); diff --git a/MediaBrowser.Providers/Plugins/AudioDb/AlbumProvider.cs b/MediaBrowser.Providers/Plugins/AudioDb/AlbumProvider.cs index b1a54f22f..96224b366 100644 --- a/MediaBrowser.Providers/Plugins/AudioDb/AlbumProvider.cs +++ b/MediaBrowser.Providers/Plugins/AudioDb/AlbumProvider.cs @@ -210,42 +210,79 @@ namespace MediaBrowser.Providers.Plugins.AudioDb public class Album { public string idAlbum { get; set; } + public string idArtist { get; set; } + public string strAlbum { get; set; } + public string strArtist { get; set; } + public string intYearReleased { get; set; } + public string strGenre { get; set; } + public string strSubGenre { get; set; } + public string strReleaseFormat { get; set; } + public string intSales { get; set; } + public string strAlbumThumb { get; set; } + public string strAlbumCDart { get; set; } + public string strDescriptionEN { get; set; } + public string strDescriptionDE { get; set; } + public string strDescriptionFR { get; set; } + public string strDescriptionCN { get; set; } + public string strDescriptionIT { get; set; } + public string strDescriptionJP { get; set; } + public string strDescriptionRU { get; set; } + public string strDescriptionES { get; set; } + public string strDescriptionPT { get; set; } + public string strDescriptionSE { get; set; } + public string strDescriptionNL { get; set; } + public string strDescriptionHU { get; set; } + public string strDescriptionNO { get; set; } + public string strDescriptionIL { get; set; } + public string strDescriptionPL { get; set; } + public object intLoved { get; set; } + public object intScore { get; set; } + public string strReview { get; set; } + public object strMood { get; set; } + public object strTheme { get; set; } + public object strSpeed { get; set; } + public object strLocation { get; set; } + public string strMusicBrainzID { get; set; } + public string strMusicBrainzArtistID { get; set; } + public object strItunesID { get; set; } + public object strAmazonID { get; set; } + public string strLocked { get; set; } } diff --git a/MediaBrowser.Providers/Plugins/AudioDb/ArtistProvider.cs b/MediaBrowser.Providers/Plugins/AudioDb/ArtistProvider.cs index fdba779be..14bbcddce 100644 --- a/MediaBrowser.Providers/Plugins/AudioDb/ArtistProvider.cs +++ b/MediaBrowser.Providers/Plugins/AudioDb/ArtistProvider.cs @@ -199,45 +199,85 @@ namespace MediaBrowser.Providers.Plugins.AudioDb public class Artist { public string idArtist { get; set; } + public string strArtist { get; set; } + public string strArtistAlternate { get; set; } + public object idLabel { get; set; } + public string intFormedYear { get; set; } + public string intBornYear { get; set; } + public object intDiedYear { get; set; } + public object strDisbanded { get; set; } + public string strGenre { get; set; } + public string strSubGenre { get; set; } + public string strWebsite { get; set; } + public string strFacebook { get; set; } + public string strTwitter { get; set; } + public string strBiographyEN { get; set; } + public string strBiographyDE { get; set; } + public string strBiographyFR { get; set; } + public string strBiographyCN { get; set; } + public string strBiographyIT { get; set; } + public string strBiographyJP { get; set; } + public string strBiographyRU { get; set; } + public string strBiographyES { get; set; } + public string strBiographyPT { get; set; } + public string strBiographySE { get; set; } + public string strBiographyNL { get; set; } + public string strBiographyHU { get; set; } + public string strBiographyNO { get; set; } + public string strBiographyIL { get; set; } + public string strBiographyPL { get; set; } + public string strGender { get; set; } + public string intMembers { get; set; } + public string strCountry { get; set; } + public string strCountryCode { get; set; } + public string strArtistThumb { get; set; } + public string strArtistLogo { get; set; } + public string strArtistFanart { get; set; } + public string strArtistFanart2 { get; set; } + public string strArtistFanart3 { get; set; } + public string strArtistBanner { get; set; } + public string strMusicBrainzID { get; set; } + public object strLastFMChart { get; set; } + public string strLocked { get; set; } } diff --git a/MediaBrowser.Providers/Plugins/MusicBrainz/AlbumProvider.cs b/MediaBrowser.Providers/Plugins/MusicBrainz/AlbumProvider.cs index 0a2c7c124..78b500199 100644 --- a/MediaBrowser.Providers/Plugins/MusicBrainz/AlbumProvider.cs +++ b/MediaBrowser.Providers/Plugins/MusicBrainz/AlbumProvider.cs @@ -361,6 +361,7 @@ namespace MediaBrowser.Providers.Music return ParseReleaseList(subReader).ToList(); } } + default: { reader.Skip(); @@ -396,6 +397,7 @@ namespace MediaBrowser.Providers.Music reader.Read(); continue; } + var releaseId = reader.GetAttribute("id"); using (var subReader = reader.ReadSubtree()) @@ -406,8 +408,10 @@ namespace MediaBrowser.Providers.Music yield return release; } } + break; } + default: { reader.Skip(); @@ -453,6 +457,7 @@ namespace MediaBrowser.Providers.Music { result.Year = date.Year; } + break; } case "annotation": @@ -480,6 +485,7 @@ namespace MediaBrowser.Providers.Music break; } + default: { reader.Skip(); @@ -518,6 +524,7 @@ namespace MediaBrowser.Providers.Music return ParseArtistNameCredit(subReader); } } + default: { reader.Skip(); @@ -556,6 +563,7 @@ namespace MediaBrowser.Providers.Music return ParseArtistArtistCredit(subReader, id); } } + default: { reader.Skip(); @@ -593,6 +601,7 @@ namespace MediaBrowser.Providers.Music name = reader.ReadElementContentAsString(); break; } + default: { reader.Skip(); @@ -680,11 +689,13 @@ namespace MediaBrowser.Providers.Music reader.Read(); continue; } + using (var subReader = reader.ReadSubtree()) { return GetFirstReleaseGroupId(subReader); } } + default: { reader.Skip(); @@ -719,6 +730,7 @@ namespace MediaBrowser.Providers.Music { return reader.GetAttribute("id"); } + default: { reader.Skip(); @@ -780,6 +792,7 @@ namespace MediaBrowser.Providers.Music // We retry a finite number of times, and only whilst MB is indicating 503 (throttling) } + while (attempts < MusicBrainzQueryAttempts && response.StatusCode == HttpStatusCode.ServiceUnavailable); // Log error if unable to query MB database due to throttling diff --git a/MediaBrowser.Providers/Plugins/MusicBrainz/ArtistProvider.cs b/MediaBrowser.Providers/Plugins/MusicBrainz/ArtistProvider.cs index 9d93dbdd1..101af162d 100644 --- a/MediaBrowser.Providers/Plugins/MusicBrainz/ArtistProvider.cs +++ b/MediaBrowser.Providers/Plugins/MusicBrainz/ArtistProvider.cs @@ -108,11 +108,13 @@ namespace MediaBrowser.Providers.Music reader.Read(); continue; } + using (var subReader = reader.ReadSubtree()) { return ParseArtistList(subReader).ToList(); } } + default: { reader.Skip(); @@ -150,6 +152,7 @@ namespace MediaBrowser.Providers.Music reader.Read(); continue; } + var mbzId = reader.GetAttribute("id"); using (var subReader = reader.ReadSubtree()) @@ -160,8 +163,10 @@ namespace MediaBrowser.Providers.Music yield return artist; } } + break; } + default: { reader.Skip(); @@ -202,6 +207,7 @@ namespace MediaBrowser.Providers.Music result.Overview = reader.ReadElementContentAsString(); break; } + default: { // there is sort-name if ever needed diff --git a/MediaBrowser.Providers/Plugins/Omdb/OmdbItemProvider.cs b/MediaBrowser.Providers/Plugins/Omdb/OmdbItemProvider.cs index 4a29ba4d0..b12d2a388 100644 --- a/MediaBrowser.Providers/Plugins/Omdb/OmdbItemProvider.cs +++ b/MediaBrowser.Providers/Plugins/Omdb/OmdbItemProvider.cs @@ -286,27 +286,49 @@ namespace MediaBrowser.Providers.Plugins.Omdb class SearchResult { public string Title { get; set; } + public string Year { get; set; } + public string Rated { get; set; } + public string Released { get; set; } + public string Season { get; set; } + public string Episode { get; set; } + public string Runtime { get; set; } + public string Genre { get; set; } + public string Director { get; set; } + public string Writer { get; set; } + public string Actors { get; set; } + public string Plot { get; set; } + public string Language { get; set; } + public string Country { get; set; } + public string Awards { get; set; } + public string Poster { get; set; } + public string Metascore { get; set; } + public string imdbRating { get; set; } + public string imdbVotes { get; set; } + public string imdbID { get; set; } + public string seriesID { get; set; } + public string Type { get; set; } + public string Response { get; set; } } diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Models/Collections/CollectionImages.cs b/MediaBrowser.Providers/Plugins/Tmdb/Models/Collections/CollectionImages.cs index 2410ca16b..4ebcaeeb6 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/Models/Collections/CollectionImages.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/Models/Collections/CollectionImages.cs @@ -6,6 +6,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Models.Collections public class CollectionImages { public List<Backdrop> Backdrops { get; set; } + public List<Poster> Posters { get; set; } } } diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Models/Collections/CollectionResult.cs b/MediaBrowser.Providers/Plugins/Tmdb/Models/Collections/CollectionResult.cs index 3437552df..9228bec9c 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/Models/Collections/CollectionResult.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/Models/Collections/CollectionResult.cs @@ -5,11 +5,17 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Models.Collections public class CollectionResult { public int Id { get; set; } + public string Name { get; set; } + public string Overview { get; set; } + public string Poster_Path { get; set; } + public string Backdrop_Path { get; set; } + public List<Part> Parts { get; set; } + public CollectionImages Images { get; set; } } } diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Models/Collections/Part.cs b/MediaBrowser.Providers/Plugins/Tmdb/Models/Collections/Part.cs index 462fdab53..3a464e053 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/Models/Collections/Part.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/Models/Collections/Part.cs @@ -3,9 +3,13 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Models.Collections public class Part { public string Title { get; set; } + public int Id { get; set; } + public string Release_Date { get; set; } + public string Poster_Path { get; set; } + public string Backdrop_Path { get; set; } } } diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Models/General/Backdrop.cs b/MediaBrowser.Providers/Plugins/Tmdb/Models/General/Backdrop.cs index 35e3e2112..add7a38d8 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/Models/General/Backdrop.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/Models/General/Backdrop.cs @@ -3,11 +3,17 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Models.General public class Backdrop { public double Aspect_Ratio { get; set; } + public string File_Path { get; set; } + public int Height { get; set; } + public string Iso_639_1 { get; set; } + public double Vote_Average { get; set; } + public int Vote_Count { get; set; } + public int Width { get; set; } } } diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Models/General/Crew.cs b/MediaBrowser.Providers/Plugins/Tmdb/Models/General/Crew.cs index 6a5e74ddb..3f0fe7fad 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/Models/General/Crew.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/Models/General/Crew.cs @@ -3,10 +3,15 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Models.General public class Crew { public int Id { get; set; } + public string Credit_Id { get; set; } + public string Name { get; set; } + public string Department { get; set; } + public string Job { get; set; } + public string Profile_Path { get; set; } } } diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Models/General/ExternalIds.cs b/MediaBrowser.Providers/Plugins/Tmdb/Models/General/ExternalIds.cs index a083f6e9c..8082a5e58 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/Models/General/ExternalIds.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/Models/General/ExternalIds.cs @@ -3,9 +3,13 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Models.General public class ExternalIds { public string Imdb_Id { get; set; } + public object Freebase_Id { get; set; } + public string Freebase_Mid { get; set; } + public int Tvdb_Id { get; set; } + public int Tvrage_Id { get; set; } } } diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Models/General/Genre.cs b/MediaBrowser.Providers/Plugins/Tmdb/Models/General/Genre.cs index 7f1a394c3..d7b18ff8c 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/Models/General/Genre.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/Models/General/Genre.cs @@ -3,6 +3,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Models.General public class Genre { public int Id { get; set; } + public string Name { get; set; } } } diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Models/General/Images.cs b/MediaBrowser.Providers/Plugins/Tmdb/Models/General/Images.cs index 166f9b740..bbeac878a 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/Models/General/Images.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/Models/General/Images.cs @@ -5,6 +5,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Models.General public class Images { public List<Backdrop> Backdrops { get; set; } + public List<Poster> Posters { get; set; } } } diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Models/General/Keyword.cs b/MediaBrowser.Providers/Plugins/Tmdb/Models/General/Keyword.cs index 72f417be5..07cab86a0 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/Models/General/Keyword.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/Models/General/Keyword.cs @@ -3,6 +3,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Models.General public class Keyword { public int Id { get; set; } + public string Name { get; set; } } } diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Models/General/Poster.cs b/MediaBrowser.Providers/Plugins/Tmdb/Models/General/Poster.cs index 0cf04a6ce..3ac89a77d 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/Models/General/Poster.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/Models/General/Poster.cs @@ -3,11 +3,17 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Models.General public class Poster { public double Aspect_Ratio { get; set; } + public string File_Path { get; set; } + public int Height { get; set; } + public string Iso_639_1 { get; set; } + public double Vote_Average { get; set; } + public int Vote_Count { get; set; } + public int Width { get; set; } } } diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Models/General/Profile.cs b/MediaBrowser.Providers/Plugins/Tmdb/Models/General/Profile.cs index b45cfc30f..57edbe74c 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/Models/General/Profile.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/Models/General/Profile.cs @@ -3,9 +3,13 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Models.General public class Profile { public string File_Path { get; set; } + public int Width { get; set; } + public int Height { get; set; } + public object Iso_639_1 { get; set; } + public double Aspect_Ratio { get; set; } } } diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Models/General/Still.cs b/MediaBrowser.Providers/Plugins/Tmdb/Models/General/Still.cs index 9fc82cfee..1507c6577 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/Models/General/Still.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/Models/General/Still.cs @@ -3,12 +3,19 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Models.General public class Still { public double Aspect_Ratio { get; set; } + public string File_Path { get; set; } + public int Height { get; set; } + public string Id { get; set; } + public string Iso_639_1 { get; set; } + public double Vote_Average { get; set; } + public int Vote_Count { get; set; } + public int Width { get; set; } } } diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Models/General/Video.cs b/MediaBrowser.Providers/Plugins/Tmdb/Models/General/Video.cs index 19bfd62f6..e0fef6cce 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/Models/General/Video.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/Models/General/Video.cs @@ -3,12 +3,19 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Models.General public class Video { public string Id { get; set; } + public string Iso_639_1 { get; set; } + public string Iso_3166_1 { get; set; } + public string Key { get; set; } + public string Name { get; set; } + public string Site { get; set; } + public string Size { get; set; } + public string Type { get; set; } } } diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Models/Movies/BelongsToCollection.cs b/MediaBrowser.Providers/Plugins/Tmdb/Models/Movies/BelongsToCollection.cs index aaca57f05..af5bc9282 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/Models/Movies/BelongsToCollection.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/Models/Movies/BelongsToCollection.cs @@ -3,8 +3,11 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Models.Movies public class BelongsToCollection { public int Id { get; set; } + public string Name { get; set; } + public string Poster_Path { get; set; } + public string Backdrop_Path { get; set; } } } diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Models/Movies/Cast.cs b/MediaBrowser.Providers/Plugins/Tmdb/Models/Movies/Cast.cs index d70f218aa..6775350b7 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/Models/Movies/Cast.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/Models/Movies/Cast.cs @@ -3,10 +3,15 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Models.Movies public class Cast { public int Id { get; set; } + public string Name { get; set; } + public string Character { get; set; } + public int Order { get; set; } + public int Cast_Id { get; set; } + public string Profile_Path { get; set; } } } diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Models/Movies/Casts.cs b/MediaBrowser.Providers/Plugins/Tmdb/Models/Movies/Casts.cs index c41699bc7..5601de85e 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/Models/Movies/Casts.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/Models/Movies/Casts.cs @@ -6,6 +6,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Models.Movies public class Casts { public List<Cast> Cast { get; set; } + public List<Crew> Crew { get; set; } } } diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Models/Movies/Country.cs b/MediaBrowser.Providers/Plugins/Tmdb/Models/Movies/Country.cs index 71d1f7c24..f4cbc41f6 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/Models/Movies/Country.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/Models/Movies/Country.cs @@ -5,7 +5,9 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Models.Movies public class Country { public string Iso_3166_1 { get; set; } + public string Certification { get; set; } + public DateTime Release_Date { get; set; } } } diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Models/Movies/MovieResult.cs b/MediaBrowser.Providers/Plugins/Tmdb/Models/Movies/MovieResult.cs index 2a9b9779a..8e25e4fb3 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/Models/Movies/MovieResult.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/Models/Movies/MovieResult.cs @@ -6,34 +6,63 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Models.Movies public class MovieResult { public bool Adult { get; set; } + public string Backdrop_Path { get; set; } + public BelongsToCollection Belongs_To_Collection { get; set; } + public int Budget { get; set; } + public List<Genre> Genres { get; set; } + public string Homepage { get; set; } + public int Id { get; set; } + public string Imdb_Id { get; set; } + public string Original_Title { get; set; } + public string Original_Name { get; set; } + public string Overview { get; set; } + public double Popularity { get; set; } + public string Poster_Path { get; set; } + public List<ProductionCompany> Production_Companies { get; set; } + public List<ProductionCountry> Production_Countries { get; set; } + public string Release_Date { get; set; } + public int Revenue { get; set; } + public int Runtime { get; set; } + public List<SpokenLanguage> Spoken_Languages { get; set; } + public string Status { get; set; } + public string Tagline { get; set; } + public string Title { get; set; } + public string Name { get; set; } + public double Vote_Average { get; set; } + public int Vote_Count { get; set; } + public Casts Casts { get; set; } + public Releases Releases { get; set; } + public Images Images { get; set; } + public Keywords Keywords { get; set; } + public Trailers Trailers { get; set; } public string GetOriginalTitle() diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Models/Movies/ProductionCompany.cs b/MediaBrowser.Providers/Plugins/Tmdb/Models/Movies/ProductionCompany.cs index 11158ade5..ba8e42fdd 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/Models/Movies/ProductionCompany.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/Models/Movies/ProductionCompany.cs @@ -3,6 +3,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Models.Movies public class ProductionCompany { public string Name { get; set; } + public int Id { get; set; } } } diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Models/Movies/ProductionCountry.cs b/MediaBrowser.Providers/Plugins/Tmdb/Models/Movies/ProductionCountry.cs index 43d00fe7a..a313605bd 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/Models/Movies/ProductionCountry.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/Models/Movies/ProductionCountry.cs @@ -3,6 +3,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Models.Movies public class ProductionCountry { public string Iso_3166_1 { get; set; } + public string Name { get; set; } } } diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Models/Movies/SpokenLanguage.cs b/MediaBrowser.Providers/Plugins/Tmdb/Models/Movies/SpokenLanguage.cs index 41defa9d0..9469a41f1 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/Models/Movies/SpokenLanguage.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/Models/Movies/SpokenLanguage.cs @@ -3,6 +3,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Models.Movies public class SpokenLanguage { public string Iso_639_1 { get; set; } + public string Name { get; set; } } } diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Models/Movies/Youtube.cs b/MediaBrowser.Providers/Plugins/Tmdb/Models/Movies/Youtube.cs index 6be4ef5b5..499e368a4 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/Models/Movies/Youtube.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/Models/Movies/Youtube.cs @@ -3,7 +3,9 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Models.Movies public class Youtube { public string Name { get; set; } + public string Size { get; set; } + public string Source { get; set; } } } diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Models/People/PersonResult.cs b/MediaBrowser.Providers/Plugins/Tmdb/Models/People/PersonResult.cs index 50c47eefd..076648a6c 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/Models/People/PersonResult.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/Models/People/PersonResult.cs @@ -6,18 +6,31 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Models.People public class PersonResult { public bool Adult { get; set; } + public List<string> Also_Known_As { get; set; } + public string Biography { get; set; } + public string Birthday { get; set; } + public string Deathday { get; set; } + public string Homepage { get; set; } + public int Id { get; set; } + public string Imdb_Id { get; set; } + public string Name { get; set; } + public string Place_Of_Birth { get; set; } + public double Popularity { get; set; } + public string Profile_Path { get; set; } + public PersonImages Images { get; set; } + public ExternalIds External_Ids { get; set; } } } diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Models/Search/TvResult.cs b/MediaBrowser.Providers/Plugins/Tmdb/Models/Search/TvResult.cs index b7fbd294c..c611bcd5f 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/Models/Search/TvResult.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/Models/Search/TvResult.cs @@ -3,13 +3,21 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Models.Search public class TvResult { public string Backdrop_Path { get; set; } + public string First_Air_Date { get; set; } + public int Id { get; set; } + public string Original_Name { get; set; } + public string Poster_Path { get; set; } + public double Popularity { get; set; } + public string Name { get; set; } + public double Vote_Average { get; set; } + public int Vote_Count { get; set; } } } diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Models/TV/Cast.cs b/MediaBrowser.Providers/Plugins/Tmdb/Models/TV/Cast.cs index 9c770545c..ebf7ba6e4 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/Models/TV/Cast.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/Models/TV/Cast.cs @@ -3,10 +3,15 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Models.TV public class Cast { public string Character { get; set; } + public string Credit_Id { get; set; } + public int Id { get; set; } + public string Name { get; set; } + public string Profile_Path { get; set; } + public int Order { get; set; } } } diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Models/TV/ContentRating.cs b/MediaBrowser.Providers/Plugins/Tmdb/Models/TV/ContentRating.cs index bccb234e7..9de674e7f 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/Models/TV/ContentRating.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/Models/TV/ContentRating.cs @@ -3,6 +3,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Models.TV public class ContentRating { public string Iso_3166_1 { get; set; } + public string Rating { get; set; } } } diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Models/TV/CreatedBy.cs b/MediaBrowser.Providers/Plugins/Tmdb/Models/TV/CreatedBy.cs index 35e8eaecb..1ef65bb98 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/Models/TV/CreatedBy.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/Models/TV/CreatedBy.cs @@ -3,7 +3,9 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Models.TV public class CreatedBy { public int Id { get; set; } + public string Name { get; set; } + public string Profile_Path { get; set; } } } diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Models/TV/Credits.cs b/MediaBrowser.Providers/Plugins/Tmdb/Models/TV/Credits.cs index ebf412c2d..836fbcbe5 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/Models/TV/Credits.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/Models/TV/Credits.cs @@ -6,6 +6,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Models.TV public class Credits { public List<Cast> Cast { get; set; } + public List<Crew> Crew { get; set; } } } diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Models/TV/Episode.cs b/MediaBrowser.Providers/Plugins/Tmdb/Models/TV/Episode.cs index 8203632b7..a38012e31 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/Models/TV/Episode.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/Models/TV/Episode.cs @@ -3,12 +3,19 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Models.TV public class Episode { public string Air_Date { get; set; } + public int Episode_Number { get; set; } + public int Id { get; set; } + public string Name { get; set; } + public string Overview { get; set; } + public string Still_Path { get; set; } + public double Vote_Average { get; set; } + public int Vote_Count { get; set; } } } diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Models/TV/EpisodeCredits.cs b/MediaBrowser.Providers/Plugins/Tmdb/Models/TV/EpisodeCredits.cs index f89859f85..5068e8f9b 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/Models/TV/EpisodeCredits.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/Models/TV/EpisodeCredits.cs @@ -6,7 +6,9 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Models.TV public class EpisodeCredits { public List<Cast> Cast { get; set; } + public List<Crew> Crew { get; set; } + public List<GuestStar> Guest_Stars { get; set; } } } diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Models/TV/EpisodeResult.cs b/MediaBrowser.Providers/Plugins/Tmdb/Models/TV/EpisodeResult.cs index e25b65d70..a4d6a130e 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/Models/TV/EpisodeResult.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/Models/TV/EpisodeResult.cs @@ -6,18 +6,31 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Models.TV public class EpisodeResult { public DateTime Air_Date { get; set; } + public int Episode_Number { get; set; } + public string Name { get; set; } + public string Overview { get; set; } + public int Id { get; set; } + public object Production_Code { get; set; } + public int Season_Number { get; set; } + public string Still_Path { get; set; } + public double Vote_Average { get; set; } + public int Vote_Count { get; set; } + public StillImages Images { get; set; } + public ExternalIds External_Ids { get; set; } + public EpisodeCredits Credits { get; set; } + public Tmdb.Models.General.Videos Videos { get; set; } } } diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Models/TV/GuestStar.cs b/MediaBrowser.Providers/Plugins/Tmdb/Models/TV/GuestStar.cs index 260f3f610..da5e63171 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/Models/TV/GuestStar.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/Models/TV/GuestStar.cs @@ -3,10 +3,15 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Models.TV public class GuestStar { public int Id { get; set; } + public string Name { get; set; } + public string Credit_Id { get; set; } + public string Character { get; set; } + public int Order { get; set; } + public string Profile_Path { get; set; } } } diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Models/TV/Network.cs b/MediaBrowser.Providers/Plugins/Tmdb/Models/TV/Network.cs index 5ed310827..0eba92ae2 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/Models/TV/Network.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/Models/TV/Network.cs @@ -3,6 +3,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Models.TV public class Network { public int Id { get; set; } + public string Name { get; set; } } } diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Models/TV/Season.cs b/MediaBrowser.Providers/Plugins/Tmdb/Models/TV/Season.cs index fddf950ee..2e39c5901 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/Models/TV/Season.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/Models/TV/Season.cs @@ -3,9 +3,13 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Models.TV public class Season { public string Air_Date { get; set; } + public int Episode_Count { get; set; } + public int Id { get; set; } + public string Poster_Path { get; set; } + public int Season_Number { get; set; } } } diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Models/TV/SeasonResult.cs b/MediaBrowser.Providers/Plugins/Tmdb/Models/TV/SeasonResult.cs index 13b4c30f8..328bd1ebc 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/Models/TV/SeasonResult.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/Models/TV/SeasonResult.cs @@ -7,15 +7,25 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Models.TV public class SeasonResult { public DateTime Air_Date { get; set; } + public List<Episode> Episodes { get; set; } + public string Name { get; set; } + public string Overview { get; set; } + public int Id { get; set; } + public string Poster_Path { get; set; } + public int Season_Number { get; set; } + public Credits Credits { get; set; } + public SeasonImages Images { get; set; } + public ExternalIds External_Ids { get; set; } + public General.Videos Videos { get; set; } } } diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Models/TV/SeriesResult.cs b/MediaBrowser.Providers/Plugins/Tmdb/Models/TV/SeriesResult.cs index 5c1666c77..499249b8e 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/Models/TV/SeriesResult.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/Models/TV/SeriesResult.cs @@ -7,34 +7,63 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Models.TV public class SeriesResult { public string Backdrop_Path { get; set; } + public List<CreatedBy> Created_By { get; set; } + public List<int> Episode_Run_Time { get; set; } + public DateTime First_Air_Date { get; set; } + public List<Genre> Genres { get; set; } + public string Homepage { get; set; } + public int Id { get; set; } + public bool In_Production { get; set; } + public List<string> Languages { get; set; } + public DateTime Last_Air_Date { get; set; } + public string Name { get; set; } + public List<Network> Networks { get; set; } + public int Number_Of_Episodes { get; set; } + public int Number_Of_Seasons { get; set; } + public string Original_Name { get; set; } + public List<string> Origin_Country { get; set; } + public string Overview { get; set; } + public string Popularity { get; set; } + public string Poster_Path { get; set; } + public List<Season> Seasons { get; set; } + public string Status { get; set; } + public double Vote_Average { get; set; } + public int Vote_Count { get; set; } + public Credits Credits { get; set; } + public Images Images { get; set; } + public Keywords Keywords { get; set; } + public ExternalIds External_Ids { get; set; } + public General.Videos Videos { get; set; } + public ContentRatings Content_Ratings { get; set; } + public string ResultLanguage { get; set; } } } diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbImageProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbImageProvider.cs index a11c89459..8ecd6b917 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbImageProvider.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbImageProvider.cs @@ -107,6 +107,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Movies { return 3; } + if (!isLanguageEn) { if (string.Equals("en", i.Language, StringComparison.OrdinalIgnoreCase)) @@ -114,10 +115,12 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Movies return 2; } } + if (string.IsNullOrEmpty(i.Language)) { return isLanguageEn ? 3 : 2; } + return 0; }) .ThenByDescending(i => i.CommunityRating ?? 0) diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbSettings.cs b/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbSettings.cs index 03669ca67..3a45d4a55 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbSettings.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbSettings.cs @@ -5,8 +5,11 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Movies internal class TmdbImageSettings { public List<string> backdrop_sizes { get; set; } + public string secure_base_url { get; set; } + public List<string> poster_sizes { get; set; } + public List<string> profile_sizes { get; set; } public string GetImageUrl(string image) diff --git a/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonImageProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonImageProvider.cs index 525c0072b..edd90475d 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonImageProvider.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonImageProvider.cs @@ -98,6 +98,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.People { return 3; } + if (!isLanguageEn) { if (string.Equals("en", i.Language, StringComparison.OrdinalIgnoreCase)) @@ -105,10 +106,12 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.People return 2; } } + if (string.IsNullOrEmpty(i.Language)) { return isLanguageEn ? 3 : 2; } + return 0; }) .ThenByDescending(i => i.CommunityRating ?? 0) diff --git a/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonProvider.cs index 654e42a90..a13d41dc2 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonProvider.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonProvider.cs @@ -173,6 +173,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.People { item.ProductionLocations = new string[] { info.Place_Of_Birth }; } + item.Overview = info.Biography; if (DateTime.TryParseExact(info.Birthday, "yyyy-MM-dd", new CultureInfo("en-US"), DateTimeStyles.None, out var date)) diff --git a/MediaBrowser.Providers/Subtitles/SubtitleManager.cs b/MediaBrowser.Providers/Subtitles/SubtitleManager.cs index 8086533eb..24c29a219 100644 --- a/MediaBrowser.Providers/Subtitles/SubtitleManager.cs +++ b/MediaBrowser.Providers/Subtitles/SubtitleManager.cs @@ -104,6 +104,7 @@ namespace MediaBrowser.Providers.Subtitles _logger.LogError(ex, "Error downloading subtitles from {Provider}", provider.Name); } } + return Array.Empty<RemoteSubtitleInfo>(); } diff --git a/MediaBrowser.Providers/TV/DummySeasonProvider.cs b/MediaBrowser.Providers/TV/DummySeasonProvider.cs index 6e0511971..92c42e9d8 100644 --- a/MediaBrowser.Providers/TV/DummySeasonProvider.cs +++ b/MediaBrowser.Providers/TV/DummySeasonProvider.cs @@ -72,6 +72,7 @@ namespace MediaBrowser.Providers.TV { seasons = series.Children.OfType<Season>().ToList(); } + var existingSeason = seasons .FirstOrDefault(i => i.IndexNumber.HasValue && i.IndexNumber.Value == seasonNumber); diff --git a/MediaBrowser.Providers/TV/SeriesMetadataService.cs b/MediaBrowser.Providers/TV/SeriesMetadataService.cs index 7a753e832..6d303fab1 100644 --- a/MediaBrowser.Providers/TV/SeriesMetadataService.cs +++ b/MediaBrowser.Providers/TV/SeriesMetadataService.cs @@ -67,10 +67,12 @@ namespace MediaBrowser.Providers.TV { return false; } + if (!item.ProductionYear.HasValue) { return false; } + return base.IsFullLocalMetadata(item); } diff --git a/RSSDP/DiscoveredSsdpDevice.cs b/RSSDP/DiscoveredSsdpDevice.cs index 1244ce523..9093199dd 100644 --- a/RSSDP/DiscoveredSsdpDevice.cs +++ b/RSSDP/DiscoveredSsdpDevice.cs @@ -45,6 +45,7 @@ namespace Rssdp public DateTimeOffset AsAt { get { return _AsAt; } + set { if (_AsAt != value) diff --git a/RSSDP/HttpParserBase.cs b/RSSDP/HttpParserBase.cs index c2eb0bf92..e7172cb1c 100644 --- a/RSSDP/HttpParserBase.cs +++ b/RSSDP/HttpParserBase.cs @@ -135,6 +135,7 @@ namespace Rssdp.Infrastructure ParseHeader(line, headers, contentHeaders); } + return lineIndex; } diff --git a/RSSDP/SsdpCommunicationsServer.cs b/RSSDP/SsdpCommunicationsServer.cs index 863f2b15c..fe49fb7d3 100644 --- a/RSSDP/SsdpCommunicationsServer.cs +++ b/RSSDP/SsdpCommunicationsServer.cs @@ -311,6 +311,7 @@ namespace Rssdp.Infrastructure public bool IsShared { get { return _IsShared; } + set { _IsShared = value; } } diff --git a/RSSDP/SsdpDevice.cs b/RSSDP/SsdpDevice.cs index 691ba2a14..f89bafb19 100644 --- a/RSSDP/SsdpDevice.cs +++ b/RSSDP/SsdpDevice.cs @@ -90,6 +90,7 @@ namespace Rssdp { return _DeviceType; } + set { _DeviceType = value; @@ -111,6 +112,7 @@ namespace Rssdp { return _DeviceTypeNamespace; } + set { _DeviceTypeNamespace = value; @@ -130,6 +132,7 @@ namespace Rssdp { return _DeviceVersion; } + set { _DeviceVersion = value; @@ -181,6 +184,7 @@ namespace Rssdp else return _Udn; } + set { _Udn = value; diff --git a/RSSDP/SsdpDeviceLocator.cs b/RSSDP/SsdpDeviceLocator.cs index a626e13b9..9b48cf31c 100644 --- a/RSSDP/SsdpDeviceLocator.cs +++ b/RSSDP/SsdpDeviceLocator.cs @@ -579,6 +579,7 @@ namespace Rssdp.Infrastructure return d; } } + return null; } diff --git a/RSSDP/SsdpDevicePublisher.cs b/RSSDP/SsdpDevicePublisher.cs index 5dfb6a8c2..b4cf2fb48 100644 --- a/RSSDP/SsdpDevicePublisher.cs +++ b/RSSDP/SsdpDevicePublisher.cs @@ -156,6 +156,7 @@ namespace Rssdp.Infrastructure public bool SupportPnpRootDevice { get { return _SupportPnpRootDevice; } + set { _SupportPnpRootDevice = value; @@ -564,7 +565,9 @@ namespace Rssdp.Infrastructure private class SearchRequest { public IPEndPoint EndPoint { get; set; } + public DateTime Received { get; set; } + public string SearchTarget { get; set; } public string Key diff --git a/RSSDP/SsdpEmbeddedDevice.cs b/RSSDP/SsdpEmbeddedDevice.cs index 4810703d7..ff644993b 100644 --- a/RSSDP/SsdpEmbeddedDevice.cs +++ b/RSSDP/SsdpEmbeddedDevice.cs @@ -33,6 +33,7 @@ namespace Rssdp { return _RootDevice; } + internal set { _RootDevice = value; -- cgit v1.2.3 From 4be476ec5312387f87134915d0fd132b2ad5fa3f Mon Sep 17 00:00:00 2001 From: ConfusedPolarBear <33811686+ConfusedPolarBear@users.noreply.github.com> Date: Thu, 18 Jun 2020 01:29:47 -0500 Subject: Move all settings into the main server configuration Decreased the timeout from 30 minutes to 5. Public lookup values have been replaced with the short code. --- .../QuickConnect/ConfigurationExtension.cs | 20 ------- .../QuickConnect/QuickConnectConfiguration.cs | 15 ----- .../QuickConnectConfigurationFactory.cs | 27 --------- .../QuickConnect/QuickConnectManager.cs | 66 ++++++++++------------ .../QuickConnect/IQuickConnect.cs | 8 +-- .../Configuration/ServerConfiguration.cs | 6 ++ .../QuickConnect/QuickConnectResult.cs | 5 -- .../QuickConnect/QuickConnectResultDto.cs | 14 +---- 8 files changed, 41 insertions(+), 120 deletions(-) delete mode 100644 Emby.Server.Implementations/QuickConnect/ConfigurationExtension.cs delete mode 100644 Emby.Server.Implementations/QuickConnect/QuickConnectConfiguration.cs delete mode 100644 Emby.Server.Implementations/QuickConnect/QuickConnectConfigurationFactory.cs (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/QuickConnect/ConfigurationExtension.cs b/Emby.Server.Implementations/QuickConnect/ConfigurationExtension.cs deleted file mode 100644 index 2a19fc36c..000000000 --- a/Emby.Server.Implementations/QuickConnect/ConfigurationExtension.cs +++ /dev/null @@ -1,20 +0,0 @@ -using MediaBrowser.Common.Configuration; - -namespace Emby.Server.Implementations.QuickConnect -{ - /// <summary> - /// Configuration extension to support persistent quick connect configuration. - /// </summary> - public static class ConfigurationExtension - { - /// <summary> - /// Return the current quick connect configuration. - /// </summary> - /// <param name="manager">Configuration manager.</param> - /// <returns>Current quick connect configuration.</returns> - public static QuickConnectConfiguration GetQuickConnectConfiguration(this IConfigurationManager manager) - { - return manager.GetConfiguration<QuickConnectConfiguration>("quickconnect"); - } - } -} diff --git a/Emby.Server.Implementations/QuickConnect/QuickConnectConfiguration.cs b/Emby.Server.Implementations/QuickConnect/QuickConnectConfiguration.cs deleted file mode 100644 index 2302ddbc3..000000000 --- a/Emby.Server.Implementations/QuickConnect/QuickConnectConfiguration.cs +++ /dev/null @@ -1,15 +0,0 @@ -using MediaBrowser.Model.QuickConnect; - -namespace Emby.Server.Implementations.QuickConnect -{ - /// <summary> - /// Persistent quick connect configuration. - /// </summary> - public class QuickConnectConfiguration - { - /// <summary> - /// Gets or sets persistent quick connect availability state. - /// </summary> - public QuickConnectState State { get; set; } - } -} diff --git a/Emby.Server.Implementations/QuickConnect/QuickConnectConfigurationFactory.cs b/Emby.Server.Implementations/QuickConnect/QuickConnectConfigurationFactory.cs deleted file mode 100644 index d7bc84c5e..000000000 --- a/Emby.Server.Implementations/QuickConnect/QuickConnectConfigurationFactory.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System.Collections.Generic; -using MediaBrowser.Common.Configuration; - -namespace Emby.Server.Implementations.QuickConnect -{ - /// <summary> - /// Configuration factory for quick connect. - /// </summary> - public class QuickConnectConfigurationFactory : IConfigurationFactory - { - /// <summary> - /// Returns the current quick connect configuration. - /// </summary> - /// <returns>Current quick connect configuration.</returns> - public IEnumerable<ConfigurationStore> GetConfigurations() - { - return new[] - { - new ConfigurationStore - { - Key = "quickconnect", - ConfigurationType = typeof(QuickConnectConfiguration) - } - }; - } - } -} diff --git a/Emby.Server.Implementations/QuickConnect/QuickConnectManager.cs b/Emby.Server.Implementations/QuickConnect/QuickConnectManager.cs index 7a584c7cd..8d704f32b 100644 --- a/Emby.Server.Implementations/QuickConnect/QuickConnectManager.cs +++ b/Emby.Server.Implementations/QuickConnect/QuickConnectManager.cs @@ -11,7 +11,9 @@ using MediaBrowser.Controller.QuickConnect; using MediaBrowser.Controller.Security; using MediaBrowser.Model.QuickConnect; using MediaBrowser.Model.Services; +using MediaBrowser.Common; using Microsoft.Extensions.Logging; +using MediaBrowser.Common.Extensions; namespace Emby.Server.Implementations.QuickConnect { @@ -64,9 +66,7 @@ namespace Emby.Server.Implementations.QuickConnect public QuickConnectState State { get; private set; } = QuickConnectState.Unavailable; /// <inheritdoc/> - public int RequestExpiry { get; set; } = 30; - - private bool TemporaryActivation { get; set; } = false; + public int Timeout { get; set; } = 5; private DateTime DateActivated { get; set; } @@ -82,10 +82,9 @@ namespace Emby.Server.Implementations.QuickConnect /// <inheritdoc/> public QuickConnectResult Activate() { - // This should not call SetEnabled since that would persist the "temporary" activation to the configuration file - State = QuickConnectState.Active; + SetEnabled(QuickConnectState.Active); + DateActivated = DateTime.Now; - TemporaryActivation = true; return new QuickConnectResult(); } @@ -96,12 +95,10 @@ namespace Emby.Server.Implementations.QuickConnect _logger.LogDebug("Changed quick connect state from {0} to {1}", State, newState); ExpireRequests(true); - State = newState; - _config.SaveConfiguration("quickconnect", new QuickConnectConfiguration() - { - State = State - }); + State = newState; + _config.Configuration.QuickConnectAvailable = newState == QuickConnectState.Available || newState == QuickConnectState.Active; + _config.SaveConfiguration(); _logger.LogDebug("Configuration saved"); } @@ -123,17 +120,16 @@ namespace Emby.Server.Implementations.QuickConnect _logger.LogDebug("Got new quick connect request from {friendlyName}", friendlyName); - var lookup = GenerateSecureRandom(); + var code = GenerateCode(); var result = new QuickConnectResult() { - Lookup = lookup, Secret = GenerateSecureRandom(), FriendlyName = friendlyName, DateAdded = DateTime.Now, - Code = GenerateCode() + Code = code }; - _currentRequests[lookup] = result; + _currentRequests[code] = result; return result; } @@ -143,17 +139,16 @@ namespace Emby.Server.Implementations.QuickConnect ExpireRequests(); AssertActive(); - string lookup = _currentRequests.Where(x => x.Value.Secret == secret).Select(x => x.Value.Lookup).DefaultIfEmpty(string.Empty).First(); + string code = _currentRequests.Where(x => x.Value.Secret == secret).Select(x => x.Value.Code).DefaultIfEmpty(string.Empty).First(); - if (!_currentRequests.TryGetValue(lookup, out QuickConnectResult result)) + if (!_currentRequests.TryGetValue(code, out QuickConnectResult result)) { - throw new KeyNotFoundException("Unable to find request with provided identifier"); + throw new ResourceNotFoundException("Unable to find request with provided secret"); } return result; } - /// <inheritdoc/> public List<QuickConnectResultDto> GetCurrentRequests() { return GetCurrentRequestsInternal().Select(x => (QuickConnectResultDto)x).ToList(); @@ -186,16 +181,16 @@ namespace Emby.Server.Implementations.QuickConnect } /// <inheritdoc/> - public bool AuthorizeRequest(IRequest request, string lookup) + public bool AuthorizeRequest(IRequest request, string code) { ExpireRequests(); AssertActive(); var auth = _authContext.GetAuthorizationInfo(request); - if (!_currentRequests.TryGetValue(lookup, out QuickConnectResult result)) + if (!_currentRequests.TryGetValue(code, out QuickConnectResult result)) { - throw new KeyNotFoundException("Unable to find request"); + throw new ResourceNotFoundException("Unable to find request"); } if (result.Authenticated) @@ -205,9 +200,9 @@ namespace Emby.Server.Implementations.QuickConnect result.Authentication = Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture); - // Advance the time on the request so it expires sooner as the client will pick up the changes in a few seconds - var added = result.DateAdded ?? DateTime.Now.Subtract(new TimeSpan(0, RequestExpiry, 0)); - result.DateAdded = added.Subtract(new TimeSpan(0, RequestExpiry - 1, 0)); + // Change the time on the request so it expires one minute into the future. It can't expire immediately as otherwise some clients wouldn't ever see that they have been authenticated. + var added = result.DateAdded ?? DateTime.Now.Subtract(new TimeSpan(0, Timeout, 0)); + result.DateAdded = added.Subtract(new TimeSpan(0, Timeout - 1, 0)); _authenticationRepository.Create(new AuthenticationInfo { @@ -271,7 +266,7 @@ namespace Emby.Server.Implementations.QuickConnect var bytes = new byte[length]; _rng.GetBytes(bytes); - return string.Join(string.Empty, bytes.Select(x => x.ToString("x2", CultureInfo.InvariantCulture))); + return Hex.Encode(bytes); } /// <summary> @@ -281,12 +276,11 @@ namespace Emby.Server.Implementations.QuickConnect private void ExpireRequests(bool expireAll = false) { // Check if quick connect should be deactivated - if (TemporaryActivation && DateTime.Now > DateActivated.AddMinutes(10) && State == QuickConnectState.Active && !expireAll) + if (State == QuickConnectState.Active && DateTime.Now > DateActivated.AddMinutes(Timeout) && !expireAll) { _logger.LogDebug("Quick connect time expired, deactivating"); SetEnabled(QuickConnectState.Available); expireAll = true; - TemporaryActivation = false; } // Expire stale connection requests @@ -296,28 +290,28 @@ namespace Emby.Server.Implementations.QuickConnect for (int i = 0; i < values.Count; i++) { var added = values[i].DateAdded ?? DateTime.UnixEpoch; - if (DateTime.Now > added.AddMinutes(RequestExpiry) || expireAll) + if (DateTime.Now > added.AddMinutes(Timeout) || expireAll) { - delete.Add(values[i].Lookup); + delete.Add(values[i].Code); } } - foreach (var lookup in delete) + foreach (var code in delete) { - _logger.LogDebug("Removing expired request {lookup}", lookup); + _logger.LogDebug("Removing expired request {code}", code); - if (!_currentRequests.TryRemove(lookup, out _)) + if (!_currentRequests.TryRemove(code, out _)) { - _logger.LogWarning("Request {lookup} already expired", lookup); + _logger.LogWarning("Request {code} already expired", code); } } } private void ReloadConfiguration() { - var config = _config.GetQuickConnectConfiguration(); + var available = _config.Configuration.QuickConnectAvailable; - State = config.State; + State = available ? QuickConnectState.Available : QuickConnectState.Unavailable; } } } diff --git a/MediaBrowser.Controller/QuickConnect/IQuickConnect.cs b/MediaBrowser.Controller/QuickConnect/IQuickConnect.cs index d44765e11..d31d0e509 100644 --- a/MediaBrowser.Controller/QuickConnect/IQuickConnect.cs +++ b/MediaBrowser.Controller/QuickConnect/IQuickConnect.cs @@ -26,9 +26,9 @@ namespace MediaBrowser.Controller.QuickConnect public QuickConnectState State { get; } /// <summary> - /// Gets or sets the time (in minutes) before a pending request will expire. + /// Gets or sets the time (in minutes) before quick connect will automatically deactivate. /// </summary> - public int RequestExpiry { get; set; } + public int Timeout { get; set; } /// <summary> /// Assert that quick connect is currently active and throws an exception if it is not. @@ -77,9 +77,9 @@ namespace MediaBrowser.Controller.QuickConnect /// Authorizes a quick connect request to connect as the calling user. /// </summary> /// <param name="request">HTTP request object.</param> - /// <param name="lookup">Public request lookup value.</param> + /// <param name="lookup">Identifying code for the request..</param> /// <returns>A boolean indicating if the authorization completed successfully.</returns> - bool AuthorizeRequest(IRequest request, string lookup); + bool AuthorizeRequest(IRequest request, string code); /// <summary> /// Deletes all quick connect access tokens for the provided user. diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs index afbe02dd3..76b290606 100644 --- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs +++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs @@ -76,6 +76,11 @@ namespace MediaBrowser.Model.Configuration /// <value><c>true</c> if this instance is port authorized; otherwise, <c>false</c>.</value> public bool IsPortAuthorized { get; set; } + /// <summary> + /// Gets or sets if quick connect is available for use on this server. + /// </summary> + public bool QuickConnectAvailable { get; set; } + public bool AutoRunWebApp { get; set; } public bool EnableRemoteAccess { get; set; } @@ -281,6 +286,7 @@ namespace MediaBrowser.Model.Configuration AutoRunWebApp = true; EnableRemoteAccess = true; + QuickConnectAvailable = false; EnableUPnP = false; MinResumePct = 5; diff --git a/MediaBrowser.Model/QuickConnect/QuickConnectResult.cs b/MediaBrowser.Model/QuickConnect/QuickConnectResult.cs index 32d7f6aba..a10d60d57 100644 --- a/MediaBrowser.Model/QuickConnect/QuickConnectResult.cs +++ b/MediaBrowser.Model/QuickConnect/QuickConnectResult.cs @@ -17,11 +17,6 @@ namespace MediaBrowser.Model.QuickConnect /// </summary> public string? Secret { get; set; } - /// <summary> - /// Gets or sets the public value used to uniquely identify this request. Can only be used to authorize the request. - /// </summary> - public string? Lookup { get; set; } - /// <summary> /// Gets or sets the user facing code used so the user can quickly differentiate this request from others. /// </summary> diff --git a/MediaBrowser.Model/QuickConnect/QuickConnectResultDto.cs b/MediaBrowser.Model/QuickConnect/QuickConnectResultDto.cs index 19acc7cd8..26084caf1 100644 --- a/MediaBrowser.Model/QuickConnect/QuickConnectResultDto.cs +++ b/MediaBrowser.Model/QuickConnect/QuickConnectResultDto.cs @@ -17,25 +17,15 @@ namespace MediaBrowser.Model.QuickConnect /// </summary> public string? Code { get; private set; } - /// <summary> - /// Gets the public value used to uniquely identify this request. Can only be used to authorize the request. - /// </summary> - public string? Lookup { get; private set; } - /// <summary> /// Gets the device friendly name. /// </summary> public string? FriendlyName { get; private set; } - /// <summary> - /// Gets the DateTime that this request was created. - /// </summary> - public DateTime? DateAdded { get; private set; } - /// <summary> /// Cast an internal quick connect result to a DTO by removing all sensitive properties. /// </summary> - /// <param name="result">QuickConnectResult object to cast</param> + /// <param name="result">QuickConnectResult object to cast.</param> public static implicit operator QuickConnectResultDto(QuickConnectResult result) { QuickConnectResultDto resultDto = new QuickConnectResultDto @@ -43,8 +33,6 @@ namespace MediaBrowser.Model.QuickConnect Authenticated = result.Authenticated, Code = result.Code, FriendlyName = result.FriendlyName, - DateAdded = result.DateAdded, - Lookup = result.Lookup }; return resultDto; -- cgit v1.2.3 From 329980c727cf03587ff5f4011a3af3ef2fa5e4f1 Mon Sep 17 00:00:00 2001 From: ConfusedPolarBear <33811686+ConfusedPolarBear@users.noreply.github.com> Date: Thu, 18 Jun 2020 01:58:58 -0500 Subject: API cleanup --- .../QuickConnect/QuickConnectManager.cs | 35 +++-------- .../QuickConnect/QuickConnectService.cs | 67 ++++------------------ .../QuickConnect/IQuickConnect.cs | 23 +++----- .../QuickConnect/QuickConnectResultDto.cs | 41 ------------- 4 files changed, 27 insertions(+), 139 deletions(-) delete mode 100644 MediaBrowser.Model/QuickConnect/QuickConnectResultDto.cs (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/QuickConnect/QuickConnectManager.cs b/Emby.Server.Implementations/QuickConnect/QuickConnectManager.cs index 8d704f32b..263556e9d 100644 --- a/Emby.Server.Implementations/QuickConnect/QuickConnectManager.cs +++ b/Emby.Server.Implementations/QuickConnect/QuickConnectManager.cs @@ -75,18 +75,15 @@ namespace Emby.Server.Implementations.QuickConnect { if (State != QuickConnectState.Active) { - throw new InvalidOperationException("Quick connect is not active on this server"); + throw new ArgumentException("Quick connect is not active on this server"); } } /// <inheritdoc/> - public QuickConnectResult Activate() + public void Activate() { - SetEnabled(QuickConnectState.Active); - DateActivated = DateTime.Now; - - return new QuickConnectResult(); + SetEnabled(QuickConnectState.Active); } /// <inheritdoc/> @@ -149,19 +146,6 @@ namespace Emby.Server.Implementations.QuickConnect return result; } - public List<QuickConnectResultDto> GetCurrentRequests() - { - return GetCurrentRequestsInternal().Select(x => (QuickConnectResultDto)x).ToList(); - } - - /// <inheritdoc/> - public List<QuickConnectResult> GetCurrentRequestsInternal() - { - ExpireRequests(); - AssertActive(); - return _currentRequests.Values.ToList(); - } - /// <inheritdoc/> public string GenerateCode() { @@ -215,7 +199,7 @@ namespace Emby.Server.Implementations.QuickConnect UserId = auth.UserId }); - _logger.LogInformation("Allowing device {0} to login as user {1} with quick connect code {2}", result.FriendlyName, auth.User.Name, result.Code); + _logger.LogInformation("Allowing device {0} to login as user {1} with quick connect code {2}", result.FriendlyName, auth.User.Username, result.Code); return true; } @@ -269,11 +253,8 @@ namespace Emby.Server.Implementations.QuickConnect return Hex.Encode(bytes); } - /// <summary> - /// Expire quick connect requests that are over the time limit. If <paramref name="expireAll"/> is true, all requests are unconditionally expired. - /// </summary> - /// <param name="expireAll">If true, all requests will be expired.</param> - private void ExpireRequests(bool expireAll = false) + /// <inheritdoc/> + public void ExpireRequests(bool expireAll = false) { // Check if quick connect should be deactivated if (State == QuickConnectState.Active && DateTime.Now > DateActivated.AddMinutes(Timeout) && !expireAll) @@ -309,9 +290,7 @@ namespace Emby.Server.Implementations.QuickConnect private void ReloadConfiguration() { - var available = _config.Configuration.QuickConnectAvailable; - - State = available ? QuickConnectState.Available : QuickConnectState.Unavailable; + State = _config.Configuration.QuickConnectAvailable ? QuickConnectState.Available : QuickConnectState.Unavailable; } } } diff --git a/MediaBrowser.Api/QuickConnect/QuickConnectService.cs b/MediaBrowser.Api/QuickConnect/QuickConnectService.cs index 60d6ac414..9047a1e95 100644 --- a/MediaBrowser.Api/QuickConnect/QuickConnectService.cs +++ b/MediaBrowser.Api/QuickConnect/QuickConnectService.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Net; @@ -24,18 +23,12 @@ namespace MediaBrowser.Api.QuickConnect public string Secret { get; set; } } - [Route("/QuickConnect/List", "GET", Summary = "Lists all quick connect requests")] - [Authenticated] - public class QuickConnectList : IReturn<List<QuickConnectResultDto>> - { - } - [Route("/QuickConnect/Authorize", "POST", Summary = "Authorizes a pending quick connect request")] [Authenticated] - public class Authorize : IReturn<QuickConnectResultDto> + public class Authorize : IReturn<bool> { - [ApiMember(Name = "Lookup", Description = "Quick connect public lookup", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")] - public string Lookup { get; set; } + [ApiMember(Name = "Code", Description = "Quick connect identifying code", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")] + public string Code { get; set; } } [Route("/QuickConnect/Deauthorize", "POST", Summary = "Deletes all quick connect authorization tokens for the current user")] @@ -62,8 +55,9 @@ namespace MediaBrowser.Api.QuickConnect [Route("/QuickConnect/Activate", "POST", Summary = "Temporarily activates quick connect for the time period defined in the server configuration")] [Authenticated] - public class Activate : IReturn<QuickConnectState> + public class Activate : IReturn<bool> { + } public class QuickConnectService : BaseApiService @@ -96,18 +90,9 @@ namespace MediaBrowser.Api.QuickConnect return _quickConnect.CheckRequestStatus(request.Secret); } - public object Get(QuickConnectList request) - { - if(_quickConnect.State != QuickConnectState.Active) - { - return Array.Empty<QuickConnectResultDto>(); - } - - return _quickConnect.GetCurrentRequests(); - } - public object Get(QuickConnectStatus request) { + _quickConnect.ExpireRequests(); return _quickConnect.State; } @@ -120,55 +105,27 @@ namespace MediaBrowser.Api.QuickConnect public object Post(Authorize request) { - bool result = _quickConnect.AuthorizeRequest(Request, request.Lookup); - - Logger.LogInformation("Result of authorizing quick connect {0}: {1}", request.Lookup[..10], result); - - return result; + return _quickConnect.AuthorizeRequest(Request, request.Code); } public object Post(Activate request) { - string name = _authContext.GetAuthorizationInfo(Request).User.Name; - if(_quickConnect.State == QuickConnectState.Unavailable) { - return new QuickConnectResult() - { - Error = "Quick connect is not enabled on this server" - }; + return false; } - else if(_quickConnect.State == QuickConnectState.Available) - { - var result = _quickConnect.Activate(); - - if (string.IsNullOrEmpty(result.Error)) - { - Logger.LogInformation("{name} temporarily activated quick connect", name); - } + string name = _authContext.GetAuthorizationInfo(Request).User.Username; - return result; - } + Logger.LogInformation("{name} temporarily activated quick connect", name); + _quickConnect.Activate(); - else if(_quickConnect.State == QuickConnectState.Active) - { - return new QuickConnectResult() - { - Error = "" - }; - } - - return new QuickConnectResult() - { - Error = "Unknown current state" - }; + return true; } public object Post(Available request) { _quickConnect.SetEnabled(request.Status); - return _quickConnect.State; } } diff --git a/MediaBrowser.Controller/QuickConnect/IQuickConnect.cs b/MediaBrowser.Controller/QuickConnect/IQuickConnect.cs index d31d0e509..10ec9e6cb 100644 --- a/MediaBrowser.Controller/QuickConnect/IQuickConnect.cs +++ b/MediaBrowser.Controller/QuickConnect/IQuickConnect.cs @@ -38,8 +38,7 @@ namespace MediaBrowser.Controller.QuickConnect /// <summary> /// Temporarily activates quick connect for a short amount of time. /// </summary> - /// <returns>A quick connect result object indicating success.</returns> - QuickConnectResult Activate(); + void Activate(); /// <summary> /// Changes the status of quick connect. @@ -61,26 +60,20 @@ namespace MediaBrowser.Controller.QuickConnect /// <returns>Quick connect result.</returns> QuickConnectResult CheckRequestStatus(string secret); - /// <summary> - /// Returns all current quick connect requests as DTOs. Does not include sensitive information. - /// </summary> - /// <returns>List of all quick connect results.</returns> - List<QuickConnectResultDto> GetCurrentRequests(); - - /// <summary> - /// Returns all current quick connect requests (including sensitive information). - /// </summary> - /// <returns>List of all quick connect results.</returns> - List<QuickConnectResult> GetCurrentRequestsInternal(); - /// <summary> /// Authorizes a quick connect request to connect as the calling user. /// </summary> /// <param name="request">HTTP request object.</param> - /// <param name="lookup">Identifying code for the request..</param> + /// <param name="code">Identifying code for the request.</param> /// <returns>A boolean indicating if the authorization completed successfully.</returns> bool AuthorizeRequest(IRequest request, string code); + /// <summary> + /// Expire quick connect requests that are over the time limit. If <paramref name="expireAll"/> is true, all requests are unconditionally expired. + /// </summary> + /// <param name="expireAll">If true, all requests will be expired.</param> + public void ExpireRequests(bool expireAll = false); + /// <summary> /// Deletes all quick connect access tokens for the provided user. /// </summary> diff --git a/MediaBrowser.Model/QuickConnect/QuickConnectResultDto.cs b/MediaBrowser.Model/QuickConnect/QuickConnectResultDto.cs deleted file mode 100644 index 26084caf1..000000000 --- a/MediaBrowser.Model/QuickConnect/QuickConnectResultDto.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System; - -namespace MediaBrowser.Model.QuickConnect -{ - /// <summary> - /// Stores the non-sensitive results of an incoming quick connect request. - /// </summary> - public class QuickConnectResultDto - { - /// <summary> - /// Gets a value indicating whether this request is authorized. - /// </summary> - public bool Authenticated { get; private set; } - - /// <summary> - /// Gets the user facing code used so the user can quickly differentiate this request from others. - /// </summary> - public string? Code { get; private set; } - - /// <summary> - /// Gets the device friendly name. - /// </summary> - public string? FriendlyName { get; private set; } - - /// <summary> - /// Cast an internal quick connect result to a DTO by removing all sensitive properties. - /// </summary> - /// <param name="result">QuickConnectResult object to cast.</param> - public static implicit operator QuickConnectResultDto(QuickConnectResult result) - { - QuickConnectResultDto resultDto = new QuickConnectResultDto - { - Authenticated = result.Authenticated, - Code = result.Code, - FriendlyName = result.FriendlyName, - }; - - return resultDto; - } - } -} -- cgit v1.2.3 From afe09612e82a49c4021fbc2ceddf1816db9f959d Mon Sep 17 00:00:00 2001 From: telans <telans@protonmail.com> Date: Fri, 19 Jun 2020 21:57:37 +1200 Subject: fix SA1119 --- .../HttpServer/HttpResultFactory.cs | 2 +- Emby.Server.Implementations/HttpServer/ResponseFilter.cs | 4 ++-- .../LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs | 2 +- .../Security/AuthenticationRepository.cs | 4 ++-- Emby.Server.Implementations/Services/ServicePath.cs | 4 ++-- Jellyfin.Data/Entities/Artwork.cs | 6 +++--- Jellyfin.Data/Entities/BookMetadata.cs | 2 +- Jellyfin.Data/Entities/Chapter.cs | 10 +++++----- Jellyfin.Data/Entities/Collection.cs | 4 ++-- Jellyfin.Data/Entities/CollectionItem.cs | 2 +- Jellyfin.Data/Entities/Company.cs | 2 +- Jellyfin.Data/Entities/CompanyMetadata.cs | 8 ++++---- Jellyfin.Data/Entities/Episode.cs | 2 +- Jellyfin.Data/Entities/EpisodeMetadata.cs | 6 +++--- Jellyfin.Data/Entities/Genre.cs | 4 ++-- Jellyfin.Data/Entities/Library.cs | 4 ++-- Jellyfin.Data/Entities/LibraryItem.cs | 6 +++--- Jellyfin.Data/Entities/LibraryRoot.cs | 6 +++--- Jellyfin.Data/Entities/MediaFile.cs | 6 +++--- Jellyfin.Data/Entities/MediaFileStream.cs | 4 ++-- Jellyfin.Data/Entities/Metadata.cs | 16 ++++++++-------- Jellyfin.Data/Entities/MetadataProvider.cs | 4 ++-- Jellyfin.Data/Entities/MetadataProviderId.cs | 4 ++-- Jellyfin.Data/Entities/MovieMetadata.cs | 8 ++++---- Jellyfin.Data/Entities/MusicAlbumMetadata.cs | 6 +++--- Jellyfin.Data/Entities/Person.cs | 12 ++++++------ Jellyfin.Data/Entities/PersonRole.cs | 6 +++--- Jellyfin.Data/Entities/Rating.cs | 6 +++--- Jellyfin.Data/Entities/RatingSource.cs | 8 ++++---- Jellyfin.Data/Entities/Release.cs | 4 ++-- Jellyfin.Data/Entities/Season.cs | 2 +- Jellyfin.Data/Entities/SeasonMetadata.cs | 2 +- Jellyfin.Data/Entities/Series.cs | 6 +++--- Jellyfin.Data/Entities/SeriesMetadata.cs | 8 ++++---- Jellyfin.Data/Entities/Track.cs | 2 +- MediaBrowser.Controller/Entities/CollectionFolder.cs | 2 +- MediaBrowser.Controller/Entities/Folder.cs | 4 ++-- MediaBrowser.Controller/Library/ItemResolveArgs.cs | 2 +- MediaBrowser.Providers/Manager/MetadataService.cs | 2 +- 39 files changed, 96 insertions(+), 96 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs b/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs index ad31b3e1e..7b7da703b 100644 --- a/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs +++ b/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs @@ -426,7 +426,7 @@ namespace Emby.Server.Implementations.HttpServer /// </summary> private object GetCachedResult(IRequest requestContext, IDictionary<string, string> responseHeaders, StaticResultOptions options) { - bool noCache = (requestContext.Headers[HeaderNames.CacheControl].ToString()).IndexOf("no-cache", StringComparison.OrdinalIgnoreCase) != -1; + bool noCache = requestContext.Headers[HeaderNames.CacheControl].ToString().IndexOf("no-cache", StringComparison.OrdinalIgnoreCase) != -1; AddCachingHeaders(responseHeaders, options.CacheDuration, noCache, options.DateLastModified); if (!noCache) diff --git a/Emby.Server.Implementations/HttpServer/ResponseFilter.cs b/Emby.Server.Implementations/HttpServer/ResponseFilter.cs index 3ab5dbc16..a8cd2ac8f 100644 --- a/Emby.Server.Implementations/HttpServer/ResponseFilter.cs +++ b/Emby.Server.Implementations/HttpServer/ResponseFilter.cs @@ -41,11 +41,11 @@ namespace Emby.Server.Implementations.HttpServer res.Headers.Add(key, value); } // Try to prevent compatibility view - res.Headers["Access-Control-Allow-Headers"] = ("Accept, Accept-Language, Authorization, Cache-Control, " + + res.Headers["Access-Control-Allow-Headers"] = "Accept, Accept-Language, Authorization, Cache-Control, " + "Content-Disposition, Content-Encoding, Content-Language, Content-Length, Content-MD5, Content-Range, " + "Content-Type, Cookie, 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"); + "X-Emby-Authorization"; if (dto is Exception exception) { diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs index dff113a2a..db9d24028 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs @@ -691,7 +691,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun { var model = ModelNumber ?? string.Empty; - if ((model.IndexOf("hdtc", StringComparison.OrdinalIgnoreCase) != -1)) + if (model.IndexOf("hdtc", StringComparison.OrdinalIgnoreCase) != -1) { return true; } diff --git a/Emby.Server.Implementations/Security/AuthenticationRepository.cs b/Emby.Server.Implementations/Security/AuthenticationRepository.cs index 9c1be9a1a..4dfadc703 100644 --- a/Emby.Server.Implementations/Security/AuthenticationRepository.cs +++ b/Emby.Server.Implementations/Security/AuthenticationRepository.cs @@ -98,7 +98,7 @@ namespace Emby.Server.Implementations.Security statement.TryBind("@AppName", info.AppName); statement.TryBind("@AppVersion", info.AppVersion); statement.TryBind("@DeviceName", info.DeviceName); - statement.TryBind("@UserId", (info.UserId.Equals(Guid.Empty) ? null : info.UserId.ToString("N", CultureInfo.InvariantCulture))); + statement.TryBind("@UserId", info.UserId.Equals(Guid.Empty) ? null : info.UserId.ToString("N", CultureInfo.InvariantCulture)); statement.TryBind("@UserName", info.UserName); statement.TryBind("@IsActive", true); statement.TryBind("@DateCreated", info.DateCreated.ToDateTimeParamValue()); @@ -131,7 +131,7 @@ namespace Emby.Server.Implementations.Security statement.TryBind("@AppName", info.AppName); statement.TryBind("@AppVersion", info.AppVersion); statement.TryBind("@DeviceName", info.DeviceName); - statement.TryBind("@UserId", (info.UserId.Equals(Guid.Empty) ? null : info.UserId.ToString("N", CultureInfo.InvariantCulture))); + statement.TryBind("@UserId", info.UserId.Equals(Guid.Empty) ? null : info.UserId.ToString("N", CultureInfo.InvariantCulture)); statement.TryBind("@UserName", info.UserName); statement.TryBind("@DateCreated", info.DateCreated.ToDateTimeParamValue()); statement.TryBind("@DateLastActivity", info.DateLastActivity.ToDateTimeParamValue()); diff --git a/Emby.Server.Implementations/Services/ServicePath.cs b/Emby.Server.Implementations/Services/ServicePath.cs index 3b7ffaf2c..14ae126a3 100644 --- a/Emby.Server.Implementations/Services/ServicePath.cs +++ b/Emby.Server.Implementations/Services/ServicePath.cs @@ -302,9 +302,9 @@ namespace Emby.Server.Implementations.Services } // Routes with least wildcard matches get the highest score - var score = Math.Max((100 - wildcardMatchCount), 1) * 1000 + var score = Math.Max(100 - wildcardMatchCount, 1) * 1000 // Routes with less variable (and more literal) matches - + Math.Max((10 - VariableArgsCount), 1) * 100; + + Math.Max(10 - VariableArgsCount, 1) * 100; // Exact verb match is better than ANY if (Verbs.Length == 1 && string.Equals(httpMethod, Verbs[0], StringComparison.OrdinalIgnoreCase)) diff --git a/Jellyfin.Data/Entities/Artwork.cs b/Jellyfin.Data/Entities/Artwork.cs index 852d742a5..df071e477 100644 --- a/Jellyfin.Data/Entities/Artwork.cs +++ b/Jellyfin.Data/Entities/Artwork.cs @@ -87,7 +87,7 @@ namespace Jellyfin.Data.Entities { int value = _Id; GetId(ref value); - return (_Id = value); + return _Id = value; } protected set @@ -126,7 +126,7 @@ namespace Jellyfin.Data.Entities { string value = _Path; GetPath(ref value); - return (_Path = value); + return _Path = value; } set @@ -163,7 +163,7 @@ namespace Jellyfin.Data.Entities { Enums.ArtKind value = _Kind; GetKind(ref value); - return (_Kind = value); + return _Kind = value; } set diff --git a/Jellyfin.Data/Entities/BookMetadata.cs b/Jellyfin.Data/Entities/BookMetadata.cs index 47578dc46..914eda064 100644 --- a/Jellyfin.Data/Entities/BookMetadata.cs +++ b/Jellyfin.Data/Entities/BookMetadata.cs @@ -82,7 +82,7 @@ namespace Jellyfin.Data.Entities { long? value = _ISBN; GetISBN(ref value); - return (_ISBN = value); + return _ISBN = value; } set diff --git a/Jellyfin.Data/Entities/Chapter.cs b/Jellyfin.Data/Entities/Chapter.cs index d5b2b39ce..77685add6 100644 --- a/Jellyfin.Data/Entities/Chapter.cs +++ b/Jellyfin.Data/Entities/Chapter.cs @@ -84,7 +84,7 @@ namespace Jellyfin.Data.Entities { int value = _Id; GetId(ref value); - return (_Id = value); + return _Id = value; } protected set @@ -122,7 +122,7 @@ namespace Jellyfin.Data.Entities { string value = _Name; GetName(ref value); - return (_Name = value); + return _Name = value; } set @@ -163,7 +163,7 @@ namespace Jellyfin.Data.Entities { string value = _Language; GetLanguage(ref value); - return (_Language = value); + return _Language = value; } set @@ -200,7 +200,7 @@ namespace Jellyfin.Data.Entities { long value = _TimeStart; GetTimeStart(ref value); - return (_TimeStart = value); + return _TimeStart = value; } set @@ -233,7 +233,7 @@ namespace Jellyfin.Data.Entities { long? value = _TimeEnd; GetTimeEnd(ref value); - return (_TimeEnd = value); + return _TimeEnd = value; } set diff --git a/Jellyfin.Data/Entities/Collection.cs b/Jellyfin.Data/Entities/Collection.cs index d2f441d03..01836d893 100644 --- a/Jellyfin.Data/Entities/Collection.cs +++ b/Jellyfin.Data/Entities/Collection.cs @@ -47,7 +47,7 @@ namespace Jellyfin.Data.Entities { int value = _Id; GetId(ref value); - return (_Id = value); + return _Id = value; } protected set @@ -85,7 +85,7 @@ namespace Jellyfin.Data.Entities { string value = _Name; GetName(ref value); - return (_Name = value); + return _Name = value; } set diff --git a/Jellyfin.Data/Entities/CollectionItem.cs b/Jellyfin.Data/Entities/CollectionItem.cs index 7cfdbbe16..08b0e99f4 100644 --- a/Jellyfin.Data/Entities/CollectionItem.cs +++ b/Jellyfin.Data/Entities/CollectionItem.cs @@ -91,7 +91,7 @@ namespace Jellyfin.Data.Entities { int value = _Id; GetId(ref value); - return (_Id = value); + return _Id = value; } protected set diff --git a/Jellyfin.Data/Entities/Company.cs b/Jellyfin.Data/Entities/Company.cs index 908e41f3d..2ac7bcfe5 100644 --- a/Jellyfin.Data/Entities/Company.cs +++ b/Jellyfin.Data/Entities/Company.cs @@ -99,7 +99,7 @@ namespace Jellyfin.Data.Entities { int value = _Id; GetId(ref value); - return (_Id = value); + return _Id = value; } protected set diff --git a/Jellyfin.Data/Entities/CompanyMetadata.cs b/Jellyfin.Data/Entities/CompanyMetadata.cs index 240cccbff..695c7f096 100644 --- a/Jellyfin.Data/Entities/CompanyMetadata.cs +++ b/Jellyfin.Data/Entities/CompanyMetadata.cs @@ -83,7 +83,7 @@ namespace Jellyfin.Data.Entities { string value = _Description; GetDescription(ref value); - return (_Description = value); + return _Description = value; } set @@ -121,7 +121,7 @@ namespace Jellyfin.Data.Entities { string value = _Headquarters; GetHeadquarters(ref value); - return (_Headquarters = value); + return _Headquarters = value; } set @@ -159,7 +159,7 @@ namespace Jellyfin.Data.Entities { string value = _Country; GetCountry(ref value); - return (_Country = value); + return _Country = value; } set @@ -197,7 +197,7 @@ namespace Jellyfin.Data.Entities { string value = _Homepage; GetHomepage(ref value); - return (_Homepage = value); + return _Homepage = value; } set diff --git a/Jellyfin.Data/Entities/Episode.cs b/Jellyfin.Data/Entities/Episode.cs index 405c815cd..69106ab79 100644 --- a/Jellyfin.Data/Entities/Episode.cs +++ b/Jellyfin.Data/Entities/Episode.cs @@ -84,7 +84,7 @@ namespace Jellyfin.Data.Entities { int? value = _EpisodeNumber; GetEpisodeNumber(ref value); - return (_EpisodeNumber = value); + return _EpisodeNumber = value; } set diff --git a/Jellyfin.Data/Entities/EpisodeMetadata.cs b/Jellyfin.Data/Entities/EpisodeMetadata.cs index 4999842aa..da5ea43cc 100644 --- a/Jellyfin.Data/Entities/EpisodeMetadata.cs +++ b/Jellyfin.Data/Entities/EpisodeMetadata.cs @@ -83,7 +83,7 @@ namespace Jellyfin.Data.Entities { string value = _Outline; GetOutline(ref value); - return (_Outline = value); + return _Outline = value; } set @@ -121,7 +121,7 @@ namespace Jellyfin.Data.Entities { string value = _Plot; GetPlot(ref value); - return (_Plot = value); + return _Plot = value; } set @@ -159,7 +159,7 @@ namespace Jellyfin.Data.Entities { string value = _Tagline; GetTagline(ref value); - return (_Tagline = value); + return _Tagline = value; } set diff --git a/Jellyfin.Data/Entities/Genre.cs b/Jellyfin.Data/Entities/Genre.cs index 0f6f681a4..9b2264921 100644 --- a/Jellyfin.Data/Entities/Genre.cs +++ b/Jellyfin.Data/Entities/Genre.cs @@ -80,7 +80,7 @@ namespace Jellyfin.Data.Entities { int value = _Id; GetId(ref value); - return (_Id = value); + return _Id = value; } protected set @@ -119,7 +119,7 @@ namespace Jellyfin.Data.Entities { string value = _Name; GetName(ref value); - return (_Name = value); + return _Name = value; } set diff --git a/Jellyfin.Data/Entities/Library.cs b/Jellyfin.Data/Entities/Library.cs index a091ece03..ff94b93f0 100644 --- a/Jellyfin.Data/Entities/Library.cs +++ b/Jellyfin.Data/Entities/Library.cs @@ -75,7 +75,7 @@ namespace Jellyfin.Data.Entities { int value = _Id; GetId(ref value); - return (_Id = value); + return _Id = value; } protected set @@ -114,7 +114,7 @@ namespace Jellyfin.Data.Entities { string value = _Name; GetName(ref value); - return (_Name = value); + return _Name = value; } set diff --git a/Jellyfin.Data/Entities/LibraryItem.cs b/Jellyfin.Data/Entities/LibraryItem.cs index d29d6250e..f41753560 100644 --- a/Jellyfin.Data/Entities/LibraryItem.cs +++ b/Jellyfin.Data/Entities/LibraryItem.cs @@ -57,7 +57,7 @@ namespace Jellyfin.Data.Entities { int value = _Id; GetId(ref value); - return (_Id = value); + return _Id = value; } protected set @@ -95,7 +95,7 @@ namespace Jellyfin.Data.Entities { Guid value = _UrlId; GetUrlId(ref value); - return (_UrlId = value); + return _UrlId = value; } set @@ -132,7 +132,7 @@ namespace Jellyfin.Data.Entities { DateTime value = _DateAdded; GetDateAdded(ref value); - return (_DateAdded = value); + return _DateAdded = value; } internal set diff --git a/Jellyfin.Data/Entities/LibraryRoot.cs b/Jellyfin.Data/Entities/LibraryRoot.cs index d9a4f62e5..16fbc92f6 100644 --- a/Jellyfin.Data/Entities/LibraryRoot.cs +++ b/Jellyfin.Data/Entities/LibraryRoot.cs @@ -75,7 +75,7 @@ namespace Jellyfin.Data.Entities { int value = _Id; GetId(ref value); - return (_Id = value); + return _Id = value; } protected set @@ -115,7 +115,7 @@ namespace Jellyfin.Data.Entities { string value = _Path; GetPath(ref value); - return (_Path = value); + return _Path = value; } set @@ -154,7 +154,7 @@ namespace Jellyfin.Data.Entities { string value = _NetworkPath; GetNetworkPath(ref value); - return (_NetworkPath = value); + return _NetworkPath = value; } set diff --git a/Jellyfin.Data/Entities/MediaFile.cs b/Jellyfin.Data/Entities/MediaFile.cs index 6e6602bfa..8201eed52 100644 --- a/Jellyfin.Data/Entities/MediaFile.cs +++ b/Jellyfin.Data/Entities/MediaFile.cs @@ -88,7 +88,7 @@ namespace Jellyfin.Data.Entities { int value = _Id; GetId(ref value); - return (_Id = value); + return _Id = value; } protected set @@ -128,7 +128,7 @@ namespace Jellyfin.Data.Entities { string value = _Path; GetPath(ref value); - return (_Path = value); + return _Path = value; } set @@ -165,7 +165,7 @@ namespace Jellyfin.Data.Entities { Enums.MediaFileKind value = _Kind; GetKind(ref value); - return (_Kind = value); + return _Kind = value; } set diff --git a/Jellyfin.Data/Entities/MediaFileStream.cs b/Jellyfin.Data/Entities/MediaFileStream.cs index 823988d6c..c018c0cbf 100644 --- a/Jellyfin.Data/Entities/MediaFileStream.cs +++ b/Jellyfin.Data/Entities/MediaFileStream.cs @@ -79,7 +79,7 @@ namespace Jellyfin.Data.Entities { int value = _Id; GetId(ref value); - return (_Id = value); + return _Id = value; } protected set @@ -116,7 +116,7 @@ namespace Jellyfin.Data.Entities { int value = _StreamNumber; GetStreamNumber(ref value); - return (_StreamNumber = value); + return _StreamNumber = value; } set diff --git a/Jellyfin.Data/Entities/Metadata.cs b/Jellyfin.Data/Entities/Metadata.cs index a6ca61709..146c70a10 100644 --- a/Jellyfin.Data/Entities/Metadata.cs +++ b/Jellyfin.Data/Entities/Metadata.cs @@ -74,7 +74,7 @@ namespace Jellyfin.Data.Entities { int value = _Id; GetId(ref value); - return (_Id = value); + return _Id = value; } protected set @@ -114,7 +114,7 @@ namespace Jellyfin.Data.Entities { string value = _Title; GetTitle(ref value); - return (_Title = value); + return _Title = value; } set @@ -152,7 +152,7 @@ namespace Jellyfin.Data.Entities { string value = _OriginalTitle; GetOriginalTitle(ref value); - return (_OriginalTitle = value); + return _OriginalTitle = value; } set @@ -190,7 +190,7 @@ namespace Jellyfin.Data.Entities { string value = _SortTitle; GetSortTitle(ref value); - return (_SortTitle = value); + return _SortTitle = value; } set @@ -231,7 +231,7 @@ namespace Jellyfin.Data.Entities { string value = _Language; GetLanguage(ref value); - return (_Language = value); + return _Language = value; } set @@ -264,7 +264,7 @@ namespace Jellyfin.Data.Entities { DateTimeOffset? value = _ReleaseDate; GetReleaseDate(ref value); - return (_ReleaseDate = value); + return _ReleaseDate = value; } set @@ -301,7 +301,7 @@ namespace Jellyfin.Data.Entities { DateTime value = _DateAdded; GetDateAdded(ref value); - return (_DateAdded = value); + return _DateAdded = value; } internal set @@ -338,7 +338,7 @@ namespace Jellyfin.Data.Entities { DateTime value = _DateModified; GetDateModified(ref value); - return (_DateModified = value); + return _DateModified = value; } internal set diff --git a/Jellyfin.Data/Entities/MetadataProvider.cs b/Jellyfin.Data/Entities/MetadataProvider.cs index 8c6c4000a..ae22ccfeb 100644 --- a/Jellyfin.Data/Entities/MetadataProvider.cs +++ b/Jellyfin.Data/Entities/MetadataProvider.cs @@ -75,7 +75,7 @@ namespace Jellyfin.Data.Entities { int value = _Id; GetId(ref value); - return (_Id = value); + return _Id = value; } protected set @@ -114,7 +114,7 @@ namespace Jellyfin.Data.Entities { string value = _Name; GetName(ref value); - return (_Name = value); + return _Name = value; } set diff --git a/Jellyfin.Data/Entities/MetadataProviderId.cs b/Jellyfin.Data/Entities/MetadataProviderId.cs index 67ffc4f0c..30683ced3 100644 --- a/Jellyfin.Data/Entities/MetadataProviderId.cs +++ b/Jellyfin.Data/Entities/MetadataProviderId.cs @@ -101,7 +101,7 @@ namespace Jellyfin.Data.Entities { int value = _Id; GetId(ref value); - return (_Id = value); + return _Id = value; } protected set @@ -140,7 +140,7 @@ namespace Jellyfin.Data.Entities { string value = _ProviderId; GetProviderId(ref value); - return (_ProviderId = value); + return _ProviderId = value; } set diff --git a/Jellyfin.Data/Entities/MovieMetadata.cs b/Jellyfin.Data/Entities/MovieMetadata.cs index cb722c015..48584dd13 100644 --- a/Jellyfin.Data/Entities/MovieMetadata.cs +++ b/Jellyfin.Data/Entities/MovieMetadata.cs @@ -88,7 +88,7 @@ namespace Jellyfin.Data.Entities { string value = _Outline; GetOutline(ref value); - return (_Outline = value); + return _Outline = value; } set @@ -126,7 +126,7 @@ namespace Jellyfin.Data.Entities { string value = _Plot; GetPlot(ref value); - return (_Plot = value); + return _Plot = value; } set @@ -164,7 +164,7 @@ namespace Jellyfin.Data.Entities { string value = _Tagline; GetTagline(ref value); - return (_Tagline = value); + return _Tagline = value; } set @@ -202,7 +202,7 @@ namespace Jellyfin.Data.Entities { string value = _Country; GetCountry(ref value); - return (_Country = value); + return _Country = value; } set diff --git a/Jellyfin.Data/Entities/MusicAlbumMetadata.cs b/Jellyfin.Data/Entities/MusicAlbumMetadata.cs index 4b9f9cb62..5847101ca 100644 --- a/Jellyfin.Data/Entities/MusicAlbumMetadata.cs +++ b/Jellyfin.Data/Entities/MusicAlbumMetadata.cs @@ -88,7 +88,7 @@ namespace Jellyfin.Data.Entities { string value = _Barcode; GetBarcode(ref value); - return (_Barcode = value); + return _Barcode = value; } set @@ -126,7 +126,7 @@ namespace Jellyfin.Data.Entities { string value = _LabelNumber; GetLabelNumber(ref value); - return (_LabelNumber = value); + return _LabelNumber = value; } set @@ -164,7 +164,7 @@ namespace Jellyfin.Data.Entities { string value = _Country; GetCountry(ref value); - return (_Country = value); + return _Country = value; } set diff --git a/Jellyfin.Data/Entities/Person.cs b/Jellyfin.Data/Entities/Person.cs index e9b91a19e..206fe7709 100644 --- a/Jellyfin.Data/Entities/Person.cs +++ b/Jellyfin.Data/Entities/Person.cs @@ -83,7 +83,7 @@ namespace Jellyfin.Data.Entities { int value = _Id; GetId(ref value); - return (_Id = value); + return _Id = value; } protected set @@ -120,7 +120,7 @@ namespace Jellyfin.Data.Entities { Guid value = _UrlId; GetUrlId(ref value); - return (_UrlId = value); + return _UrlId = value; } set @@ -159,7 +159,7 @@ namespace Jellyfin.Data.Entities { string value = _Name; GetName(ref value); - return (_Name = value); + return _Name = value; } set @@ -197,7 +197,7 @@ namespace Jellyfin.Data.Entities { string value = _SourceId; GetSourceId(ref value); - return (_SourceId = value); + return _SourceId = value; } set @@ -234,7 +234,7 @@ namespace Jellyfin.Data.Entities { DateTime value = _DateAdded; GetDateAdded(ref value); - return (_DateAdded = value); + return _DateAdded = value; } internal set @@ -271,7 +271,7 @@ namespace Jellyfin.Data.Entities { DateTime value = _DateModified; GetDateModified(ref value); - return (_DateModified = value); + return _DateModified = value; } internal set diff --git a/Jellyfin.Data/Entities/PersonRole.cs b/Jellyfin.Data/Entities/PersonRole.cs index 2f14044ac..928eb74ae 100644 --- a/Jellyfin.Data/Entities/PersonRole.cs +++ b/Jellyfin.Data/Entities/PersonRole.cs @@ -89,7 +89,7 @@ namespace Jellyfin.Data.Entities { int value = _Id; GetId(ref value); - return (_Id = value); + return _Id = value; } protected set @@ -127,7 +127,7 @@ namespace Jellyfin.Data.Entities { string value = _Role; GetRole(ref value); - return (_Role = value); + return _Role = value; } set @@ -164,7 +164,7 @@ namespace Jellyfin.Data.Entities { Enums.PersonRoleType value = _Type; GetType(ref value); - return (_Type = value); + return _Type = value; } set diff --git a/Jellyfin.Data/Entities/Rating.cs b/Jellyfin.Data/Entities/Rating.cs index 2c27dbd49..e00d5297d 100644 --- a/Jellyfin.Data/Entities/Rating.cs +++ b/Jellyfin.Data/Entities/Rating.cs @@ -79,7 +79,7 @@ namespace Jellyfin.Data.Entities { int value = _Id; GetId(ref value); - return (_Id = value); + return _Id = value; } protected set @@ -116,7 +116,7 @@ namespace Jellyfin.Data.Entities { double value = _Value; GetValue(ref value); - return (_Value = value); + return _Value = value; } set @@ -149,7 +149,7 @@ namespace Jellyfin.Data.Entities { int? value = _Votes; GetVotes(ref value); - return (_Votes = value); + return _Votes = value; } set diff --git a/Jellyfin.Data/Entities/RatingSource.cs b/Jellyfin.Data/Entities/RatingSource.cs index 2a4bed7ec..941f53e52 100644 --- a/Jellyfin.Data/Entities/RatingSource.cs +++ b/Jellyfin.Data/Entities/RatingSource.cs @@ -86,7 +86,7 @@ namespace Jellyfin.Data.Entities { int value = _Id; GetId(ref value); - return (_Id = value); + return _Id = value; } protected set @@ -124,7 +124,7 @@ namespace Jellyfin.Data.Entities { string value = _Name; GetName(ref value); - return (_Name = value); + return _Name = value; } set @@ -161,7 +161,7 @@ namespace Jellyfin.Data.Entities { double value = _MaximumValue; GetMaximumValue(ref value); - return (_MaximumValue = value); + return _MaximumValue = value; } set @@ -198,7 +198,7 @@ namespace Jellyfin.Data.Entities { double value = _MinimumValue; GetMinimumValue(ref value); - return (_MinimumValue = value); + return _MinimumValue = value; } set diff --git a/Jellyfin.Data/Entities/Release.cs b/Jellyfin.Data/Entities/Release.cs index 098a78ca0..e08c04545 100644 --- a/Jellyfin.Data/Entities/Release.cs +++ b/Jellyfin.Data/Entities/Release.cs @@ -111,7 +111,7 @@ namespace Jellyfin.Data.Entities { int value = _Id; GetId(ref value); - return (_Id = value); + return _Id = value; } protected set @@ -150,7 +150,7 @@ namespace Jellyfin.Data.Entities { string value = _Name; GetName(ref value); - return (_Name = value); + return _Name = value; } set diff --git a/Jellyfin.Data/Entities/Season.cs b/Jellyfin.Data/Entities/Season.cs index 03b3805cf..d71f4b522 100644 --- a/Jellyfin.Data/Entities/Season.cs +++ b/Jellyfin.Data/Entities/Season.cs @@ -84,7 +84,7 @@ namespace Jellyfin.Data.Entities { int? value = _SeasonNumber; GetSeasonNumber(ref value); - return (_SeasonNumber = value); + return _SeasonNumber = value; } set diff --git a/Jellyfin.Data/Entities/SeasonMetadata.cs b/Jellyfin.Data/Entities/SeasonMetadata.cs index 35ff6e89a..865938338 100644 --- a/Jellyfin.Data/Entities/SeasonMetadata.cs +++ b/Jellyfin.Data/Entities/SeasonMetadata.cs @@ -84,7 +84,7 @@ namespace Jellyfin.Data.Entities { string value = _Outline; GetOutline(ref value); - return (_Outline = value); + return _Outline = value; } set diff --git a/Jellyfin.Data/Entities/Series.cs b/Jellyfin.Data/Entities/Series.cs index 69b1854ab..bede14acf 100644 --- a/Jellyfin.Data/Entities/Series.cs +++ b/Jellyfin.Data/Entities/Series.cs @@ -65,7 +65,7 @@ namespace Jellyfin.Data.Entities { DayOfWeek? value = _AirsDayOfWeek; GetAirsDayOfWeek(ref value); - return (_AirsDayOfWeek = value); + return _AirsDayOfWeek = value; } set @@ -101,7 +101,7 @@ namespace Jellyfin.Data.Entities { DateTimeOffset? value = _AirsTime; GetAirsTime(ref value); - return (_AirsTime = value); + return _AirsTime = value; } set @@ -134,7 +134,7 @@ namespace Jellyfin.Data.Entities { DateTimeOffset? value = _FirstAired; GetFirstAired(ref value); - return (_FirstAired = value); + return _FirstAired = value; } set diff --git a/Jellyfin.Data/Entities/SeriesMetadata.cs b/Jellyfin.Data/Entities/SeriesMetadata.cs index e72de07fd..bb7426754 100644 --- a/Jellyfin.Data/Entities/SeriesMetadata.cs +++ b/Jellyfin.Data/Entities/SeriesMetadata.cs @@ -88,7 +88,7 @@ namespace Jellyfin.Data.Entities { string value = _Outline; GetOutline(ref value); - return (_Outline = value); + return _Outline = value; } set @@ -126,7 +126,7 @@ namespace Jellyfin.Data.Entities { string value = _Plot; GetPlot(ref value); - return (_Plot = value); + return _Plot = value; } set @@ -164,7 +164,7 @@ namespace Jellyfin.Data.Entities { string value = _Tagline; GetTagline(ref value); - return (_Tagline = value); + return _Tagline = value; } set @@ -202,7 +202,7 @@ namespace Jellyfin.Data.Entities { string value = _Country; GetCountry(ref value); - return (_Country = value); + return _Country = value; } set diff --git a/Jellyfin.Data/Entities/Track.cs b/Jellyfin.Data/Entities/Track.cs index 59a9eb4af..e13a53d38 100644 --- a/Jellyfin.Data/Entities/Track.cs +++ b/Jellyfin.Data/Entities/Track.cs @@ -84,7 +84,7 @@ namespace Jellyfin.Data.Entities { int? value = _TrackNumber; GetTrackNumber(ref value); - return (_TrackNumber = value); + return _TrackNumber = value; } set diff --git a/MediaBrowser.Controller/Entities/CollectionFolder.cs b/MediaBrowser.Controller/Entities/CollectionFolder.cs index 5c02bd2b5..5c6a9d2a2 100644 --- a/MediaBrowser.Controller/Entities/CollectionFolder.cs +++ b/MediaBrowser.Controller/Entities/CollectionFolder.cs @@ -225,7 +225,7 @@ namespace MediaBrowser.Controller.Entities return null; } - return (totalProgresses / foldersWithProgress); + return totalProgresses / foldersWithProgress; } protected override bool RefreshLinkedChildren(IEnumerable<FileSystemMetadata> fileSystemChildren) diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index d4fa8f9b3..6441340f9 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -480,7 +480,7 @@ namespace MediaBrowser.Controller.Entities innerProgress.RegisterAction(p => { double innerPercent = currentInnerPercent; - innerPercent += p / (count); + innerPercent += p / count; progress.Report(innerPercent); }); @@ -556,7 +556,7 @@ namespace MediaBrowser.Controller.Entities innerProgress.RegisterAction(p => { double innerPercent = currentInnerPercent; - innerPercent += p / (count); + innerPercent += p / count; progress.Report(innerPercent); }); diff --git a/MediaBrowser.Controller/Library/ItemResolveArgs.cs b/MediaBrowser.Controller/Library/ItemResolveArgs.cs index 92473eaa1..1516bb1e9 100644 --- a/MediaBrowser.Controller/Library/ItemResolveArgs.cs +++ b/MediaBrowser.Controller/Library/ItemResolveArgs.cs @@ -42,7 +42,7 @@ namespace MediaBrowser.Controller.Library public LibraryOptions GetLibraryOptions() { - return LibraryOptions ?? (LibraryOptions = (Parent == null ? new LibraryOptions() : BaseItem.LibraryManager.GetLibraryOptions(Parent))); + return LibraryOptions ?? (LibraryOptions = Parent == null ? new LibraryOptions() : BaseItem.LibraryManager.GetLibraryOptions(Parent)); } /// <summary> diff --git a/MediaBrowser.Providers/Manager/MetadataService.cs b/MediaBrowser.Providers/Manager/MetadataService.cs index a3920d26f..6f03d33ae 100644 --- a/MediaBrowser.Providers/Manager/MetadataService.cs +++ b/MediaBrowser.Providers/Manager/MetadataService.cs @@ -391,7 +391,7 @@ namespace MediaBrowser.Providers.Manager { if (!child.IsFolder) { - ticks += (child.RunTimeTicks ?? 0); + ticks += child.RunTimeTicks ?? 0; } } -- cgit v1.2.3 From 8de6452967d229624c81e06d992b1cb0cb6715b1 Mon Sep 17 00:00:00 2001 From: telans <telans@protonmail.com> Date: Fri, 19 Jun 2020 22:21:49 +1200 Subject: fix some documentation periods --- Emby.Server.Implementations/Data/SqliteItemRepository.cs | 2 +- Emby.Server.Implementations/Library/LibraryManager.cs | 4 ++-- .../Library/Resolvers/TV/SeasonResolver.cs | 4 ++-- Emby.Server.Implementations/ScheduledTasks/TaskManager.cs | 2 +- Jellyfin.Data/Entities/BookMetadata.cs | 8 ++++---- Jellyfin.Data/Entities/Chapter.cs | 4 ++-- Jellyfin.Data/Entities/CompanyMetadata.cs | 8 ++++---- Jellyfin.Data/Entities/CustomItemMetadata.cs | 8 ++++---- Jellyfin.Data/Entities/EpisodeMetadata.cs | 8 ++++---- Jellyfin.Data/Entities/Group.cs | 2 +- Jellyfin.Data/Entities/LibraryRoot.cs | 4 ++-- Jellyfin.Data/Entities/MediaFile.cs | 4 ++-- Jellyfin.Data/Entities/Metadata.cs | 4 ++-- Jellyfin.Data/Entities/MovieMetadata.cs | 8 ++++---- Jellyfin.Data/Entities/MusicAlbumMetadata.cs | 8 ++++---- Jellyfin.Data/Entities/PhotoMetadata.cs | 8 ++++---- Jellyfin.Data/Entities/SeasonMetadata.cs | 8 ++++---- Jellyfin.Data/Entities/SeriesMetadata.cs | 8 ++++---- Jellyfin.Data/Entities/TrackMetadata.cs | 8 ++++---- MediaBrowser.Controller/Drawing/IImageProcessor.cs | 6 +++--- MediaBrowser.Controller/Entities/BaseItem.cs | 2 +- MediaBrowser.Controller/Net/AuthenticatedAttribute.cs | 6 +++--- MediaBrowser.Controller/Net/SecurityException.cs | 2 +- MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 2 +- MediaBrowser.Model/Services/QueryParamCollection.cs | 4 ++-- MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieProvider.cs | 2 +- 26 files changed, 67 insertions(+), 67 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index da37a8c86..6e5389ad4 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -6308,7 +6308,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type /// Gets the attachment. /// </summary> /// <param name="reader">The reader.</param> - /// <returns>MediaAttachment</returns> + /// <returns>MediaAttachment.</returns> private MediaAttachment GetMediaAttachment(IReadOnlyList<IResultSetValue> reader) { var item = new MediaAttachment diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index 893af4cae..edb58e910 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -136,7 +136,7 @@ namespace Emby.Server.Implementations.Library /// <summary> /// Initializes a new instance of the <see cref="LibraryManager" /> class. /// </summary> - /// <param name="appHost">The application host</param> + /// <param name="appHost">The application host.</param> /// <param name="logger">The logger.</param> /// <param name="taskManager">The task manager.</param> /// <param name="userManager">The user manager.</param> @@ -1793,7 +1793,7 @@ namespace Emby.Server.Implementations.Library /// Creates the items. /// </summary> /// <param name="items">The items.</param> - /// <param name="parent">The parent item</param> + /// <param name="parent">The parent item.</param> /// <param name="cancellationToken">The cancellation token.</param> public void CreateItems(IEnumerable<BaseItem> items, BaseItem parent, CancellationToken cancellationToken) { diff --git a/Emby.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs b/Emby.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs index c43a0ec6b..c8e41001a 100644 --- a/Emby.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs @@ -23,8 +23,8 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV /// </summary> /// <param name="config">The config.</param> /// <param name="libraryManager">The library manager.</param> - /// <param name="localization">The localization</param> - /// <param name="logger">The logger</param> + /// <param name="localization">The localization.</param> + /// <param name="logger">The logger.</param> public SeasonResolver( IServerConfigurationManager config, ILibraryManager libraryManager, diff --git a/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs b/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs index 0ad4253e4..3fe15ec68 100644 --- a/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs +++ b/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs @@ -95,7 +95,7 @@ namespace Emby.Server.Implementations.ScheduledTasks /// Queues the scheduled task. /// </summary> /// <typeparam name="T"></typeparam> - /// <param name="options">Task options</param> + /// <param name="options">Task options.</param> public void QueueScheduledTask<T>(TaskOptions options) where T : IScheduledTask { diff --git a/Jellyfin.Data/Entities/BookMetadata.cs b/Jellyfin.Data/Entities/BookMetadata.cs index 914eda064..dc7146371 100644 --- a/Jellyfin.Data/Entities/BookMetadata.cs +++ b/Jellyfin.Data/Entities/BookMetadata.cs @@ -29,8 +29,8 @@ namespace Jellyfin.Data.Entities /// <summary> /// Public constructor with required data. /// </summary> - /// <param name="title">The title or name of the object</param> - /// <param name="language">ISO-639-3 3-character language codes</param> + /// <param name="title">The title or name of the object.</param> + /// <param name="language">ISO-639-3 3-character language codes.</param> /// <param name="_book0"></param> public BookMetadata(string title, string language, DateTime dateadded, DateTime datemodified, Book _book0) { @@ -51,8 +51,8 @@ namespace Jellyfin.Data.Entities /// <summary> /// Static create function (for use in LINQ queries, etc.) /// </summary> - /// <param name="title">The title or name of the object</param> - /// <param name="language">ISO-639-3 3-character language codes</param> + /// <param name="title">The title or name of the object.</param> + /// <param name="language">ISO-639-3 3-character language codes.</param> /// <param name="_book0"></param> public static BookMetadata Create(string title, string language, DateTime dateadded, DateTime datemodified, Book _book0) { diff --git a/Jellyfin.Data/Entities/Chapter.cs b/Jellyfin.Data/Entities/Chapter.cs index 77685add6..960853e15 100644 --- a/Jellyfin.Data/Entities/Chapter.cs +++ b/Jellyfin.Data/Entities/Chapter.cs @@ -27,7 +27,7 @@ namespace Jellyfin.Data.Entities /// <summary> /// Public constructor with required data. /// </summary> - /// <param name="language">ISO-639-3 3-character language codes</param> + /// <param name="language">ISO-639-3 3-character language codes.</param> /// <param name="timestart"></param> /// <param name="_release0"></param> public Chapter(string language, long timestart, Release _release0) @@ -47,7 +47,7 @@ namespace Jellyfin.Data.Entities /// <summary> /// Static create function (for use in LINQ queries, etc.) /// </summary> - /// <param name="language">ISO-639-3 3-character language codes</param> + /// <param name="language">ISO-639-3 3-character language codes.</param> /// <param name="timestart"></param> /// <param name="_release0"></param> public static Chapter Create(string language, long timestart, Release _release0) diff --git a/Jellyfin.Data/Entities/CompanyMetadata.cs b/Jellyfin.Data/Entities/CompanyMetadata.cs index 695c7f096..12f213310 100644 --- a/Jellyfin.Data/Entities/CompanyMetadata.cs +++ b/Jellyfin.Data/Entities/CompanyMetadata.cs @@ -26,8 +26,8 @@ namespace Jellyfin.Data.Entities /// <summary> /// Public constructor with required data. /// </summary> - /// <param name="title">The title or name of the object</param> - /// <param name="language">ISO-639-3 3-character language codes</param> + /// <param name="title">The title or name of the object.</param> + /// <param name="language">ISO-639-3 3-character language codes.</param> /// <param name="_company0"></param> public CompanyMetadata(string title, string language, DateTime dateadded, DateTime datemodified, Company _company0) { @@ -47,8 +47,8 @@ namespace Jellyfin.Data.Entities /// <summary> /// Static create function (for use in LINQ queries, etc.) /// </summary> - /// <param name="title">The title or name of the object</param> - /// <param name="language">ISO-639-3 3-character language codes</param> + /// <param name="title">The title or name of the object.</param> + /// <param name="language">ISO-639-3 3-character language codes.</param> /// <param name="_company0"></param> public static CompanyMetadata Create(string title, string language, DateTime dateadded, DateTime datemodified, Company _company0) { diff --git a/Jellyfin.Data/Entities/CustomItemMetadata.cs b/Jellyfin.Data/Entities/CustomItemMetadata.cs index b81408aa6..dd66c8f83 100644 --- a/Jellyfin.Data/Entities/CustomItemMetadata.cs +++ b/Jellyfin.Data/Entities/CustomItemMetadata.cs @@ -25,8 +25,8 @@ namespace Jellyfin.Data.Entities /// <summary> /// Public constructor with required data. /// </summary> - /// <param name="title">The title or name of the object</param> - /// <param name="language">ISO-639-3 3-character language codes</param> + /// <param name="title">The title or name of the object.</param> + /// <param name="language">ISO-639-3 3-character language codes.</param> /// <param name="_customitem0"></param> public CustomItemMetadata(string title, string language, DateTime dateadded, DateTime datemodified, CustomItem _customitem0) { @@ -46,8 +46,8 @@ namespace Jellyfin.Data.Entities /// <summary> /// Static create function (for use in LINQ queries, etc.) /// </summary> - /// <param name="title">The title or name of the object</param> - /// <param name="language">ISO-639-3 3-character language codes</param> + /// <param name="title">The title or name of the object.</param> + /// <param name="language">ISO-639-3 3-character language codes.</param> /// <param name="_customitem0"></param> public static CustomItemMetadata Create(string title, string language, DateTime dateadded, DateTime datemodified, CustomItem _customitem0) { diff --git a/Jellyfin.Data/Entities/EpisodeMetadata.cs b/Jellyfin.Data/Entities/EpisodeMetadata.cs index da5ea43cc..b17e4aa19 100644 --- a/Jellyfin.Data/Entities/EpisodeMetadata.cs +++ b/Jellyfin.Data/Entities/EpisodeMetadata.cs @@ -26,8 +26,8 @@ namespace Jellyfin.Data.Entities /// <summary> /// Public constructor with required data. /// </summary> - /// <param name="title">The title or name of the object</param> - /// <param name="language">ISO-639-3 3-character language codes</param> + /// <param name="title">The title or name of the object.</param> + /// <param name="language">ISO-639-3 3-character language codes.</param> /// <param name="_episode0"></param> public EpisodeMetadata(string title, string language, DateTime dateadded, DateTime datemodified, Episode _episode0) { @@ -47,8 +47,8 @@ namespace Jellyfin.Data.Entities /// <summary> /// Static create function (for use in LINQ queries, etc.) /// </summary> - /// <param name="title">The title or name of the object</param> - /// <param name="language">ISO-639-3 3-character language codes</param> + /// <param name="title">The title or name of the object.</param> + /// <param name="language">ISO-639-3 3-character language codes.</param> /// <param name="_episode0"></param> public static EpisodeMetadata Create(string title, string language, DateTime dateadded, DateTime datemodified, Episode _episode0) { diff --git a/Jellyfin.Data/Entities/Group.cs b/Jellyfin.Data/Entities/Group.cs index 5cbb126f9..47833378e 100644 --- a/Jellyfin.Data/Entities/Group.cs +++ b/Jellyfin.Data/Entities/Group.cs @@ -99,7 +99,7 @@ namespace Jellyfin.Data.Entities /// <summary> /// Static create function (for use in LINQ queries, etc.) /// </summary> - /// <param name="name">The name of this group</param> + /// <param name="name">The name of this group.</param> public static Group Create(string name) { return new Group(name); diff --git a/Jellyfin.Data/Entities/LibraryRoot.cs b/Jellyfin.Data/Entities/LibraryRoot.cs index 16fbc92f6..a6f3e49c9 100644 --- a/Jellyfin.Data/Entities/LibraryRoot.cs +++ b/Jellyfin.Data/Entities/LibraryRoot.cs @@ -27,7 +27,7 @@ namespace Jellyfin.Data.Entities /// <summary> /// Public constructor with required data. /// </summary> - /// <param name="path">Absolute Path</param> + /// <param name="path">Absolute Path.</param> public LibraryRoot(string path) { if (string.IsNullOrEmpty(path)) throw new ArgumentNullException(nameof(path)); @@ -40,7 +40,7 @@ namespace Jellyfin.Data.Entities /// <summary> /// Static create function (for use in LINQ queries, etc.) /// </summary> - /// <param name="path">Absolute Path</param> + /// <param name="path">Absolute Path.</param> public static LibraryRoot Create(string path) { return new LibraryRoot(path); diff --git a/Jellyfin.Data/Entities/MediaFile.cs b/Jellyfin.Data/Entities/MediaFile.cs index 8201eed52..5d9448d41 100644 --- a/Jellyfin.Data/Entities/MediaFile.cs +++ b/Jellyfin.Data/Entities/MediaFile.cs @@ -30,7 +30,7 @@ namespace Jellyfin.Data.Entities /// <summary> /// Public constructor with required data. /// </summary> - /// <param name="path">Relative to the LibraryRoot</param> + /// <param name="path">Relative to the LibraryRoot.</param> /// <param name="kind"></param> /// <param name="_release0"></param> public MediaFile(string path, Enums.MediaFileKind kind, Release _release0) @@ -51,7 +51,7 @@ namespace Jellyfin.Data.Entities /// <summary> /// Static create function (for use in LINQ queries, etc.) /// </summary> - /// <param name="path">Relative to the LibraryRoot</param> + /// <param name="path">Relative to the LibraryRoot.</param> /// <param name="kind"></param> /// <param name="_release0"></param> public static MediaFile Create(string path, Enums.MediaFileKind kind, Release _release0) diff --git a/Jellyfin.Data/Entities/Metadata.cs b/Jellyfin.Data/Entities/Metadata.cs index 146c70a10..8446c30b2 100644 --- a/Jellyfin.Data/Entities/Metadata.cs +++ b/Jellyfin.Data/Entities/Metadata.cs @@ -26,8 +26,8 @@ namespace Jellyfin.Data.Entities /// <summary> /// Public constructor with required data. /// </summary> - /// <param name="title">The title or name of the object</param> - /// <param name="language">ISO-639-3 3-character language codes</param> + /// <param name="title">The title or name of the object.</param> + /// <param name="language">ISO-639-3 3-character language codes.</param> protected Metadata(string title, string language, DateTime dateadded, DateTime datemodified) { if (string.IsNullOrEmpty(title)) throw new ArgumentNullException(nameof(title)); diff --git a/Jellyfin.Data/Entities/MovieMetadata.cs b/Jellyfin.Data/Entities/MovieMetadata.cs index 48584dd13..4fda88e8e 100644 --- a/Jellyfin.Data/Entities/MovieMetadata.cs +++ b/Jellyfin.Data/Entities/MovieMetadata.cs @@ -30,8 +30,8 @@ namespace Jellyfin.Data.Entities /// <summary> /// Public constructor with required data. /// </summary> - /// <param name="title">The title or name of the object</param> - /// <param name="language">ISO-639-3 3-character language codes</param> + /// <param name="title">The title or name of the object.</param> + /// <param name="language">ISO-639-3 3-character language codes.</param> /// <param name="_movie0"></param> public MovieMetadata(string title, string language, DateTime dateadded, DateTime datemodified, Movie _movie0) { @@ -52,8 +52,8 @@ namespace Jellyfin.Data.Entities /// <summary> /// Static create function (for use in LINQ queries, etc.) /// </summary> - /// <param name="title">The title or name of the object</param> - /// <param name="language">ISO-639-3 3-character language codes</param> + /// <param name="title">The title or name of the object.</param> + /// <param name="language">ISO-639-3 3-character language codes.</param> /// <param name="_movie0"></param> public static MovieMetadata Create(string title, string language, DateTime dateadded, DateTime datemodified, Movie _movie0) { diff --git a/Jellyfin.Data/Entities/MusicAlbumMetadata.cs b/Jellyfin.Data/Entities/MusicAlbumMetadata.cs index 5847101ca..a5056adc0 100644 --- a/Jellyfin.Data/Entities/MusicAlbumMetadata.cs +++ b/Jellyfin.Data/Entities/MusicAlbumMetadata.cs @@ -30,8 +30,8 @@ namespace Jellyfin.Data.Entities /// <summary> /// Public constructor with required data. /// </summary> - /// <param name="title">The title or name of the object</param> - /// <param name="language">ISO-639-3 3-character language codes</param> + /// <param name="title">The title or name of the object.</param> + /// <param name="language">ISO-639-3 3-character language codes.</param> /// <param name="_musicalbum0"></param> public MusicAlbumMetadata(string title, string language, DateTime dateadded, DateTime datemodified, MusicAlbum _musicalbum0) { @@ -52,8 +52,8 @@ namespace Jellyfin.Data.Entities /// <summary> /// Static create function (for use in LINQ queries, etc.) /// </summary> - /// <param name="title">The title or name of the object</param> - /// <param name="language">ISO-639-3 3-character language codes</param> + /// <param name="title">The title or name of the object.</param> + /// <param name="language">ISO-639-3 3-character language codes.</param> /// <param name="_musicalbum0"></param> public static MusicAlbumMetadata Create(string title, string language, DateTime dateadded, DateTime datemodified, MusicAlbum _musicalbum0) { diff --git a/Jellyfin.Data/Entities/PhotoMetadata.cs b/Jellyfin.Data/Entities/PhotoMetadata.cs index 5a9cf5b66..4a0b07ff8 100644 --- a/Jellyfin.Data/Entities/PhotoMetadata.cs +++ b/Jellyfin.Data/Entities/PhotoMetadata.cs @@ -26,8 +26,8 @@ namespace Jellyfin.Data.Entities /// <summary> /// Public constructor with required data. /// </summary> - /// <param name="title">The title or name of the object</param> - /// <param name="language">ISO-639-3 3-character language codes</param> + /// <param name="title">The title or name of the object.</param> + /// <param name="language">ISO-639-3 3-character language codes.</param> /// <param name="_photo0"></param> public PhotoMetadata(string title, string language, DateTime dateadded, DateTime datemodified, Photo _photo0) { @@ -47,8 +47,8 @@ namespace Jellyfin.Data.Entities /// <summary> /// Static create function (for use in LINQ queries, etc.) /// </summary> - /// <param name="title">The title or name of the object</param> - /// <param name="language">ISO-639-3 3-character language codes</param> + /// <param name="title">The title or name of the object.</param> + /// <param name="language">ISO-639-3 3-character language codes.</param> /// <param name="_photo0"></param> public static PhotoMetadata Create(string title, string language, DateTime dateadded, DateTime datemodified, Photo _photo0) { diff --git a/Jellyfin.Data/Entities/SeasonMetadata.cs b/Jellyfin.Data/Entities/SeasonMetadata.cs index 865938338..8c72d9952 100644 --- a/Jellyfin.Data/Entities/SeasonMetadata.cs +++ b/Jellyfin.Data/Entities/SeasonMetadata.cs @@ -27,8 +27,8 @@ namespace Jellyfin.Data.Entities /// <summary> /// Public constructor with required data. /// </summary> - /// <param name="title">The title or name of the object</param> - /// <param name="language">ISO-639-3 3-character language codes</param> + /// <param name="title">The title or name of the object.</param> + /// <param name="language">ISO-639-3 3-character language codes.</param> /// <param name="_season0"></param> public SeasonMetadata(string title, string language, DateTime dateadded, DateTime datemodified, Season _season0) { @@ -48,8 +48,8 @@ namespace Jellyfin.Data.Entities /// <summary> /// Static create function (for use in LINQ queries, etc.) /// </summary> - /// <param name="title">The title or name of the object</param> - /// <param name="language">ISO-639-3 3-character language codes</param> + /// <param name="title">The title or name of the object.</param> + /// <param name="language">ISO-639-3 3-character language codes.</param> /// <param name="_season0"></param> public static SeasonMetadata Create(string title, string language, DateTime dateadded, DateTime datemodified, Season _season0) { diff --git a/Jellyfin.Data/Entities/SeriesMetadata.cs b/Jellyfin.Data/Entities/SeriesMetadata.cs index bb7426754..2c04ef12f 100644 --- a/Jellyfin.Data/Entities/SeriesMetadata.cs +++ b/Jellyfin.Data/Entities/SeriesMetadata.cs @@ -30,8 +30,8 @@ namespace Jellyfin.Data.Entities /// <summary> /// Public constructor with required data. /// </summary> - /// <param name="title">The title or name of the object</param> - /// <param name="language">ISO-639-3 3-character language codes</param> + /// <param name="title">The title or name of the object.</param> + /// <param name="language">ISO-639-3 3-character language codes.</param> /// <param name="_series0"></param> public SeriesMetadata(string title, string language, DateTime dateadded, DateTime datemodified, Series _series0) { @@ -52,8 +52,8 @@ namespace Jellyfin.Data.Entities /// <summary> /// Static create function (for use in LINQ queries, etc.) /// </summary> - /// <param name="title">The title or name of the object</param> - /// <param name="language">ISO-639-3 3-character language codes</param> + /// <param name="title">The title or name of the object.</param> + /// <param name="language">ISO-639-3 3-character language codes.</param> /// <param name="_series0"></param> public static SeriesMetadata Create(string title, string language, DateTime dateadded, DateTime datemodified, Series _series0) { diff --git a/Jellyfin.Data/Entities/TrackMetadata.cs b/Jellyfin.Data/Entities/TrackMetadata.cs index 05bb953f8..55f4a38e0 100644 --- a/Jellyfin.Data/Entities/TrackMetadata.cs +++ b/Jellyfin.Data/Entities/TrackMetadata.cs @@ -26,8 +26,8 @@ namespace Jellyfin.Data.Entities /// <summary> /// Public constructor with required data. /// </summary> - /// <param name="title">The title or name of the object</param> - /// <param name="language">ISO-639-3 3-character language codes</param> + /// <param name="title">The title or name of the object.</param> + /// <param name="language">ISO-639-3 3-character language codes.</param> /// <param name="_track0"></param> public TrackMetadata(string title, string language, DateTime dateadded, DateTime datemodified, Track _track0) { @@ -47,8 +47,8 @@ namespace Jellyfin.Data.Entities /// <summary> /// Static create function (for use in LINQ queries, etc.) /// </summary> - /// <param name="title">The title or name of the object</param> - /// <param name="language">ISO-639-3 3-character language codes</param> + /// <param name="title">The title or name of the object.</param> + /// <param name="language">ISO-639-3 3-character language codes.</param> /// <param name="_track0"></param> public static TrackMetadata Create(string title, string language, DateTime dateadded, DateTime datemodified, Track _track0) { diff --git a/MediaBrowser.Controller/Drawing/IImageProcessor.cs b/MediaBrowser.Controller/Drawing/IImageProcessor.cs index 488692c03..69d799165 100644 --- a/MediaBrowser.Controller/Drawing/IImageProcessor.cs +++ b/MediaBrowser.Controller/Drawing/IImageProcessor.cs @@ -30,7 +30,7 @@ namespace MediaBrowser.Controller.Drawing /// Gets the dimensions of the image. /// </summary> /// <param name="path">Path to the image file.</param> - /// <returns>ImageDimensions</returns> + /// <returns>ImageDimensions.</returns> ImageDimensions GetImageDimensions(string path); /// <summary> @@ -38,14 +38,14 @@ namespace MediaBrowser.Controller.Drawing /// </summary> /// <param name="item">The base item.</param> /// <param name="info">The information.</param> - /// <returns>ImageDimensions</returns> + /// <returns>ImageDimensions.</returns> ImageDimensions GetImageDimensions(BaseItem item, ItemImageInfo info); /// <summary> /// Gets the blurhash of the image. /// </summary> /// <param name="path">Path to the image file.</param> - /// <returns>BlurHash</returns> + /// <returns>BlurHash.</returns> string GetImageBlurHash(string path); /// <summary> diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index d76409afc..7b833c36b 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -1371,7 +1371,7 @@ namespace MediaBrowser.Controller.Entities /// </summary> /// <param name="options">The options.</param> /// <param name="cancellationToken">The cancellation token.</param> - /// <returns>true if a provider reports we changed</returns> + /// <returns>true if a provider reports we changed.</returns> public async Task<ItemUpdateType> RefreshMetadata(MetadataRefreshOptions options, CancellationToken cancellationToken) { TriggerOnRefreshStart(); diff --git a/MediaBrowser.Controller/Net/AuthenticatedAttribute.cs b/MediaBrowser.Controller/Net/AuthenticatedAttribute.cs index ba3c715b8..ad786f97b 100644 --- a/MediaBrowser.Controller/Net/AuthenticatedAttribute.cs +++ b/MediaBrowser.Controller/Net/AuthenticatedAttribute.cs @@ -31,9 +31,9 @@ namespace MediaBrowser.Controller.Net /// <summary> /// The request filter is executed before the service. /// </summary> - /// <param name="request">The http request wrapper</param> - /// <param name="response">The http response wrapper</param> - /// <param name="requestDto">The request DTO</param> + /// <param name="request">The http request wrapper.</param> + /// <param name="response">The http response wrapper.</param> + /// <param name="requestDto">The request DTO.</param> public void RequestFilter(IRequest request, HttpResponse response, object requestDto) { AuthService.Authenticate(request, this); diff --git a/MediaBrowser.Controller/Net/SecurityException.cs b/MediaBrowser.Controller/Net/SecurityException.cs index a5b94ea5e..f0d0b45a0 100644 --- a/MediaBrowser.Controller/Net/SecurityException.cs +++ b/MediaBrowser.Controller/Net/SecurityException.cs @@ -27,7 +27,7 @@ namespace MediaBrowser.Controller.Net /// <summary> /// Initializes a new instance of the <see cref="SecurityException"/> class. /// </summary> - /// <param name="message">The message that describes the error</param> + /// <param name="message">The message that describes the error.</param> /// <param name="innerException">The exception that is the cause of the current exception, or a null reference if no inner exception is specified.</param> public SecurityException(string message, Exception innerException) : base(message, innerException) diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index 1183e9fb2..9397a347f 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -166,7 +166,7 @@ namespace MediaBrowser.MediaEncoding.Encoder /// Validates the supplied FQPN to ensure it is a ffmpeg utility. /// If checks pass, global variable FFmpegPath and EncoderLocation are updated. /// </summary> - /// <param name="path">FQPN to test</param> + /// <param name="path">FQPN to test.</param> /// <param name="location">Location (External, Custom, System) of tool</param> /// <returns></returns> private bool ValidatePath(string path, FFmpegLocation location) diff --git a/MediaBrowser.Model/Services/QueryParamCollection.cs b/MediaBrowser.Model/Services/QueryParamCollection.cs index d07ff1548..bdb0cabdf 100644 --- a/MediaBrowser.Model/Services/QueryParamCollection.cs +++ b/MediaBrowser.Model/Services/QueryParamCollection.cs @@ -124,8 +124,8 @@ namespace MediaBrowser.Model.Services /// Gets or sets a query parameter value by name. A query may contain multiple values of the same name /// (i.e. "x=1&x=2"), in which case the value is an array, which works for both getting and setting. /// </summary> - /// <param name="name">The query parameter name</param> - /// <returns>The query parameter value or array of values</returns> + /// <param name="name">The query parameter name.</param> + /// <returns>The query parameter value or array of values.</returns> public string this[string name] { get => Get(name); diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieProvider.cs index 3c0922f39..1961e8bff 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieProvider.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieProvider.cs @@ -312,7 +312,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Movies /// <param name="id">The id.</param> /// <param name="isTmdbId">if set to <c>true</c> [is TMDB identifier].</param> /// <param name="language">The language.</param> - /// <param name="cancellationToken">The cancellation token</param> + /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task{CompleteMovieData}.</returns> internal async Task<MovieResult> FetchMainResult(string id, bool isTmdbId, string language, CancellationToken cancellationToken) { -- cgit v1.2.3 From 8e3d8748021fe0336e2fc1211810cc9bbe2c8850 Mon Sep 17 00:00:00 2001 From: telans <telans@protonmail.com> Date: Sat, 20 Jun 2020 18:20:33 +1200 Subject: remove regions --- Emby.Dlna/PlayTo/Device.cs | 23 ++-------- MediaBrowser.Controller/Library/ItemResolveArgs.cs | 5 -- MediaBrowser.Controller/Library/Profiler.cs | 3 -- RSSDP/DeviceAvailableEventArgs.cs | 13 +----- RSSDP/DeviceEventArgs.cs | 13 ------ RSSDP/DeviceUnavailableEventArgs.cs | 14 +----- RSSDP/DiscoveredSsdpDevice.cs | 17 ------- RSSDP/DisposableManagedObjectBase.cs | 14 ------ RSSDP/HttpParserBase.cs | 14 ------ RSSDP/HttpRequestParser.cs | 19 ++------ RSSDP/HttpResponseParser.cs | 19 ++------ RSSDP/ISsdpCommunicationsServer.cs | 13 ------ RSSDP/ISsdpDeviceLocator.cs | 18 -------- RSSDP/RequestReceivedEventArgs.cs | 13 +----- RSSDP/ResponseReceivedEventArgs.cs | 14 +----- RSSDP/SsdpCommunicationsServer.cs | 30 ------------ RSSDP/SsdpDevice.cs | 25 ---------- RSSDP/SsdpDeviceLocator.cs | 53 ---------------------- RSSDP/SsdpEmbeddedDevice.cs | 12 ----- RSSDP/SsdpRootDevice.cs | 12 ----- 20 files changed, 13 insertions(+), 331 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Dlna/PlayTo/Device.cs b/Emby.Dlna/PlayTo/Device.cs index 6982e7333..c86fc4f37 100644 --- a/Emby.Dlna/PlayTo/Device.cs +++ b/Emby.Dlna/PlayTo/Device.cs @@ -19,8 +19,6 @@ namespace Emby.Dlna.PlayTo { public class Device : IDisposable { - #region Fields & Properties - private Timer _timer; public DeviceInfo Properties { get; set; } @@ -53,10 +51,10 @@ namespace Emby.Dlna.PlayTo public bool IsStopped => TransportState == TRANSPORTSTATE.STOPPED; - #endregion - private readonly IHttpClient _httpClient; + private readonly ILogger _logger; + private readonly IServerConfigurationManager _config; public Action OnDeviceUnavailable { get; set; } @@ -142,8 +140,6 @@ namespace Emby.Dlna.PlayTo } } - #region Commanding - public Task VolumeDown(CancellationToken cancellationToken) { var sendVolume = Math.Max(Volume - 5, 0); @@ -402,11 +398,8 @@ namespace Emby.Dlna.PlayTo RestartTimer(true); } - #endregion - - #region Get data - private int _connectFailureCount; + private async void TimerCallback(object sender) { if (_disposed) @@ -870,10 +863,6 @@ namespace Emby.Dlna.PlayTo return new string[4]; } - #endregion - - #region From XML - private async Task<TransportCommands> GetAVProtocolAsync(CancellationToken cancellationToken) { if (AvCommands != null) @@ -1068,8 +1057,6 @@ namespace Emby.Dlna.PlayTo return new Device(deviceProperties, httpClient, logger, config); } - #endregion - private static readonly CultureInfo UsCulture = new CultureInfo("en-US"); private static DeviceIcon CreateIcon(XElement element) { @@ -1193,8 +1180,6 @@ namespace Emby.Dlna.PlayTo }); } - #region IDisposable - bool _disposed; public void Dispose() @@ -1221,8 +1206,6 @@ namespace Emby.Dlna.PlayTo _disposed = true; } - #endregion - public override string ToString() { return string.Format("{0} - {1}", Properties.Name, Properties.BaseUrl); diff --git a/MediaBrowser.Controller/Library/ItemResolveArgs.cs b/MediaBrowser.Controller/Library/ItemResolveArgs.cs index 1516bb1e9..731c6d667 100644 --- a/MediaBrowser.Controller/Library/ItemResolveArgs.cs +++ b/MediaBrowser.Controller/Library/ItemResolveArgs.cs @@ -224,8 +224,6 @@ namespace MediaBrowser.Controller.Library public string CollectionType { get; set; } - #region Equality Overrides - /// <summary> /// Determines whether the specified <see cref="object" /> is equal to this instance. /// </summary> @@ -260,8 +258,5 @@ namespace MediaBrowser.Controller.Library return false; } - - #endregion } - } diff --git a/MediaBrowser.Controller/Library/Profiler.cs b/MediaBrowser.Controller/Library/Profiler.cs index f9808a4f4..399378a09 100644 --- a/MediaBrowser.Controller/Library/Profiler.cs +++ b/MediaBrowser.Controller/Library/Profiler.cs @@ -37,7 +37,6 @@ namespace MediaBrowser.Controller.Library _stopwatch = new Stopwatch(); _stopwatch.Start(); } - #region IDisposable Members /// <summary> /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. @@ -71,7 +70,5 @@ namespace MediaBrowser.Controller.Library _logger.LogInformation(message); } } - - #endregion } } diff --git a/RSSDP/DeviceAvailableEventArgs.cs b/RSSDP/DeviceAvailableEventArgs.cs index 439cee467..9c57471ca 100644 --- a/RSSDP/DeviceAvailableEventArgs.cs +++ b/RSSDP/DeviceAvailableEventArgs.cs @@ -10,14 +10,9 @@ namespace Rssdp { public IPAddress LocalIpAddress { get; set; } - #region Fields - private readonly DiscoveredSsdpDevice _DiscoveredDevice; - private readonly bool _IsNewlyDiscovered; - #endregion - - #region Constructors + private readonly bool _IsNewlyDiscovered; /// <summary> /// Full constructor. @@ -33,10 +28,6 @@ namespace Rssdp _IsNewlyDiscovered = isNewlyDiscovered; } - #endregion - - #region Public Properties - /// <summary> /// Returns true if the device was discovered due to an alive notification, or a search and was not already in the cache. Returns false if the item came from the cache but matched the current search request. /// </summary> @@ -52,7 +43,5 @@ namespace Rssdp { get { return _DiscoveredDevice; } } - - #endregion } } diff --git a/RSSDP/DeviceEventArgs.cs b/RSSDP/DeviceEventArgs.cs index faeff8347..b124527ca 100644 --- a/RSSDP/DeviceEventArgs.cs +++ b/RSSDP/DeviceEventArgs.cs @@ -7,15 +7,8 @@ namespace Rssdp /// </summary> public sealed class DeviceEventArgs : EventArgs { - - #region Fields - private readonly SsdpDevice _Device; - #endregion - - #region Constructors - /// <summary> /// Constructs a new instance for the specified <see cref="SsdpDevice"/>. /// </summary> @@ -28,10 +21,6 @@ namespace Rssdp _Device = device; } - #endregion - - #region Public Properties - /// <summary> /// Returns the <see cref="SsdpDevice"/> instance the event being raised for. /// </summary> @@ -39,7 +28,5 @@ namespace Rssdp { get { return _Device; } } - - #endregion } } diff --git a/RSSDP/DeviceUnavailableEventArgs.cs b/RSSDP/DeviceUnavailableEventArgs.cs index ef04904bd..cee59268d 100644 --- a/RSSDP/DeviceUnavailableEventArgs.cs +++ b/RSSDP/DeviceUnavailableEventArgs.cs @@ -7,15 +7,9 @@ namespace Rssdp /// </summary> public sealed class DeviceUnavailableEventArgs : EventArgs { - - #region Fields - private readonly DiscoveredSsdpDevice _DiscoveredDevice; - private readonly bool _Expired; - - #endregion - #region Constructors + private readonly bool _Expired; /// <summary> /// Full constructor. @@ -31,10 +25,6 @@ namespace Rssdp _Expired = expired; } - #endregion - - #region Public Properties - /// <summary> /// Returns true if the device is considered unavailable because it's cached information expired before a new alive notification or search result was received. Returns false if the device is unavailable because it sent an explicit notification of it's unavailability. /// </summary> @@ -50,7 +40,5 @@ namespace Rssdp { get { return _DiscoveredDevice; } } - - #endregion } } diff --git a/RSSDP/DiscoveredSsdpDevice.cs b/RSSDP/DiscoveredSsdpDevice.cs index fb323c1fb..322bd55e5 100644 --- a/RSSDP/DiscoveredSsdpDevice.cs +++ b/RSSDP/DiscoveredSsdpDevice.cs @@ -10,15 +10,8 @@ namespace Rssdp /// <seealso cref="Infrastructure.ISsdpDeviceLocator"/> public sealed class DiscoveredSsdpDevice { - - #region Fields - private DateTimeOffset _AsAt; - #endregion - - #region Public Properties - /// <summary> /// Sets or returns the type of notification, being either a uuid, device type, service type or upnp:rootdevice. /// </summary> @@ -60,10 +53,6 @@ namespace Rssdp /// </summary> public HttpHeaders ResponseHeaders { get; set; } - #endregion - - #region Public Methods - /// <summary> /// Returns true if this device information has expired, based on the current date/time, and the <see cref="CacheLifetime"/> & <see cref="AsAt"/> properties. /// </summary> @@ -73,10 +62,6 @@ namespace Rssdp return this.CacheLifetime == TimeSpan.Zero || this.AsAt.Add(this.CacheLifetime) <= DateTimeOffset.Now; } - #endregion - - #region Overrides - /// <summary> /// Returns the device's <see cref="Usn"/> value. /// </summary> @@ -85,7 +70,5 @@ namespace Rssdp { return this.Usn; } - - #endregion } } diff --git a/RSSDP/DisposableManagedObjectBase.cs b/RSSDP/DisposableManagedObjectBase.cs index 39589f022..befa4ccff 100644 --- a/RSSDP/DisposableManagedObjectBase.cs +++ b/RSSDP/DisposableManagedObjectBase.cs @@ -9,9 +9,6 @@ namespace Rssdp.Infrastructure /// </summary> public abstract class DisposableManagedObjectBase : IDisposable { - - #region Public Methods - /// <summary> /// Override this method and dispose any objects you own the lifetime of if disposing is true; /// </summary> @@ -29,10 +26,6 @@ namespace Rssdp.Infrastructure if (this.IsDisposed) throw new ObjectDisposedException(this.GetType().FullName); } - #endregion - - #region Public Properties - /// <summary> /// Sets or returns a boolean indicating whether or not this instance has been disposed. /// </summary> @@ -42,9 +35,6 @@ namespace Rssdp.Infrastructure get; private set; } - - #endregion - public string BuildMessage(string header, Dictionary<string, string> values) { var builder = new StringBuilder(); @@ -63,8 +53,6 @@ namespace Rssdp.Infrastructure return builder.ToString(); } - #region IDisposable Members - /// <summary> /// Disposes this object instance and all internally managed resources. /// </summary> @@ -79,7 +67,5 @@ namespace Rssdp.Infrastructure Dispose(true); } - - #endregion } } diff --git a/RSSDP/HttpParserBase.cs b/RSSDP/HttpParserBase.cs index e7172cb1c..ff97b6db8 100644 --- a/RSSDP/HttpParserBase.cs +++ b/RSSDP/HttpParserBase.cs @@ -11,16 +11,9 @@ namespace Rssdp.Infrastructure /// <typeparam name="T"></typeparam> public abstract class HttpParserBase<T> where T : new() { - - #region Fields - private readonly string[] LineTerminators = new string[] { "\r\n", "\n" }; private readonly char[] SeparatorCharacters = new char[] { ',', ';' }; - #endregion - - #region Public Methods - /// <summary> /// Parses the <paramref name="data"/> provided into either a <see cref="HttpRequestMessage"/> or <see cref="HttpResponseMessage"/> object. /// </summary> @@ -81,10 +74,6 @@ namespace Rssdp.Infrastructure return Version.Parse(versionData.Substring(versionSeparatorIndex + 1)); } - #endregion - - #region Private Methods - /// <summary> /// Parses a line from an HTTP request or response message containing a header name and value pair. /// </summary> @@ -202,8 +191,5 @@ namespace Rssdp.Infrastructure else return trimmedSegment; } - - #endregion - } } diff --git a/RSSDP/HttpRequestParser.cs b/RSSDP/HttpRequestParser.cs index 3fc328b8c..31f042791 100644 --- a/RSSDP/HttpRequestParser.cs +++ b/RSSDP/HttpRequestParser.cs @@ -9,17 +9,10 @@ namespace Rssdp.Infrastructure /// </summary> public sealed class HttpRequestParser : HttpParserBase<HttpRequestMessage> { - - #region Fields & Constants - private readonly string[] ContentHeaderNames = new string[] - { - "Allow", "Content-Disposition", "Content-Encoding", "Content-Language", "Content-Length", "Content-Location", "Content-MD5", "Content-Range", "Content-Type", "Expires", "Last-Modified" - }; - - #endregion - - #region Public Methods + { + "Allow", "Content-Disposition", "Content-Encoding", "Content-Language", "Content-Length", "Content-Location", "Content-MD5", "Content-Range", "Content-Type", "Expires", "Last-Modified" + }; /// <summary> /// Parses the specified data into a <see cref="HttpRequestMessage"/> instance. @@ -45,10 +38,6 @@ namespace Rssdp.Infrastructure } } - #endregion - - #region Overrides - /// <summary> /// Used to parse the first line of an HTTP request or response and assign the values to the appropriate properties on the <paramref name="message"/>. /// </summary> @@ -83,7 +72,5 @@ namespace Rssdp.Infrastructure { return ContentHeaderNames.Contains(headerName, StringComparer.OrdinalIgnoreCase); } - - #endregion } } diff --git a/RSSDP/HttpResponseParser.cs b/RSSDP/HttpResponseParser.cs index b96eaf625..02c548d72 100644 --- a/RSSDP/HttpResponseParser.cs +++ b/RSSDP/HttpResponseParser.cs @@ -10,17 +10,10 @@ namespace Rssdp.Infrastructure /// </summary> public sealed class HttpResponseParser : HttpParserBase<HttpResponseMessage> { - - #region Fields & Constants - private readonly string[] ContentHeaderNames = new string[] - { - "Allow", "Content-Disposition", "Content-Encoding", "Content-Language", "Content-Length", "Content-Location", "Content-MD5", "Content-Range", "Content-Type", "Expires", "Last-Modified" - }; - - #endregion - - #region Public Methods + { + "Allow", "Content-Disposition", "Content-Encoding", "Content-Language", "Content-Length", "Content-Location", "Content-MD5", "Content-Range", "Content-Type", "Expires", "Last-Modified" + }; /// <summary> /// Parses the specified data into a <see cref="HttpResponseMessage"/> instance. @@ -47,10 +40,6 @@ namespace Rssdp.Infrastructure } } - #endregion - - #region Overrides Methods - /// <summary> /// Returns a boolean indicating whether the specified HTTP header name represents a content header (true), or a message header (false). /// </summary> @@ -87,7 +76,5 @@ namespace Rssdp.Infrastructure message.ReasonPhrase = parts[2].Trim(); } } - - #endregion } } diff --git a/RSSDP/ISsdpCommunicationsServer.cs b/RSSDP/ISsdpCommunicationsServer.cs index 02c3af0e5..aa35811ef 100644 --- a/RSSDP/ISsdpCommunicationsServer.cs +++ b/RSSDP/ISsdpCommunicationsServer.cs @@ -10,9 +10,6 @@ namespace Rssdp.Infrastructure /// </summary> public interface ISsdpCommunicationsServer : IDisposable { - - #region Events - /// <summary> /// Raised when a HTTPU request message is received by a socket (unicast or multicast). /// </summary> @@ -23,10 +20,6 @@ namespace Rssdp.Infrastructure /// </summary> event EventHandler<ResponseReceivedEventArgs> ResponseReceived; - #endregion - - #region Methods - /// <summary> /// Causes the server to begin listening for multicast messages, being SSDP search requests and notifications. /// </summary> @@ -48,10 +41,6 @@ namespace Rssdp.Infrastructure Task SendMulticastMessage(string message, IPAddress fromLocalIpAddress, CancellationToken cancellationToken); Task SendMulticastMessage(string message, int sendCount, IPAddress fromLocalIpAddress, CancellationToken cancellationToken); - #endregion - - #region Properties - /// <summary> /// Gets or sets a boolean value indicating whether or not this instance is shared amongst multiple <see cref="SsdpDeviceLocatorBase"/> and/or <see cref="ISsdpDevicePublisher"/> instances. /// </summary> @@ -59,7 +48,5 @@ namespace Rssdp.Infrastructure /// <para>If true, disposing an instance of a <see cref="SsdpDeviceLocatorBase"/>or a <see cref="ISsdpDevicePublisher"/> will not dispose this comms server instance. The calling code is responsible for managing the lifetime of the server.</para> /// </remarks> bool IsShared { get; set; } - - #endregion } } diff --git a/RSSDP/ISsdpDeviceLocator.cs b/RSSDP/ISsdpDeviceLocator.cs index 8f0d39e75..413055643 100644 --- a/RSSDP/ISsdpDeviceLocator.cs +++ b/RSSDP/ISsdpDeviceLocator.cs @@ -13,9 +13,6 @@ namespace Rssdp.Infrastructure /// <seealso cref="ISsdpDevicePublisher"/> public interface ISsdpDeviceLocator { - - #region Events - /// <summary> /// Event raised when a device becomes available or is found by a search request. /// </summary> @@ -34,10 +31,6 @@ namespace Rssdp.Infrastructure /// <seealso cref="StopListeningForNotifications"/> event EventHandler<DeviceUnavailableEventArgs> DeviceUnavailable; - #endregion - - #region Properties - /// <summary> /// Sets or returns a string containing the filter for notifications. Notifications not matching the filter will not raise the <see cref="DeviceAvailable"/> or <see cref="DeviceUnavailable"/> events. /// </summary> @@ -58,12 +51,6 @@ namespace Rssdp.Infrastructure set; } - #endregion - - #region Methods - - #region SearchAsync Overloads - /// <summary> /// Aynchronously performs a search for all devices using the default search timeout, and returns an awaitable task that can be used to retrieve the results. /// </summary> @@ -108,8 +95,6 @@ namespace Rssdp.Infrastructure /// <returns>A task whose result is an <see cref="System.Collections.Generic.IEnumerable{T}"/> of <see cref="DiscoveredSsdpDevice" /> instances, representing all found devices.</returns> System.Threading.Tasks.Task<System.Collections.Generic.IEnumerable<DiscoveredSsdpDevice>> SearchAsync(TimeSpan searchWaitTime); - #endregion - /// <summary> /// Starts listening for broadcast notifications of service availability. /// </summary> @@ -134,8 +119,5 @@ namespace Rssdp.Infrastructure /// <seealso cref="DeviceUnavailable"/> /// <seealso cref="NotificationFilter"/> void StopListeningForNotifications(); - - #endregion - } } diff --git a/RSSDP/RequestReceivedEventArgs.cs b/RSSDP/RequestReceivedEventArgs.cs index b753950f0..025c4d2e0 100644 --- a/RSSDP/RequestReceivedEventArgs.cs +++ b/RSSDP/RequestReceivedEventArgs.cs @@ -9,17 +9,12 @@ namespace Rssdp.Infrastructure /// </summary> public sealed class RequestReceivedEventArgs : EventArgs { - #region Fields - private readonly HttpRequestMessage _Message; - private readonly IPEndPoint _ReceivedFrom; - #endregion + private readonly IPEndPoint _ReceivedFrom; public IPAddress LocalIpAddress { get; private set; } - #region Constructors - /// <summary> /// Full constructor. /// </summary> @@ -30,10 +25,6 @@ namespace Rssdp.Infrastructure LocalIpAddress = localIpAddress; } - #endregion - - #region Public Properties - /// <summary> /// The <see cref="HttpRequestMessage"/> that was received. /// </summary> @@ -49,7 +40,5 @@ namespace Rssdp.Infrastructure { get { return _ReceivedFrom; } } - - #endregion } } diff --git a/RSSDP/ResponseReceivedEventArgs.cs b/RSSDP/ResponseReceivedEventArgs.cs index f9f9c3040..708113da1 100644 --- a/RSSDP/ResponseReceivedEventArgs.cs +++ b/RSSDP/ResponseReceivedEventArgs.cs @@ -9,17 +9,11 @@ namespace Rssdp.Infrastructure /// </summary> public sealed class ResponseReceivedEventArgs : EventArgs { - public IPAddress LocalIpAddress { get; set; } - #region Fields - private readonly HttpResponseMessage _Message; - private readonly IPEndPoint _ReceivedFrom; - - #endregion - #region Constructors + private readonly IPEndPoint _ReceivedFrom; /// <summary> /// Full constructor. @@ -30,10 +24,6 @@ namespace Rssdp.Infrastructure _ReceivedFrom = receivedFrom; } - #endregion - - #region Public Properties - /// <summary> /// The <see cref="HttpResponseMessage"/> that was received. /// </summary> @@ -49,7 +39,5 @@ namespace Rssdp.Infrastructure { get { return _ReceivedFrom; } } - - #endregion } } diff --git a/RSSDP/SsdpCommunicationsServer.cs b/RSSDP/SsdpCommunicationsServer.cs index fe49fb7d3..12ecf24f3 100644 --- a/RSSDP/SsdpCommunicationsServer.cs +++ b/RSSDP/SsdpCommunicationsServer.cs @@ -19,9 +19,6 @@ namespace Rssdp.Infrastructure /// </summary> public sealed class SsdpCommunicationsServer : DisposableManagedObjectBase, ISsdpCommunicationsServer { - - #region Fields - /* We could technically use one socket listening on port 1900 for everything. * This should get both multicast (notifications) and unicast (search response) messages, however * this often doesn't work under Windows because the MS SSDP service is running. If that service @@ -55,10 +52,6 @@ namespace Rssdp.Infrastructure private bool _IsShared; private readonly bool _enableMultiSocketBinding; - #endregion - - #region Events - /// <summary> /// Raised when a HTTPU request message is received by a socket (unicast or multicast). /// </summary> @@ -69,10 +62,6 @@ namespace Rssdp.Infrastructure /// </summary> public event EventHandler<ResponseReceivedEventArgs> ResponseReceived; - #endregion - - #region Constructors - /// <summary> /// Minimum constructor. /// </summary> @@ -109,10 +98,6 @@ namespace Rssdp.Infrastructure _enableMultiSocketBinding = enableMultiSocketBinding; } - #endregion - - #region Public Methods - /// <summary> /// Causes the server to begin listening for multicast messages, being SSDP search requests and notifications. /// </summary> @@ -298,10 +283,6 @@ namespace Rssdp.Infrastructure } } - #endregion - - #region Public Properties - /// <summary> /// Gets or sets a boolean value indicating whether or not this instance is shared amongst multiple <see cref="SsdpDeviceLocatorBase"/> and/or <see cref="ISsdpDevicePublisher"/> instances. /// </summary> @@ -315,10 +296,6 @@ namespace Rssdp.Infrastructure set { _IsShared = value; } } - #endregion - - #region Overrides - /// <summary> /// Stops listening for requests, disposes this instance and all internal resources. /// </summary> @@ -333,10 +310,6 @@ namespace Rssdp.Infrastructure } } - #endregion - - #region Private Methods - private Task SendMessageIfSocketNotDisposed(byte[] messageData, IPEndPoint destination, IPAddress fromLocalIpAddress, CancellationToken cancellationToken) { var sockets = _sendSockets; @@ -506,8 +479,5 @@ namespace Rssdp.Infrastructure LocalIpAddress = localIpAddress }); } - - #endregion - } } diff --git a/RSSDP/SsdpDevice.cs b/RSSDP/SsdpDevice.cs index f89bafb19..5b7d782b5 100644 --- a/RSSDP/SsdpDevice.cs +++ b/RSSDP/SsdpDevice.cs @@ -15,9 +15,6 @@ namespace Rssdp /// <seealso cref="SsdpEmbeddedDevice"/> public abstract class SsdpDevice { - - #region Fields - private string _Udn; private string _DeviceType; private string _DeviceTypeNamespace; @@ -25,10 +22,6 @@ namespace Rssdp private IList<SsdpDevice> _Devices; - #endregion - - #region Events - /// <summary> /// Raised when a new child device is added. /// </summary> @@ -43,10 +36,6 @@ namespace Rssdp /// <seealso cref="DeviceRemoved"/> public event EventHandler<DeviceEventArgs> DeviceRemoved; - #endregion - - #region Constructors - /// <summary> /// Derived type constructor, allows constructing a device with no parent. Should only be used from derived types that are or inherit from <see cref="SsdpRootDevice"/>. /// </summary> @@ -60,8 +49,6 @@ namespace Rssdp this.Devices = new ReadOnlyCollection<SsdpDevice>(_Devices); } - #endregion - public SsdpRootDevice ToRootDevice() { var device = this; @@ -73,10 +60,6 @@ namespace Rssdp return rootDevice; } - #region Public Properties - - #region UPnP Device Description Properties - /// <summary> /// Sets or returns the core device type (not including namespace, version etc.). Required. /// </summary> @@ -252,8 +235,6 @@ namespace Rssdp /// </remarks> public Uri PresentationUrl { get; set; } - #endregion - /// <summary> /// Returns a read-only enumerable set of <see cref="SsdpDevice"/> objects representing children of this device. Child devices are optional. /// </summary> @@ -265,10 +246,6 @@ namespace Rssdp private set; } - #endregion - - #region Public Methods - /// <summary> /// Adds a child device to the <see cref="Devices"/> collection. /// </summary> @@ -351,7 +328,5 @@ namespace Rssdp if (handlers != null) handlers(this, new DeviceEventArgs(device)); } - - #endregion } } diff --git a/RSSDP/SsdpDeviceLocator.cs b/RSSDP/SsdpDeviceLocator.cs index 9b48cf31c..b117c0b1e 100644 --- a/RSSDP/SsdpDeviceLocator.cs +++ b/RSSDP/SsdpDeviceLocator.cs @@ -13,9 +13,6 @@ namespace Rssdp.Infrastructure /// </summary> public class SsdpDeviceLocator : DisposableManagedObjectBase { - - #region Fields & Constants - private List<DiscoveredSsdpDevice> _Devices; private ISsdpCommunicationsServer _CommunicationsServer; @@ -25,10 +22,6 @@ namespace Rssdp.Infrastructure private readonly TimeSpan DefaultSearchWaitTime = TimeSpan.FromSeconds(4); private readonly TimeSpan OneSecond = TimeSpan.FromSeconds(1); - #endregion - - #region Constructors - /// <summary> /// Default constructor. /// </summary> @@ -42,10 +35,6 @@ namespace Rssdp.Infrastructure _Devices = new List<DiscoveredSsdpDevice>(); } - #endregion - - #region Events - /// <summary> /// Raised for when /// <list type="bullet"> @@ -76,12 +65,6 @@ namespace Rssdp.Infrastructure /// <seealso cref="StopListeningForNotifications"/> public event EventHandler<DeviceUnavailableEventArgs> DeviceUnavailable; - #endregion - - #region Public Methods - - #region Search Overloads - public void RestartBroadcastTimer(TimeSpan dueTime, TimeSpan period) { lock (_timerLock) @@ -167,8 +150,6 @@ namespace Rssdp.Infrastructure return BroadcastDiscoverMessage(searchTarget, SearchTimeToMXValue(searchWaitTime), cancellationToken); } - #endregion - /// <summary> /// Starts listening for broadcast notifications of service availability. /// </summary> @@ -236,10 +217,6 @@ namespace Rssdp.Infrastructure handlers(this, new DeviceUnavailableEventArgs(device, expired)); } - #endregion - - #region Public Properties - /// <summary> /// Sets or returns a string containing the filter for notifications. Notifications not matching the filter will not raise the <see cref="ISsdpDeviceLocator.DeviceAvailable"/> or <see cref="ISsdpDeviceLocator.DeviceUnavailable"/> events. /// </summary> @@ -261,10 +238,6 @@ namespace Rssdp.Infrastructure set; } - #endregion - - #region Overrides - /// <summary> /// Disposes this object and all internal resources. Stops listening for all network messages. /// </summary> @@ -285,12 +258,6 @@ namespace Rssdp.Infrastructure } } - #endregion - - #region Private Methods - - #region Discovery/Device Add - private void AddOrUpdateDiscoveredDevice(DiscoveredSsdpDevice device, IPAddress localIpAddress) { bool isNewDevice = false; @@ -326,10 +293,6 @@ namespace Rssdp.Infrastructure || device.NotificationType == this.NotificationFilter; } - #endregion - - #region Network Message Processing - private Task BroadcastDiscoverMessage(string serviceType, TimeSpan mxValue, CancellationToken cancellationToken) { var values = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); @@ -429,8 +392,6 @@ namespace Rssdp.Infrastructure } } - #region Header/Message Processing Utilities - private string GetFirstHeaderStringValue(string headerName, HttpResponseMessage message) { string retVal = null; @@ -498,12 +459,6 @@ namespace Rssdp.Infrastructure return (TimeSpan)(headerValue.MaxAge ?? headerValue.SharedMaxAge ?? TimeSpan.Zero); } - #endregion - - #endregion - - #region Expiry and Device Removal - private void RemoveExpiredDevicesFromCache() { if (this.IsDisposed) return; @@ -560,8 +515,6 @@ namespace Rssdp.Infrastructure return false; } - #endregion - private TimeSpan SearchTimeToMXValue(TimeSpan searchWaitTime) { if (searchWaitTime.TotalSeconds < 2 || searchWaitTime == TimeSpan.Zero) @@ -598,10 +551,6 @@ namespace Rssdp.Infrastructure return list; } - #endregion - - #region Event Handlers - private void CommsServer_ResponseReceived(object sender, ResponseReceivedEventArgs e) { ProcessSearchResponseMessage(e.Message, e.LocalIpAddress); @@ -611,7 +560,5 @@ namespace Rssdp.Infrastructure { ProcessNotificationMessage(e.Message, e.LocalIpAddress); } - - #endregion } } diff --git a/RSSDP/SsdpEmbeddedDevice.cs b/RSSDP/SsdpEmbeddedDevice.cs index ff644993b..f1a598111 100644 --- a/RSSDP/SsdpEmbeddedDevice.cs +++ b/RSSDP/SsdpEmbeddedDevice.cs @@ -5,14 +5,8 @@ namespace Rssdp /// </summary> public class SsdpEmbeddedDevice : SsdpDevice { - - #region Fields private SsdpRootDevice _RootDevice; - #endregion - - #region Constructors - /// <summary> /// Default constructor. /// </summary> @@ -20,10 +14,6 @@ namespace Rssdp { } - #endregion - - #region Public Properties - /// <summary> /// Returns the <see cref="SsdpRootDevice"/> that is this device's first ancestor. If this device is itself an <see cref="SsdpRootDevice"/>, then returns a reference to itself. /// </summary> @@ -46,7 +36,5 @@ namespace Rssdp } } } - - #endregion } } diff --git a/RSSDP/SsdpRootDevice.cs b/RSSDP/SsdpRootDevice.cs index 0f2de7b15..8937ec331 100644 --- a/RSSDP/SsdpRootDevice.cs +++ b/RSSDP/SsdpRootDevice.cs @@ -12,14 +12,8 @@ namespace Rssdp /// </remarks> public class SsdpRootDevice : SsdpDevice { - #region Fields - private Uri _UrlBase; - #endregion - - #region Constructors - /// <summary> /// Default constructor. /// </summary> @@ -27,10 +21,6 @@ namespace Rssdp { } - #endregion - - #region Public Properties - /// <summary> /// Specifies how long clients can cache this device's details for. Optional but defaults to <see cref="TimeSpan.Zero"/> which means no-caching. Recommended value is half an hour. /// </summary> @@ -77,7 +67,5 @@ namespace Rssdp _UrlBase = value; } } - - #endregion } } -- cgit v1.2.3 From 98db8f72e01b608e6c384ecf5b107fc2d105b652 Mon Sep 17 00:00:00 2001 From: telans <telans@protonmail.com> Date: Sat, 20 Jun 2020 20:35:29 +1200 Subject: fix SA1503 for one line if statements --- DvdLib/Ifo/Dvd.cs | 16 +++- DvdLib/Ifo/DvdTime.cs | 10 ++- DvdLib/Ifo/ProgramChain.cs | 11 ++- DvdLib/Ifo/Title.cs | 5 +- Emby.Dlna/PlayTo/PlayToManager.cs | 10 ++- .../Data/SqliteItemRepository.cs | 95 ++++++++++++++++++---- .../LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs | 9 +- Emby.Server.Implementations/Net/UdpSocket.cs | 10 ++- .../Playlists/PlaylistManager.cs | 12 ++- .../Services/ServiceController.cs | 5 +- .../Services/ServiceExec.cs | 5 +- .../Services/ServicePath.cs | 5 +- Jellyfin.Data/Entities/Artwork.cs | 19 ++++- Jellyfin.Data/Entities/BookMetadata.cs | 18 +++- Jellyfin.Data/Entities/Chapter.cs | 12 ++- Jellyfin.Data/Entities/CollectionItem.cs | 19 ++++- Jellyfin.Data/Entities/Company.cs | 30 +++++-- Jellyfin.Data/Entities/CompanyMetadata.cs | 19 ++++- Jellyfin.Data/Entities/CustomItemMetadata.cs | 19 ++++- Jellyfin.Data/Entities/Episode.cs | 6 +- Jellyfin.Data/Entities/EpisodeMetadata.cs | 19 ++++- Jellyfin.Data/Entities/Genre.cs | 13 ++- Jellyfin.Data/Entities/Library.cs | 7 +- Jellyfin.Data/Entities/LibraryRoot.cs | 7 +- Jellyfin.Data/Entities/MediaFile.cs | 12 ++- Jellyfin.Data/Entities/MediaFileStream.cs | 7 +- Jellyfin.Data/Entities/Metadata.cs | 12 ++- Jellyfin.Data/Entities/MetadataProvider.cs | 7 +- Jellyfin.Data/Entities/MetadataProviderId.cs | 31 +++++-- Jellyfin.Data/Entities/MovieMetadata.cs | 18 +++- Jellyfin.Data/Entities/MusicAlbumMetadata.cs | 18 +++- Jellyfin.Data/Entities/Person.cs | 6 +- Jellyfin.Data/Entities/PersonRole.cs | 6 +- Jellyfin.Data/Entities/PhotoMetadata.cs | 19 ++++- Jellyfin.Data/Entities/ProviderMapping.cs | 19 ++++- Jellyfin.Data/Entities/Rating.cs | 7 +- Jellyfin.Data/Entities/RatingSource.cs | 7 +- Jellyfin.Data/Entities/Release.cs | 42 ++++++++-- Jellyfin.Data/Entities/Season.cs | 6 +- Jellyfin.Data/Entities/SeasonMetadata.cs | 19 ++++- Jellyfin.Data/Entities/SeriesMetadata.cs | 18 +++- Jellyfin.Data/Entities/Track.cs | 6 +- Jellyfin.Data/Entities/TrackMetadata.cs | 19 ++++- MediaBrowser.Controller/Entities/BaseItem.cs | 5 +- MediaBrowser.Controller/Library/ItemResolveArgs.cs | 6 +- .../Probing/ProbeResultNormalizer.cs | 30 +++++-- MediaBrowser.Model/Dlna/StreamBuilder.cs | 5 +- MediaBrowser.Model/Entities/MediaStream.cs | 5 +- MediaBrowser.Model/Services/RouteAttribute.cs | 18 +++- .../Manager/ItemImageProvider.cs | 5 +- .../Plugins/Tmdb/BoxSets/TmdbBoxSetProvider.cs | 5 +- .../Plugins/Tmdb/Movies/TmdbMovieProvider.cs | 5 +- RSSDP/DeviceAvailableEventArgs.cs | 5 +- RSSDP/DeviceEventArgs.cs | 5 +- RSSDP/DeviceUnavailableEventArgs.cs | 5 +- RSSDP/DisposableManagedObjectBase.cs | 5 +- RSSDP/HttpParserBase.cs | 27 ++++-- RSSDP/HttpRequestParser.cs | 16 +++- RSSDP/HttpResponseParser.cs | 16 +++- RSSDP/IEnumerableExtensions.cs | 11 ++- RSSDP/SsdpCommunicationsServer.cs | 21 ++++- RSSDP/SsdpDevice.cs | 22 ++++- RSSDP/SsdpDeviceLocator.cs | 84 +++++++++++++++---- RSSDP/SsdpDevicePublisher.cs | 75 ++++++++++++++--- 64 files changed, 843 insertions(+), 193 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/DvdLib/Ifo/Dvd.cs b/DvdLib/Ifo/Dvd.cs index ca20baa73..361319625 100644 --- a/DvdLib/Ifo/Dvd.cs +++ b/DvdLib/Ifo/Dvd.cs @@ -117,12 +117,19 @@ namespace DvdLib.Ifo uint chapNum = 1; vtsFs.Seek(baseAddr + offsets[titleNum], SeekOrigin.Begin); var t = Titles.FirstOrDefault(vtst => vtst.IsVTSTitle(vtsNum, titleNum + 1)); - if (t == null) continue; + if (t == null) + { + continue; + } do { t.Chapters.Add(new Chapter(vtsRead.ReadUInt16(), vtsRead.ReadUInt16(), chapNum)); - if (titleNum + 1 < numTitles && vtsFs.Position == (baseAddr + offsets[titleNum + 1])) break; + if (titleNum + 1 < numTitles && vtsFs.Position == (baseAddr + offsets[titleNum + 1])) + { + break; + } + chapNum++; } while (vtsFs.Position < (baseAddr + endaddr)); @@ -147,7 +154,10 @@ namespace DvdLib.Ifo uint vtsPgcOffset = vtsRead.ReadUInt32(); var t = Titles.FirstOrDefault(vtst => vtst.IsVTSTitle(vtsNum, titleNum)); - if (t != null) t.AddPgc(vtsRead, startByte + vtsPgcOffset, entryPgc, pgcNum); + if (t != null) + { + t.AddPgc(vtsRead, startByte + vtsPgcOffset, entryPgc, pgcNum); + } } } } diff --git a/DvdLib/Ifo/DvdTime.cs b/DvdLib/Ifo/DvdTime.cs index 978af90c2..d23140610 100644 --- a/DvdLib/Ifo/DvdTime.cs +++ b/DvdLib/Ifo/DvdTime.cs @@ -15,8 +15,14 @@ namespace DvdLib.Ifo Second = GetBCDValue(data[2]); Frames = GetBCDValue((byte)(data[3] & 0x3F)); - if ((data[3] & 0x80) != 0) FrameRate = 30; - else if ((data[3] & 0x40) != 0) FrameRate = 25; + if ((data[3] & 0x80) != 0) + { + FrameRate = 30; + } + else if ((data[3] & 0x40) != 0) + { + FrameRate = 25; + } } private static byte GetBCDValue(byte data) diff --git a/DvdLib/Ifo/ProgramChain.cs b/DvdLib/Ifo/ProgramChain.cs index 8048f4bbd..83c0051b9 100644 --- a/DvdLib/Ifo/ProgramChain.cs +++ b/DvdLib/Ifo/ProgramChain.cs @@ -75,8 +75,15 @@ namespace DvdLib.Ifo StillTime = br.ReadByte(); byte pbMode = br.ReadByte(); - if (pbMode == 0) PlaybackMode = ProgramPlaybackMode.Sequential; - else PlaybackMode = ((pbMode & 0x80) == 0) ? ProgramPlaybackMode.Random : ProgramPlaybackMode.Shuffle; + if (pbMode == 0) + { + PlaybackMode = ProgramPlaybackMode.Sequential; + } + else + { + PlaybackMode = ((pbMode & 0x80) == 0) ? ProgramPlaybackMode.Random : ProgramPlaybackMode.Shuffle; + } + ProgramCount = (uint)(pbMode & 0x7F); Palette = br.ReadBytes(64); diff --git a/DvdLib/Ifo/Title.cs b/DvdLib/Ifo/Title.cs index 4af3af754..29a0b95c7 100644 --- a/DvdLib/Ifo/Title.cs +++ b/DvdLib/Ifo/Title.cs @@ -59,7 +59,10 @@ namespace DvdLib.Ifo var pgc = new ProgramChain(pgcNum); pgc.ParseHeader(br); ProgramChains.Add(pgc); - if (entryPgc) EntryProgramChain = pgc; + if (entryPgc) + { + EntryProgramChain = pgc; + } br.BaseStream.Seek(curPos, SeekOrigin.Begin); } diff --git a/Emby.Dlna/PlayTo/PlayToManager.cs b/Emby.Dlna/PlayTo/PlayToManager.cs index 240c8a7d9..512589e4d 100644 --- a/Emby.Dlna/PlayTo/PlayToManager.cs +++ b/Emby.Dlna/PlayTo/PlayToManager.cs @@ -78,9 +78,15 @@ namespace Emby.Dlna.PlayTo var info = e.Argument; - if (!info.Headers.TryGetValue("USN", out string usn)) usn = string.Empty; + if (!info.Headers.TryGetValue("USN", out string usn)) + { + usn = string.Empty; + } - if (!info.Headers.TryGetValue("NT", out string nt)) nt = string.Empty; + if (!info.Headers.TryGetValue("NT", out string nt)) + { + nt = string.Empty; + } string location = info.Location.ToString(); diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index 6e5389ad4..a6390b1ef 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -2775,22 +2775,85 @@ namespace Emby.Server.Implementations.Data private string FixUnicodeChars(string buffer) { - if (buffer.IndexOf('\u2013') > -1) buffer = buffer.Replace('\u2013', '-'); // en dash - if (buffer.IndexOf('\u2014') > -1) buffer = buffer.Replace('\u2014', '-'); // em dash - if (buffer.IndexOf('\u2015') > -1) buffer = buffer.Replace('\u2015', '-'); // horizontal bar - if (buffer.IndexOf('\u2017') > -1) buffer = buffer.Replace('\u2017', '_'); // double low line - if (buffer.IndexOf('\u2018') > -1) buffer = buffer.Replace('\u2018', '\''); // left single quotation mark - if (buffer.IndexOf('\u2019') > -1) buffer = buffer.Replace('\u2019', '\''); // right single quotation mark - if (buffer.IndexOf('\u201a') > -1) buffer = buffer.Replace('\u201a', ','); // single low-9 quotation mark - if (buffer.IndexOf('\u201b') > -1) buffer = buffer.Replace('\u201b', '\''); // single high-reversed-9 quotation mark - if (buffer.IndexOf('\u201c') > -1) buffer = buffer.Replace('\u201c', '\"'); // left double quotation mark - if (buffer.IndexOf('\u201d') > -1) buffer = buffer.Replace('\u201d', '\"'); // right double quotation mark - if (buffer.IndexOf('\u201e') > -1) buffer = buffer.Replace('\u201e', '\"'); // double low-9 quotation mark - if (buffer.IndexOf('\u2026') > -1) buffer = buffer.Replace("\u2026", "..."); // horizontal ellipsis - if (buffer.IndexOf('\u2032') > -1) buffer = buffer.Replace('\u2032', '\''); // prime - if (buffer.IndexOf('\u2033') > -1) buffer = buffer.Replace('\u2033', '\"'); // double prime - if (buffer.IndexOf('\u0060') > -1) buffer = buffer.Replace('\u0060', '\''); // grave accent - if (buffer.IndexOf('\u00B4') > -1) buffer = buffer.Replace('\u00B4', '\''); // acute accent + if (buffer.IndexOf('\u2013') > -1) + { + buffer = buffer.Replace('\u2013', '-'); // en dash + } + + if (buffer.IndexOf('\u2014') > -1) + { + buffer = buffer.Replace('\u2014', '-'); // em dash + } + + if (buffer.IndexOf('\u2015') > -1) + { + buffer = buffer.Replace('\u2015', '-'); // horizontal bar + } + + if (buffer.IndexOf('\u2017') > -1) + { + buffer = buffer.Replace('\u2017', '_'); // double low line + } + + if (buffer.IndexOf('\u2018') > -1) + { + buffer = buffer.Replace('\u2018', '\''); // left single quotation mark + } + + if (buffer.IndexOf('\u2019') > -1) + { + buffer = buffer.Replace('\u2019', '\''); // right single quotation mark + } + + if (buffer.IndexOf('\u201a') > -1) + { + buffer = buffer.Replace('\u201a', ','); // single low-9 quotation mark + } + + if (buffer.IndexOf('\u201b') > -1) + { + buffer = buffer.Replace('\u201b', '\''); // single high-reversed-9 quotation mark + } + + if (buffer.IndexOf('\u201c') > -1) + { + buffer = buffer.Replace('\u201c', '\"'); // left double quotation mark + } + + if (buffer.IndexOf('\u201d') > -1) + { + buffer = buffer.Replace('\u201d', '\"'); // right double quotation mark + } + + if (buffer.IndexOf('\u201e') > -1) + { + buffer = buffer.Replace('\u201e', '\"'); // double low-9 quotation mark + } + + if (buffer.IndexOf('\u2026') > -1) + { + buffer = buffer.Replace("\u2026", "..."); // horizontal ellipsis + } + + if (buffer.IndexOf('\u2032') > -1) + { + buffer = buffer.Replace('\u2032', '\''); // prime + } + + if (buffer.IndexOf('\u2033') > -1) + { + buffer = buffer.Replace('\u2033', '\"'); // double prime + } + + if (buffer.IndexOf('\u0060') > -1) + { + buffer = buffer.Replace('\u0060', '\''); // grave accent + } + + if (buffer.IndexOf('\u00B4') > -1) + { + buffer = buffer.Replace('\u00B4', '\''); // acute accent + } return buffer; } diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs index db9d24028..2e2488e6e 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs @@ -201,7 +201,14 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun var index = line.IndexOf("Channel", StringComparison.OrdinalIgnoreCase); var name = line.Substring(0, index - 1); var currentChannel = line.Substring(index + 7); - if (currentChannel != "none") { status = LiveTvTunerStatus.LiveTv; } else { status = LiveTvTunerStatus.Available; } + if (currentChannel != "none") + { + status = LiveTvTunerStatus.LiveTv; + } + else + { + status = LiveTvTunerStatus.Available; + } tuners.Add(new LiveTvTunerInfo { diff --git a/Emby.Server.Implementations/Net/UdpSocket.cs b/Emby.Server.Implementations/Net/UdpSocket.cs index 848f82d85..b51c03446 100644 --- a/Emby.Server.Implementations/Net/UdpSocket.cs +++ b/Emby.Server.Implementations/Net/UdpSocket.cs @@ -37,7 +37,10 @@ namespace Emby.Server.Implementations.Net public UdpSocket(Socket socket, int localPort, IPAddress ip) { - if (socket == null) throw new ArgumentNullException(nameof(socket)); + if (socket == null) + { + throw new ArgumentNullException(nameof(socket)); + } _socket = socket; _localPort = localPort; @@ -103,7 +106,10 @@ namespace Emby.Server.Implementations.Net public UdpSocket(Socket socket, IPEndPoint endPoint) { - if (socket == null) throw new ArgumentNullException(nameof(socket)); + if (socket == null) + { + throw new ArgumentNullException(nameof(socket)); + } _socket = socket; _socket.Connect(endPoint); diff --git a/Emby.Server.Implementations/Playlists/PlaylistManager.cs b/Emby.Server.Implementations/Playlists/PlaylistManager.cs index ac816ccd9..5dd1af4b8 100644 --- a/Emby.Server.Implementations/Playlists/PlaylistManager.cs +++ b/Emby.Server.Implementations/Playlists/PlaylistManager.cs @@ -539,13 +539,21 @@ namespace Emby.Server.Implementations.Playlists private static string UnEscape(string content) { - if (content == null) return content; + if (content == null) + { + return content; + } + return content.Replace("&", "&").Replace("'", "'").Replace(""", "\"").Replace(">", ">").Replace("<", "<"); } private static string Escape(string content) { - if (content == null) return null; + if (content == null) + { + return null; + } + return content.Replace("&", "&").Replace("'", "'").Replace("\"", """).Replace(">", ">").Replace("<", "<"); } diff --git a/Emby.Server.Implementations/Services/ServiceController.cs b/Emby.Server.Implementations/Services/ServiceController.cs index b84e47140..857df591a 100644 --- a/Emby.Server.Implementations/Services/ServiceController.cs +++ b/Emby.Server.Implementations/Services/ServiceController.cs @@ -144,7 +144,10 @@ namespace Emby.Server.Implementations.Services var yieldedWildcardMatches = RestPath.GetFirstMatchWildCardHashKeys(matchUsingPathParts); foreach (var potentialHashMatch in yieldedWildcardMatches) { - if (!this.RestPathMap.TryGetValue(potentialHashMatch, out firstMatches)) continue; + if (!this.RestPathMap.TryGetValue(potentialHashMatch, out firstMatches)) + { + continue; + } var bestScore = -1; RestPath bestMatch = null; diff --git a/Emby.Server.Implementations/Services/ServiceExec.cs b/Emby.Server.Implementations/Services/ServiceExec.cs index 606f2a240..18d7ab46e 100644 --- a/Emby.Server.Implementations/Services/ServiceExec.cs +++ b/Emby.Server.Implementations/Services/ServiceExec.cs @@ -63,7 +63,10 @@ namespace Emby.Server.Implementations.Services { foreach (var actionCtx in actions) { - if (execMap.ContainsKey(actionCtx.Id)) continue; + if (execMap.ContainsKey(actionCtx.Id)) + { + continue; + } execMap[actionCtx.Id] = actionCtx; } diff --git a/Emby.Server.Implementations/Services/ServicePath.cs b/Emby.Server.Implementations/Services/ServicePath.cs index 14ae126a3..eb0744189 100644 --- a/Emby.Server.Implementations/Services/ServicePath.cs +++ b/Emby.Server.Implementations/Services/ServicePath.cs @@ -124,7 +124,10 @@ namespace Emby.Server.Implementations.Services var hasSeparators = new List<bool>(); foreach (var component in this.restPath.Split(PathSeperatorChar)) { - if (string.IsNullOrEmpty(component)) continue; + if (string.IsNullOrEmpty(component)) + { + continue; + } if (component.IndexOf(VariablePrefix, StringComparison.OrdinalIgnoreCase) != -1 && component.IndexOf(ComponentSeperator) != -1) diff --git a/Jellyfin.Data/Entities/Artwork.cs b/Jellyfin.Data/Entities/Artwork.cs index df071e477..6ed32eac3 100644 --- a/Jellyfin.Data/Entities/Artwork.cs +++ b/Jellyfin.Data/Entities/Artwork.cs @@ -32,17 +32,28 @@ namespace Jellyfin.Data.Entities /// <param name="_personrole1"></param> public Artwork(string path, Enums.ArtKind kind, Metadata _metadata0, PersonRole _personrole1) { - if (string.IsNullOrEmpty(path)) throw new ArgumentNullException(nameof(path)); + if (string.IsNullOrEmpty(path)) + { + throw new ArgumentNullException(nameof(path)); + } + this.Path = path; this.Kind = kind; - if (_metadata0 == null) throw new ArgumentNullException(nameof(_metadata0)); + if (_metadata0 == null) + { + throw new ArgumentNullException(nameof(_metadata0)); + } + _metadata0.Artwork.Add(this); - if (_personrole1 == null) throw new ArgumentNullException(nameof(_personrole1)); - _personrole1.Artwork = this; + if (_personrole1 == null) + { + throw new ArgumentNullException(nameof(_personrole1)); + } + _personrole1.Artwork = this; Init(); } diff --git a/Jellyfin.Data/Entities/BookMetadata.cs b/Jellyfin.Data/Entities/BookMetadata.cs index dc7146371..df43090d3 100644 --- a/Jellyfin.Data/Entities/BookMetadata.cs +++ b/Jellyfin.Data/Entities/BookMetadata.cs @@ -34,13 +34,25 @@ namespace Jellyfin.Data.Entities /// <param name="_book0"></param> public BookMetadata(string title, string language, DateTime dateadded, DateTime datemodified, Book _book0) { - if (string.IsNullOrEmpty(title)) throw new ArgumentNullException(nameof(title)); + if (string.IsNullOrEmpty(title)) + { + throw new ArgumentNullException(nameof(title)); + } + this.Title = title; - if (string.IsNullOrEmpty(language)) throw new ArgumentNullException(nameof(language)); + if (string.IsNullOrEmpty(language)) + { + throw new ArgumentNullException(nameof(language)); + } + this.Language = language; - if (_book0 == null) throw new ArgumentNullException(nameof(_book0)); + if (_book0 == null) + { + throw new ArgumentNullException(nameof(_book0)); + } + _book0.BookMetadata.Add(this); this.Publishers = new HashSet<Company>(); diff --git a/Jellyfin.Data/Entities/Chapter.cs b/Jellyfin.Data/Entities/Chapter.cs index 960853e15..4575cdb4d 100644 --- a/Jellyfin.Data/Entities/Chapter.cs +++ b/Jellyfin.Data/Entities/Chapter.cs @@ -32,12 +32,20 @@ namespace Jellyfin.Data.Entities /// <param name="_release0"></param> public Chapter(string language, long timestart, Release _release0) { - if (string.IsNullOrEmpty(language)) throw new ArgumentNullException(nameof(language)); + if (string.IsNullOrEmpty(language)) + { + throw new ArgumentNullException(nameof(language)); + } + this.Language = language; this.TimeStart = timestart; - if (_release0 == null) throw new ArgumentNullException(nameof(_release0)); + if (_release0 == null) + { + throw new ArgumentNullException(nameof(_release0)); + } + _release0.Chapters.Add(this); diff --git a/Jellyfin.Data/Entities/CollectionItem.cs b/Jellyfin.Data/Entities/CollectionItem.cs index 08b0e99f4..d879806ee 100644 --- a/Jellyfin.Data/Entities/CollectionItem.cs +++ b/Jellyfin.Data/Entities/CollectionItem.cs @@ -38,15 +38,26 @@ namespace Jellyfin.Data.Entities // NOTE: This class has one-to-one associations with CollectionItem. // One-to-one associations are not validated in constructors since this causes a scenario where each one must be constructed before the other. - if (_collection0 == null) throw new ArgumentNullException(nameof(_collection0)); + if (_collection0 == null) + { + throw new ArgumentNullException(nameof(_collection0)); + } + _collection0.CollectionItem.Add(this); - if (_collectionitem1 == null) throw new ArgumentNullException(nameof(_collectionitem1)); + if (_collectionitem1 == null) + { + throw new ArgumentNullException(nameof(_collectionitem1)); + } + _collectionitem1.Next = this; - if (_collectionitem2 == null) throw new ArgumentNullException(nameof(_collectionitem2)); - _collectionitem2.Previous = this; + if (_collectionitem2 == null) + { + throw new ArgumentNullException(nameof(_collectionitem2)); + } + _collectionitem2.Previous = this; Init(); } diff --git a/Jellyfin.Data/Entities/Company.cs b/Jellyfin.Data/Entities/Company.cs index 2ac7bcfe5..e905a17da 100644 --- a/Jellyfin.Data/Entities/Company.cs +++ b/Jellyfin.Data/Entities/Company.cs @@ -37,19 +37,39 @@ namespace Jellyfin.Data.Entities /// <param name="_company4"></param> public Company(MovieMetadata _moviemetadata0, SeriesMetadata _seriesmetadata1, MusicAlbumMetadata _musicalbummetadata2, BookMetadata _bookmetadata3, Company _company4) { - if (_moviemetadata0 == null) throw new ArgumentNullException(nameof(_moviemetadata0)); + if (_moviemetadata0 == null) + { + throw new ArgumentNullException(nameof(_moviemetadata0)); + } + _moviemetadata0.Studios.Add(this); - if (_seriesmetadata1 == null) throw new ArgumentNullException(nameof(_seriesmetadata1)); + if (_seriesmetadata1 == null) + { + throw new ArgumentNullException(nameof(_seriesmetadata1)); + } + _seriesmetadata1.Networks.Add(this); - if (_musicalbummetadata2 == null) throw new ArgumentNullException(nameof(_musicalbummetadata2)); + if (_musicalbummetadata2 == null) + { + throw new ArgumentNullException(nameof(_musicalbummetadata2)); + } + _musicalbummetadata2.Labels.Add(this); - if (_bookmetadata3 == null) throw new ArgumentNullException(nameof(_bookmetadata3)); + if (_bookmetadata3 == null) + { + throw new ArgumentNullException(nameof(_bookmetadata3)); + } + _bookmetadata3.Publishers.Add(this); - if (_company4 == null) throw new ArgumentNullException(nameof(_company4)); + if (_company4 == null) + { + throw new ArgumentNullException(nameof(_company4)); + } + _company4.Parent = this; this.CompanyMetadata = new HashSet<CompanyMetadata>(); diff --git a/Jellyfin.Data/Entities/CompanyMetadata.cs b/Jellyfin.Data/Entities/CompanyMetadata.cs index 12f213310..e75349cf2 100644 --- a/Jellyfin.Data/Entities/CompanyMetadata.cs +++ b/Jellyfin.Data/Entities/CompanyMetadata.cs @@ -31,15 +31,26 @@ namespace Jellyfin.Data.Entities /// <param name="_company0"></param> public CompanyMetadata(string title, string language, DateTime dateadded, DateTime datemodified, Company _company0) { - if (string.IsNullOrEmpty(title)) throw new ArgumentNullException(nameof(title)); + if (string.IsNullOrEmpty(title)) + { + throw new ArgumentNullException(nameof(title)); + } + this.Title = title; - if (string.IsNullOrEmpty(language)) throw new ArgumentNullException(nameof(language)); + if (string.IsNullOrEmpty(language)) + { + throw new ArgumentNullException(nameof(language)); + } + this.Language = language; - if (_company0 == null) throw new ArgumentNullException(nameof(_company0)); - _company0.CompanyMetadata.Add(this); + if (_company0 == null) + { + throw new ArgumentNullException(nameof(_company0)); + } + _company0.CompanyMetadata.Add(this); Init(); } diff --git a/Jellyfin.Data/Entities/CustomItemMetadata.cs b/Jellyfin.Data/Entities/CustomItemMetadata.cs index dd66c8f83..965ed731f 100644 --- a/Jellyfin.Data/Entities/CustomItemMetadata.cs +++ b/Jellyfin.Data/Entities/CustomItemMetadata.cs @@ -30,15 +30,26 @@ namespace Jellyfin.Data.Entities /// <param name="_customitem0"></param> public CustomItemMetadata(string title, string language, DateTime dateadded, DateTime datemodified, CustomItem _customitem0) { - if (string.IsNullOrEmpty(title)) throw new ArgumentNullException(nameof(title)); + if (string.IsNullOrEmpty(title)) + { + throw new ArgumentNullException(nameof(title)); + } + this.Title = title; - if (string.IsNullOrEmpty(language)) throw new ArgumentNullException(nameof(language)); + if (string.IsNullOrEmpty(language)) + { + throw new ArgumentNullException(nameof(language)); + } + this.Language = language; - if (_customitem0 == null) throw new ArgumentNullException(nameof(_customitem0)); - _customitem0.CustomItemMetadata.Add(this); + if (_customitem0 == null) + { + throw new ArgumentNullException(nameof(_customitem0)); + } + _customitem0.CustomItemMetadata.Add(this); Init(); } diff --git a/Jellyfin.Data/Entities/Episode.cs b/Jellyfin.Data/Entities/Episode.cs index 69106ab79..57fbf894b 100644 --- a/Jellyfin.Data/Entities/Episode.cs +++ b/Jellyfin.Data/Entities/Episode.cs @@ -42,7 +42,11 @@ namespace Jellyfin.Data.Entities this.UrlId = urlid; - if (_season0 == null) throw new ArgumentNullException(nameof(_season0)); + if (_season0 == null) + { + throw new ArgumentNullException(nameof(_season0)); + } + _season0.Episodes.Add(this); this.Releases = new HashSet<Release>(); diff --git a/Jellyfin.Data/Entities/EpisodeMetadata.cs b/Jellyfin.Data/Entities/EpisodeMetadata.cs index b17e4aa19..9a21fd50f 100644 --- a/Jellyfin.Data/Entities/EpisodeMetadata.cs +++ b/Jellyfin.Data/Entities/EpisodeMetadata.cs @@ -31,15 +31,26 @@ namespace Jellyfin.Data.Entities /// <param name="_episode0"></param> public EpisodeMetadata(string title, string language, DateTime dateadded, DateTime datemodified, Episode _episode0) { - if (string.IsNullOrEmpty(title)) throw new ArgumentNullException(nameof(title)); + if (string.IsNullOrEmpty(title)) + { + throw new ArgumentNullException(nameof(title)); + } + this.Title = title; - if (string.IsNullOrEmpty(language)) throw new ArgumentNullException(nameof(language)); + if (string.IsNullOrEmpty(language)) + { + throw new ArgumentNullException(nameof(language)); + } + this.Language = language; - if (_episode0 == null) throw new ArgumentNullException(nameof(_episode0)); - _episode0.EpisodeMetadata.Add(this); + if (_episode0 == null) + { + throw new ArgumentNullException(nameof(_episode0)); + } + _episode0.EpisodeMetadata.Add(this); Init(); } diff --git a/Jellyfin.Data/Entities/Genre.cs b/Jellyfin.Data/Entities/Genre.cs index 9b2264921..24e6815d8 100644 --- a/Jellyfin.Data/Entities/Genre.cs +++ b/Jellyfin.Data/Entities/Genre.cs @@ -31,12 +31,19 @@ namespace Jellyfin.Data.Entities /// <param name="_metadata0"></param> public Genre(string name, Metadata _metadata0) { - if (string.IsNullOrEmpty(name)) throw new ArgumentNullException(nameof(name)); + if (string.IsNullOrEmpty(name)) + { + throw new ArgumentNullException(nameof(name)); + } + this.Name = name; - if (_metadata0 == null) throw new ArgumentNullException(nameof(_metadata0)); - _metadata0.Genres.Add(this); + if (_metadata0 == null) + { + throw new ArgumentNullException(nameof(_metadata0)); + } + _metadata0.Genres.Add(this); Init(); } diff --git a/Jellyfin.Data/Entities/Library.cs b/Jellyfin.Data/Entities/Library.cs index ff94b93f0..d935e43b1 100644 --- a/Jellyfin.Data/Entities/Library.cs +++ b/Jellyfin.Data/Entities/Library.cs @@ -30,9 +30,12 @@ namespace Jellyfin.Data.Entities /// <param name="name"></param> public Library(string name) { - if (string.IsNullOrEmpty(name)) throw new ArgumentNullException(nameof(name)); - this.Name = name; + if (string.IsNullOrEmpty(name)) + { + throw new ArgumentNullException(nameof(name)); + } + this.Name = name; Init(); } diff --git a/Jellyfin.Data/Entities/LibraryRoot.cs b/Jellyfin.Data/Entities/LibraryRoot.cs index a6f3e49c9..9695ed638 100644 --- a/Jellyfin.Data/Entities/LibraryRoot.cs +++ b/Jellyfin.Data/Entities/LibraryRoot.cs @@ -30,9 +30,12 @@ namespace Jellyfin.Data.Entities /// <param name="path">Absolute Path.</param> public LibraryRoot(string path) { - if (string.IsNullOrEmpty(path)) throw new ArgumentNullException(nameof(path)); - this.Path = path; + if (string.IsNullOrEmpty(path)) + { + throw new ArgumentNullException(nameof(path)); + } + this.Path = path; Init(); } diff --git a/Jellyfin.Data/Entities/MediaFile.cs b/Jellyfin.Data/Entities/MediaFile.cs index 5d9448d41..7382cda95 100644 --- a/Jellyfin.Data/Entities/MediaFile.cs +++ b/Jellyfin.Data/Entities/MediaFile.cs @@ -35,12 +35,20 @@ namespace Jellyfin.Data.Entities /// <param name="_release0"></param> public MediaFile(string path, Enums.MediaFileKind kind, Release _release0) { - if (string.IsNullOrEmpty(path)) throw new ArgumentNullException(nameof(path)); + if (string.IsNullOrEmpty(path)) + { + throw new ArgumentNullException(nameof(path)); + } + this.Path = path; this.Kind = kind; - if (_release0 == null) throw new ArgumentNullException(nameof(_release0)); + if (_release0 == null) + { + throw new ArgumentNullException(nameof(_release0)); + } + _release0.MediaFiles.Add(this); this.MediaFileStreams = new HashSet<MediaFileStream>(); diff --git a/Jellyfin.Data/Entities/MediaFileStream.cs b/Jellyfin.Data/Entities/MediaFileStream.cs index c018c0cbf..977fd54e1 100644 --- a/Jellyfin.Data/Entities/MediaFileStream.cs +++ b/Jellyfin.Data/Entities/MediaFileStream.cs @@ -33,9 +33,12 @@ namespace Jellyfin.Data.Entities { this.StreamNumber = streamnumber; - if (_mediafile0 == null) throw new ArgumentNullException(nameof(_mediafile0)); - _mediafile0.MediaFileStreams.Add(this); + if (_mediafile0 == null) + { + throw new ArgumentNullException(nameof(_mediafile0)); + } + _mediafile0.MediaFileStreams.Add(this); Init(); } diff --git a/Jellyfin.Data/Entities/Metadata.cs b/Jellyfin.Data/Entities/Metadata.cs index 8446c30b2..a4ac6dc54 100644 --- a/Jellyfin.Data/Entities/Metadata.cs +++ b/Jellyfin.Data/Entities/Metadata.cs @@ -30,10 +30,18 @@ namespace Jellyfin.Data.Entities /// <param name="language">ISO-639-3 3-character language codes.</param> protected Metadata(string title, string language, DateTime dateadded, DateTime datemodified) { - if (string.IsNullOrEmpty(title)) throw new ArgumentNullException(nameof(title)); + if (string.IsNullOrEmpty(title)) + { + throw new ArgumentNullException(nameof(title)); + } + this.Title = title; - if (string.IsNullOrEmpty(language)) throw new ArgumentNullException(nameof(language)); + if (string.IsNullOrEmpty(language)) + { + throw new ArgumentNullException(nameof(language)); + } + this.Language = language; this.PersonRoles = new HashSet<PersonRole>(); diff --git a/Jellyfin.Data/Entities/MetadataProvider.cs b/Jellyfin.Data/Entities/MetadataProvider.cs index ae22ccfeb..e93ea97d6 100644 --- a/Jellyfin.Data/Entities/MetadataProvider.cs +++ b/Jellyfin.Data/Entities/MetadataProvider.cs @@ -30,9 +30,12 @@ namespace Jellyfin.Data.Entities /// <param name="name"></param> public MetadataProvider(string name) { - if (string.IsNullOrEmpty(name)) throw new ArgumentNullException(nameof(name)); - this.Name = name; + if (string.IsNullOrEmpty(name)) + { + throw new ArgumentNullException(nameof(name)); + } + this.Name = name; Init(); } diff --git a/Jellyfin.Data/Entities/MetadataProviderId.cs b/Jellyfin.Data/Entities/MetadataProviderId.cs index 30683ced3..68f139436 100644 --- a/Jellyfin.Data/Entities/MetadataProviderId.cs +++ b/Jellyfin.Data/Entities/MetadataProviderId.cs @@ -40,21 +40,40 @@ namespace Jellyfin.Data.Entities // NOTE: This class has one-to-one associations with MetadataProviderId. // One-to-one associations are not validated in constructors since this causes a scenario where each one must be constructed before the other. - if (string.IsNullOrEmpty(providerid)) throw new ArgumentNullException(nameof(providerid)); + if (string.IsNullOrEmpty(providerid)) + { + throw new ArgumentNullException(nameof(providerid)); + } + this.ProviderId = providerid; - if (_metadata0 == null) throw new ArgumentNullException(nameof(_metadata0)); + if (_metadata0 == null) + { + throw new ArgumentNullException(nameof(_metadata0)); + } + _metadata0.Sources.Add(this); - if (_person1 == null) throw new ArgumentNullException(nameof(_person1)); + if (_person1 == null) + { + throw new ArgumentNullException(nameof(_person1)); + } + _person1.Sources.Add(this); - if (_personrole2 == null) throw new ArgumentNullException(nameof(_personrole2)); + if (_personrole2 == null) + { + throw new ArgumentNullException(nameof(_personrole2)); + } + _personrole2.Sources.Add(this); - if (_ratingsource3 == null) throw new ArgumentNullException(nameof(_ratingsource3)); - _ratingsource3.Source = this; + if (_ratingsource3 == null) + { + throw new ArgumentNullException(nameof(_ratingsource3)); + } + _ratingsource3.Source = this; Init(); } diff --git a/Jellyfin.Data/Entities/MovieMetadata.cs b/Jellyfin.Data/Entities/MovieMetadata.cs index 4fda88e8e..cbcb78e37 100644 --- a/Jellyfin.Data/Entities/MovieMetadata.cs +++ b/Jellyfin.Data/Entities/MovieMetadata.cs @@ -35,13 +35,25 @@ namespace Jellyfin.Data.Entities /// <param name="_movie0"></param> public MovieMetadata(string title, string language, DateTime dateadded, DateTime datemodified, Movie _movie0) { - if (string.IsNullOrEmpty(title)) throw new ArgumentNullException(nameof(title)); + if (string.IsNullOrEmpty(title)) + { + throw new ArgumentNullException(nameof(title)); + } + this.Title = title; - if (string.IsNullOrEmpty(language)) throw new ArgumentNullException(nameof(language)); + if (string.IsNullOrEmpty(language)) + { + throw new ArgumentNullException(nameof(language)); + } + this.Language = language; - if (_movie0 == null) throw new ArgumentNullException(nameof(_movie0)); + if (_movie0 == null) + { + throw new ArgumentNullException(nameof(_movie0)); + } + _movie0.MovieMetadata.Add(this); this.Studios = new HashSet<Company>(); diff --git a/Jellyfin.Data/Entities/MusicAlbumMetadata.cs b/Jellyfin.Data/Entities/MusicAlbumMetadata.cs index a5056adc0..bfcbebbe8 100644 --- a/Jellyfin.Data/Entities/MusicAlbumMetadata.cs +++ b/Jellyfin.Data/Entities/MusicAlbumMetadata.cs @@ -35,13 +35,25 @@ namespace Jellyfin.Data.Entities /// <param name="_musicalbum0"></param> public MusicAlbumMetadata(string title, string language, DateTime dateadded, DateTime datemodified, MusicAlbum _musicalbum0) { - if (string.IsNullOrEmpty(title)) throw new ArgumentNullException(nameof(title)); + if (string.IsNullOrEmpty(title)) + { + throw new ArgumentNullException(nameof(title)); + } + this.Title = title; - if (string.IsNullOrEmpty(language)) throw new ArgumentNullException(nameof(language)); + if (string.IsNullOrEmpty(language)) + { + throw new ArgumentNullException(nameof(language)); + } + this.Language = language; - if (_musicalbum0 == null) throw new ArgumentNullException(nameof(_musicalbum0)); + if (_musicalbum0 == null) + { + throw new ArgumentNullException(nameof(_musicalbum0)); + } + _musicalbum0.MusicAlbumMetadata.Add(this); this.Labels = new HashSet<Company>(); diff --git a/Jellyfin.Data/Entities/Person.cs b/Jellyfin.Data/Entities/Person.cs index 206fe7709..b6d91ea86 100644 --- a/Jellyfin.Data/Entities/Person.cs +++ b/Jellyfin.Data/Entities/Person.cs @@ -36,7 +36,11 @@ namespace Jellyfin.Data.Entities { this.UrlId = urlid; - if (string.IsNullOrEmpty(name)) throw new ArgumentNullException(nameof(name)); + if (string.IsNullOrEmpty(name)) + { + throw new ArgumentNullException(nameof(name)); + } + this.Name = name; this.Sources = new HashSet<MetadataProviderId>(); diff --git a/Jellyfin.Data/Entities/PersonRole.cs b/Jellyfin.Data/Entities/PersonRole.cs index 928eb74ae..2dd5f116f 100644 --- a/Jellyfin.Data/Entities/PersonRole.cs +++ b/Jellyfin.Data/Entities/PersonRole.cs @@ -42,7 +42,11 @@ namespace Jellyfin.Data.Entities this.Type = type; - if (_metadata0 == null) throw new ArgumentNullException(nameof(_metadata0)); + if (_metadata0 == null) + { + throw new ArgumentNullException(nameof(_metadata0)); + } + _metadata0.PersonRoles.Add(this); this.Sources = new HashSet<MetadataProviderId>(); diff --git a/Jellyfin.Data/Entities/PhotoMetadata.cs b/Jellyfin.Data/Entities/PhotoMetadata.cs index 4a0b07ff8..b5aec7229 100644 --- a/Jellyfin.Data/Entities/PhotoMetadata.cs +++ b/Jellyfin.Data/Entities/PhotoMetadata.cs @@ -31,15 +31,26 @@ namespace Jellyfin.Data.Entities /// <param name="_photo0"></param> public PhotoMetadata(string title, string language, DateTime dateadded, DateTime datemodified, Photo _photo0) { - if (string.IsNullOrEmpty(title)) throw new ArgumentNullException(nameof(title)); + if (string.IsNullOrEmpty(title)) + { + throw new ArgumentNullException(nameof(title)); + } + this.Title = title; - if (string.IsNullOrEmpty(language)) throw new ArgumentNullException(nameof(language)); + if (string.IsNullOrEmpty(language)) + { + throw new ArgumentNullException(nameof(language)); + } + this.Language = language; - if (_photo0 == null) throw new ArgumentNullException(nameof(_photo0)); - _photo0.PhotoMetadata.Add(this); + if (_photo0 == null) + { + throw new ArgumentNullException(nameof(_photo0)); + } + _photo0.PhotoMetadata.Add(this); Init(); } diff --git a/Jellyfin.Data/Entities/ProviderMapping.cs b/Jellyfin.Data/Entities/ProviderMapping.cs index 4125eabcd..c53e3bf40 100644 --- a/Jellyfin.Data/Entities/ProviderMapping.cs +++ b/Jellyfin.Data/Entities/ProviderMapping.cs @@ -34,15 +34,26 @@ namespace Jellyfin.Data.Entities /// <param name="_group1"></param> public ProviderMapping(string providername, string providersecrets, string providerdata, User _user0, Group _group1) { - if (string.IsNullOrEmpty(providername)) throw new ArgumentNullException(nameof(providername)); + if (string.IsNullOrEmpty(providername)) + { + throw new ArgumentNullException(nameof(providername)); + } + this.ProviderName = providername; - if (string.IsNullOrEmpty(providersecrets)) throw new ArgumentNullException(nameof(providersecrets)); + if (string.IsNullOrEmpty(providersecrets)) + { + throw new ArgumentNullException(nameof(providersecrets)); + } + this.ProviderSecrets = providersecrets; - if (string.IsNullOrEmpty(providerdata)) throw new ArgumentNullException(nameof(providerdata)); - this.ProviderData = providerdata; + if (string.IsNullOrEmpty(providerdata)) + { + throw new ArgumentNullException(nameof(providerdata)); + } + this.ProviderData = providerdata; Init(); } diff --git a/Jellyfin.Data/Entities/Rating.cs b/Jellyfin.Data/Entities/Rating.cs index e00d5297d..49a0d502d 100644 --- a/Jellyfin.Data/Entities/Rating.cs +++ b/Jellyfin.Data/Entities/Rating.cs @@ -33,9 +33,12 @@ namespace Jellyfin.Data.Entities { this.Value = value; - if (_metadata0 == null) throw new ArgumentNullException(nameof(_metadata0)); - _metadata0.Ratings.Add(this); + if (_metadata0 == null) + { + throw new ArgumentNullException(nameof(_metadata0)); + } + _metadata0.Ratings.Add(this); Init(); } diff --git a/Jellyfin.Data/Entities/RatingSource.cs b/Jellyfin.Data/Entities/RatingSource.cs index 941f53e52..b62d8b444 100644 --- a/Jellyfin.Data/Entities/RatingSource.cs +++ b/Jellyfin.Data/Entities/RatingSource.cs @@ -39,9 +39,12 @@ namespace Jellyfin.Data.Entities this.MinimumValue = minimumvalue; - if (_rating0 == null) throw new ArgumentNullException(nameof(_rating0)); - _rating0.RatingType = this; + if (_rating0 == null) + { + throw new ArgumentNullException(nameof(_rating0)); + } + _rating0.RatingType = this; Init(); } diff --git a/Jellyfin.Data/Entities/Release.cs b/Jellyfin.Data/Entities/Release.cs index e08c04545..1e9faa5a1 100644 --- a/Jellyfin.Data/Entities/Release.cs +++ b/Jellyfin.Data/Entities/Release.cs @@ -40,25 +40,53 @@ namespace Jellyfin.Data.Entities /// <param name="_photo5"></param> public Release(string name, Movie _movie0, Episode _episode1, Track _track2, CustomItem _customitem3, Book _book4, Photo _photo5) { - if (string.IsNullOrEmpty(name)) throw new ArgumentNullException(nameof(name)); + if (string.IsNullOrEmpty(name)) + { + throw new ArgumentNullException(nameof(name)); + } + this.Name = name; - if (_movie0 == null) throw new ArgumentNullException(nameof(_movie0)); + if (_movie0 == null) + { + throw new ArgumentNullException(nameof(_movie0)); + } + _movie0.Releases.Add(this); - if (_episode1 == null) throw new ArgumentNullException(nameof(_episode1)); + if (_episode1 == null) + { + throw new ArgumentNullException(nameof(_episode1)); + } + _episode1.Releases.Add(this); - if (_track2 == null) throw new ArgumentNullException(nameof(_track2)); + if (_track2 == null) + { + throw new ArgumentNullException(nameof(_track2)); + } + _track2.Releases.Add(this); - if (_customitem3 == null) throw new ArgumentNullException(nameof(_customitem3)); + if (_customitem3 == null) + { + throw new ArgumentNullException(nameof(_customitem3)); + } + _customitem3.Releases.Add(this); - if (_book4 == null) throw new ArgumentNullException(nameof(_book4)); + if (_book4 == null) + { + throw new ArgumentNullException(nameof(_book4)); + } + _book4.Releases.Add(this); - if (_photo5 == null) throw new ArgumentNullException(nameof(_photo5)); + if (_photo5 == null) + { + throw new ArgumentNullException(nameof(_photo5)); + } + _photo5.Releases.Add(this); this.MediaFiles = new HashSet<MediaFile>(); diff --git a/Jellyfin.Data/Entities/Season.cs b/Jellyfin.Data/Entities/Season.cs index d71f4b522..4b1e78575 100644 --- a/Jellyfin.Data/Entities/Season.cs +++ b/Jellyfin.Data/Entities/Season.cs @@ -42,7 +42,11 @@ namespace Jellyfin.Data.Entities this.UrlId = urlid; - if (_series0 == null) throw new ArgumentNullException(nameof(_series0)); + if (_series0 == null) + { + throw new ArgumentNullException(nameof(_series0)); + } + _series0.Seasons.Add(this); this.SeasonMetadata = new HashSet<SeasonMetadata>(); diff --git a/Jellyfin.Data/Entities/SeasonMetadata.cs b/Jellyfin.Data/Entities/SeasonMetadata.cs index 8c72d9952..10d19875e 100644 --- a/Jellyfin.Data/Entities/SeasonMetadata.cs +++ b/Jellyfin.Data/Entities/SeasonMetadata.cs @@ -32,15 +32,26 @@ namespace Jellyfin.Data.Entities /// <param name="_season0"></param> public SeasonMetadata(string title, string language, DateTime dateadded, DateTime datemodified, Season _season0) { - if (string.IsNullOrEmpty(title)) throw new ArgumentNullException(nameof(title)); + if (string.IsNullOrEmpty(title)) + { + throw new ArgumentNullException(nameof(title)); + } + this.Title = title; - if (string.IsNullOrEmpty(language)) throw new ArgumentNullException(nameof(language)); + if (string.IsNullOrEmpty(language)) + { + throw new ArgumentNullException(nameof(language)); + } + this.Language = language; - if (_season0 == null) throw new ArgumentNullException(nameof(_season0)); - _season0.SeasonMetadata.Add(this); + if (_season0 == null) + { + throw new ArgumentNullException(nameof(_season0)); + } + _season0.SeasonMetadata.Add(this); Init(); } diff --git a/Jellyfin.Data/Entities/SeriesMetadata.cs b/Jellyfin.Data/Entities/SeriesMetadata.cs index 2c04ef12f..16eb59315 100644 --- a/Jellyfin.Data/Entities/SeriesMetadata.cs +++ b/Jellyfin.Data/Entities/SeriesMetadata.cs @@ -35,13 +35,25 @@ namespace Jellyfin.Data.Entities /// <param name="_series0"></param> public SeriesMetadata(string title, string language, DateTime dateadded, DateTime datemodified, Series _series0) { - if (string.IsNullOrEmpty(title)) throw new ArgumentNullException(nameof(title)); + if (string.IsNullOrEmpty(title)) + { + throw new ArgumentNullException(nameof(title)); + } + this.Title = title; - if (string.IsNullOrEmpty(language)) throw new ArgumentNullException(nameof(language)); + if (string.IsNullOrEmpty(language)) + { + throw new ArgumentNullException(nameof(language)); + } + this.Language = language; - if (_series0 == null) throw new ArgumentNullException(nameof(_series0)); + if (_series0 == null) + { + throw new ArgumentNullException(nameof(_series0)); + } + _series0.SeriesMetadata.Add(this); this.Networks = new HashSet<Company>(); diff --git a/Jellyfin.Data/Entities/Track.cs b/Jellyfin.Data/Entities/Track.cs index e13a53d38..b7d7b5873 100644 --- a/Jellyfin.Data/Entities/Track.cs +++ b/Jellyfin.Data/Entities/Track.cs @@ -42,7 +42,11 @@ namespace Jellyfin.Data.Entities this.UrlId = urlid; - if (_musicalbum0 == null) throw new ArgumentNullException(nameof(_musicalbum0)); + if (_musicalbum0 == null) + { + throw new ArgumentNullException(nameof(_musicalbum0)); + } + _musicalbum0.Tracks.Add(this); this.Releases = new HashSet<Release>(); diff --git a/Jellyfin.Data/Entities/TrackMetadata.cs b/Jellyfin.Data/Entities/TrackMetadata.cs index 55f4a38e0..23e1219aa 100644 --- a/Jellyfin.Data/Entities/TrackMetadata.cs +++ b/Jellyfin.Data/Entities/TrackMetadata.cs @@ -31,15 +31,26 @@ namespace Jellyfin.Data.Entities /// <param name="_track0"></param> public TrackMetadata(string title, string language, DateTime dateadded, DateTime datemodified, Track _track0) { - if (string.IsNullOrEmpty(title)) throw new ArgumentNullException(nameof(title)); + if (string.IsNullOrEmpty(title)) + { + throw new ArgumentNullException(nameof(title)); + } + this.Title = title; - if (string.IsNullOrEmpty(language)) throw new ArgumentNullException(nameof(language)); + if (string.IsNullOrEmpty(language)) + { + throw new ArgumentNullException(nameof(language)); + } + this.Language = language; - if (_track0 == null) throw new ArgumentNullException(nameof(_track0)); - _track0.TrackMetadata.Add(this); + if (_track0 == null) + { + throw new ArgumentNullException(nameof(_track0)); + } + _track0.TrackMetadata.Add(this); Init(); } diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 7b833c36b..2ad1c717c 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -690,7 +690,10 @@ namespace MediaBrowser.Controller.Entities /// <returns>System.String.</returns> protected virtual string CreateSortName() { - if (Name == null) return null; // some items may not have name filled in properly + if (Name == null) + { + return null; // some items may not have name filled in properly + } if (!EnableAlphaNumericSorting) { diff --git a/MediaBrowser.Controller/Library/ItemResolveArgs.cs b/MediaBrowser.Controller/Library/ItemResolveArgs.cs index 731c6d667..2e5dcc4c5 100644 --- a/MediaBrowser.Controller/Library/ItemResolveArgs.cs +++ b/MediaBrowser.Controller/Library/ItemResolveArgs.cs @@ -252,7 +252,11 @@ namespace MediaBrowser.Controller.Library { if (args != null) { - if (args.Path == null && Path == null) return true; + if (args.Path == null && Path == null) + { + return true; + } + return args.Path != null && BaseItem.FileSystem.AreEqual(args.Path, Path); } diff --git a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs index ba807ab85..190abaa05 100644 --- a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs +++ b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs @@ -1065,23 +1065,43 @@ namespace MediaBrowser.MediaEncoding.Probing // These support mulitple values, but for now we only store the first. var mb = GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MusicBrainz Album Artist Id")); - if (mb == null) mb = GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MUSICBRAINZ_ALBUMARTISTID")); + if (mb == null) + { + mb = GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MUSICBRAINZ_ALBUMARTISTID")); + } + audio.SetProviderId(MetadataProvider.MusicBrainzAlbumArtist, mb); mb = GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MusicBrainz Artist Id")); - if (mb == null) mb = GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MUSICBRAINZ_ARTISTID")); + if (mb == null) + { + mb = GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MUSICBRAINZ_ARTISTID")); + } + audio.SetProviderId(MetadataProvider.MusicBrainzArtist, mb); mb = GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MusicBrainz Album Id")); - if (mb == null) mb = GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MUSICBRAINZ_ALBUMID")); + if (mb == null) + { + mb = GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MUSICBRAINZ_ALBUMID")); + } + audio.SetProviderId(MetadataProvider.MusicBrainzAlbum, mb); mb = GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MusicBrainz Release Group Id")); - if (mb == null) mb = GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MUSICBRAINZ_RELEASEGROUPID")); + if (mb == null) + { + mb = GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MUSICBRAINZ_RELEASEGROUPID")); + } + audio.SetProviderId(MetadataProvider.MusicBrainzReleaseGroup, mb); mb = GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MusicBrainz Release Track Id")); - if (mb == null) mb = GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MUSICBRAINZ_RELEASETRACKID")); + if (mb == null) + { + mb = GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MUSICBRAINZ_RELEASETRACKID")); + } + audio.SetProviderId(MetadataProvider.MusicBrainzTrack, mb); } diff --git a/MediaBrowser.Model/Dlna/StreamBuilder.cs b/MediaBrowser.Model/Dlna/StreamBuilder.cs index 06bd24476..cfe862f5a 100644 --- a/MediaBrowser.Model/Dlna/StreamBuilder.cs +++ b/MediaBrowser.Model/Dlna/StreamBuilder.cs @@ -384,7 +384,10 @@ namespace MediaBrowser.Model.Dlna audioCodecProfiles.Add(i); } - if (audioCodecProfiles.Count >= 1) break; + if (audioCodecProfiles.Count >= 1) + { + break; + } } var audioTranscodingConditions = new List<ProfileCondition>(); diff --git a/MediaBrowser.Model/Entities/MediaStream.cs b/MediaBrowser.Model/Entities/MediaStream.cs index d8ee79d0d..7a488005e 100644 --- a/MediaBrowser.Model/Entities/MediaStream.cs +++ b/MediaBrowser.Model/Entities/MediaStream.cs @@ -421,7 +421,10 @@ namespace MediaBrowser.Model.Entities { get { - if (Type != MediaStreamType.Subtitle) return false; + if (Type != MediaStreamType.Subtitle) + { + return false; + } if (string.IsNullOrEmpty(Codec) && !IsExternal) { diff --git a/MediaBrowser.Model/Services/RouteAttribute.cs b/MediaBrowser.Model/Services/RouteAttribute.cs index 162576aa7..f8bf51112 100644 --- a/MediaBrowser.Model/Services/RouteAttribute.cs +++ b/MediaBrowser.Model/Services/RouteAttribute.cs @@ -128,9 +128,21 @@ namespace MediaBrowser.Model.Services public override bool Equals(object obj) { - if (ReferenceEquals(null, obj)) return false; - if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != this.GetType()) return false; + if (ReferenceEquals(null, obj)) + { + return false; + } + + if (ReferenceEquals(this, obj)) + { + return true; + } + + if (obj.GetType() != this.GetType()) + { + return false; + } + return Equals((RouteAttribute)obj); } diff --git a/MediaBrowser.Providers/Manager/ItemImageProvider.cs b/MediaBrowser.Providers/Manager/ItemImageProvider.cs index cf5546602..82ed65ebb 100644 --- a/MediaBrowser.Providers/Manager/ItemImageProvider.cs +++ b/MediaBrowser.Providers/Manager/ItemImageProvider.cs @@ -113,7 +113,10 @@ namespace MediaBrowser.Providers.Manager foreach (var imageType in images) { - if (!IsEnabled(savedOptions, imageType, item)) continue; + if (!IsEnabled(savedOptions, imageType, item)) + { + continue; + } if (!HasImage(item, imageType) || (refreshOptions.IsReplacingImage(imageType) && !downloadedImages.Contains(imageType))) { diff --git a/MediaBrowser.Providers/Plugins/Tmdb/BoxSets/TmdbBoxSetProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/BoxSets/TmdbBoxSetProvider.cs index 15f0a9004..71799efa4 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/BoxSets/TmdbBoxSetProvider.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/BoxSets/TmdbBoxSetProvider.cs @@ -159,7 +159,10 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.BoxSets { var mainResult = await FetchMainResult(tmdbId, preferredMetadataLanguage, cancellationToken).ConfigureAwait(false); - if (mainResult == null) return; + if (mainResult == null) + { + return; + } var dataFilePath = GetDataFilePath(_config.ApplicationPaths, tmdbId, preferredMetadataLanguage); diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieProvider.cs index 1961e8bff..1c4cf1da1 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieProvider.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieProvider.cs @@ -194,7 +194,10 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Movies { var mainResult = await FetchMainResult(id, true, preferredMetadataLanguage, cancellationToken).ConfigureAwait(false); - if (mainResult == null) return; + if (mainResult == null) + { + return; + } var dataFilePath = GetDataFilePath(id, preferredMetadataLanguage); diff --git a/RSSDP/DeviceAvailableEventArgs.cs b/RSSDP/DeviceAvailableEventArgs.cs index 9c57471ca..b7d22a7df 100644 --- a/RSSDP/DeviceAvailableEventArgs.cs +++ b/RSSDP/DeviceAvailableEventArgs.cs @@ -22,7 +22,10 @@ namespace Rssdp /// <exception cref="ArgumentNullException">Thrown if the <paramref name="discoveredDevice"/> parameter is null.</exception> public DeviceAvailableEventArgs(DiscoveredSsdpDevice discoveredDevice, bool isNewlyDiscovered) { - if (discoveredDevice == null) throw new ArgumentNullException(nameof(discoveredDevice)); + if (discoveredDevice == null) + { + throw new ArgumentNullException(nameof(discoveredDevice)); + } _DiscoveredDevice = discoveredDevice; _IsNewlyDiscovered = isNewlyDiscovered; diff --git a/RSSDP/DeviceEventArgs.cs b/RSSDP/DeviceEventArgs.cs index b124527ca..2455ccbfa 100644 --- a/RSSDP/DeviceEventArgs.cs +++ b/RSSDP/DeviceEventArgs.cs @@ -16,7 +16,10 @@ namespace Rssdp /// <exception cref="ArgumentNullException">Thrown if the <paramref name="device"/> argument is null.</exception> public DeviceEventArgs(SsdpDevice device) { - if (device == null) throw new ArgumentNullException(nameof(device)); + if (device == null) + { + throw new ArgumentNullException(nameof(device)); + } _Device = device; } diff --git a/RSSDP/DeviceUnavailableEventArgs.cs b/RSSDP/DeviceUnavailableEventArgs.cs index cee59268d..94248f39f 100644 --- a/RSSDP/DeviceUnavailableEventArgs.cs +++ b/RSSDP/DeviceUnavailableEventArgs.cs @@ -19,7 +19,10 @@ namespace Rssdp /// <exception cref="ArgumentNullException">Thrown if the <paramref name="discoveredDevice"/> parameter is null.</exception> public DeviceUnavailableEventArgs(DiscoveredSsdpDevice discoveredDevice, bool expired) { - if (discoveredDevice == null) throw new ArgumentNullException(nameof(discoveredDevice)); + if (discoveredDevice == null) + { + throw new ArgumentNullException(nameof(discoveredDevice)); + } _DiscoveredDevice = discoveredDevice; _Expired = expired; diff --git a/RSSDP/DisposableManagedObjectBase.cs b/RSSDP/DisposableManagedObjectBase.cs index befa4ccff..628572b17 100644 --- a/RSSDP/DisposableManagedObjectBase.cs +++ b/RSSDP/DisposableManagedObjectBase.cs @@ -23,7 +23,10 @@ namespace Rssdp.Infrastructure /// <seealso cref="Dispose()"/> protected virtual void ThrowIfDisposed() { - if (this.IsDisposed) throw new ObjectDisposedException(this.GetType().FullName); + if (this.IsDisposed) + { + throw new ObjectDisposedException(this.GetType().FullName); + } } /// <summary> diff --git a/RSSDP/HttpParserBase.cs b/RSSDP/HttpParserBase.cs index ff97b6db8..058bfbf55 100644 --- a/RSSDP/HttpParserBase.cs +++ b/RSSDP/HttpParserBase.cs @@ -31,9 +31,20 @@ namespace Rssdp.Infrastructure [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2202:Do not dispose objects multiple times", Justification = "Honestly, it's fine. MemoryStream doesn't mind.")] protected virtual void Parse(T message, System.Net.Http.Headers.HttpHeaders headers, string data) { - if (data == null) throw new ArgumentNullException(nameof(data)); - if (data.Length == 0) throw new ArgumentException("data cannot be an empty string.", nameof(data)); - if (!LineTerminators.Any(data.Contains)) throw new ArgumentException("data is not a valid request, it does not contain any CRLF/LF terminators.", nameof(data)); + if (data == null) + { + throw new ArgumentNullException(nameof(data)); + } + + if (data.Length == 0) + { + throw new ArgumentException("data cannot be an empty string.", nameof(data)); + } + + if (!LineTerminators.Any(data.Contains)) + { + throw new ArgumentException("data is not a valid request, it does not contain any CRLF/LF terminators.", nameof(data)); + } using (var retVal = new ByteArrayContent(Array.Empty<byte>())) { @@ -66,10 +77,16 @@ namespace Rssdp.Infrastructure /// <returns>A <see cref="Version"/> object containing the parsed version data.</returns> protected Version ParseHttpVersion(string versionData) { - if (versionData == null) throw new ArgumentNullException(nameof(versionData)); + if (versionData == null) + { + throw new ArgumentNullException(nameof(versionData)); + } var versionSeparatorIndex = versionData.IndexOf('/'); - if (versionSeparatorIndex <= 0 || versionSeparatorIndex == versionData.Length) throw new ArgumentException("request header line is invalid. Http Version not supplied or incorrect format.", nameof(versionData)); + if (versionSeparatorIndex <= 0 || versionSeparatorIndex == versionData.Length) + { + throw new ArgumentException("request header line is invalid. Http Version not supplied or incorrect format.", nameof(versionData)); + } return Version.Parse(versionData.Substring(versionSeparatorIndex + 1)); } diff --git a/RSSDP/HttpRequestParser.cs b/RSSDP/HttpRequestParser.cs index 31f042791..6b27fc4df 100644 --- a/RSSDP/HttpRequestParser.cs +++ b/RSSDP/HttpRequestParser.cs @@ -45,11 +45,21 @@ namespace Rssdp.Infrastructure /// <param name="message">Either a <see cref="HttpResponseMessage"/> or <see cref="HttpRequestMessage"/> to assign the parsed values to.</param> protected override void ParseStatusLine(string data, HttpRequestMessage message) { - if (data == null) throw new ArgumentNullException(nameof(data)); - if (message == null) throw new ArgumentNullException(nameof(message)); + if (data == null) + { + throw new ArgumentNullException(nameof(data)); + } + + if (message == null) + { + throw new ArgumentNullException(nameof(message)); + } var parts = data.Split(' '); - if (parts.Length < 2) throw new ArgumentException("Status line is invalid. Insufficient status parts.", nameof(data)); + if (parts.Length < 2) + { + throw new ArgumentException("Status line is invalid. Insufficient status parts.", nameof(data)); + } message.Method = new HttpMethod(parts[0].Trim()); Uri requestUri; diff --git a/RSSDP/HttpResponseParser.cs b/RSSDP/HttpResponseParser.cs index 02c548d72..0337b3e36 100644 --- a/RSSDP/HttpResponseParser.cs +++ b/RSSDP/HttpResponseParser.cs @@ -57,11 +57,21 @@ namespace Rssdp.Infrastructure /// <param name="message">Either a <see cref="HttpResponseMessage"/> or <see cref="HttpRequestMessage"/> to assign the parsed values to.</param> protected override void ParseStatusLine(string data, HttpResponseMessage message) { - if (data == null) throw new ArgumentNullException(nameof(data)); - if (message == null) throw new ArgumentNullException(nameof(message)); + if (data == null) + { + throw new ArgumentNullException(nameof(data)); + } + + if (message == null) + { + throw new ArgumentNullException(nameof(message)); + } var parts = data.Split(' '); - if (parts.Length < 2) throw new ArgumentException("data status line is invalid. Insufficient status parts.", nameof(data)); + if (parts.Length < 2) + { + throw new ArgumentException("data status line is invalid. Insufficient status parts.", nameof(data)); + } message.Version = ParseHttpVersion(parts[0].Trim()); diff --git a/RSSDP/IEnumerableExtensions.cs b/RSSDP/IEnumerableExtensions.cs index 371454893..1f0daad3e 100644 --- a/RSSDP/IEnumerableExtensions.cs +++ b/RSSDP/IEnumerableExtensions.cs @@ -8,8 +8,15 @@ namespace Rssdp.Infrastructure { public static IEnumerable<T> SelectManyRecursive<T>(this IEnumerable<T> source, Func<T, IEnumerable<T>> selector) { - if (source == null) throw new ArgumentNullException(nameof(source)); - if (selector == null) throw new ArgumentNullException(nameof(selector)); + if (source == null) + { + throw new ArgumentNullException(nameof(source)); + } + + if (selector == null) + { + throw new ArgumentNullException(nameof(selector)); + } return !source.Any() ? source : source.Concat( diff --git a/RSSDP/SsdpCommunicationsServer.cs b/RSSDP/SsdpCommunicationsServer.cs index 12ecf24f3..31ca90424 100644 --- a/RSSDP/SsdpCommunicationsServer.cs +++ b/RSSDP/SsdpCommunicationsServer.cs @@ -80,8 +80,15 @@ namespace Rssdp.Infrastructure /// <exception cref="ArgumentOutOfRangeException">The <paramref name="multicastTimeToLive"/> argument is less than or equal to zero.</exception> public SsdpCommunicationsServer(ISocketFactory socketFactory, int localPort, int multicastTimeToLive, INetworkManager networkManager, ILogger logger, bool enableMultiSocketBinding) { - if (socketFactory == null) throw new ArgumentNullException(nameof(socketFactory)); - if (multicastTimeToLive <= 0) throw new ArgumentOutOfRangeException(nameof(multicastTimeToLive), "multicastTimeToLive must be greater than zero."); + if (socketFactory == null) + { + throw new ArgumentNullException(nameof(socketFactory)); + } + + if (multicastTimeToLive <= 0) + { + throw new ArgumentOutOfRangeException(nameof(multicastTimeToLive), "multicastTimeToLive must be greater than zero."); + } _BroadcastListenSocketSynchroniser = new object(); _SendSocketSynchroniser = new object(); @@ -151,7 +158,10 @@ namespace Rssdp.Infrastructure /// </summary> public async Task SendMessage(byte[] messageData, IPEndPoint destination, IPAddress fromLocalIpAddress, CancellationToken cancellationToken) { - if (messageData == null) throw new ArgumentNullException(nameof(messageData)); + if (messageData == null) + { + throw new ArgumentNullException(nameof(messageData)); + } ThrowIfDisposed(); @@ -234,7 +244,10 @@ namespace Rssdp.Infrastructure /// </summary> public async Task SendMulticastMessage(string message, int sendCount, IPAddress fromLocalIpAddress, CancellationToken cancellationToken) { - if (message == null) throw new ArgumentNullException(nameof(message)); + if (message == null) + { + throw new ArgumentNullException(nameof(message)); + } byte[] messageData = Encoding.UTF8.GetBytes(message); diff --git a/RSSDP/SsdpDevice.cs b/RSSDP/SsdpDevice.cs index 5b7d782b5..42f95862c 100644 --- a/RSSDP/SsdpDevice.cs +++ b/RSSDP/SsdpDevice.cs @@ -259,9 +259,20 @@ namespace Rssdp /// <seealso cref="DeviceAdded"/> public void AddDevice(SsdpEmbeddedDevice device) { - if (device == null) throw new ArgumentNullException(nameof(device)); - if (device.RootDevice != null && device.RootDevice != this.ToRootDevice()) throw new InvalidOperationException("This device is already associated with a different root device (has been added as a child in another branch)."); - if (device == this) throw new InvalidOperationException("Can't add device to itself."); + if (device == null) + { + throw new ArgumentNullException(nameof(device)); + } + + if (device.RootDevice != null && device.RootDevice != this.ToRootDevice()) + { + throw new InvalidOperationException("This device is already associated with a different root device (has been added as a child in another branch)."); + } + + if (device == this) + { + throw new InvalidOperationException("Can't add device to itself."); + } bool wasAdded = false; lock (_Devices) @@ -287,7 +298,10 @@ namespace Rssdp /// <seealso cref="DeviceRemoved"/> public void RemoveDevice(SsdpEmbeddedDevice device) { - if (device == null) throw new ArgumentNullException(nameof(device)); + if (device == null) + { + throw new ArgumentNullException(nameof(device)); + } bool wasRemoved = false; lock (_Devices) diff --git a/RSSDP/SsdpDeviceLocator.cs b/RSSDP/SsdpDeviceLocator.cs index b117c0b1e..a774ee23c 100644 --- a/RSSDP/SsdpDeviceLocator.cs +++ b/RSSDP/SsdpDeviceLocator.cs @@ -27,7 +27,10 @@ namespace Rssdp.Infrastructure /// </summary> public SsdpDeviceLocator(ISsdpCommunicationsServer communicationsServer) { - if (communicationsServer == null) throw new ArgumentNullException(nameof(communicationsServer)); + if (communicationsServer == null) + { + throw new ArgumentNullException(nameof(communicationsServer)); + } _CommunicationsServer = communicationsServer; _CommunicationsServer.ResponseReceived += CommsServer_ResponseReceived; @@ -140,10 +143,25 @@ namespace Rssdp.Infrastructure private Task SearchAsync(string searchTarget, TimeSpan searchWaitTime, CancellationToken cancellationToken) { - if (searchTarget == null) throw new ArgumentNullException(nameof(searchTarget)); - if (searchTarget.Length == 0) throw new ArgumentException("searchTarget cannot be an empty string.", nameof(searchTarget)); - if (searchWaitTime.TotalSeconds < 0) throw new ArgumentException("searchWaitTime must be a positive time."); - if (searchWaitTime.TotalSeconds > 0 && searchWaitTime.TotalSeconds <= 1) throw new ArgumentException("searchWaitTime must be zero (if you are not using the result and relying entirely in the events), or greater than one second."); + if (searchTarget == null) + { + throw new ArgumentNullException(nameof(searchTarget)); + } + + if (searchTarget.Length == 0) + { + throw new ArgumentException("searchTarget cannot be an empty string.", nameof(searchTarget)); + } + + if (searchWaitTime.TotalSeconds < 0) + { + throw new ArgumentException("searchWaitTime must be a positive time."); + } + + if (searchWaitTime.TotalSeconds > 0 && searchWaitTime.TotalSeconds <= 1) + { + throw new ArgumentException("searchWaitTime must be zero (if you are not using the result and relying entirely in the events), or greater than one second."); + } ThrowIfDisposed(); @@ -192,7 +210,10 @@ namespace Rssdp.Infrastructure /// <seealso cref="DeviceAvailable"/> protected virtual void OnDeviceAvailable(DiscoveredSsdpDevice device, bool isNewDevice, IPAddress localIpAddress) { - if (this.IsDisposed) return; + if (this.IsDisposed) + { + return; + } var handlers = this.DeviceAvailable; if (handlers != null) @@ -210,11 +231,16 @@ namespace Rssdp.Infrastructure /// <seealso cref="DeviceUnavailable"/> protected virtual void OnDeviceUnavailable(DiscoveredSsdpDevice device, bool expired) { - if (this.IsDisposed) return; + if (this.IsDisposed) + { + return; + } var handlers = this.DeviceUnavailable; if (handlers != null) + { handlers(this, new DeviceUnavailableEventArgs(device, expired)); + } } /// <summary> @@ -281,7 +307,10 @@ namespace Rssdp.Infrastructure private void DeviceFound(DiscoveredSsdpDevice device, bool isNewDevice, IPAddress localIpAddress) { - if (!NotificationTypeMatchesFilter(device)) return; + if (!NotificationTypeMatchesFilter(device)) + { + return; + } OnDeviceAvailable(device, isNewDevice, localIpAddress); } @@ -318,7 +347,10 @@ namespace Rssdp.Infrastructure private void ProcessSearchResponseMessage(HttpResponseMessage message, IPAddress localIpAddress) { - if (!message.IsSuccessStatusCode) return; + if (!message.IsSuccessStatusCode) + { + return; + } var location = GetFirstHeaderUriValue("Location", message); if (location != null) @@ -339,13 +371,20 @@ namespace Rssdp.Infrastructure private void ProcessNotificationMessage(HttpRequestMessage message, IPAddress localIpAddress) { - if (String.Compare(message.Method.Method, "Notify", StringComparison.OrdinalIgnoreCase) != 0) return; + if (String.Compare(message.Method.Method, "Notify", StringComparison.OrdinalIgnoreCase) != 0) + { + return; + } var notificationType = GetFirstHeaderStringValue("NTS", message); if (String.Compare(notificationType, SsdpConstants.SsdpKeepAliveNotification, StringComparison.OrdinalIgnoreCase) == 0) + { ProcessAliveNotification(message, localIpAddress); + } else if (String.Compare(notificationType, SsdpConstants.SsdpByeByeNotification, StringComparison.OrdinalIgnoreCase) == 0) + { ProcessByeByeNotification(message); + } } private void ProcessAliveNotification(HttpRequestMessage message, IPAddress localIpAddress) @@ -454,14 +493,20 @@ namespace Rssdp.Infrastructure private TimeSpan CacheAgeFromHeader(System.Net.Http.Headers.CacheControlHeaderValue headerValue) { - if (headerValue == null) return TimeSpan.Zero; + if (headerValue == null) + { + return TimeSpan.Zero; + } return (TimeSpan)(headerValue.MaxAge ?? headerValue.SharedMaxAge ?? TimeSpan.Zero); } private void RemoveExpiredDevicesFromCache() { - if (this.IsDisposed) return; + if (this.IsDisposed) + { + return; + } DiscoveredSsdpDevice[] expiredDevices = null; lock (_Devices) @@ -470,7 +515,10 @@ namespace Rssdp.Infrastructure foreach (var device in expiredDevices) { - if (this.IsDisposed) return; + if (this.IsDisposed) + { + return; + } _Devices.Remove(device); } @@ -481,7 +529,10 @@ namespace Rssdp.Infrastructure // problems. foreach (var expiredUsn in (from expiredDevice in expiredDevices select expiredDevice.Usn).Distinct()) { - if (this.IsDisposed) return; + if (this.IsDisposed) + { + return; + } DeviceDied(expiredUsn, true); } @@ -495,7 +546,10 @@ namespace Rssdp.Infrastructure existingDevices = FindExistingDeviceNotifications(_Devices, deviceUsn); foreach (var existingDevice in existingDevices) { - if (this.IsDisposed) return true; + if (this.IsDisposed) + { + return true; + } _Devices.Remove(existingDevice); } diff --git a/RSSDP/SsdpDevicePublisher.cs b/RSSDP/SsdpDevicePublisher.cs index b4cf2fb48..1b64d230d 100644 --- a/RSSDP/SsdpDevicePublisher.cs +++ b/RSSDP/SsdpDevicePublisher.cs @@ -40,12 +40,35 @@ namespace Rssdp.Infrastructure public SsdpDevicePublisher(ISsdpCommunicationsServer communicationsServer, INetworkManager networkManager, string osName, string osVersion, bool sendOnlyMatchedHost) { - if (communicationsServer == null) throw new ArgumentNullException(nameof(communicationsServer)); - if (networkManager == null) throw new ArgumentNullException(nameof(networkManager)); - if (osName == null) throw new ArgumentNullException(nameof(osName)); - if (osName.Length == 0) throw new ArgumentException("osName cannot be an empty string.", nameof(osName)); - if (osVersion == null) throw new ArgumentNullException(nameof(osVersion)); - if (osVersion.Length == 0) throw new ArgumentException("osVersion cannot be an empty string.", nameof(osName)); + if (communicationsServer == null) + { + throw new ArgumentNullException(nameof(communicationsServer)); + } + + if (networkManager == null) + { + throw new ArgumentNullException(nameof(networkManager)); + } + + if (osName == null) + { + throw new ArgumentNullException(nameof(osName)); + } + + if (osName.Length == 0) + { + throw new ArgumentException("osName cannot be an empty string.", nameof(osName)); + } + + if (osVersion == null) + { + throw new ArgumentNullException(nameof(osVersion)); + } + + if (osVersion.Length == 0) + { + throw new ArgumentException("osVersion cannot be an empty string.", nameof(osName)); + } _SupportPnpRootDevice = true; _Devices = new List<SsdpRootDevice>(); @@ -82,7 +105,10 @@ namespace Rssdp.Infrastructure [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1804:RemoveUnusedLocals", MessageId = "t", Justification = "Capture task to local variable supresses compiler warning, but task is not really needed.")] public void AddDevice(SsdpRootDevice device) { - if (device == null) throw new ArgumentNullException(nameof(device)); + if (device == null) + { + throw new ArgumentNullException(nameof(device)); + } ThrowIfDisposed(); @@ -115,7 +141,10 @@ namespace Rssdp.Infrastructure /// <exception cref="ArgumentNullException">Thrown if the <paramref name="device"/> argument is null.</exception> public async Task RemoveDevice(SsdpRootDevice device) { - if (device == null) throw new ArgumentNullException(nameof(device)); + if (device == null) + { + throw new ArgumentNullException(nameof(device)); + } bool wasRemoved = false; lock (_Devices) @@ -227,10 +256,15 @@ namespace Rssdp.Infrastructure // return; } - if (!Int32.TryParse(mx, out maxWaitInterval) || maxWaitInterval <= 0) return; + if (!Int32.TryParse(mx, out maxWaitInterval) || maxWaitInterval <= 0) + { + return; + } if (maxWaitInterval > 120) + { maxWaitInterval = _Random.Next(0, 120); + } // Do not block synchronously as that may tie up a threadpool thread for several seconds. Task.Delay(_Random.Next(16, (maxWaitInterval * 1000))).ContinueWith((parentTask) => @@ -240,13 +274,21 @@ namespace Rssdp.Infrastructure lock (_Devices) { if (String.Compare(SsdpConstants.SsdpDiscoverAllSTHeader, searchTarget, StringComparison.OrdinalIgnoreCase) == 0) + { devices = GetAllDevicesAsFlatEnumerable().ToArray(); + } else if (String.Compare(SsdpConstants.UpnpDeviceTypeRootDevice, searchTarget, StringComparison.OrdinalIgnoreCase) == 0 || (this.SupportPnpRootDevice && String.Compare(SsdpConstants.PnpDeviceTypeRootDevice, searchTarget, StringComparison.OrdinalIgnoreCase) == 0)) + { devices = _Devices.ToArray(); + } else if (searchTarget.Trim().StartsWith("uuid:", StringComparison.OrdinalIgnoreCase)) + { devices = (from device in GetAllDevicesAsFlatEnumerable() where String.Compare(device.Uuid, searchTarget.Substring(5), StringComparison.OrdinalIgnoreCase) == 0 select device).ToArray(); + } else if (searchTarget.StartsWith("urn:", StringComparison.OrdinalIgnoreCase)) + { devices = (from device in GetAllDevicesAsFlatEnumerable() where String.Compare(device.FullDeviceType, searchTarget, StringComparison.OrdinalIgnoreCase) == 0 select device).ToArray(); + } } if (devices != null) @@ -382,7 +424,10 @@ namespace Rssdp.Infrastructure { try { - if (IsDisposed) return; + if (IsDisposed) + { + return; + } // WriteTrace("Begin Sending Alive Notifications For All Devices"); @@ -394,7 +439,10 @@ namespace Rssdp.Infrastructure foreach (var device in devices) { - if (IsDisposed) return; + if (IsDisposed) + { + return; + } SendAliveNotifications(device, true, CancellationToken.None); } @@ -547,7 +595,10 @@ namespace Rssdp.Infrastructure private void CommsServer_RequestReceived(object sender, RequestReceivedEventArgs e) { - if (this.IsDisposed) return; + if (this.IsDisposed) + { + return; + } if (string.Equals(e.Message.Method.Method, SsdpConstants.MSearchMethod, StringComparison.OrdinalIgnoreCase)) { -- cgit v1.2.3 From 7f307f9082cb4be296e745c2c066334858f000af Mon Sep 17 00:00:00 2001 From: telans <telans@protonmail.com> Date: Sat, 20 Jun 2020 21:12:36 +1200 Subject: brace multiline if statements --- Emby.Dlna/DlnaManager.cs | 18 +++++ Emby.Dlna/PlayTo/Device.cs | 14 ++++ .../Library/Resolvers/Books/BookResolver.cs | 4 ++ .../Services/ResponseHelper.cs | 2 + .../Services/ServiceExec.cs | 4 ++ .../Services/ServicePath.cs | 2 + .../Sorting/DateCreatedComparer.cs | 4 ++ .../Sorting/RuntimeComparer.cs | 4 ++ .../Sorting/SortNameComparer.cs | 4 ++ MediaBrowser.Controller/Entities/BaseItem.cs | 2 + MediaBrowser.MediaEncoding/Subtitles/SrtParser.cs | 3 + MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs | 58 +++++++++++++++ .../Dlna/MediaFormatProfileResolver.cs | 83 +++++++++++++++++++++- RSSDP/HttpParserBase.cs | 12 ++++ RSSDP/HttpRequestParser.cs | 4 ++ RSSDP/HttpResponseParser.cs | 4 ++ RSSDP/SsdpCommunicationsServer.cs | 4 ++ RSSDP/SsdpDevice.cs | 12 ++++ RSSDP/SsdpDeviceLocator.cs | 16 +++++ RSSDP/SsdpDevicePublisher.cs | 31 ++++++-- 20 files changed, 280 insertions(+), 5 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Dlna/DlnaManager.cs b/Emby.Dlna/DlnaManager.cs index cbe4ea643..5911a73ef 100644 --- a/Emby.Dlna/DlnaManager.cs +++ b/Emby.Dlna/DlnaManager.cs @@ -140,55 +140,73 @@ namespace Emby.Dlna if (!string.IsNullOrEmpty(profileInfo.DeviceDescription)) { if (deviceInfo.DeviceDescription == null || !IsRegexMatch(deviceInfo.DeviceDescription, profileInfo.DeviceDescription)) + { return false; + } } if (!string.IsNullOrEmpty(profileInfo.FriendlyName)) { if (deviceInfo.FriendlyName == null || !IsRegexMatch(deviceInfo.FriendlyName, profileInfo.FriendlyName)) + { return false; + } } if (!string.IsNullOrEmpty(profileInfo.Manufacturer)) { if (deviceInfo.Manufacturer == null || !IsRegexMatch(deviceInfo.Manufacturer, profileInfo.Manufacturer)) + { return false; + } } if (!string.IsNullOrEmpty(profileInfo.ManufacturerUrl)) { if (deviceInfo.ManufacturerUrl == null || !IsRegexMatch(deviceInfo.ManufacturerUrl, profileInfo.ManufacturerUrl)) + { return false; + } } if (!string.IsNullOrEmpty(profileInfo.ModelDescription)) { if (deviceInfo.ModelDescription == null || !IsRegexMatch(deviceInfo.ModelDescription, profileInfo.ModelDescription)) + { return false; + } } if (!string.IsNullOrEmpty(profileInfo.ModelName)) { if (deviceInfo.ModelName == null || !IsRegexMatch(deviceInfo.ModelName, profileInfo.ModelName)) + { return false; + } } if (!string.IsNullOrEmpty(profileInfo.ModelNumber)) { if (deviceInfo.ModelNumber == null || !IsRegexMatch(deviceInfo.ModelNumber, profileInfo.ModelNumber)) + { return false; + } } if (!string.IsNullOrEmpty(profileInfo.ModelUrl)) { if (deviceInfo.ModelUrl == null || !IsRegexMatch(deviceInfo.ModelUrl, profileInfo.ModelUrl)) + { return false; + } } if (!string.IsNullOrEmpty(profileInfo.SerialNumber)) { if (deviceInfo.SerialNumber == null || !IsRegexMatch(deviceInfo.SerialNumber, profileInfo.SerialNumber)) + { return false; + } } return true; diff --git a/Emby.Dlna/PlayTo/Device.cs b/Emby.Dlna/PlayTo/Device.cs index c86fc4f37..c5080b90f 100644 --- a/Emby.Dlna/PlayTo/Device.cs +++ b/Emby.Dlna/PlayTo/Device.cs @@ -208,7 +208,9 @@ namespace Emby.Dlna.PlayTo var command = rendererCommands.ServiceActions.FirstOrDefault(c => c.Name == "SetMute"); if (command == null) + { return false; + } var service = GetServiceRenderingControl(); @@ -237,7 +239,9 @@ namespace Emby.Dlna.PlayTo var command = rendererCommands.ServiceActions.FirstOrDefault(c => c.Name == "SetVolume"); if (command == null) + { return; + } var service = GetServiceRenderingControl(); @@ -260,7 +264,9 @@ namespace Emby.Dlna.PlayTo var command = avCommands.ServiceActions.FirstOrDefault(c => c.Name == "Seek"); if (command == null) + { return; + } var service = GetAvTransportService(); @@ -285,7 +291,9 @@ namespace Emby.Dlna.PlayTo var command = avCommands.ServiceActions.FirstOrDefault(c => c.Name == "SetAVTransportURI"); if (command == null) + { return; + } var dictionary = new Dictionary<string, string> { @@ -452,7 +460,9 @@ namespace Emby.Dlna.PlayTo _connectFailureCount = 0; if (_disposed) + { return; + } // If we're not playing anything make sure we don't get data more often than neccessry to keep the Session alive if (transportState.Value == TRANSPORTSTATE.STOPPED) @@ -472,7 +482,9 @@ namespace Emby.Dlna.PlayTo catch (Exception ex) { if (_disposed) + { return; + } _logger.LogError(ex, "Error updating device info for {DeviceName}", Properties.Name); @@ -573,7 +585,9 @@ namespace Emby.Dlna.PlayTo cancellationToken: cancellationToken).ConfigureAwait(false); if (result == null || result.Document == null) + { return; + } var valueNode = result.Document.Descendants(uPnpNamespaces.RenderingControl + "GetMuteResponse") .Select(i => i.Element("CurrentMute")) diff --git a/Emby.Server.Implementations/Library/Resolvers/Books/BookResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Books/BookResolver.cs index 503de0b4e..86a5d8b7d 100644 --- a/Emby.Server.Implementations/Library/Resolvers/Books/BookResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/Books/BookResolver.cs @@ -19,7 +19,9 @@ namespace Emby.Server.Implementations.Library.Resolvers.Books // Only process items that are in a collection folder containing books if (!string.Equals(collectionType, CollectionType.Books, StringComparison.OrdinalIgnoreCase)) + { return null; + } if (args.IsDirectory) { @@ -55,7 +57,9 @@ namespace Emby.Server.Implementations.Library.Resolvers.Books // Don't return a Book if there is more (or less) than one document in the directory if (bookFiles.Count != 1) + { return null; + } return new Book { diff --git a/Emby.Server.Implementations/Services/ResponseHelper.cs b/Emby.Server.Implementations/Services/ResponseHelper.cs index 3f1672e94..a329b531d 100644 --- a/Emby.Server.Implementations/Services/ResponseHelper.cs +++ b/Emby.Server.Implementations/Services/ResponseHelper.cs @@ -40,7 +40,9 @@ namespace Emby.Server.Implementations.Services if (httpResult != null) { if (httpResult.RequestContext == null) + { httpResult.RequestContext = request; + } response.StatusCode = httpResult.Status; } diff --git a/Emby.Server.Implementations/Services/ServiceExec.cs b/Emby.Server.Implementations/Services/ServiceExec.cs index 18d7ab46e..cbc4b754d 100644 --- a/Emby.Server.Implementations/Services/ServiceExec.cs +++ b/Emby.Server.Implementations/Services/ServiceExec.cs @@ -42,11 +42,15 @@ namespace Emby.Server.Implementations.Services } if (mi.GetParameters().Length != 1) + { continue; + } var actionName = mi.Name; if (!AllVerbs.Contains(actionName, StringComparer.OrdinalIgnoreCase)) + { continue; + } list.Add(mi); } diff --git a/Emby.Server.Implementations/Services/ServicePath.cs b/Emby.Server.Implementations/Services/ServicePath.cs index eb0744189..89538ae72 100644 --- a/Emby.Server.Implementations/Services/ServicePath.cs +++ b/Emby.Server.Implementations/Services/ServicePath.cs @@ -445,12 +445,14 @@ namespace Emby.Server.Implementations.Services && requestComponents.Length >= this.TotalComponentsCount - this.wildcardCount; if (!isValidWildCardPath) + { throw new ArgumentException( string.Format( CultureInfo.InvariantCulture, "Path Mismatch: Request Path '{0}' has invalid number of components compared to: '{1}'", pathInfo, this.restPath)); + } } var requestKeyValuesMap = new Dictionary<string, string>(); diff --git a/Emby.Server.Implementations/Sorting/DateCreatedComparer.cs b/Emby.Server.Implementations/Sorting/DateCreatedComparer.cs index ea981e840..cbca300d2 100644 --- a/Emby.Server.Implementations/Sorting/DateCreatedComparer.cs +++ b/Emby.Server.Implementations/Sorting/DateCreatedComparer.cs @@ -19,10 +19,14 @@ namespace Emby.Server.Implementations.Sorting public int Compare(BaseItem x, BaseItem y) { if (x == null) + { throw new ArgumentNullException(nameof(x)); + } if (y == null) + { throw new ArgumentNullException(nameof(y)); + } return DateTime.Compare(x.DateCreated, y.DateCreated); } diff --git a/Emby.Server.Implementations/Sorting/RuntimeComparer.cs b/Emby.Server.Implementations/Sorting/RuntimeComparer.cs index f165123ea..dde44333d 100644 --- a/Emby.Server.Implementations/Sorting/RuntimeComparer.cs +++ b/Emby.Server.Implementations/Sorting/RuntimeComparer.cs @@ -19,10 +19,14 @@ namespace Emby.Server.Implementations.Sorting public int Compare(BaseItem x, BaseItem y) { if (x == null) + { throw new ArgumentNullException(nameof(x)); + } if (y == null) + { throw new ArgumentNullException(nameof(y)); + } return (x.RunTimeTicks ?? 0).CompareTo(y.RunTimeTicks ?? 0); } diff --git a/Emby.Server.Implementations/Sorting/SortNameComparer.cs b/Emby.Server.Implementations/Sorting/SortNameComparer.cs index 93389fc3e..f745e193b 100644 --- a/Emby.Server.Implementations/Sorting/SortNameComparer.cs +++ b/Emby.Server.Implementations/Sorting/SortNameComparer.cs @@ -19,10 +19,14 @@ namespace Emby.Server.Implementations.Sorting public int Compare(BaseItem x, BaseItem y) { if (x == null) + { throw new ArgumentNullException(nameof(x)); + } if (y == null) + { throw new ArgumentNullException(nameof(y)); + } return string.Compare(x.SortName, y.SortName, StringComparison.CurrentCultureIgnoreCase); } diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 2ad1c717c..8e0e63ff0 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -2951,7 +2951,9 @@ namespace MediaBrowser.Controller.Entities public IEnumerable<BaseItem> GetTrailers() { if (this is IHasTrailers) + { return ((IHasTrailers)this).LocalTrailerIds.Select(LibraryManager.GetItemById).Where(i => i != null).OrderBy(i => i.SortName); + } else return Array.Empty<BaseItem>(); } diff --git a/MediaBrowser.MediaEncoding/Subtitles/SrtParser.cs b/MediaBrowser.MediaEncoding/Subtitles/SrtParser.cs index a8d383a2a..728efa788 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SrtParser.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SrtParser.cs @@ -58,7 +58,10 @@ namespace MediaBrowser.MediaEncoding.Subtitles var endTime = time[1]; var idx = endTime.IndexOf(" ", StringComparison.Ordinal); if (idx > 0) + { endTime = endTime.Substring(0, idx); + } + subEvent.EndPositionTicks = GetTicks(endTime); var multiline = new List<string>(); while ((line = reader.ReadLine()) != null) diff --git a/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs b/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs index 9a8fcc431..630a3dce0 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs @@ -41,7 +41,9 @@ namespace MediaBrowser.MediaEncoding.Subtitles lineNumber++; if (!eventsStarted) + { header.AppendLine(line); + } if (line.Trim().ToLowerInvariant() == "[events]") { @@ -62,17 +64,29 @@ namespace MediaBrowser.MediaEncoding.Subtitles for (int i = 0; i < format.Length; i++) { if (format[i].Trim().ToLowerInvariant() == "layer") + { indexLayer = i; + } else if (format[i].Trim().ToLowerInvariant() == "start") + { indexStart = i; + } else if (format[i].Trim().ToLowerInvariant() == "end") + { indexEnd = i; + } else if (format[i].Trim().ToLowerInvariant() == "text") + { indexText = i; + } else if (format[i].Trim().ToLowerInvariant() == "effect") + { indexEffect = i; + } else if (format[i].Trim().ToLowerInvariant() == "style") + { indexStyle = i; + } } } } @@ -89,28 +103,48 @@ namespace MediaBrowser.MediaEncoding.Subtitles string[] splittedLine; if (s.StartsWith("dialogue:")) + { splittedLine = line.Substring(10).Split(','); + } else + { splittedLine = line.Split(','); + } for (int i = 0; i < splittedLine.Length; i++) { if (i == indexStart) + { start = splittedLine[i].Trim(); + } else if (i == indexEnd) + { end = splittedLine[i].Trim(); + } else if (i == indexLayer) + { layer = splittedLine[i]; + } else if (i == indexEffect) + { effect = splittedLine[i]; + } else if (i == indexText) + { text = splittedLine[i]; + } else if (i == indexStyle) + { style = splittedLine[i]; + } else if (i == indexName) + { name = splittedLine[i]; + } else if (i > indexText) + { text += "," + splittedLine[i]; + } } try @@ -169,13 +203,17 @@ namespace MediaBrowser.MediaEncoding.Subtitles CheckAndAddSubTags(ref fontName, ref extraTags, out italic); text = text.Remove(start, end - start + 1); if (italic) + { text = text.Insert(start, "<font face=\"" + fontName + "\"" + extraTags + "><i>"); + } else text = text.Insert(start, "<font face=\"" + fontName + "\"" + extraTags + ">"); int indexOfEndTag = text.IndexOf("{\\fn}", start); if (indexOfEndTag > 0) + { text = text.Remove(indexOfEndTag, "{\\fn}".Length).Insert(indexOfEndTag, "</font>"); + } else text += "</font>"; } @@ -194,13 +232,17 @@ namespace MediaBrowser.MediaEncoding.Subtitles { text = text.Remove(start, end - start + 1); if (italic) + { text = text.Insert(start, "<font size=\"" + fontSize + "\"" + extraTags + "><i>"); + } else text = text.Insert(start, "<font size=\"" + fontSize + "\"" + extraTags + ">"); int indexOfEndTag = text.IndexOf("{\\fs}", start); if (indexOfEndTag > 0) + { text = text.Remove(indexOfEndTag, "{\\fs}".Length).Insert(indexOfEndTag, "</font>"); + } else text += "</font>"; } @@ -226,12 +268,16 @@ namespace MediaBrowser.MediaEncoding.Subtitles text = text.Remove(start, end - start + 1); if (italic) + { text = text.Insert(start, "<font color=\"" + color + "\"" + extraTags + "><i>"); + } else text = text.Insert(start, "<font color=\"" + color + "\"" + extraTags + ">"); int indexOfEndTag = text.IndexOf("{\\c}", start); if (indexOfEndTag > 0) + { text = text.Remove(indexOfEndTag, "{\\c}".Length).Insert(indexOfEndTag, "</font>"); + } else text += "</font>"; } @@ -256,7 +302,9 @@ namespace MediaBrowser.MediaEncoding.Subtitles text = text.Remove(start, end - start + 1); if (italic) + { text = text.Insert(start, "<font color=\"" + color + "\"" + extraTags + "><i>"); + } else text = text.Insert(start, "<font color=\"" + color + "\"" + extraTags + ">"); text += "</font>"; @@ -268,19 +316,25 @@ namespace MediaBrowser.MediaEncoding.Subtitles text = text.Replace(@"{\i0}", "</i>"); text = text.Replace(@"{\i}", "</i>"); if (CountTagInText(text, "<i>") > CountTagInText(text, "</i>")) + { text += "</i>"; + } text = text.Replace(@"{\u1}", "<u>"); text = text.Replace(@"{\u0}", "</u>"); text = text.Replace(@"{\u}", "</u>"); if (CountTagInText(text, "<u>") > CountTagInText(text, "</u>")) + { text += "</u>"; + } text = text.Replace(@"{\b1}", "<b>"); text = text.Replace(@"{\b0}", "</b>"); text = text.Replace(@"{\b}", "</b>"); if (CountTagInText(text, "<b>") > CountTagInText(text, "</b>")) + { text += "</b>"; + } return text; } @@ -288,7 +342,9 @@ namespace MediaBrowser.MediaEncoding.Subtitles private static bool IsInteger(string s) { if (int.TryParse(s, out var i)) + { return true; + } return false; } @@ -300,7 +356,9 @@ namespace MediaBrowser.MediaEncoding.Subtitles { count++; if (index == text.Length) + { return count; + } index = text.IndexOf(tag, index + 1); } diff --git a/MediaBrowser.Model/Dlna/MediaFormatProfileResolver.cs b/MediaBrowser.Model/Dlna/MediaFormatProfileResolver.cs index 47cc89210..df10f8c53 100644 --- a/MediaBrowser.Model/Dlna/MediaFormatProfileResolver.cs +++ b/MediaBrowser.Model/Dlna/MediaFormatProfileResolver.cs @@ -32,18 +32,25 @@ namespace MediaBrowser.Model.Dlna } if (string.Equals(container, "avi", StringComparison.OrdinalIgnoreCase)) + { return new MediaFormatProfile[] { MediaFormatProfile.AVI }; + } if (string.Equals(container, "mkv", StringComparison.OrdinalIgnoreCase)) + { return new MediaFormatProfile[] { MediaFormatProfile.MATROSKA }; + } if (string.Equals(container, "mpeg2ps", StringComparison.OrdinalIgnoreCase) || string.Equals(container, "ts", StringComparison.OrdinalIgnoreCase)) - + { return new MediaFormatProfile[] { MediaFormatProfile.MPEG_PS_NTSC, MediaFormatProfile.MPEG_PS_PAL }; + } if (string.Equals(container, "mpeg1video", StringComparison.OrdinalIgnoreCase)) + { return new MediaFormatProfile[] { MediaFormatProfile.MPEG1 }; + } if (string.Equals(container, "mpeg2ts", StringComparison.OrdinalIgnoreCase) || string.Equals(container, "mpegts", StringComparison.OrdinalIgnoreCase) || @@ -54,10 +61,14 @@ namespace MediaBrowser.Model.Dlna } if (string.Equals(container, "flv", StringComparison.OrdinalIgnoreCase)) + { return new MediaFormatProfile[] { MediaFormatProfile.FLV }; + } if (string.Equals(container, "wtv", StringComparison.OrdinalIgnoreCase)) + { return new MediaFormatProfile[] { MediaFormatProfile.WTV }; + } if (string.Equals(container, "3gp", StringComparison.OrdinalIgnoreCase)) { @@ -66,7 +77,9 @@ namespace MediaBrowser.Model.Dlna } if (string.Equals(container, "ogv", StringComparison.OrdinalIgnoreCase) || string.Equals(container, "ogg", StringComparison.OrdinalIgnoreCase)) + { return new MediaFormatProfile[] { MediaFormatProfile.OGV }; + } return Array.Empty<MediaFormatProfile>(); } @@ -111,7 +124,9 @@ namespace MediaBrowser.Model.Dlna if (string.Equals(videoCodec, "h264", StringComparison.OrdinalIgnoreCase)) { if (string.Equals(audioCodec, "lpcm", StringComparison.OrdinalIgnoreCase)) + { return new MediaFormatProfile[] { MediaFormatProfile.AVC_TS_HD_50_LPCM_T }; + } if (string.Equals(audioCodec, "dts", StringComparison.OrdinalIgnoreCase)) { @@ -134,14 +149,20 @@ namespace MediaBrowser.Model.Dlna } if (string.Equals(audioCodec, "aac", StringComparison.OrdinalIgnoreCase)) + { return new MediaFormatProfile[] { ValueOf(string.Format("AVC_TS_MP_{0}D_AAC_MULT5{1}", resolution, suffix)) }; + } if (string.Equals(audioCodec, "mp3", StringComparison.OrdinalIgnoreCase)) + { return new MediaFormatProfile[] { ValueOf(string.Format("AVC_TS_MP_{0}D_MPEG1_L3{1}", resolution, suffix)) }; + } if (string.IsNullOrEmpty(audioCodec) || string.Equals(audioCodec, "ac3", StringComparison.OrdinalIgnoreCase)) + { return new MediaFormatProfile[] { ValueOf(string.Format("AVC_TS_MP_{0}D_AC3{1}", resolution, suffix)) }; + } } else if (string.Equals(videoCodec, "vc1", StringComparison.OrdinalIgnoreCase)) { @@ -165,13 +186,24 @@ namespace MediaBrowser.Model.Dlna else if (string.Equals(videoCodec, "mpeg4", StringComparison.OrdinalIgnoreCase) || string.Equals(videoCodec, "msmpeg4", StringComparison.OrdinalIgnoreCase)) { if (string.Equals(audioCodec, "aac", StringComparison.OrdinalIgnoreCase)) + { return new MediaFormatProfile[] { ValueOf(string.Format("MPEG4_P2_TS_ASP_AAC{0}", suffix)) }; + } + if (string.Equals(audioCodec, "mp3", StringComparison.OrdinalIgnoreCase)) + { return new MediaFormatProfile[] { ValueOf(string.Format("MPEG4_P2_TS_ASP_MPEG1_L3{0}", suffix)) }; + } + if (string.Equals(audioCodec, "mp2", StringComparison.OrdinalIgnoreCase)) + { return new MediaFormatProfile[] { ValueOf(string.Format("MPEG4_P2_TS_ASP_MPEG2_L2{0}", suffix)) }; + } + if (string.Equals(audioCodec, "ac3", StringComparison.OrdinalIgnoreCase)) + { return new MediaFormatProfile[] { ValueOf(string.Format("MPEG4_P2_TS_ASP_AC3{0}", suffix)) }; + } } return new MediaFormatProfile[] { }; @@ -187,7 +219,9 @@ namespace MediaBrowser.Model.Dlna if (string.Equals(videoCodec, "h264", StringComparison.OrdinalIgnoreCase)) { if (string.Equals(audioCodec, "lpcm", StringComparison.OrdinalIgnoreCase)) + { return MediaFormatProfile.AVC_MP4_LPCM; + } if (string.IsNullOrEmpty(audioCodec) || string.Equals(audioCodec, "ac3", StringComparison.OrdinalIgnoreCase)) { @@ -204,12 +238,16 @@ namespace MediaBrowser.Model.Dlna if ((width.Value <= 720) && (height.Value <= 576)) { if (string.Equals(audioCodec, "aac", StringComparison.OrdinalIgnoreCase)) + { return MediaFormatProfile.AVC_MP4_MP_SD_AAC_MULT5; + } } else if ((width.Value <= 1280) && (height.Value <= 720)) { if (string.Equals(audioCodec, "aac", StringComparison.OrdinalIgnoreCase)) + { return MediaFormatProfile.AVC_MP4_MP_HD_720p_AAC; + } } else if ((width.Value <= 1920) && (height.Value <= 1080)) { @@ -226,7 +264,9 @@ namespace MediaBrowser.Model.Dlna if (width.HasValue && height.HasValue && width.Value <= 720 && height.Value <= 576) { if (string.IsNullOrEmpty(audioCodec) || string.Equals(audioCodec, "aac", StringComparison.OrdinalIgnoreCase)) + { return MediaFormatProfile.MPEG4_P2_MP4_ASP_AAC; + } if (string.Equals(audioCodec, "ac3", StringComparison.OrdinalIgnoreCase) || string.Equals(audioCodec, "mp3", StringComparison.OrdinalIgnoreCase)) { return MediaFormatProfile.MPEG4_P2_MP4_NDSD; @@ -250,15 +290,22 @@ namespace MediaBrowser.Model.Dlna if (string.Equals(videoCodec, "h264", StringComparison.OrdinalIgnoreCase)) { if (string.IsNullOrEmpty(audioCodec) || string.Equals(audioCodec, "aac", StringComparison.OrdinalIgnoreCase)) + { return MediaFormatProfile.AVC_3GPP_BL_QCIF15_AAC; + } } else if (string.Equals(videoCodec, "mpeg4", StringComparison.OrdinalIgnoreCase) || string.Equals(videoCodec, "msmpeg4", StringComparison.OrdinalIgnoreCase)) { if (string.IsNullOrEmpty(audioCodec) || string.Equals(audioCodec, "wma", StringComparison.OrdinalIgnoreCase)) + { return MediaFormatProfile.MPEG4_P2_3GPP_SP_L0B_AAC; + } + if (string.Equals(audioCodec, "amrnb", StringComparison.OrdinalIgnoreCase)) + { return MediaFormatProfile.MPEG4_P2_3GPP_SP_L0B_AMR; + } } else if (string.Equals(videoCodec, "h263", StringComparison.OrdinalIgnoreCase) && string.Equals(audioCodec, "amrnb", StringComparison.OrdinalIgnoreCase)) { @@ -300,11 +347,19 @@ namespace MediaBrowser.Model.Dlna if (width.HasValue && height.HasValue) { if ((width.Value <= 720) && (height.Value <= 576)) + { return MediaFormatProfile.VC1_ASF_AP_L1_WMA; + } + if ((width.Value <= 1280) && (height.Value <= 720)) + { return MediaFormatProfile.VC1_ASF_AP_L2_WMA; + } + if ((width.Value <= 1920) && (height.Value <= 1080)) + { return MediaFormatProfile.VC1_ASF_AP_L3_WMA; + } } } else if (string.Equals(videoCodec, "mpeg2video", StringComparison.OrdinalIgnoreCase)) @@ -318,27 +373,41 @@ namespace MediaBrowser.Model.Dlna public MediaFormatProfile? ResolveAudioFormat(string container, int? bitrate, int? frequency, int? channels) { if (string.Equals(container, "asf", StringComparison.OrdinalIgnoreCase)) + { return ResolveAudioASFFormat(bitrate); + } if (string.Equals(container, "mp3", StringComparison.OrdinalIgnoreCase)) + { return MediaFormatProfile.MP3; + } if (string.Equals(container, "lpcm", StringComparison.OrdinalIgnoreCase)) + { return ResolveAudioLPCMFormat(frequency, channels); + } if (string.Equals(container, "mp4", StringComparison.OrdinalIgnoreCase) || string.Equals(container, "aac", StringComparison.OrdinalIgnoreCase)) + { return ResolveAudioMP4Format(bitrate); + } if (string.Equals(container, "adts", StringComparison.OrdinalIgnoreCase)) + { return ResolveAudioADTSFormat(bitrate); + } if (string.Equals(container, "flac", StringComparison.OrdinalIgnoreCase)) + { return MediaFormatProfile.FLAC; + } if (string.Equals(container, "oga", StringComparison.OrdinalIgnoreCase) || string.Equals(container, "ogg", StringComparison.OrdinalIgnoreCase)) + { return MediaFormatProfile.OGG; + } return null; } @@ -410,13 +479,19 @@ namespace MediaBrowser.Model.Dlna return ResolveImageJPGFormat(width, height); if (string.Equals(container, "png", StringComparison.OrdinalIgnoreCase)) + { return ResolveImagePNGFormat(width, height); + } if (string.Equals(container, "gif", StringComparison.OrdinalIgnoreCase)) + { return MediaFormatProfile.GIF_LRG; + } if (string.Equals(container, "raw", StringComparison.OrdinalIgnoreCase)) + { return MediaFormatProfile.RAW; + } return null; } @@ -426,10 +501,14 @@ namespace MediaBrowser.Model.Dlna if (width.HasValue && height.HasValue) { if ((width.Value <= 160) && (height.Value <= 160)) + { return MediaFormatProfile.JPEG_TN; + } if ((width.Value <= 640) && (height.Value <= 480)) + { return MediaFormatProfile.JPEG_SM; + } if ((width.Value <= 1024) && (height.Value <= 768)) { @@ -447,7 +526,9 @@ namespace MediaBrowser.Model.Dlna if (width.HasValue && height.HasValue) { if ((width.Value <= 160) && (height.Value <= 160)) + { return MediaFormatProfile.PNG_TN; + } } return MediaFormatProfile.PNG_LRG; diff --git a/RSSDP/HttpParserBase.cs b/RSSDP/HttpParserBase.cs index 058bfbf55..00c2b7b45 100644 --- a/RSSDP/HttpParserBase.cs +++ b/RSSDP/HttpParserBase.cs @@ -114,9 +114,13 @@ namespace Rssdp.Infrastructure var headersToAddTo = IsContentHeader(headerName) ? contentHeaders : headers; if (values.Count > 1) + { headersToAddTo.TryAddWithoutValidation(headerName, values); + } else + { headersToAddTo.TryAddWithoutValidation(headerName, values.First()); + } } private int ParseHeaders(System.Net.Http.Headers.HttpHeaders headers, System.Net.Http.Headers.HttpHeaders contentHeaders, string[] lines) @@ -160,7 +164,9 @@ namespace Rssdp.Infrastructure var indexOfSeparator = headerValue.IndexOfAny(SeparatorCharacters); if (indexOfSeparator <= 0) + { values.Add(headerValue); + } else { var segments = headerValue.Split(SeparatorCharacters); @@ -170,7 +176,9 @@ namespace Rssdp.Infrastructure { var segment = segments[segmentIndex]; if (segment.Trim().StartsWith("\"", StringComparison.OrdinalIgnoreCase)) + { segment = CombineQuotedSegments(segments, ref segmentIndex, segment); + } values.Add(segment); } @@ -199,12 +207,16 @@ namespace Rssdp.Infrastructure } if (index + 1 < segments.Length) + { trimmedSegment += "," + segments[index + 1].TrimEnd(); + } } segmentIndex = segments.Length; if (trimmedSegment.StartsWith("\"", StringComparison.OrdinalIgnoreCase) && trimmedSegment.EndsWith("\"", StringComparison.OrdinalIgnoreCase)) + { return trimmedSegment.Substring(1, trimmedSegment.Length - 2); + } else return trimmedSegment; } diff --git a/RSSDP/HttpRequestParser.cs b/RSSDP/HttpRequestParser.cs index 6b27fc4df..7fa42f466 100644 --- a/RSSDP/HttpRequestParser.cs +++ b/RSSDP/HttpRequestParser.cs @@ -34,7 +34,9 @@ namespace Rssdp.Infrastructure finally { if (retVal != null) + { retVal.Dispose(); + } } } @@ -64,7 +66,9 @@ namespace Rssdp.Infrastructure message.Method = new HttpMethod(parts[0].Trim()); Uri requestUri; if (Uri.TryCreate(parts[1].Trim(), UriKind.RelativeOrAbsolute, out requestUri)) + { message.RequestUri = requestUri; + } else System.Diagnostics.Debug.WriteLine(parts[1]); diff --git a/RSSDP/HttpResponseParser.cs b/RSSDP/HttpResponseParser.cs index 0337b3e36..0dd4bb45a 100644 --- a/RSSDP/HttpResponseParser.cs +++ b/RSSDP/HttpResponseParser.cs @@ -34,7 +34,9 @@ namespace Rssdp.Infrastructure catch { if (retVal != null) + { retVal.Dispose(); + } throw; } @@ -77,7 +79,9 @@ namespace Rssdp.Infrastructure int statusCode = -1; if (!Int32.TryParse(parts[1].Trim(), out statusCode)) + { throw new ArgumentException("data status line is invalid. Status code is not a valid integer.", nameof(data)); + } message.StatusCode = (HttpStatusCode)statusCode; diff --git a/RSSDP/SsdpCommunicationsServer.cs b/RSSDP/SsdpCommunicationsServer.cs index 31ca90424..e4c4a2017 100644 --- a/RSSDP/SsdpCommunicationsServer.cs +++ b/RSSDP/SsdpCommunicationsServer.cs @@ -480,17 +480,21 @@ namespace Rssdp.Infrastructure var handlers = this.RequestReceived; if (handlers != null) + { handlers(this, new RequestReceivedEventArgs(data, remoteEndPoint, receivedOnLocalIpAddress)); + } } private void OnResponseReceived(HttpResponseMessage data, IPEndPoint endPoint, IPAddress localIpAddress) { var handlers = this.ResponseReceived; if (handlers != null) + { handlers(this, new ResponseReceivedEventArgs(data, endPoint) { LocalIpAddress = localIpAddress }); + } } } } diff --git a/RSSDP/SsdpDevice.cs b/RSSDP/SsdpDevice.cs index 42f95862c..7030c6ec1 100644 --- a/RSSDP/SsdpDevice.cs +++ b/RSSDP/SsdpDevice.cs @@ -55,7 +55,9 @@ namespace Rssdp var rootDevice = device as SsdpRootDevice; if (rootDevice == null) + { rootDevice = ((SsdpEmbeddedDevice)device).RootDevice; + } return rootDevice; } @@ -163,7 +165,9 @@ namespace Rssdp get { if (String.IsNullOrEmpty(_Udn) && !String.IsNullOrEmpty(this.Uuid)) + { return "uuid:" + this.Uuid; + } else return _Udn; } @@ -283,7 +287,9 @@ namespace Rssdp } if (wasAdded) + { OnDeviceAdded(device); + } } /// <summary> @@ -314,7 +320,9 @@ namespace Rssdp } if (wasRemoved) + { OnDeviceRemoved(device); + } } /// <summary> @@ -327,7 +335,9 @@ namespace Rssdp { var handlers = this.DeviceAdded; if (handlers != null) + { handlers(this, new DeviceEventArgs(device)); + } } /// <summary> @@ -340,7 +350,9 @@ namespace Rssdp { var handlers = this.DeviceRemoved; if (handlers != null) + { handlers(this, new DeviceEventArgs(device)); + } } } } diff --git a/RSSDP/SsdpDeviceLocator.cs b/RSSDP/SsdpDeviceLocator.cs index a774ee23c..9a31db7a2 100644 --- a/RSSDP/SsdpDeviceLocator.cs +++ b/RSSDP/SsdpDeviceLocator.cs @@ -217,10 +217,12 @@ namespace Rssdp.Infrastructure var handlers = this.DeviceAvailable; if (handlers != null) + { handlers(this, new DeviceAvailableEventArgs(device, isNewDevice) { LocalIpAddress = localIpAddress }); + } } /// <summary> @@ -426,7 +428,9 @@ namespace Rssdp.Infrastructure }; if (NotificationTypeMatchesFilter(deadDevice)) + { OnDeviceUnavailable(deadDevice, false); + } } } } @@ -439,7 +443,9 @@ namespace Rssdp.Infrastructure { message.Headers.TryGetValues(headerName, out values); if (values != null) + { retVal = values.FirstOrDefault(); + } } return retVal; @@ -453,7 +459,9 @@ namespace Rssdp.Infrastructure { message.Headers.TryGetValues(headerName, out values); if (values != null) + { retVal = values.FirstOrDefault(); + } } return retVal; @@ -467,7 +475,9 @@ namespace Rssdp.Infrastructure { request.Headers.TryGetValues(headerName, out values); if (values != null) + { value = values.FirstOrDefault(); + } } Uri retVal; @@ -483,7 +493,9 @@ namespace Rssdp.Infrastructure { response.Headers.TryGetValues(headerName, out values); if (values != null) + { value = values.FirstOrDefault(); + } } Uri retVal; @@ -560,7 +572,9 @@ namespace Rssdp.Infrastructure foreach (var removedDevice in existingDevices) { if (NotificationTypeMatchesFilter(removedDevice)) + { OnDeviceUnavailable(removedDevice, expired); + } } return true; @@ -572,7 +586,9 @@ namespace Rssdp.Infrastructure private TimeSpan SearchTimeToMXValue(TimeSpan searchWaitTime) { if (searchWaitTime.TotalSeconds < 2 || searchWaitTime == TimeSpan.Zero) + { return OneSecond; + } else return searchWaitTime.Subtract(OneSecond); } diff --git a/RSSDP/SsdpDevicePublisher.cs b/RSSDP/SsdpDevicePublisher.cs index 1b64d230d..7c6e87201 100644 --- a/RSSDP/SsdpDevicePublisher.cs +++ b/RSSDP/SsdpDevicePublisher.cs @@ -215,7 +215,9 @@ namespace Rssdp.Infrastructure if (commsServer != null) { if (!commsServer.IsShared) + { commsServer.Dispose(); + } } _RecentSearchRequests = null; @@ -328,7 +330,9 @@ namespace Rssdp.Infrastructure { SendSearchResponse(SsdpConstants.UpnpDeviceTypeRootDevice, device, GetUsn(device.Udn, SsdpConstants.UpnpDeviceTypeRootDevice), endPoint, receivedOnlocalIpAddress, cancellationToken); if (this.SupportPnpRootDevice) + { SendSearchResponse(SsdpConstants.PnpDeviceTypeRootDevice, device, GetUsn(device.Udn, SsdpConstants.PnpDeviceTypeRootDevice), endPoint, receivedOnlocalIpAddress, cancellationToken); + } } SendSearchResponse(device.Udn, device, device.Udn, endPoint, receivedOnlocalIpAddress, cancellationToken); @@ -394,7 +398,9 @@ namespace Rssdp.Infrastructure { var lastRequest = _RecentSearchRequests[newRequest.Key]; if (lastRequest.IsOld()) + { _RecentSearchRequests[newRequest.Key] = newRequest; + } else isDuplicateRequest = true; } @@ -402,7 +408,9 @@ namespace Rssdp.Infrastructure { _RecentSearchRequests.Add(newRequest.Key, newRequest); if (_RecentSearchRequests.Count > 10) + { CleanUpRecentSearchRequestsAsync(); + } } } @@ -462,7 +470,9 @@ namespace Rssdp.Infrastructure { SendAliveNotification(device, SsdpConstants.UpnpDeviceTypeRootDevice, GetUsn(device.Udn, SsdpConstants.UpnpDeviceTypeRootDevice), cancellationToken); if (this.SupportPnpRootDevice) + { SendAliveNotification(device, SsdpConstants.PnpDeviceTypeRootDevice, GetUsn(device.Udn, SsdpConstants.PnpDeviceTypeRootDevice), cancellationToken); + } } SendAliveNotification(device, device.Udn, device.Udn, cancellationToken); @@ -506,7 +516,9 @@ namespace Rssdp.Infrastructure { tasks.Add(SendByeByeNotification(device, SsdpConstants.UpnpDeviceTypeRootDevice, GetUsn(device.Udn, SsdpConstants.UpnpDeviceTypeRootDevice), cancellationToken)); if (this.SupportPnpRootDevice) + { tasks.Add(SendByeByeNotification(device, "pnp:rootdevice", GetUsn(device.Udn, "pnp:rootdevice"), cancellationToken)); + } } tasks.Add(SendByeByeNotification(device, device.Udn, device.Udn, cancellationToken)); @@ -547,20 +559,27 @@ namespace Rssdp.Infrastructure var timer = _RebroadcastAliveNotificationsTimer; _RebroadcastAliveNotificationsTimer = null; if (timer != null) + { timer.Dispose(); + } } private TimeSpan GetMinimumNonZeroCacheLifetime() { - var nonzeroCacheLifetimesQuery = (from device - in _Devices - where device.CacheLifetime != TimeSpan.Zero - select device.CacheLifetime).ToList(); + var nonzeroCacheLifetimesQuery = ( + from device + in _Devices + where device.CacheLifetime != TimeSpan.Zero + select device.CacheLifetime).ToList(); if (nonzeroCacheLifetimesQuery.Any()) + { return nonzeroCacheLifetimesQuery.Min(); + } else + { return TimeSpan.Zero; + } } private string GetFirstHeaderValue(System.Net.Http.Headers.HttpRequestHeaders httpRequestHeaders, string headerName) @@ -568,7 +587,9 @@ namespace Rssdp.Infrastructure string retVal = null; IEnumerable<String> values = null; if (httpRequestHeaders.TryGetValues(headerName, out values) && values != null) + { retVal = values.FirstOrDefault(); + } return retVal; } @@ -588,7 +609,9 @@ namespace Rssdp.Infrastructure { var rootDevice = device as SsdpRootDevice; if (rootDevice != null) + { WriteTrace(text + " " + device.DeviceType + " - " + device.Uuid + " - " + rootDevice.Location); + } else WriteTrace(text + " " + device.DeviceType + " - " + device.Uuid); } -- cgit v1.2.3 From 5bb639a59a9ab4c42804e364c94b34aaca594796 Mon Sep 17 00:00:00 2001 From: telans <telans@protonmail.com> Date: Sat, 20 Jun 2020 21:13:48 +1200 Subject: newlines after braces --- MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs | 11 +++++++++++ MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs | 2 ++ MediaBrowser.Model/Configuration/EncodingOptions.cs | 3 +++ MediaBrowser.Model/Dlna/MediaFormatProfileResolver.cs | 2 ++ RSSDP/DisposableManagedObjectBase.cs | 1 + 5 files changed, 19 insertions(+) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 8da714858..d3fb6a46d 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -2603,6 +2603,7 @@ namespace MediaBrowser.Controller.MediaEncoding { return "-c:v vp8_qsv"; } + break; case "vp9": if (_mediaEncoder.SupportsDecoder("vp9_qsv") && encodingOptions.HardwareDecodingCodecs.Contains("vp9", StringComparer.OrdinalIgnoreCase)) @@ -2610,6 +2611,7 @@ namespace MediaBrowser.Controller.MediaEncoding return (isColorDepth10 && !encodingOptions.EnableDecodingColorDepth10Vp9) ? null : "-c:v vp9_qsv"; } + break; } } @@ -2667,6 +2669,7 @@ namespace MediaBrowser.Controller.MediaEncoding { return "-c:v vp8_cuvid"; } + break; case "vp9": if (_mediaEncoder.SupportsDecoder("vp9_cuvid") && encodingOptions.HardwareDecodingCodecs.Contains("vp9", StringComparer.OrdinalIgnoreCase)) @@ -2674,6 +2677,7 @@ namespace MediaBrowser.Controller.MediaEncoding return (isColorDepth10 && !encodingOptions.EnableDecodingColorDepth10Vp9) ? null : "-c:v vp9_cuvid"; } + break; } } @@ -2818,6 +2822,7 @@ namespace MediaBrowser.Controller.MediaEncoding { return "-c:v h264_opencl"; } + break; case "hevc": case "h265": @@ -2826,30 +2831,35 @@ namespace MediaBrowser.Controller.MediaEncoding return (isColorDepth10 && !encodingOptions.EnableDecodingColorDepth10Hevc) ? null : "-c:v hevc_opencl"; } + break; case "mpeg2video": if (_mediaEncoder.SupportsDecoder("mpeg2_opencl") && encodingOptions.HardwareDecodingCodecs.Contains("mpeg2video", StringComparer.OrdinalIgnoreCase)) { return "-c:v mpeg2_opencl"; } + break; case "mpeg4": if (_mediaEncoder.SupportsDecoder("mpeg4_opencl") && encodingOptions.HardwareDecodingCodecs.Contains("mpeg4", StringComparer.OrdinalIgnoreCase)) { return "-c:v mpeg4_opencl"; } + break; case "vc1": if (_mediaEncoder.SupportsDecoder("vc1_opencl") && encodingOptions.HardwareDecodingCodecs.Contains("vc1", StringComparer.OrdinalIgnoreCase)) { return "-c:v vc1_opencl"; } + break; case "vp8": if (_mediaEncoder.SupportsDecoder("vp8_opencl") && encodingOptions.HardwareDecodingCodecs.Contains("vc1", StringComparer.OrdinalIgnoreCase)) { return "-c:v vp8_opencl"; } + break; case "vp9": if (_mediaEncoder.SupportsDecoder("vp9_opencl") && encodingOptions.HardwareDecodingCodecs.Contains("vc1", StringComparer.OrdinalIgnoreCase)) @@ -2857,6 +2867,7 @@ namespace MediaBrowser.Controller.MediaEncoding return (isColorDepth10 && !encodingOptions.EnableDecodingColorDepth10Vp9) ? null : "-c:v vp9_opencl"; } + break; } } diff --git a/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs b/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs index 630a3dce0..52b486dc7 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs @@ -345,6 +345,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles { return true; } + return false; } @@ -359,6 +360,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles { return count; } + index = text.IndexOf(tag, index + 1); } diff --git a/MediaBrowser.Model/Configuration/EncodingOptions.cs b/MediaBrowser.Model/Configuration/EncodingOptions.cs index a790ec42a..9a30f7e9f 100644 --- a/MediaBrowser.Model/Configuration/EncodingOptions.cs +++ b/MediaBrowser.Model/Configuration/EncodingOptions.cs @@ -36,8 +36,11 @@ namespace MediaBrowser.Model.Configuration public string EncoderPreset { get; set; } public string DeinterlaceMethod { get; set; } + public bool EnableDecodingColorDepth10Hevc { get; set; } + public bool EnableDecodingColorDepth10Vp9 { get; set; } + public bool EnableHardwareEncoding { get; set; } public bool EnableSubtitleExtraction { get; set; } diff --git a/MediaBrowser.Model/Dlna/MediaFormatProfileResolver.cs b/MediaBrowser.Model/Dlna/MediaFormatProfileResolver.cs index df10f8c53..398c5db8c 100644 --- a/MediaBrowser.Model/Dlna/MediaFormatProfileResolver.cs +++ b/MediaBrowser.Model/Dlna/MediaFormatProfileResolver.cs @@ -222,6 +222,7 @@ namespace MediaBrowser.Model.Dlna { return MediaFormatProfile.AVC_MP4_LPCM; } + if (string.IsNullOrEmpty(audioCodec) || string.Equals(audioCodec, "ac3", StringComparison.OrdinalIgnoreCase)) { @@ -267,6 +268,7 @@ namespace MediaBrowser.Model.Dlna { return MediaFormatProfile.MPEG4_P2_MP4_ASP_AAC; } + if (string.Equals(audioCodec, "ac3", StringComparison.OrdinalIgnoreCase) || string.Equals(audioCodec, "mp3", StringComparison.OrdinalIgnoreCase)) { return MediaFormatProfile.MPEG4_P2_MP4_NDSD; diff --git a/RSSDP/DisposableManagedObjectBase.cs b/RSSDP/DisposableManagedObjectBase.cs index 628572b17..66a0c5ec4 100644 --- a/RSSDP/DisposableManagedObjectBase.cs +++ b/RSSDP/DisposableManagedObjectBase.cs @@ -38,6 +38,7 @@ namespace Rssdp.Infrastructure get; private set; } + public string BuildMessage(string header, Dictionary<string, string> values) { var builder = new StringBuilder(); -- cgit v1.2.3 From 6556bec646a28d08267f30640125865cf42240d0 Mon Sep 17 00:00:00 2001 From: telans <telans@protonmail.com> Date: Sat, 20 Jun 2020 21:19:16 +1200 Subject: brace multiline if statements (cont.) --- MediaBrowser.Controller/Entities/BaseItem.cs | 2 ++ .../Probing/ProbeResultNormalizer.cs | 4 ++++ MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs | 14 ++++++++++++++ RSSDP/HttpParserBase.cs | 6 ++++++ RSSDP/HttpRequestParser.cs | 2 ++ RSSDP/SsdpDevice.cs | 2 ++ RSSDP/SsdpDeviceLocator.cs | 2 ++ RSSDP/SsdpDevicePublisher.cs | 4 ++++ 8 files changed, 36 insertions(+) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 8e0e63ff0..bf87c0336 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -2955,7 +2955,9 @@ namespace MediaBrowser.Controller.Entities return ((IHasTrailers)this).LocalTrailerIds.Select(LibraryManager.GetItemById).Where(i => i != null).OrderBy(i => i.SortName); } else + { return Array.Empty<BaseItem>(); + } } public virtual bool IsHD => Height >= 720; diff --git a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs index 190abaa05..3f21c2bd4 100644 --- a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs +++ b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs @@ -1384,14 +1384,18 @@ namespace MediaBrowser.MediaEncoding.Probing description = string.Join(" ", numbers, 1, numbers.Length - 1).Trim(); // Skip the first, concatenate the rest, clean up spaces and save it } else + { throw new Exception(); // Switch to default parsing + } } catch // Default parsing { if (subtitle.Contains(".")) // skip the comment, keep the subtitle description = string.Join(".", subtitle.Split('.'), 1, subtitle.Split('.').Length - 1).Trim(); // skip the first else + { description = subtitle.Trim(); // Clean up whitespaces and save it + } } } } diff --git a/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs b/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs index 52b486dc7..77033c6b4 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs @@ -207,7 +207,9 @@ namespace MediaBrowser.MediaEncoding.Subtitles text = text.Insert(start, "<font face=\"" + fontName + "\"" + extraTags + "><i>"); } else + { text = text.Insert(start, "<font face=\"" + fontName + "\"" + extraTags + ">"); + } int indexOfEndTag = text.IndexOf("{\\fn}", start); if (indexOfEndTag > 0) @@ -215,7 +217,9 @@ namespace MediaBrowser.MediaEncoding.Subtitles text = text.Remove(indexOfEndTag, "{\\fn}".Length).Insert(indexOfEndTag, "</font>"); } else + { text += "</font>"; + } } } @@ -236,7 +240,9 @@ namespace MediaBrowser.MediaEncoding.Subtitles text = text.Insert(start, "<font size=\"" + fontSize + "\"" + extraTags + "><i>"); } else + { text = text.Insert(start, "<font size=\"" + fontSize + "\"" + extraTags + ">"); + } int indexOfEndTag = text.IndexOf("{\\fs}", start); if (indexOfEndTag > 0) @@ -244,7 +250,9 @@ namespace MediaBrowser.MediaEncoding.Subtitles text = text.Remove(indexOfEndTag, "{\\fs}".Length).Insert(indexOfEndTag, "</font>"); } else + { text += "</font>"; + } } } } @@ -272,14 +280,18 @@ namespace MediaBrowser.MediaEncoding.Subtitles text = text.Insert(start, "<font color=\"" + color + "\"" + extraTags + "><i>"); } else + { text = text.Insert(start, "<font color=\"" + color + "\"" + extraTags + ">"); + } int indexOfEndTag = text.IndexOf("{\\c}", start); if (indexOfEndTag > 0) { text = text.Remove(indexOfEndTag, "{\\c}".Length).Insert(indexOfEndTag, "</font>"); } else + { text += "</font>"; + } } } @@ -306,7 +318,9 @@ namespace MediaBrowser.MediaEncoding.Subtitles text = text.Insert(start, "<font color=\"" + color + "\"" + extraTags + "><i>"); } else + { text = text.Insert(start, "<font color=\"" + color + "\"" + extraTags + ">"); + } text += "</font>"; } } diff --git a/RSSDP/HttpParserBase.cs b/RSSDP/HttpParserBase.cs index 00c2b7b45..a40612bc2 100644 --- a/RSSDP/HttpParserBase.cs +++ b/RSSDP/HttpParserBase.cs @@ -140,7 +140,9 @@ namespace Rssdp.Infrastructure lineIndex++; } else + { break; + } } ParseHeader(line, headers, contentHeaders); @@ -184,7 +186,9 @@ namespace Rssdp.Infrastructure } } else + { values.AddRange(segments); + } } return values; @@ -218,7 +222,9 @@ namespace Rssdp.Infrastructure return trimmedSegment.Substring(1, trimmedSegment.Length - 2); } else + { return trimmedSegment; + } } } } diff --git a/RSSDP/HttpRequestParser.cs b/RSSDP/HttpRequestParser.cs index 7fa42f466..4114195a6 100644 --- a/RSSDP/HttpRequestParser.cs +++ b/RSSDP/HttpRequestParser.cs @@ -70,7 +70,9 @@ namespace Rssdp.Infrastructure message.RequestUri = requestUri; } else + { System.Diagnostics.Debug.WriteLine(parts[1]); + } if (parts.Length >= 3) { diff --git a/RSSDP/SsdpDevice.cs b/RSSDP/SsdpDevice.cs index 7030c6ec1..4005d836d 100644 --- a/RSSDP/SsdpDevice.cs +++ b/RSSDP/SsdpDevice.cs @@ -169,7 +169,9 @@ namespace Rssdp return "uuid:" + this.Uuid; } else + { return _Udn; + } } set diff --git a/RSSDP/SsdpDeviceLocator.cs b/RSSDP/SsdpDeviceLocator.cs index 9a31db7a2..38562ce49 100644 --- a/RSSDP/SsdpDeviceLocator.cs +++ b/RSSDP/SsdpDeviceLocator.cs @@ -590,7 +590,9 @@ namespace Rssdp.Infrastructure return OneSecond; } else + { return searchWaitTime.Subtract(OneSecond); + } } private DiscoveredSsdpDevice FindExistingDeviceNotification(IEnumerable<DiscoveredSsdpDevice> devices, string notificationType, string usn) diff --git a/RSSDP/SsdpDevicePublisher.cs b/RSSDP/SsdpDevicePublisher.cs index 7c6e87201..1a8577d8d 100644 --- a/RSSDP/SsdpDevicePublisher.cs +++ b/RSSDP/SsdpDevicePublisher.cs @@ -402,7 +402,9 @@ namespace Rssdp.Infrastructure _RecentSearchRequests[newRequest.Key] = newRequest; } else + { isDuplicateRequest = true; + } } else { @@ -613,7 +615,9 @@ namespace Rssdp.Infrastructure WriteTrace(text + " " + device.DeviceType + " - " + device.Uuid + " - " + rootDevice.Location); } else + { WriteTrace(text + " " + device.DeviceType + " - " + device.Uuid); + } } private void CommsServer_RequestReceived(object sender, RequestReceivedEventArgs e) -- cgit v1.2.3 From 1c78482b480034738516596248955e3e09756dd6 Mon Sep 17 00:00:00 2001 From: David <daullmer@gmail.com> Date: Sat, 20 Jun 2020 18:02:03 +0200 Subject: Use authorization code from api-migration to fix startup wizard --- .../HttpServer/Security/AuthService.cs | 16 ++++ .../HttpServer/Security/AuthorizationContext.cs | 101 ++++++++++++++------- Jellyfin.Api/Auth/CustomAuthenticationHandler.cs | 11 +-- MediaBrowser.Controller/Net/IAuthService.cs | 7 ++ .../Net/IAuthorizationContext.cs | 11 +++ 5 files changed, 108 insertions(+), 38 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/HttpServer/Security/AuthService.cs b/Emby.Server.Implementations/HttpServer/Security/AuthService.cs index 2e6ff65a6..318bc6a24 100644 --- a/Emby.Server.Implementations/HttpServer/Security/AuthService.cs +++ b/Emby.Server.Implementations/HttpServer/Security/AuthService.cs @@ -51,6 +51,22 @@ namespace Emby.Server.Implementations.HttpServer.Security return user; } + public AuthorizationInfo Authenticate(HttpRequest request) + { + var auth = _authorizationContext.GetAuthorizationInfo(request); + if (auth?.User == null) + { + return null; + } + + if (auth.User.HasPermission(PermissionKind.IsDisabled)) + { + throw new SecurityException("User account has been disabled."); + } + + return auth; + } + private User ValidateUser(IRequest request, IAuthenticationAttributes authAttribtues) { // This code is executed before the service diff --git a/Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs b/Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs index bbade00ff..078ce0d8a 100644 --- a/Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs +++ b/Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs @@ -8,6 +8,7 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Net; using MediaBrowser.Controller.Security; using MediaBrowser.Model.Services; +using Microsoft.AspNetCore.Http; using Microsoft.Net.Http.Headers; namespace Emby.Server.Implementations.HttpServer.Security @@ -38,6 +39,14 @@ namespace Emby.Server.Implementations.HttpServer.Security return GetAuthorization(requestContext); } + public AuthorizationInfo GetAuthorizationInfo(HttpRequest requestContext) + { + var auth = GetAuthorizationDictionary(requestContext); + var (authInfo, _) = + GetAuthorizationInfoFromDictionary(auth, requestContext.Headers, requestContext.Query); + return authInfo; + } + /// <summary> /// Gets the authorization. /// </summary> @@ -46,7 +55,23 @@ namespace Emby.Server.Implementations.HttpServer.Security private AuthorizationInfo GetAuthorization(IRequest httpReq) { var auth = GetAuthorizationDictionary(httpReq); + var (authInfo, originalAuthInfo) = + GetAuthorizationInfoFromDictionary(auth, httpReq.Headers, httpReq.QueryString); + + if (originalAuthInfo != null) + { + httpReq.Items["OriginalAuthenticationInfo"] = originalAuthInfo; + } + + httpReq.Items["AuthorizationInfo"] = authInfo; + return authInfo; + } + private (AuthorizationInfo authInfo, AuthenticationInfo originalAuthenticationInfo) GetAuthorizationInfoFromDictionary( + in Dictionary<string, string> auth, + in IHeaderDictionary headers, + in IQueryCollection queryString) + { string deviceId = null; string device = null; string client = null; @@ -64,20 +89,20 @@ namespace Emby.Server.Implementations.HttpServer.Security if (string.IsNullOrEmpty(token)) { - token = httpReq.Headers["X-Emby-Token"]; + token = headers["X-Emby-Token"]; } if (string.IsNullOrEmpty(token)) { - token = httpReq.Headers["X-MediaBrowser-Token"]; + token = headers["X-MediaBrowser-Token"]; } if (string.IsNullOrEmpty(token)) { - token = httpReq.QueryString["api_key"]; + token = queryString["api_key"]; } - var info = new AuthorizationInfo + var authInfo = new AuthorizationInfo { Client = client, Device = device, @@ -86,6 +111,7 @@ namespace Emby.Server.Implementations.HttpServer.Security Token = token }; + AuthenticationInfo originalAuthenticationInfo = null; if (!string.IsNullOrWhiteSpace(token)) { var result = _authRepo.Get(new AuthenticationInfoQuery @@ -93,81 +119,77 @@ namespace Emby.Server.Implementations.HttpServer.Security AccessToken = token }); - var tokenInfo = result.Items.Count > 0 ? result.Items[0] : null; + originalAuthenticationInfo = result.Items.Count > 0 ? result.Items[0] : null; - if (tokenInfo != null) + if (originalAuthenticationInfo != null) { var updateToken = false; // TODO: Remove these checks for IsNullOrWhiteSpace - if (string.IsNullOrWhiteSpace(info.Client)) + if (string.IsNullOrWhiteSpace(authInfo.Client)) { - info.Client = tokenInfo.AppName; + authInfo.Client = originalAuthenticationInfo.AppName; } - if (string.IsNullOrWhiteSpace(info.DeviceId)) + if (string.IsNullOrWhiteSpace(authInfo.DeviceId)) { - info.DeviceId = tokenInfo.DeviceId; + authInfo.DeviceId = originalAuthenticationInfo.DeviceId; } // Temporary. TODO - allow clients to specify that the token has been shared with a casting device - var allowTokenInfoUpdate = info.Client == null || info.Client.IndexOf("chromecast", StringComparison.OrdinalIgnoreCase) == -1; + var allowTokenInfoUpdate = authInfo.Client == null || authInfo.Client.IndexOf("chromecast", StringComparison.OrdinalIgnoreCase) == -1; - if (string.IsNullOrWhiteSpace(info.Device)) + if (string.IsNullOrWhiteSpace(authInfo.Device)) { - info.Device = tokenInfo.DeviceName; + authInfo.Device = originalAuthenticationInfo.DeviceName; } - else if (!string.Equals(info.Device, tokenInfo.DeviceName, StringComparison.OrdinalIgnoreCase)) + else if (!string.Equals(authInfo.Device, originalAuthenticationInfo.DeviceName, StringComparison.OrdinalIgnoreCase)) { if (allowTokenInfoUpdate) { updateToken = true; - tokenInfo.DeviceName = info.Device; + originalAuthenticationInfo.DeviceName = authInfo.Device; } } - if (string.IsNullOrWhiteSpace(info.Version)) + if (string.IsNullOrWhiteSpace(authInfo.Version)) { - info.Version = tokenInfo.AppVersion; + authInfo.Version = originalAuthenticationInfo.AppVersion; } - else if (!string.Equals(info.Version, tokenInfo.AppVersion, StringComparison.OrdinalIgnoreCase)) + else if (!string.Equals(authInfo.Version, originalAuthenticationInfo.AppVersion, StringComparison.OrdinalIgnoreCase)) { if (allowTokenInfoUpdate) { updateToken = true; - tokenInfo.AppVersion = info.Version; + originalAuthenticationInfo.AppVersion = authInfo.Version; } } - if ((DateTime.UtcNow - tokenInfo.DateLastActivity).TotalMinutes > 3) + if ((DateTime.UtcNow - originalAuthenticationInfo.DateLastActivity).TotalMinutes > 3) { - tokenInfo.DateLastActivity = DateTime.UtcNow; + originalAuthenticationInfo.DateLastActivity = DateTime.UtcNow; updateToken = true; } - if (!tokenInfo.UserId.Equals(Guid.Empty)) + if (!originalAuthenticationInfo.UserId.Equals(Guid.Empty)) { - info.User = _userManager.GetUserById(tokenInfo.UserId); + authInfo.User = _userManager.GetUserById(originalAuthenticationInfo.UserId); - if (info.User != null && !string.Equals(info.User.Username, tokenInfo.UserName, StringComparison.OrdinalIgnoreCase)) + if (authInfo.User != null && !string.Equals(authInfo.User.Username, originalAuthenticationInfo.UserName, StringComparison.OrdinalIgnoreCase)) { - tokenInfo.UserName = info.User.Username; + originalAuthenticationInfo.UserName = authInfo.User.Username; updateToken = true; } } if (updateToken) { - _authRepo.Update(tokenInfo); + _authRepo.Update(originalAuthenticationInfo); } } - - httpReq.Items["OriginalAuthenticationInfo"] = tokenInfo; } - httpReq.Items["AuthorizationInfo"] = info; - - return info; + return (authInfo, originalAuthenticationInfo); } /// <summary> @@ -187,6 +209,23 @@ namespace Emby.Server.Implementations.HttpServer.Security return GetAuthorization(auth); } + /// <summary> + /// Gets the auth. + /// </summary> + /// <param name="httpReq">The HTTP req.</param> + /// <returns>Dictionary{System.StringSystem.String}.</returns> + private Dictionary<string, string> GetAuthorizationDictionary(HttpRequest httpReq) + { + var auth = httpReq.Headers["X-Emby-Authorization"]; + + if (string.IsNullOrEmpty(auth)) + { + auth = httpReq.Headers[HeaderNames.Authorization]; + } + + return GetAuthorization(auth); + } + /// <summary> /// Gets the authorization. /// </summary> diff --git a/Jellyfin.Api/Auth/CustomAuthenticationHandler.cs b/Jellyfin.Api/Auth/CustomAuthenticationHandler.cs index 767ba9fd4..f86f75b1c 100644 --- a/Jellyfin.Api/Auth/CustomAuthenticationHandler.cs +++ b/Jellyfin.Api/Auth/CustomAuthenticationHandler.cs @@ -39,21 +39,18 @@ namespace Jellyfin.Api.Auth /// <inheritdoc /> protected override Task<AuthenticateResult> HandleAuthenticateAsync() { - var authenticatedAttribute = new AuthenticatedAttribute(); try { - var user = _authService.Authenticate(Request, authenticatedAttribute); - if (user == null) + var authorizationInfo = _authService.Authenticate(Request); + if (authorizationInfo == null) { return Task.FromResult(AuthenticateResult.Fail("Invalid user")); } var claims = new[] { - new Claim(ClaimTypes.Name, user.Username), - new Claim( - ClaimTypes.Role, - value: user.HasPermission(PermissionKind.IsAdministrator) ? UserRoles.Administrator : UserRoles.User) + new Claim(ClaimTypes.Name, authorizationInfo.User.Username), + new Claim(ClaimTypes.Role, authorizationInfo.User.HasPermission(PermissionKind.IsAdministrator) ? UserRoles.Administrator : UserRoles.User) }; var identity = new ClaimsIdentity(claims, Scheme.Name); var principal = new ClaimsPrincipal(identity); diff --git a/MediaBrowser.Controller/Net/IAuthService.cs b/MediaBrowser.Controller/Net/IAuthService.cs index d8f6d19da..56737dc65 100644 --- a/MediaBrowser.Controller/Net/IAuthService.cs +++ b/MediaBrowser.Controller/Net/IAuthService.cs @@ -11,5 +11,12 @@ namespace MediaBrowser.Controller.Net void Authenticate(IRequest request, IAuthenticationAttributes authAttribtues); User? Authenticate(HttpRequest request, IAuthenticationAttributes authAttribtues); + + /// <summary> + /// Authenticate request. + /// </summary> + /// <param name="request">The request.</param> + /// <returns>Authorization information. Null if unauthenticated.</returns> + AuthorizationInfo Authenticate(HttpRequest request); } } diff --git a/MediaBrowser.Controller/Net/IAuthorizationContext.cs b/MediaBrowser.Controller/Net/IAuthorizationContext.cs index 61598391f..37a7425b9 100644 --- a/MediaBrowser.Controller/Net/IAuthorizationContext.cs +++ b/MediaBrowser.Controller/Net/IAuthorizationContext.cs @@ -1,7 +1,11 @@ using MediaBrowser.Model.Services; +using Microsoft.AspNetCore.Http; namespace MediaBrowser.Controller.Net { + /// <summary> + /// IAuthorization context. + /// </summary> public interface IAuthorizationContext { /// <summary> @@ -17,5 +21,12 @@ namespace MediaBrowser.Controller.Net /// <param name="requestContext">The request context.</param> /// <returns>AuthorizationInfo.</returns> AuthorizationInfo GetAuthorizationInfo(IRequest requestContext); + + /// <summary> + /// Gets the authorization information. + /// </summary> + /// <param name="requestContext">The request context.</param> + /// <returns>AuthorizationInfo.</returns> + AuthorizationInfo GetAuthorizationInfo(HttpRequest requestContext); } } -- cgit v1.2.3 From 1398c2117c8bd20cdab0c5afb5167de3fde4cd08 Mon Sep 17 00:00:00 2001 From: crobibero <cody@robibe.ro> Date: Tue, 23 Jun 2020 07:31:59 -0600 Subject: Revert ILoggerFactory usage in BaseItem.cs --- MediaBrowser.Controller/Entities/BaseItem.cs | 2 -- MediaBrowser.Controller/Entities/UserView.cs | 2 +- MediaBrowser.Controller/Entities/UserViewBuilder.cs | 5 +++-- 3 files changed, 4 insertions(+), 5 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index bf87c0336..25933bc90 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -560,8 +560,6 @@ namespace MediaBrowser.Controller.Entities /// <summary> /// The logger. /// </summary> - public static ILoggerFactory LoggerFactory { get; set; } - public static ILogger<BaseItem> Logger { get; set; } public static ILibraryManager LibraryManager { get; set; } diff --git a/MediaBrowser.Controller/Entities/UserView.cs b/MediaBrowser.Controller/Entities/UserView.cs index ceca77bc0..1fba8a30f 100644 --- a/MediaBrowser.Controller/Entities/UserView.cs +++ b/MediaBrowser.Controller/Entities/UserView.cs @@ -68,7 +68,7 @@ namespace MediaBrowser.Controller.Entities parent = LibraryManager.GetItemById(ParentId) as Folder ?? parent; } - return new UserViewBuilder(UserViewManager, LibraryManager, LoggerFactory.CreateLogger<UserViewBuilder>(), UserDataManager, TVSeriesManager, ConfigurationManager) + return new UserViewBuilder(UserViewManager, LibraryManager, Logger, UserDataManager, TVSeriesManager, ConfigurationManager) .GetUserItems(parent, this, CollectionType, query); } diff --git a/MediaBrowser.Controller/Entities/UserViewBuilder.cs b/MediaBrowser.Controller/Entities/UserViewBuilder.cs index 061e6001c..cb35d6e32 100644 --- a/MediaBrowser.Controller/Entities/UserViewBuilder.cs +++ b/MediaBrowser.Controller/Entities/UserViewBuilder.cs @@ -7,6 +7,7 @@ using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.TV; +using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Querying; using Microsoft.Extensions.Logging; @@ -22,7 +23,7 @@ namespace MediaBrowser.Controller.Entities { private readonly IUserViewManager _userViewManager; private readonly ILibraryManager _libraryManager; - private readonly ILogger<UserViewBuilder> _logger; + private readonly ILogger<BaseItem> _logger; private readonly IUserDataManager _userDataManager; private readonly ITVSeriesManager _tvSeriesManager; private readonly IServerConfigurationManager _config; @@ -30,7 +31,7 @@ namespace MediaBrowser.Controller.Entities public UserViewBuilder( IUserViewManager userViewManager, ILibraryManager libraryManager, - ILogger<UserViewBuilder> logger, + ILogger<BaseItem> logger, IUserDataManager userDataManager, ITVSeriesManager tvSeriesManager, IServerConfigurationManager config) -- cgit v1.2.3 From ef8bec23c4f1ce9b97a155913ed57bc387184e22 Mon Sep 17 00:00:00 2001 From: crobibero <cody@robibe.ro> Date: Wed, 24 Jun 2020 15:09:15 -0600 Subject: revert missing session fields --- Emby.Server.Implementations/Session/SessionManager.cs | 3 ++- MediaBrowser.Controller/Session/SessionInfo.cs | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/Session/SessionManager.cs b/Emby.Server.Implementations/Session/SessionManager.cs index 75fdedd10..d069d1ada 100644 --- a/Emby.Server.Implementations/Session/SessionManager.cs +++ b/Emby.Server.Implementations/Session/SessionManager.cs @@ -502,7 +502,8 @@ namespace Emby.Server.Implementations.Session Client = appName, DeviceId = deviceId, ApplicationVersion = appVersion, - Id = key.GetMD5().ToString("N", CultureInfo.InvariantCulture) + Id = key.GetMD5().ToString("N", CultureInfo.InvariantCulture), + ServerId = _appHost.SystemId }; var username = user?.Username; diff --git a/MediaBrowser.Controller/Session/SessionInfo.cs b/MediaBrowser.Controller/Session/SessionInfo.cs index 36bc11be4..4b088998c 100644 --- a/MediaBrowser.Controller/Session/SessionInfo.cs +++ b/MediaBrowser.Controller/Session/SessionInfo.cs @@ -108,6 +108,12 @@ namespace MediaBrowser.Controller.Session /// <value>The name of the device.</value> public string DeviceName { get; set; } + /// <summary> + /// Gets or sets the type of the device. + /// </summary> + /// <value>The type of the device.</value> + public string DeviceType { get; set; } + /// <summary> /// Gets or sets the now playing item. /// </summary> @@ -215,8 +221,17 @@ namespace MediaBrowser.Controller.Session public string PlaylistItemId { get; set; } + public string ServerId { get; set; } + public string UserPrimaryImageTag { get; set; } + /// <summary> + /// Gets or sets the supported commands. + /// </summary> + /// <value>The supported commands.</value> + public string[] SupportedCommands + => Capabilities == null ? Array.Empty<string>() : Capabilities.SupportedCommands; + public Tuple<ISessionController, bool> EnsureController<T>(Func<SessionInfo, ISessionController> factory) { var controllers = SessionControllers.ToList(); -- cgit v1.2.3 From 9a01cd8590ffcae8ce561e6f733bf59fe54932fa Mon Sep 17 00:00:00 2001 From: Patrick Barron <barronpm@gmail.com> Date: Wed, 24 Jun 2020 20:19:47 -0400 Subject: Fix user deletion. --- Jellyfin.Server.Implementations/Users/UserManager.cs | 19 ++++++++++++++----- MediaBrowser.Api/UserService.cs | 11 ++--------- MediaBrowser.Controller/Library/IUserManager.cs | 4 ++-- 3 files changed, 18 insertions(+), 16 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Jellyfin.Server.Implementations/Users/UserManager.cs b/Jellyfin.Server.Implementations/Users/UserManager.cs index 904114758..d86b25f81 100644 --- a/Jellyfin.Server.Implementations/Users/UserManager.cs +++ b/Jellyfin.Server.Implementations/Users/UserManager.cs @@ -192,15 +192,15 @@ namespace Jellyfin.Server.Implementations.Users } /// <inheritdoc/> - public void DeleteUser(User user) + public void DeleteUser(Guid userId) { + var dbContext = _dbProvider.CreateContext(); + var user = dbContext.Users.Find(userId); if (user == null) { - throw new ArgumentNullException(nameof(user)); + throw new ArgumentNullException(nameof(userId)); } - var dbContext = _dbProvider.CreateContext(); - if (dbContext.Users.Find(user.Id) == null) { throw new ArgumentException(string.Format( @@ -226,9 +226,18 @@ namespace Jellyfin.Server.Implementations.Users CultureInfo.InvariantCulture, "The user '{0}' cannot be deleted because there must be at least one admin user in the system.", user.Username), - nameof(user)); + nameof(userId)); + } + + // Clear all entities related to the user from the database. + if (user.ProfileImage != null) + { + dbContext.Remove(user.ProfileImage); } + dbContext.RemoveRange(user.Permissions); + dbContext.RemoveRange(user.Preferences); + dbContext.RemoveRange(user.AccessSchedules); dbContext.Users.Remove(user); dbContext.SaveChanges(); OnUserDeleted?.Invoke(this, new GenericEventArgs<User>(user)); diff --git a/MediaBrowser.Api/UserService.cs b/MediaBrowser.Api/UserService.cs index 131def554..6e9d788dc 100644 --- a/MediaBrowser.Api/UserService.cs +++ b/MediaBrowser.Api/UserService.cs @@ -365,15 +365,8 @@ namespace MediaBrowser.Api public Task DeleteAsync(DeleteUser request) { - var user = _userManager.GetUserById(request.Id); - - if (user == null) - { - throw new ResourceNotFoundException("User not found"); - } - - _sessionMananger.RevokeUserTokens(user.Id, null); - _userManager.DeleteUser(user); + _userManager.DeleteUser(request.Id); + _sessionMananger.RevokeUserTokens(request.Id, null); return Task.CompletedTask; } diff --git a/MediaBrowser.Controller/Library/IUserManager.cs b/MediaBrowser.Controller/Library/IUserManager.cs index fe3e4f9e6..4ff3cee0f 100644 --- a/MediaBrowser.Controller/Library/IUserManager.cs +++ b/MediaBrowser.Controller/Library/IUserManager.cs @@ -111,8 +111,8 @@ namespace MediaBrowser.Controller.Library /// <summary> /// Deletes the specified user. /// </summary> - /// <param name="user">The user to be deleted.</param> - void DeleteUser(User user); + /// <param name="userId">The if of the user to be deleted.</param> + void DeleteUser(Guid userId); /// <summary> /// Resets the password. -- cgit v1.2.3 From 5ee419ebe4ada7de98f877daa49dfc1755b375ef Mon Sep 17 00:00:00 2001 From: Patrick Barron <barronpm@gmail.com> Date: Wed, 24 Jun 2020 21:07:39 -0400 Subject: Fix typo --- MediaBrowser.Controller/Library/IUserManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/Library/IUserManager.cs b/MediaBrowser.Controller/Library/IUserManager.cs index 4ff3cee0f..e73fe7120 100644 --- a/MediaBrowser.Controller/Library/IUserManager.cs +++ b/MediaBrowser.Controller/Library/IUserManager.cs @@ -111,7 +111,7 @@ namespace MediaBrowser.Controller.Library /// <summary> /// Deletes the specified user. /// </summary> - /// <param name="userId">The if of the user to be deleted.</param> + /// <param name="userId">The id of the user to be deleted.</param> void DeleteUser(Guid userId); /// <summary> -- cgit v1.2.3 From 0f07b19ca5d6433a8574363cfe3c20fbfd285514 Mon Sep 17 00:00:00 2001 From: Claus Vium <clausvium@gmail.com> Date: Thu, 25 Jun 2020 11:33:10 +0200 Subject: Remove AllowIgnorePath --- Emby.Server.Implementations/Library/LibraryManager.cs | 13 ++++++------- MediaBrowser.Controller/Library/ILibraryManager.cs | 4 +--- 2 files changed, 7 insertions(+), 10 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index edb58e910..9b8091aa7 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -514,8 +514,8 @@ namespace Emby.Server.Implementations.Library return key.GetMD5(); } - public BaseItem ResolvePath(FileSystemMetadata fileInfo, Folder parent = null, bool allowIgnorePath = true) - => ResolvePath(fileInfo, new DirectoryService(_fileSystem), null, parent, allowIgnorePath: allowIgnorePath); + public BaseItem ResolvePath(FileSystemMetadata fileInfo, Folder parent = null) + => ResolvePath(fileInfo, new DirectoryService(_fileSystem), null, parent); private BaseItem ResolvePath( FileSystemMetadata fileInfo, @@ -523,8 +523,7 @@ namespace Emby.Server.Implementations.Library IItemResolver[] resolvers, Folder parent = null, string collectionType = null, - LibraryOptions libraryOptions = null, - bool allowIgnorePath = true) + LibraryOptions libraryOptions = null) { if (fileInfo == null) { @@ -548,7 +547,7 @@ namespace Emby.Server.Implementations.Library }; // Return null if ignore rules deem that we should do so - if (allowIgnorePath && IgnoreFile(args.FileInfo, args.Parent)) + if (IgnoreFile(args.FileInfo, args.Parent)) { return null; } @@ -713,7 +712,7 @@ namespace Emby.Server.Implementations.Library Directory.CreateDirectory(rootFolderPath); var rootFolder = GetItemById(GetNewItemId(rootFolderPath, typeof(AggregateFolder))) as AggregateFolder ?? - ((Folder) ResolvePath(_fileSystem.GetDirectoryInfo(rootFolderPath), allowIgnorePath: false)) + ((Folder) ResolvePath(_fileSystem.GetDirectoryInfo(rootFolderPath))) .DeepCopy<Folder, AggregateFolder>(); // In case program data folder was moved @@ -795,7 +794,7 @@ namespace Emby.Server.Implementations.Library if (tmpItem == null) { _logger.LogDebug("Creating new userRootFolder with DeepCopy"); - tmpItem = ((Folder)ResolvePath(_fileSystem.GetDirectoryInfo(userRootPath), allowIgnorePath: false)).DeepCopy<Folder, UserRootFolder>(); + tmpItem = ((Folder)ResolvePath(_fileSystem.GetDirectoryInfo(userRootPath))).DeepCopy<Folder, UserRootFolder>(); } // In case program data folder was moved diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs index 47c080ebd..9d6646857 100644 --- a/MediaBrowser.Controller/Library/ILibraryManager.cs +++ b/MediaBrowser.Controller/Library/ILibraryManager.cs @@ -30,12 +30,10 @@ namespace MediaBrowser.Controller.Library /// </summary> /// <param name="fileInfo">The file information.</param> /// <param name="parent">The parent.</param> - /// <param name="allowIgnorePath">Allow the path to be ignored.</param> /// <returns>BaseItem.</returns> BaseItem ResolvePath( FileSystemMetadata fileInfo, - Folder parent = null, - bool allowIgnorePath = true); + Folder parent = null); /// <summary> /// Resolves a set of files into a list of BaseItem. -- cgit v1.2.3 From 83ae4d074dc9f665c992eefd1cf4ed78eb5a8dd1 Mon Sep 17 00:00:00 2001 From: dkanada <dkanada@users.noreply.github.com> Date: Sat, 27 Jun 2020 00:22:27 +0900 Subject: use constructor to set optimal config values --- .../Collections/CollectionManager.cs | 56 --------------------- .../Configuration/ServerConfigurationManager.cs | 57 ---------------------- Jellyfin.Api/Controllers/StartupController.cs | 1 - .../Configuration/IServerConfigurationManager.cs | 2 - .../Configuration/ServerConfiguration.cs | 6 ++- 5 files changed, 4 insertions(+), 118 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/Collections/CollectionManager.cs b/Emby.Server.Implementations/Collections/CollectionManager.cs index 8fb9520d6..ac2edc1e2 100644 --- a/Emby.Server.Implementations/Collections/CollectionManager.cs +++ b/Emby.Server.Implementations/Collections/CollectionManager.cs @@ -363,60 +363,4 @@ namespace Emby.Server.Implementations.Collections return results.Values; } } - - /// <summary> - /// The collection manager entry point. - /// </summary> - public sealed class CollectionManagerEntryPoint : IServerEntryPoint - { - private readonly CollectionManager _collectionManager; - private readonly IServerConfigurationManager _config; - private readonly ILogger<CollectionManagerEntryPoint> _logger; - - /// <summary> - /// Initializes a new instance of the <see cref="CollectionManagerEntryPoint"/> class. - /// </summary> - /// <param name="collectionManager">The collection manager.</param> - /// <param name="config">The server configuration manager.</param> - /// <param name="logger">The logger.</param> - public CollectionManagerEntryPoint( - ICollectionManager collectionManager, - IServerConfigurationManager config, - ILogger<CollectionManagerEntryPoint> logger) - { - _collectionManager = (CollectionManager)collectionManager; - _config = config; - _logger = logger; - } - - /// <inheritdoc /> - public async Task RunAsync() - { - if (!_config.Configuration.CollectionsUpgraded && _config.Configuration.IsStartupWizardCompleted) - { - var path = _collectionManager.GetCollectionsFolderPath(); - - if (Directory.Exists(path)) - { - try - { - await _collectionManager.EnsureLibraryFolder(path, true).ConfigureAwait(false); - } - catch (Exception ex) - { - _logger.LogError(ex, "Error creating camera uploads library"); - } - - _config.Configuration.CollectionsUpgraded = true; - _config.SaveConfiguration(); - } - } - } - - /// <inheritdoc /> - public void Dispose() - { - // Nothing to dispose - } - } } diff --git a/Emby.Server.Implementations/Configuration/ServerConfigurationManager.cs b/Emby.Server.Implementations/Configuration/ServerConfigurationManager.cs index 94ee1ced7..a15295fca 100644 --- a/Emby.Server.Implementations/Configuration/ServerConfigurationManager.cs +++ b/Emby.Server.Implementations/Configuration/ServerConfigurationManager.cs @@ -109,7 +109,6 @@ namespace Emby.Server.Implementations.Configuration if (!string.IsNullOrWhiteSpace(newPath) && !string.Equals(Configuration.CertificatePath, newPath, StringComparison.Ordinal)) { - // Validate if (!File.Exists(newPath)) { throw new FileNotFoundException( @@ -133,7 +132,6 @@ namespace Emby.Server.Implementations.Configuration if (!string.IsNullOrWhiteSpace(newPath) && !string.Equals(Configuration.MetadataPath, newPath, StringComparison.Ordinal)) { - // Validate if (!Directory.Exists(newPath)) { throw new DirectoryNotFoundException( @@ -146,60 +144,5 @@ namespace Emby.Server.Implementations.Configuration EnsureWriteAccess(newPath); } } - - /// <summary> - /// Sets all configuration values to their optimal values. - /// </summary> - /// <returns>If the configuration changed.</returns> - public bool SetOptimalValues() - { - var config = Configuration; - - var changed = false; - - if (!config.EnableCaseSensitiveItemIds) - { - config.EnableCaseSensitiveItemIds = true; - changed = true; - } - - if (!config.SkipDeserializationForBasicTypes) - { - config.SkipDeserializationForBasicTypes = true; - changed = true; - } - - if (!config.EnableSimpleArtistDetection) - { - config.EnableSimpleArtistDetection = true; - changed = true; - } - - if (!config.EnableNormalizedItemByNameIds) - { - config.EnableNormalizedItemByNameIds = true; - changed = true; - } - - if (!config.DisableLiveTvChannelUserDataName) - { - config.DisableLiveTvChannelUserDataName = true; - changed = true; - } - - if (!config.EnableNewOmdbSupport) - { - config.EnableNewOmdbSupport = true; - changed = true; - } - - if (!config.CollectionsUpgraded) - { - config.CollectionsUpgraded = true; - changed = true; - } - - return changed; - } } } diff --git a/Jellyfin.Api/Controllers/StartupController.cs b/Jellyfin.Api/Controllers/StartupController.cs index 6ec0a4e26..04f134b8b 100644 --- a/Jellyfin.Api/Controllers/StartupController.cs +++ b/Jellyfin.Api/Controllers/StartupController.cs @@ -36,7 +36,6 @@ namespace Jellyfin.Api.Controllers public void CompleteWizard() { _config.Configuration.IsStartupWizardCompleted = true; - _config.SetOptimalValues(); _config.SaveConfiguration(); } diff --git a/MediaBrowser.Controller/Configuration/IServerConfigurationManager.cs b/MediaBrowser.Controller/Configuration/IServerConfigurationManager.cs index a5c5e3bcc..43ad04dba 100644 --- a/MediaBrowser.Controller/Configuration/IServerConfigurationManager.cs +++ b/MediaBrowser.Controller/Configuration/IServerConfigurationManager.cs @@ -19,7 +19,5 @@ namespace MediaBrowser.Controller.Configuration /// </summary> /// <value>The configuration.</value> ServerConfiguration Configuration { get; } - - bool SetOptimalValues(); } } diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs index b87c8fbab..bb4ca34fd 100644 --- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs +++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs @@ -82,8 +82,6 @@ namespace MediaBrowser.Model.Configuration public bool EnableRemoteAccess { get; set; } - public bool CollectionsUpgraded { get; set; } - /// <summary> /// Gets or sets a value indicating whether [enable case sensitive item ids]. /// </summary> @@ -269,6 +267,7 @@ namespace MediaBrowser.Model.Configuration PathSubstitutions = Array.Empty<PathSubstitution>(); IgnoreVirtualInterfaces = false; EnableSimpleArtistDetection = false; + SkipDeserializationForBasicTypes = true; DisplaySpecialsWithinSeasons = true; EnableExternalContentInSuggestions = true; @@ -282,6 +281,9 @@ namespace MediaBrowser.Model.Configuration EnableHttps = false; EnableDashboardResponseCaching = true; EnableCaseSensitiveItemIds = true; + EnableNormalizedItemByNameIds = true; + DisableLiveTvChannelUserDataName = true; + EnableNewOmdbSupport = true; AutoRunWebApp = true; EnableRemoteAccess = true; -- cgit v1.2.3 From 438977350892179d5dc2259316b0fe27ceb1e5da Mon Sep 17 00:00:00 2001 From: Neil Burrows <neil.burrows@nvable.com> Date: Mon, 29 Jun 2020 17:08:20 +0100 Subject: Respect FFMpeg path passed via Environment Variable --- Emby.Server.Implementations/ApplicationHost.cs | 3 +-- Jellyfin.Server/StartupOptions.cs | 5 +++++ MediaBrowser.Controller/Extensions/ConfigurationExtensions.cs | 5 +++++ MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 7 ++++--- 4 files changed, 15 insertions(+), 5 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index 14267b561..8d213ac57 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -568,8 +568,7 @@ namespace Emby.Server.Implementations // TODO: Refactor to eliminate the circular dependency here so that Lazy<T> isn't required // TODO: Add StartupOptions.FFmpegPath to IConfiguration and remove this custom activation serviceCollection.AddTransient(provider => new Lazy<EncodingHelper>(provider.GetRequiredService<EncodingHelper>)); - serviceCollection.AddSingleton<IMediaEncoder>(provider => - ActivatorUtilities.CreateInstance<MediaBrowser.MediaEncoding.Encoder.MediaEncoder>(provider, _startupOptions.FFmpegPath ?? string.Empty)); + serviceCollection.AddSingleton<IMediaEncoder, MediaBrowser.MediaEncoding.Encoder.MediaEncoder>(); // TODO: Refactor to eliminate the circular dependencies here so that Lazy<T> isn't required serviceCollection.AddTransient(provider => new Lazy<ILibraryMonitor>(provider.GetRequiredService<ILibraryMonitor>)); diff --git a/Jellyfin.Server/StartupOptions.cs b/Jellyfin.Server/StartupOptions.cs index a26114e77..41a1430d2 100644 --- a/Jellyfin.Server/StartupOptions.cs +++ b/Jellyfin.Server/StartupOptions.cs @@ -101,6 +101,11 @@ namespace Jellyfin.Server config.Add(UdpServer.AddressOverrideConfigKey, PublishedServerUrl.ToString()); } + if (FFmpegPath != null) + { + config.Add(ConfigurationExtensions.FfmpegPathKey, FFmpegPath); + } + return config; } } diff --git a/MediaBrowser.Controller/Extensions/ConfigurationExtensions.cs b/MediaBrowser.Controller/Extensions/ConfigurationExtensions.cs index c0043c0ef..c2932cc4c 100644 --- a/MediaBrowser.Controller/Extensions/ConfigurationExtensions.cs +++ b/MediaBrowser.Controller/Extensions/ConfigurationExtensions.cs @@ -23,6 +23,11 @@ namespace MediaBrowser.Controller.Extensions /// </summary> public const string FfmpegAnalyzeDurationKey = "FFmpeg:analyzeduration"; + /// <summary> + /// The key for the FFmpeg path option. + /// </summary> + public const string FfmpegPathKey = "ffmpeg"; + /// <summary> /// The key for a setting that indicates whether playlists should allow duplicate entries. /// </summary> diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index 9397a347f..af99f2521 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -21,6 +21,7 @@ using MediaBrowser.Model.MediaInfo; using MediaBrowser.Model.System; using Microsoft.Extensions.Logging; using System.Diagnostics; +using Microsoft.Extensions.Configuration; namespace MediaBrowser.MediaEncoding.Encoder { @@ -46,7 +47,7 @@ namespace MediaBrowser.MediaEncoding.Encoder private readonly object _runningProcessesLock = new object(); private readonly List<ProcessWrapper> _runningProcesses = new List<ProcessWrapper>(); - private string _ffmpegPath; + private string _ffmpegPath = string.Empty; private string _ffprobePath; public MediaEncoder( @@ -55,14 +56,14 @@ namespace MediaBrowser.MediaEncoding.Encoder IFileSystem fileSystem, ILocalizationManager localization, Lazy<EncodingHelper> encodingHelperFactory, - string startupOptionsFFmpegPath) + IConfiguration config) { _logger = logger; _configurationManager = configurationManager; _fileSystem = fileSystem; _localization = localization; _encodingHelperFactory = encodingHelperFactory; - _startupOptionFFmpegPath = startupOptionsFFmpegPath; + _startupOptionFFmpegPath = config.GetValue<string>(Controller.Extensions.ConfigurationExtensions.FfmpegPathKey) ?? ""; } private EncodingHelper EncodingHelper => _encodingHelperFactory.Value; -- cgit v1.2.3 From ce85cea9fa9b2444ead5b5c4857c9e9b56c4eb55 Mon Sep 17 00:00:00 2001 From: nyanmisaka <nst799610810@gmail.com> Date: Sat, 4 Jul 2020 19:21:16 +0800 Subject: solve the green line issue on QSV --- MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index d3fb6a46d..cbfdf2695 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -483,7 +483,7 @@ namespace MediaBrowser.Controller.MediaEncoding { if (isQsvDecoder) { - arg.Append("-hwaccel qsv "); + arg.Append("-hwaccel qsv -init_hw_device qsv=hw "); } // While using SW decoder else @@ -1757,7 +1757,7 @@ namespace MediaBrowser.Controller.MediaEncoding // output dimensions. Output dimensions are guaranteed to be even. var outputWidth = width.Value; var outputHeight = height.Value; - var vaapi_or_qsv = string.Equals(videoEncoder, "h264_qsv", StringComparison.OrdinalIgnoreCase) ? "qsv" : "vaapi"; + var qsv_or_vaapi = string.Equals(videoEncoder, "h264_qsv", StringComparison.OrdinalIgnoreCase); if (!videoWidth.HasValue || outputWidth != videoWidth.Value @@ -1765,17 +1765,19 @@ namespace MediaBrowser.Controller.MediaEncoding || outputHeight != videoHeight.Value) { // Force nv12 pixel format to enable 10-bit to 8-bit colour conversion. + // use vpp_qsv filter to avoid green bar when the fixed output size is requested. filters.Add( string.Format( CultureInfo.InvariantCulture, - "scale_{0}=w={1}:h={2}:format=nv12", - vaapi_or_qsv, + "{0}=w={1}:h={2}:format=nv12", + qsv_or_vaapi ? "vpp_qsv" : "scale_vaapi", outputWidth, outputHeight)); } else { - filters.Add(string.Format(CultureInfo.InvariantCulture, "scale_{0}=format=nv12", vaapi_or_qsv)); + // set w=0:h=0 for vpp_qsv to keep the original dimensions, otherwise it will fail. + filters.Add(string.Format(CultureInfo.InvariantCulture, "{0}format=nv12", qsv_or_vaapi ? "vpp_qsv=w=0:h=0:" : "scale_vaapi=")); } } else if ((videoDecoder ?? string.Empty).IndexOf("cuvid", StringComparison.OrdinalIgnoreCase) != -1 -- cgit v1.2.3 From 6d1b00da648e01a15c0c0384c79d37c824358769 Mon Sep 17 00:00:00 2001 From: Patrick Barron <barronpm@gmail.com> Date: Sat, 4 Jul 2020 11:54:25 -0400 Subject: Use Array.Empty --- Emby.Dlna/Profiles/DefaultProfile.cs | 2 +- Emby.Dlna/Profiles/DenonAvrProfile.cs | 2 +- Emby.Dlna/Profiles/DirectTvProfile.cs | 2 +- Emby.Dlna/Profiles/Foobar2000Profile.cs | 2 +- Emby.Dlna/Profiles/MarantzProfile.cs | 2 +- Emby.Dlna/Profiles/MediaMonkeyProfile.cs | 3 ++- Emby.Dlna/Profiles/SonyBlurayPlayer2013.cs | 3 ++- Emby.Dlna/Profiles/SonyBlurayPlayer2014.cs | 3 ++- Emby.Dlna/Profiles/SonyBlurayPlayer2015.cs | 3 ++- Emby.Dlna/Profiles/SonyBlurayPlayer2016.cs | 3 ++- MediaBrowser.Api/FilterService.cs | 2 +- MediaBrowser.Controller/Entities/BaseItem.cs | 2 +- MediaBrowser.Controller/Entities/Movies/BoxSet.cs | 2 +- MediaBrowser.Controller/Library/TVUtils.cs | 2 +- MediaBrowser.MediaEncoding/BdInfo/BdInfoExaminer.cs | 2 +- MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs | 4 ++-- MediaBrowser.Model/Dlna/MediaFormatProfileResolver.cs | 2 +- MediaBrowser.Model/Dlna/StreamInfo.cs | 12 ++++++------ MediaBrowser.Model/Querying/UpcomingEpisodesQuery.cs | 3 ++- MediaBrowser.Providers/Manager/MetadataService.cs | 4 ++-- 20 files changed, 33 insertions(+), 27 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Dlna/Profiles/DefaultProfile.cs b/Emby.Dlna/Profiles/DefaultProfile.cs index 2347ebd0d..90a23a4a2 100644 --- a/Emby.Dlna/Profiles/DefaultProfile.cs +++ b/Emby.Dlna/Profiles/DefaultProfile.cs @@ -164,7 +164,7 @@ namespace Emby.Dlna.Profiles public void AddXmlRootAttribute(string name, string value) { - var atts = XmlRootAttributes ?? new XmlAttribute[] { }; + var atts = XmlRootAttributes ?? System.Array.Empty<XmlAttribute>(); var list = atts.ToList(); list.Add(new XmlAttribute diff --git a/Emby.Dlna/Profiles/DenonAvrProfile.cs b/Emby.Dlna/Profiles/DenonAvrProfile.cs index 73a87c499..a5ba0f36c 100644 --- a/Emby.Dlna/Profiles/DenonAvrProfile.cs +++ b/Emby.Dlna/Profiles/DenonAvrProfile.cs @@ -28,7 +28,7 @@ namespace Emby.Dlna.Profiles }, }; - ResponseProfiles = new ResponseProfile[] { }; + ResponseProfiles = System.Array.Empty<ResponseProfile>(); } } } diff --git a/Emby.Dlna/Profiles/DirectTvProfile.cs b/Emby.Dlna/Profiles/DirectTvProfile.cs index 5ca388167..f6f98b07d 100644 --- a/Emby.Dlna/Profiles/DirectTvProfile.cs +++ b/Emby.Dlna/Profiles/DirectTvProfile.cs @@ -123,7 +123,7 @@ namespace Emby.Dlna.Profiles } }; - ResponseProfiles = new ResponseProfile[] { }; + ResponseProfiles = System.Array.Empty<ResponseProfile>(); } } } diff --git a/Emby.Dlna/Profiles/Foobar2000Profile.cs b/Emby.Dlna/Profiles/Foobar2000Profile.cs index ea3de686a..68e959770 100644 --- a/Emby.Dlna/Profiles/Foobar2000Profile.cs +++ b/Emby.Dlna/Profiles/Foobar2000Profile.cs @@ -72,7 +72,7 @@ namespace Emby.Dlna.Profiles } }; - ResponseProfiles = new ResponseProfile[] { }; + ResponseProfiles = System.Array.Empty<ResponseProfile>(); } } } diff --git a/Emby.Dlna/Profiles/MarantzProfile.cs b/Emby.Dlna/Profiles/MarantzProfile.cs index 6cfcc3b82..24078ab29 100644 --- a/Emby.Dlna/Profiles/MarantzProfile.cs +++ b/Emby.Dlna/Profiles/MarantzProfile.cs @@ -37,7 +37,7 @@ namespace Emby.Dlna.Profiles }, }; - ResponseProfiles = new ResponseProfile[] { }; + ResponseProfiles = System.Array.Empty<ResponseProfile>(); } } } diff --git a/Emby.Dlna/Profiles/MediaMonkeyProfile.cs b/Emby.Dlna/Profiles/MediaMonkeyProfile.cs index 7161af738..28d639b6d 100644 --- a/Emby.Dlna/Profiles/MediaMonkeyProfile.cs +++ b/Emby.Dlna/Profiles/MediaMonkeyProfile.cs @@ -1,5 +1,6 @@ #pragma warning disable CS1591 +using System; using MediaBrowser.Model.Dlna; namespace Emby.Dlna.Profiles @@ -37,7 +38,7 @@ namespace Emby.Dlna.Profiles } }; - ResponseProfiles = new ResponseProfile[] { }; + ResponseProfiles = Array.Empty<ResponseProfile>(); } } } diff --git a/Emby.Dlna/Profiles/SonyBlurayPlayer2013.cs b/Emby.Dlna/Profiles/SonyBlurayPlayer2013.cs index 42b066d52..238fe9f6b 100644 --- a/Emby.Dlna/Profiles/SonyBlurayPlayer2013.cs +++ b/Emby.Dlna/Profiles/SonyBlurayPlayer2013.cs @@ -1,5 +1,6 @@ #pragma warning disable CS1591 +using System; using MediaBrowser.Model.Dlna; namespace Emby.Dlna.Profiles @@ -223,7 +224,7 @@ namespace Emby.Dlna.Profiles } }; - ResponseProfiles = new ResponseProfile[] { }; + ResponseProfiles = Array.Empty<ResponseProfile>(); } } } diff --git a/Emby.Dlna/Profiles/SonyBlurayPlayer2014.cs b/Emby.Dlna/Profiles/SonyBlurayPlayer2014.cs index fbdf2c18e..812a48151 100644 --- a/Emby.Dlna/Profiles/SonyBlurayPlayer2014.cs +++ b/Emby.Dlna/Profiles/SonyBlurayPlayer2014.cs @@ -1,5 +1,6 @@ #pragma warning disable CS1591 +using System; using MediaBrowser.Model.Dlna; namespace Emby.Dlna.Profiles @@ -223,7 +224,7 @@ namespace Emby.Dlna.Profiles } }; - ResponseProfiles = new ResponseProfile[] { }; + ResponseProfiles = Array.Empty<ResponseProfile>(); } } } diff --git a/Emby.Dlna/Profiles/SonyBlurayPlayer2015.cs b/Emby.Dlna/Profiles/SonyBlurayPlayer2015.cs index ce32179a1..6bfff322e 100644 --- a/Emby.Dlna/Profiles/SonyBlurayPlayer2015.cs +++ b/Emby.Dlna/Profiles/SonyBlurayPlayer2015.cs @@ -1,5 +1,6 @@ #pragma warning disable CS1591 +using System; using MediaBrowser.Model.Dlna; namespace Emby.Dlna.Profiles @@ -211,7 +212,7 @@ namespace Emby.Dlna.Profiles } }; - ResponseProfiles = new ResponseProfile[] { }; + ResponseProfiles = Array.Empty<ResponseProfile>(); } } } diff --git a/Emby.Dlna/Profiles/SonyBlurayPlayer2016.cs b/Emby.Dlna/Profiles/SonyBlurayPlayer2016.cs index aa1721d39..ec2529574 100644 --- a/Emby.Dlna/Profiles/SonyBlurayPlayer2016.cs +++ b/Emby.Dlna/Profiles/SonyBlurayPlayer2016.cs @@ -1,5 +1,6 @@ #pragma warning disable CS1591 +using System; using MediaBrowser.Model.Dlna; namespace Emby.Dlna.Profiles @@ -211,7 +212,7 @@ namespace Emby.Dlna.Profiles } }; - ResponseProfiles = new ResponseProfile[] { }; + ResponseProfiles = Array.Empty<ResponseProfile>(); } } } diff --git a/MediaBrowser.Api/FilterService.cs b/MediaBrowser.Api/FilterService.cs index 1b736c77d..dcfdcbfed 100644 --- a/MediaBrowser.Api/FilterService.cs +++ b/MediaBrowser.Api/FilterService.cs @@ -125,7 +125,7 @@ namespace MediaBrowser.Api IncludeItemTypes = request.GetIncludeItemTypes(), DtoOptions = new Controller.Dto.DtoOptions { - Fields = new ItemFields[] { }, + Fields = Array.Empty<ItemFields>(), EnableImages = false, EnableUserData = false }, diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 25933bc90..90f62e153 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -613,7 +613,7 @@ namespace MediaBrowser.Controller.Entities { if (!IsFileProtocol) { - return new string[] { }; + return Array.Empty<string>(); } return new[] { Path }; diff --git a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs index 70c48b6f1..c131c5430 100644 --- a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs +++ b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs @@ -198,7 +198,7 @@ namespace MediaBrowser.Controller.Entities.Movies public Guid[] GetLibraryFolderIds() { - var expandedFolders = new List<Guid>() { }; + var expandedFolders = new List<Guid>(); return FlattenItems(this, expandedFolders) .SelectMany(i => LibraryManager.GetCollectionFolders(i)) diff --git a/MediaBrowser.Controller/Library/TVUtils.cs b/MediaBrowser.Controller/Library/TVUtils.cs index fc9b3f1c6..a3aa6019e 100644 --- a/MediaBrowser.Controller/Library/TVUtils.cs +++ b/MediaBrowser.Controller/Library/TVUtils.cs @@ -38,7 +38,7 @@ namespace MediaBrowser.Controller.Library }; } - return new DayOfWeek[] { }; + return Array.Empty<DayOfWeek>(); } return null; diff --git a/MediaBrowser.MediaEncoding/BdInfo/BdInfoExaminer.cs b/MediaBrowser.MediaEncoding/BdInfo/BdInfoExaminer.cs index e6359f4fb..ccfae2fa5 100644 --- a/MediaBrowser.MediaEncoding/BdInfo/BdInfoExaminer.cs +++ b/MediaBrowser.MediaEncoding/BdInfo/BdInfoExaminer.cs @@ -41,7 +41,7 @@ namespace MediaBrowser.MediaEncoding.BdInfo var outputStream = new BlurayDiscInfo { - MediaStreams = new MediaStream[] { } + MediaStreams = Array.Empty<MediaStream>() }; if (playlist == null) diff --git a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs index 3f21c2bd4..c85d963ed 100644 --- a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs +++ b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs @@ -1008,7 +1008,7 @@ namespace MediaBrowser.MediaEncoding.Probing var artist = FFProbeHelpers.GetDictionaryValue(tags, "artist"); if (string.IsNullOrWhiteSpace(artist)) { - audio.Artists = new string[] { }; + audio.Artists = Array.Empty<string>(); } else { @@ -1031,7 +1031,7 @@ namespace MediaBrowser.MediaEncoding.Probing if (string.IsNullOrWhiteSpace(albumArtist)) { - audio.AlbumArtists = new string[] { }; + audio.AlbumArtists = Array.Empty<string>(); } else { diff --git a/MediaBrowser.Model/Dlna/MediaFormatProfileResolver.cs b/MediaBrowser.Model/Dlna/MediaFormatProfileResolver.cs index 398c5db8c..bdc5f8bb7 100644 --- a/MediaBrowser.Model/Dlna/MediaFormatProfileResolver.cs +++ b/MediaBrowser.Model/Dlna/MediaFormatProfileResolver.cs @@ -206,7 +206,7 @@ namespace MediaBrowser.Model.Dlna } } - return new MediaFormatProfile[] { }; + return Array.Empty<MediaFormatProfile>(); } private MediaFormatProfile ValueOf(string value) diff --git a/MediaBrowser.Model/Dlna/StreamInfo.cs b/MediaBrowser.Model/Dlna/StreamInfo.cs index b89e9ce90..8d7554e88 100644 --- a/MediaBrowser.Model/Dlna/StreamInfo.cs +++ b/MediaBrowser.Model/Dlna/StreamInfo.cs @@ -813,18 +813,18 @@ namespace MediaBrowser.Model.Dlna { var stream = TargetAudioStream; - string inputCodec = stream == null ? null : stream.Codec; + string inputCodec = stream?.Codec; if (IsDirectStream) { - return string.IsNullOrEmpty(inputCodec) ? new string[] { } : new[] { inputCodec }; + return string.IsNullOrEmpty(inputCodec) ? Array.Empty<string>() : new[] { inputCodec }; } foreach (string codec in AudioCodecs) { if (string.Equals(codec, inputCodec, StringComparison.OrdinalIgnoreCase)) { - return string.IsNullOrEmpty(codec) ? new string[] { } : new[] { codec }; + return string.IsNullOrEmpty(codec) ? Array.Empty<string>() : new[] { codec }; } } @@ -838,18 +838,18 @@ namespace MediaBrowser.Model.Dlna { var stream = TargetVideoStream; - string inputCodec = stream == null ? null : stream.Codec; + string inputCodec = stream?.Codec; if (IsDirectStream) { - return string.IsNullOrEmpty(inputCodec) ? new string[] { } : new[] { inputCodec }; + return string.IsNullOrEmpty(inputCodec) ? Array.Empty<string>() : new[] { inputCodec }; } foreach (string codec in VideoCodecs) { if (string.Equals(codec, inputCodec, StringComparison.OrdinalIgnoreCase)) { - return string.IsNullOrEmpty(codec) ? new string[] { } : new[] { codec }; + return string.IsNullOrEmpty(codec) ? Array.Empty<string>() : new[] { codec }; } } diff --git a/MediaBrowser.Model/Querying/UpcomingEpisodesQuery.cs b/MediaBrowser.Model/Querying/UpcomingEpisodesQuery.cs index 12d537492..2ef6f7c60 100644 --- a/MediaBrowser.Model/Querying/UpcomingEpisodesQuery.cs +++ b/MediaBrowser.Model/Querying/UpcomingEpisodesQuery.cs @@ -1,6 +1,7 @@ #nullable disable #pragma warning disable CS1591 +using System; using MediaBrowser.Model.Entities; namespace MediaBrowser.Model.Querying @@ -54,7 +55,7 @@ namespace MediaBrowser.Model.Querying public UpcomingEpisodesQuery() { - EnableImageTypes = new ImageType[] { }; + EnableImageTypes = Array.Empty<ImageType>(); } } } diff --git a/MediaBrowser.Providers/Manager/MetadataService.cs b/MediaBrowser.Providers/Manager/MetadataService.cs index ecfa3d46d..3b0c7b56c 100644 --- a/MediaBrowser.Providers/Manager/MetadataService.cs +++ b/MediaBrowser.Providers/Manager/MetadataService.cs @@ -723,7 +723,7 @@ namespace MediaBrowser.Providers.Manager userDataList.AddRange(localItem.UserDataList); } - MergeData(localItem, temp, new MetadataField[] { }, !options.ReplaceAllMetadata, true); + MergeData(localItem, temp, Array.Empty<MetadataField>(), !options.ReplaceAllMetadata, true); refreshResult.UpdateType = refreshResult.UpdateType | ItemUpdateType.MetadataImport; // Only one local provider allowed per item @@ -849,7 +849,7 @@ namespace MediaBrowser.Providers.Manager { result.Provider = provider.Name; - MergeData(result, temp, new MetadataField[] { }, false, false); + MergeData(result, temp, Array.Empty<MetadataField>(), false, false); MergeNewData(temp.Item, id); refreshResult.UpdateType = refreshResult.UpdateType | ItemUpdateType.MetadataDownload; -- cgit v1.2.3 From 5e706ba7cee116ecd7a99fccfebec5fc275a8993 Mon Sep 17 00:00:00 2001 From: dkanada <dkanada@users.noreply.github.com> Date: Mon, 13 Jul 2020 06:55:03 +0900 Subject: keep playstate during syncplay group creation --- .../SyncPlay/SyncPlayController.cs | 32 ++++++++++------------ .../SyncPlay/SyncPlayManager.cs | 10 ++++--- MediaBrowser.Api/SyncPlay/SyncPlayService.cs | 25 +++-------------- MediaBrowser.Controller/SyncPlay/GroupInfo.cs | 22 +++++++-------- MediaBrowser.Controller/SyncPlay/GroupMember.cs | 2 +- .../SyncPlay/ISyncPlayController.cs | 2 +- MediaBrowser.Model/SyncPlay/JoinGroupRequest.cs | 6 ---- MediaBrowser.Model/SyncPlay/PlaybackRequestType.cs | 6 ++-- 8 files changed, 41 insertions(+), 64 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/SyncPlay/SyncPlayController.cs b/Emby.Server.Implementations/SyncPlay/SyncPlayController.cs index b1f8fd330..e596d9900 100644 --- a/Emby.Server.Implementations/SyncPlay/SyncPlayController.cs +++ b/Emby.Server.Implementations/SyncPlay/SyncPlayController.cs @@ -194,26 +194,24 @@ namespace Emby.Server.Implementations.SyncPlay } /// <inheritdoc /> - public void InitGroup(SessionInfo session, CancellationToken cancellationToken) + public void CreateGroup(SessionInfo session, CancellationToken cancellationToken) { _group.AddSession(session); _syncPlayManager.AddSessionToGroup(session, this); _group.PlayingItem = session.FullNowPlayingItem; - _group.IsPaused = true; + _group.IsPaused = session.PlayState.IsPaused; _group.PositionTicks = session.PlayState.PositionTicks ?? 0; _group.LastActivity = DateTime.UtcNow; var updateSession = NewSyncPlayGroupUpdate(GroupUpdateType.GroupJoined, DateToUTCString(DateTime.UtcNow)); SendGroupUpdate(session, BroadcastType.CurrentSession, updateSession, cancellationToken); - var pauseCommand = NewSyncPlayCommand(SendCommandType.Pause); - SendCommand(session, BroadcastType.CurrentSession, pauseCommand, cancellationToken); } /// <inheritdoc /> public void SessionJoin(SessionInfo session, JoinGroupRequest request, CancellationToken cancellationToken) { - if (session.NowPlayingItem?.Id == _group.PlayingItem.Id && request.PlayingItemId == _group.PlayingItem.Id) + if (session.NowPlayingItem?.Id == _group.PlayingItem.Id) { _group.AddSession(session); _syncPlayManager.AddSessionToGroup(session, this); @@ -224,7 +222,7 @@ namespace Emby.Server.Implementations.SyncPlay var updateOthers = NewSyncPlayGroupUpdate(GroupUpdateType.UserJoined, session.UserName); SendGroupUpdate(session, BroadcastType.AllExceptCurrentSession, updateOthers, cancellationToken); - // Client join and play, syncing will happen client side + // syncing will happen client side if (!_group.IsPaused) { var playCommand = NewSyncPlayCommand(SendCommandType.Play); @@ -262,10 +260,9 @@ namespace Emby.Server.Implementations.SyncPlay /// <inheritdoc /> public void HandleRequest(SessionInfo session, PlaybackRequest request, CancellationToken cancellationToken) { - // The server's job is to mantain a consistent state to which clients refer to, - // as also to notify clients of state changes. - // The actual syncing of media playback happens client side. - // Clients are aware of the server's time and use it to sync. + // The server's job is to maintain a consistent state for clients to reference + // and notify clients of state changes. The actual syncing of media playback + // happens client side. Clients are aware of the server's time and use it to sync. switch (request.Type) { case PlaybackRequestType.Play: @@ -277,13 +274,13 @@ namespace Emby.Server.Implementations.SyncPlay case PlaybackRequestType.Seek: HandleSeekRequest(session, request, cancellationToken); break; - case PlaybackRequestType.Buffering: + case PlaybackRequestType.Buffer: HandleBufferingRequest(session, request, cancellationToken); break; - case PlaybackRequestType.BufferingDone: + case PlaybackRequestType.Ready: HandleBufferingDoneRequest(session, request, cancellationToken); break; - case PlaybackRequestType.UpdatePing: + case PlaybackRequestType.Ping: HandlePingUpdateRequest(session, request); break; } @@ -301,7 +298,7 @@ namespace Emby.Server.Implementations.SyncPlay { // Pick a suitable time that accounts for latency var delay = _group.GetHighestPing() * 2; - delay = delay < _group.DefaulPing ? _group.DefaulPing : delay; + delay = delay < _group.DefaultPing ? _group.DefaultPing : delay; // Unpause group and set starting point in future // Clients will start playback at LastActivity (datetime) from PositionTicks (playback position) @@ -337,8 +334,9 @@ namespace Emby.Server.Implementations.SyncPlay var currentTime = DateTime.UtcNow; var elapsedTime = currentTime - _group.LastActivity; _group.LastActivity = currentTime; + // Seek only if playback actually started - // (a pause request may be issued during the delay added to account for latency) + // Pause request may be issued during the delay added to account for latency _group.PositionTicks += elapsedTime.Ticks > 0 ? elapsedTime.Ticks : 0; var command = NewSyncPlayCommand(SendCommandType.Pause); @@ -451,7 +449,7 @@ namespace Emby.Server.Implementations.SyncPlay { // Client, that was buffering, resumed playback but did not update others in time delay = _group.GetHighestPing() * 2; - delay = delay < _group.DefaulPing ? _group.DefaulPing : delay; + delay = delay < _group.DefaultPing ? _group.DefaultPing : delay; _group.LastActivity = currentTime.AddMilliseconds( delay); @@ -495,7 +493,7 @@ namespace Emby.Server.Implementations.SyncPlay private void HandlePingUpdateRequest(SessionInfo session, PlaybackRequest request) { // Collected pings are used to account for network latency when unpausing playback - _group.UpdatePing(session, request.Ping ?? _group.DefaulPing); + _group.UpdatePing(session, request.Ping ?? _group.DefaultPing); } /// <inheritdoc /> diff --git a/Emby.Server.Implementations/SyncPlay/SyncPlayManager.cs b/Emby.Server.Implementations/SyncPlay/SyncPlayManager.cs index 45a43fd78..966ed5024 100644 --- a/Emby.Server.Implementations/SyncPlay/SyncPlayManager.cs +++ b/Emby.Server.Implementations/SyncPlay/SyncPlayManager.cs @@ -170,10 +170,11 @@ namespace Emby.Server.Implementations.SyncPlay { _logger.LogWarning("NewGroup: {0} does not have permission to create groups.", session.Id); - var error = new GroupUpdate<string>() + var error = new GroupUpdate<string> { Type = GroupUpdateType.CreateGroupDenied }; + _sessionManager.SendSyncPlayGroupUpdate(session.Id, error, CancellationToken.None); return; } @@ -188,7 +189,7 @@ namespace Emby.Server.Implementations.SyncPlay var group = new SyncPlayController(_sessionManager, this); _groups[group.GetGroupId()] = group; - group.InitGroup(session, cancellationToken); + group.CreateGroup(session, cancellationToken); } } @@ -205,6 +206,7 @@ namespace Emby.Server.Implementations.SyncPlay { Type = GroupUpdateType.JoinGroupDenied }; + _sessionManager.SendSyncPlayGroupUpdate(session.Id, error, CancellationToken.None); return; } @@ -300,9 +302,9 @@ namespace Emby.Server.Implementations.SyncPlay group => group.GetPlayingItemId().Equals(filterItemId) && HasAccessToItem(user, group.GetPlayingItemId())).Select( group => group.GetInfo()).ToList(); } - // Otherwise show all available groups else { + // Otherwise show all available groups return _groups.Values.Where( group => HasAccessToItem(user, group.GetPlayingItemId())).Select( group => group.GetInfo()).ToList(); @@ -322,6 +324,7 @@ namespace Emby.Server.Implementations.SyncPlay { Type = GroupUpdateType.JoinGroupDenied }; + _sessionManager.SendSyncPlayGroupUpdate(session.Id, error, CancellationToken.None); return; } @@ -366,7 +369,6 @@ namespace Emby.Server.Implementations.SyncPlay } _sessionToGroupMap.Remove(session.Id, out var tempGroup); - if (!tempGroup.GetGroupId().Equals(group.GetGroupId())) { throw new InvalidOperationException("Session was in wrong group!"); diff --git a/MediaBrowser.Api/SyncPlay/SyncPlayService.cs b/MediaBrowser.Api/SyncPlay/SyncPlayService.cs index 18983ea5b..daa1b521f 100644 --- a/MediaBrowser.Api/SyncPlay/SyncPlayService.cs +++ b/MediaBrowser.Api/SyncPlay/SyncPlayService.cs @@ -27,13 +27,6 @@ namespace MediaBrowser.Api.SyncPlay /// <value>The Group id to join.</value> [ApiMember(Name = "GroupId", Description = "Group Id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")] public string GroupId { get; set; } - - /// <summary> - /// Gets or sets the playing item id. - /// </summary> - /// <value>The client's currently playing item id.</value> - [ApiMember(Name = "PlayingItemId", Description = "Client's playing item id", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")] - public string PlayingItemId { get; set; } } [Route("/SyncPlay/Leave", "POST", Summary = "Leave joined SyncPlay group")] @@ -89,7 +82,7 @@ namespace MediaBrowser.Api.SyncPlay public long PositionTicks { get; set; } /// <summary> - /// Gets or sets whether this is a buffering or a buffering-done request. + /// Gets or sets whether this is a buffering or a ready request. /// </summary> /// <value><c>true</c> if buffering is complete; <c>false</c> otherwise.</value> [ApiMember(Name = "BufferingDone", IsRequired = true, DataType = "bool", ParameterType = "query", Verb = "POST")] @@ -150,25 +143,15 @@ namespace MediaBrowser.Api.SyncPlay var currentSession = GetSession(_sessionContext); Guid groupId; - Guid playingItemId = Guid.Empty; - if (!Guid.TryParse(request.GroupId, out groupId)) { Logger.LogError("JoinGroup: {0} is not a valid format for GroupId. Ignoring request.", request.GroupId); return; } - // Both null and empty strings mean that client isn't playing anything - if (!string.IsNullOrEmpty(request.PlayingItemId) && !Guid.TryParse(request.PlayingItemId, out playingItemId)) - { - Logger.LogError("JoinGroup: {0} is not a valid format for PlayingItemId. Ignoring request.", request.PlayingItemId); - return; - } - var joinRequest = new JoinGroupRequest() { - GroupId = groupId, - PlayingItemId = playingItemId + GroupId = groupId }; _syncPlayManager.JoinGroup(currentSession, groupId, joinRequest, CancellationToken.None); @@ -254,7 +237,7 @@ namespace MediaBrowser.Api.SyncPlay var currentSession = GetSession(_sessionContext); var syncPlayRequest = new PlaybackRequest() { - Type = request.BufferingDone ? PlaybackRequestType.BufferingDone : PlaybackRequestType.Buffering, + Type = request.BufferingDone ? PlaybackRequestType.Ready : PlaybackRequestType.Buffer, When = DateTime.Parse(request.When), PositionTicks = request.PositionTicks }; @@ -270,7 +253,7 @@ namespace MediaBrowser.Api.SyncPlay var currentSession = GetSession(_sessionContext); var syncPlayRequest = new PlaybackRequest() { - Type = PlaybackRequestType.UpdatePing, + Type = PlaybackRequestType.Ping, Ping = Convert.ToInt64(request.Ping) }; _syncPlayManager.HandleRequest(currentSession, syncPlayRequest, CancellationToken.None); diff --git a/MediaBrowser.Controller/SyncPlay/GroupInfo.cs b/MediaBrowser.Controller/SyncPlay/GroupInfo.cs index d0fac1efa..e742df517 100644 --- a/MediaBrowser.Controller/SyncPlay/GroupInfo.cs +++ b/MediaBrowser.Controller/SyncPlay/GroupInfo.cs @@ -16,7 +16,7 @@ namespace MediaBrowser.Controller.SyncPlay /// <summary> /// Gets the default ping value used for sessions. /// </summary> - public long DefaulPing { get; } = 500; + public long DefaultPing { get; } = 500; /// <summary> /// Gets or sets the group identifier. @@ -70,16 +70,16 @@ namespace MediaBrowser.Controller.SyncPlay /// <param name="session">The session.</param> public void AddSession(SessionInfo session) { - if (ContainsSession(session.Id.ToString())) + if (ContainsSession(session.Id)) { return; } var member = new GroupMember(); member.Session = session; - member.Ping = DefaulPing; + member.Ping = DefaultPing; member.IsBuffering = false; - Participants[session.Id.ToString()] = member; + Participants[session.Id] = member; } /// <summary> @@ -88,12 +88,12 @@ namespace MediaBrowser.Controller.SyncPlay /// <param name="session">The session.</param> public void RemoveSession(SessionInfo session) { - if (!ContainsSession(session.Id.ToString())) + if (!ContainsSession(session.Id)) { return; } - Participants.Remove(session.Id.ToString(), out _); + Participants.Remove(session.Id, out _); } /// <summary> @@ -103,12 +103,12 @@ namespace MediaBrowser.Controller.SyncPlay /// <param name="ping">The ping.</param> public void UpdatePing(SessionInfo session, long ping) { - if (!ContainsSession(session.Id.ToString())) + if (!ContainsSession(session.Id)) { return; } - Participants[session.Id.ToString()].Ping = ping; + Participants[session.Id].Ping = ping; } /// <summary> @@ -117,7 +117,7 @@ namespace MediaBrowser.Controller.SyncPlay /// <value name="session">The highest ping in the group.</value> public long GetHighestPing() { - long max = Int64.MinValue; + long max = long.MinValue; foreach (var session in Participants.Values) { max = Math.Max(max, session.Ping); @@ -133,12 +133,12 @@ namespace MediaBrowser.Controller.SyncPlay /// <param name="isBuffering">The state.</param> public void SetBuffering(SessionInfo session, bool isBuffering) { - if (!ContainsSession(session.Id.ToString())) + if (!ContainsSession(session.Id)) { return; } - Participants[session.Id.ToString()].IsBuffering = isBuffering; + Participants[session.Id].IsBuffering = isBuffering; } /// <summary> diff --git a/MediaBrowser.Controller/SyncPlay/GroupMember.cs b/MediaBrowser.Controller/SyncPlay/GroupMember.cs index a3975c334..cde6f8e8c 100644 --- a/MediaBrowser.Controller/SyncPlay/GroupMember.cs +++ b/MediaBrowser.Controller/SyncPlay/GroupMember.cs @@ -8,7 +8,7 @@ namespace MediaBrowser.Controller.SyncPlay public class GroupMember { /// <summary> - /// Gets or sets whether this member is buffering. + /// Gets or sets a value indicating whether this member is buffering. /// </summary> /// <value><c>true</c> if member is buffering; <c>false</c> otherwise.</value> public bool IsBuffering { get; set; } diff --git a/MediaBrowser.Controller/SyncPlay/ISyncPlayController.cs b/MediaBrowser.Controller/SyncPlay/ISyncPlayController.cs index de1fcd259..45c543806 100644 --- a/MediaBrowser.Controller/SyncPlay/ISyncPlayController.cs +++ b/MediaBrowser.Controller/SyncPlay/ISyncPlayController.cs @@ -33,7 +33,7 @@ namespace MediaBrowser.Controller.SyncPlay /// </summary> /// <param name="session">The session.</param> /// <param name="cancellationToken">The cancellation token.</param> - void InitGroup(SessionInfo session, CancellationToken cancellationToken); + void CreateGroup(SessionInfo session, CancellationToken cancellationToken); /// <summary> /// Adds the session to the group. diff --git a/MediaBrowser.Model/SyncPlay/JoinGroupRequest.cs b/MediaBrowser.Model/SyncPlay/JoinGroupRequest.cs index d67b6bd55..0c77a6132 100644 --- a/MediaBrowser.Model/SyncPlay/JoinGroupRequest.cs +++ b/MediaBrowser.Model/SyncPlay/JoinGroupRequest.cs @@ -12,11 +12,5 @@ namespace MediaBrowser.Model.SyncPlay /// </summary> /// <value>The Group id to join.</value> public Guid GroupId { get; set; } - - /// <summary> - /// Gets or sets the playing item id. - /// </summary> - /// <value>The client's currently playing item id.</value> - public Guid PlayingItemId { get; set; } } } diff --git a/MediaBrowser.Model/SyncPlay/PlaybackRequestType.cs b/MediaBrowser.Model/SyncPlay/PlaybackRequestType.cs index 671f4e01f..e89efeed8 100644 --- a/MediaBrowser.Model/SyncPlay/PlaybackRequestType.cs +++ b/MediaBrowser.Model/SyncPlay/PlaybackRequestType.cs @@ -23,16 +23,16 @@ namespace MediaBrowser.Model.SyncPlay /// <summary> /// A user is signaling that playback is buffering. /// </summary> - Buffering = 3, + Buffer = 3, /// <summary> /// A user is signaling that playback resumed. /// </summary> - BufferingDone = 4, + Ready = 4, /// <summary> /// A user is reporting its ping. /// </summary> - UpdatePing = 5 + Ping = 5 } } -- cgit v1.2.3 From 3b085f6a03bfe945e12b104bb042be1d00981cd2 Mon Sep 17 00:00:00 2001 From: Patrick Barron <barronpm@gmail.com> Date: Wed, 17 Jun 2020 10:24:25 -0400 Subject: Remove UserManager.AddParts --- Emby.Server.Implementations/ApplicationHost.cs | 4 ++- .../Users/UserManager.cs | 35 +++++++++++----------- MediaBrowser.Controller/Library/IUserManager.cs | 3 -- 3 files changed, 20 insertions(+), 22 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index f6077400d..908fe4b30 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -547,6 +547,9 @@ namespace Emby.Server.Implementations serviceCollection.AddSingleton(ServerConfigurationManager); + serviceCollection.AddSingleton<Func<IReadOnlyCollection<IPasswordResetProvider>>>(() => GetExports<IPasswordResetProvider>()); + serviceCollection.AddSingleton<Func<IReadOnlyCollection<IAuthenticationProvider>>>(() => GetExports<IAuthenticationProvider>()); + serviceCollection.AddSingleton<ILocalizationManager, LocalizationManager>(); serviceCollection.AddSingleton<IBlurayExaminer, BdInfoExaminer>(); @@ -795,7 +798,6 @@ namespace Emby.Server.Implementations Resolve<IMediaSourceManager>().AddParts(GetExports<IMediaSourceProvider>()); Resolve<INotificationManager>().AddParts(GetExports<INotificationService>(), GetExports<INotificationTypeFactory>()); - Resolve<IUserManager>().AddParts(GetExports<IAuthenticationProvider>(), GetExports<IPasswordResetProvider>()); Resolve<IIsoManager>().AddParts(GetExports<IIsoMounter>()); } diff --git a/Jellyfin.Server.Implementations/Users/UserManager.cs b/Jellyfin.Server.Implementations/Users/UserManager.cs index 6283a1bca..d4b91f3c5 100644 --- a/Jellyfin.Server.Implementations/Users/UserManager.cs +++ b/Jellyfin.Server.Implementations/Users/UserManager.cs @@ -39,12 +39,11 @@ namespace Jellyfin.Server.Implementations.Users private readonly IApplicationHost _appHost; private readonly IImageProcessor _imageProcessor; private readonly ILogger<UserManager> _logger; - - private IAuthenticationProvider[] _authenticationProviders = null!; - private DefaultAuthenticationProvider _defaultAuthenticationProvider = null!; - private InvalidAuthProvider _invalidAuthProvider = null!; - private IPasswordResetProvider[] _passwordResetProviders = null!; - private DefaultPasswordResetProvider _defaultPasswordResetProvider = null!; + private readonly IReadOnlyCollection<IPasswordResetProvider> _passwordResetProviders; + private readonly IReadOnlyCollection<IAuthenticationProvider> _authenticationProviders; + private readonly InvalidAuthProvider _invalidAuthProvider; + private readonly DefaultAuthenticationProvider _defaultAuthenticationProvider; + private readonly DefaultPasswordResetProvider _defaultPasswordResetProvider; /// <summary> /// Initializes a new instance of the <see cref="UserManager"/> class. @@ -55,13 +54,17 @@ namespace Jellyfin.Server.Implementations.Users /// <param name="appHost">The application host.</param> /// <param name="imageProcessor">The image processor.</param> /// <param name="logger">The logger.</param> + /// <param name="passwordResetProviders">A function that returns available password reset providers.</param> + /// <param name="authenticationProviders">A function that returns available authentication providers.</param> public UserManager( JellyfinDbProvider dbProvider, ICryptoProvider cryptoProvider, INetworkManager networkManager, IApplicationHost appHost, IImageProcessor imageProcessor, - ILogger<UserManager> logger) + ILogger<UserManager> logger, + Func<IReadOnlyCollection<IPasswordResetProvider>> passwordResetProviders, + Func<IReadOnlyCollection<IAuthenticationProvider>> authenticationProviders) { _dbProvider = dbProvider; _cryptoProvider = cryptoProvider; @@ -69,6 +72,13 @@ namespace Jellyfin.Server.Implementations.Users _appHost = appHost; _imageProcessor = imageProcessor; _logger = logger; + + _passwordResetProviders = passwordResetProviders.Invoke(); + _authenticationProviders = authenticationProviders.Invoke(); + + _invalidAuthProvider = _authenticationProviders.OfType<InvalidAuthProvider>().First(); + _defaultAuthenticationProvider = _authenticationProviders.OfType<DefaultAuthenticationProvider>().First(); + _defaultPasswordResetProvider = _passwordResetProviders.OfType<DefaultPasswordResetProvider>().First(); } /// <inheritdoc/> @@ -557,17 +567,6 @@ namespace Jellyfin.Server.Implementations.Users }; } - /// <inheritdoc/> - public void AddParts(IEnumerable<IAuthenticationProvider> authenticationProviders, IEnumerable<IPasswordResetProvider> passwordResetProviders) - { - _authenticationProviders = authenticationProviders.ToArray(); - _passwordResetProviders = passwordResetProviders.ToArray(); - - _invalidAuthProvider = _authenticationProviders.OfType<InvalidAuthProvider>().First(); - _defaultAuthenticationProvider = _authenticationProviders.OfType<DefaultAuthenticationProvider>().First(); - _defaultPasswordResetProvider = _passwordResetProviders.OfType<DefaultPasswordResetProvider>().First(); - } - /// <inheritdoc /> public void Initialize() { diff --git a/MediaBrowser.Controller/Library/IUserManager.cs b/MediaBrowser.Controller/Library/IUserManager.cs index e73fe7120..88b96ddbf 100644 --- a/MediaBrowser.Controller/Library/IUserManager.cs +++ b/MediaBrowser.Controller/Library/IUserManager.cs @@ -2,7 +2,6 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; using Jellyfin.Data.Entities; -using MediaBrowser.Controller.Authentication; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Events; @@ -166,8 +165,6 @@ namespace MediaBrowser.Controller.Library /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns> Task<PinRedeemResult> RedeemPasswordResetPin(string pin); - void AddParts(IEnumerable<IAuthenticationProvider> authenticationProviders, IEnumerable<IPasswordResetProvider> passwordResetProviders); - NameIdPair[] GetAuthenticationProviders(); NameIdPair[] GetPasswordResetProviders(); -- cgit v1.2.3 From 87f5a6bdb3e3856f2dfaddcc3b0902a45ff48ca2 Mon Sep 17 00:00:00 2001 From: Max Git <rotvel@gmail.com> Date: Wed, 15 Jul 2020 05:56:05 +0200 Subject: Move videostream null check to start of GetHardwareAcceleratedVideoDecoder --- .../MediaEncoding/EncodingHelper.cs | 24 ++++++++++++++-------- 1 file changed, 15 insertions(+), 9 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index cbfdf2695..fa06de0a3 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -2523,21 +2523,21 @@ namespace MediaBrowser.Controller.MediaEncoding } /// <summary> - /// Gets the name of the output video codec. + /// Gets the ffmpeg option string for the hardware accelerated video decoder. /// </summary> + /// <param name="state">The encoding job info.</param> + /// <param name="encodingOptions">The encoding options.</param> + /// <returns>The option string or null if none available.</returns> protected string GetHardwareAcceleratedVideoDecoder(EncodingJobInfo state, EncodingOptions encodingOptions) { - var videoType = state.MediaSource.VideoType ?? VideoType.VideoFile; var videoStream = state.VideoStream; - var isColorDepth10 = !string.IsNullOrEmpty(videoStream.Profile) && (videoStream.Profile.Contains("Main 10", StringComparison.OrdinalIgnoreCase) - || videoStream.Profile.Contains("High 10", StringComparison.OrdinalIgnoreCase)); - - if (EncodingHelper.IsCopyCodec(state.OutputVideoCodec)) + if (videoStream == null) { return null; } + var videoType = state.MediaSource.VideoType ?? VideoType.VideoFile; // Only use alternative encoders for video files. // When using concat with folder rips, if the mfx session fails to initialize, ffmpeg will be stuck retrying and will not exit gracefully // Since transcoding of folder rips is expiremental anyway, it's not worth adding additional variables such as this. @@ -2546,10 +2546,16 @@ namespace MediaBrowser.Controller.MediaEncoding return null; } - if (videoStream != null - && !string.IsNullOrEmpty(videoStream.Codec) - && !string.IsNullOrEmpty(encodingOptions.HardwareAccelerationType)) + if (IsCopyCodec(state.OutputVideoCodec)) { + return null; + } + + if (!string.IsNullOrEmpty(videoStream.Codec) && !string.IsNullOrEmpty(encodingOptions.HardwareAccelerationType)) + { + var isColorDepth10 = !string.IsNullOrEmpty(videoStream.Profile) + && (videoStream.Profile.Contains("Main 10", StringComparison.OrdinalIgnoreCase) || videoStream.Profile.Contains("High 10", StringComparison.OrdinalIgnoreCase)); + // Only hevc and vp9 formats have 10-bit hardware decoder support now. if (isColorDepth10 && !(string.Equals(videoStream.Codec, "hevc", StringComparison.OrdinalIgnoreCase) || string.Equals(videoStream.Codec, "h265", StringComparison.OrdinalIgnoreCase) -- cgit v1.2.3 From b356ff6c8908e5479c0d2eb6e17b2910d8ed01e4 Mon Sep 17 00:00:00 2001 From: Max Git <rotvel@gmail.com> Date: Wed, 15 Jul 2020 06:58:36 +0200 Subject: Simplify name of IsCopyDoc --- MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index fa06de0a3..534e0c372 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -1351,7 +1351,7 @@ namespace MediaBrowser.Controller.MediaEncoding transcoderChannelLimit = 6; } - var isTranscodingAudio = !EncodingHelper.IsCopyCodec(codec); + var isTranscodingAudio = !IsCopyCodec(codec); int? resultChannels = state.GetRequestedAudioChannels(codec); if (isTranscodingAudio) @@ -2264,7 +2264,7 @@ namespace MediaBrowser.Controller.MediaEncoding flags.Add("+ignidx"); } - if (state.GenPtsInput || EncodingHelper.IsCopyCodec(state.OutputVideoCodec)) + if (state.GenPtsInput || IsCopyCodec(state.OutputVideoCodec)) { flags.Add("+genpts"); } @@ -3008,7 +3008,7 @@ namespace MediaBrowser.Controller.MediaEncoding args += " -mpegts_m2ts_mode 1"; } - if (EncodingHelper.IsCopyCodec(videoCodec)) + if (IsCopyCodec(videoCodec)) { if (state.VideoStream != null && string.Equals(state.OutputContainer, "ts", StringComparison.OrdinalIgnoreCase) @@ -3110,7 +3110,7 @@ namespace MediaBrowser.Controller.MediaEncoding var args = "-codec:a:0 " + codec; - if (EncodingHelper.IsCopyCodec(codec)) + if (IsCopyCodec(codec)) { return args; } -- cgit v1.2.3 From 32fb34a4cc675ba1751f6a66b72f7e7bda99d836 Mon Sep 17 00:00:00 2001 From: Nyanmisaka <nst799610810@gmail.com> Date: Thu, 16 Jul 2020 21:09:04 +0800 Subject: Fix QSV subtitle burn-in on windows and P010 detect --- .../MediaEncoding/EncodingHelper.cs | 171 ++++++++++++++------- 1 file changed, 112 insertions(+), 59 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 534e0c372..62811c323 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -475,22 +475,34 @@ namespace MediaBrowser.Controller.MediaEncoding if (state.IsVideoRequest && string.Equals(encodingOptions.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase)) { - var hasTextSubs = state.SubtitleStream != null && state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode; + var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode; + var isWindows = Environment.OSVersion.Platform == PlatformID.Win32NT; - if (!hasTextSubs) + if (isQsvEncoder) { - if (isQsvEncoder) + if (isQsvDecoder) { - if (isQsvDecoder) + if (!isWindows) { - arg.Append("-hwaccel qsv -init_hw_device qsv=hw "); + if (hasGraphicalSubs) + { + arg.Append("-init_hw_device qsv=hw -filter_hw_device hw "); + } + else + { + arg.Append("-hwaccel qsv -init_hw_device qsv=hw "); + } } - // While using SW decoder else { - arg.Append("-init_hw_device qsv=hw -filter_hw_device hw "); + arg.Append("-hwaccel qsv -init_hw_device qsv=hw "); } } + // While using SW decoder + else + { + arg.Append("-init_hw_device qsv=hw -filter_hw_device hw "); + } } } @@ -806,6 +818,34 @@ namespace MediaBrowser.Controller.MediaEncoding break; } } + else if (string.Equals(videoEncoder, "h264_amf", StringComparison.OrdinalIgnoreCase) + || string.Equals(videoEncoder, "hevc_amf", StringComparison.OrdinalIgnoreCase)) + { + switch (encodingOptions.EncoderPreset) + { + case "veryslow": + case "slow": + case "slower": + param += "-quality quality"; + break; + + case "medium": + param += "-quality balanced"; + break; + + case "fast": + case "faster": + case "veryfast": + case "superfast": + case "ultrafast": + param += "-quality speed"; + break; + + default: + param += "-quality speed"; + break; + } + } else if (string.Equals(videoEncoder, "libvpx", StringComparison.OrdinalIgnoreCase)) // webm { // Values 0-3, 0 being highest quality but slower @@ -1555,28 +1595,28 @@ namespace MediaBrowser.Controller.MediaEncoding var index = outputSizeParam.IndexOf("hwdownload", StringComparison.OrdinalIgnoreCase); if (index != -1) { - outputSizeParam = "," + outputSizeParam.Substring(index); + outputSizeParam = outputSizeParam.Substring(index); } else { index = outputSizeParam.IndexOf("format", StringComparison.OrdinalIgnoreCase); if (index != -1) { - outputSizeParam = "," + outputSizeParam.Substring(index); + outputSizeParam = outputSizeParam.Substring(index); } else { index = outputSizeParam.IndexOf("yadif", StringComparison.OrdinalIgnoreCase); if (index != -1) { - outputSizeParam = "," + outputSizeParam.Substring(index); + outputSizeParam = outputSizeParam.Substring(index); } else { index = outputSizeParam.IndexOf("scale", StringComparison.OrdinalIgnoreCase); if (index != -1) { - outputSizeParam = "," + outputSizeParam.Substring(index); + outputSizeParam = outputSizeParam.Substring(index); } } } @@ -1591,17 +1631,18 @@ namespace MediaBrowser.Controller.MediaEncoding { videoSizeParam = string.Format( CultureInfo.InvariantCulture, - "scale={0}:{1}", + "scale={0}x{1}", state.VideoStream.Width.Value, state.VideoStream.Height.Value); // For QSV, feed it into hardware encoder now - if (string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase)) + var isWindows = Environment.OSVersion.Platform == PlatformID.Win32NT; + if (!isWindows && string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase)) { videoSizeParam += ",hwupload=extra_hw_frames=64"; } - // For VAAPI and CUVID decoder + // For VAAPI and NVDEC decoder // these encoders cannot automatically adjust the size of graphical subtitles to fit the output video, // thus needs to be manually adjusted. if (videoDecoder.IndexOf("cuvid", StringComparison.OrdinalIgnoreCase) != -1 @@ -1618,7 +1659,7 @@ namespace MediaBrowser.Controller.MediaEncoding { videoSizeParam = string.Format( CultureInfo.InvariantCulture, - "scale={0}:{1}", + "scale={0}x{1}", width.Value, height.Value); } @@ -1634,7 +1675,10 @@ namespace MediaBrowser.Controller.MediaEncoding : state.SubtitleStream.Index; // Setup default filtergraph utilizing FFMpeg overlay() and FFMpeg scale() (see the return of this function for index reference) - var retStr = " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}][sub]overlay{3}\""; + // Always put the scaler before the overlay for better performance + var retStr = !string.IsNullOrEmpty(outputSizeParam) ? + " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}]{3}[base];[base][sub]overlay\"" : + " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}][sub]overlay\""; // When the input may or may not be hardware VAAPI decodable if (string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase)) @@ -1644,7 +1688,6 @@ namespace MediaBrowser.Controller.MediaEncoding [sub]: SW scaling subtitle to FixedOutputSize [base][sub]: SW overlay */ - outputSizeParam = outputSizeParam.TrimStart(','); retStr = " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}]{3},hwdownload[base];[base][sub]overlay,format=nv12,hwupload\""; } @@ -1657,7 +1700,6 @@ namespace MediaBrowser.Controller.MediaEncoding [sub]: SW scaling subtitle to FixedOutputSize [base][sub]: SW overlay */ - outputSizeParam = outputSizeParam.TrimStart(','); retStr = " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}]{3}[base];[base][sub]overlay\""; } else if (string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase)) @@ -1666,14 +1708,14 @@ namespace MediaBrowser.Controller.MediaEncoding QSV in FFMpeg can now setup hardware overlay for transcodes. For software decoding and hardware encoding option, frames must be hwuploaded into hardware with fixed frame size. + Currently only supports linux. */ - if (videoDecoder.IndexOf("qsv", StringComparison.OrdinalIgnoreCase) != -1) - { - retStr = " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}][sub]overlay_qsv=x=(W-w)/2:y=(H-h)/2{3}\""; - } - else + var isWindows = Environment.OSVersion.Platform == PlatformID.Win32NT; + if (!isWindows) { - retStr = " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}]hwupload=extra_hw_frames=64[v];[v][sub]overlay_qsv=x=(W-w)/2:y=(H-h)/2{3}\""; + retStr = !string.IsNullOrEmpty(outputSizeParam) ? + " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}]{3}[base];[base][sub]overlay_qsv\"" : + " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}][sub]overlay_qsv\""; } } @@ -1745,10 +1787,8 @@ namespace MediaBrowser.Controller.MediaEncoding requestedMaxWidth, requestedMaxHeight); - var hasTextSubs = state.SubtitleStream != null && state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode; - if ((string.Equals(videoEncoder, "h264_vaapi", StringComparison.OrdinalIgnoreCase) - || (string.Equals(videoEncoder, "h264_qsv", StringComparison.OrdinalIgnoreCase) && !hasTextSubs)) + || string.Equals(videoEncoder, "h264_qsv", StringComparison.OrdinalIgnoreCase)) && width.HasValue && height.HasValue) { @@ -1769,15 +1809,20 @@ namespace MediaBrowser.Controller.MediaEncoding filters.Add( string.Format( CultureInfo.InvariantCulture, - "{0}=w={1}:h={2}:format=nv12", + "{0}=w={1}:h={2}:format=nv12{3}", qsv_or_vaapi ? "vpp_qsv" : "scale_vaapi", outputWidth, - outputHeight)); + outputHeight, + (qsv_or_vaapi && state.DeInterlace("h264", true)) ? ":deinterlace=1" : string.Empty)); } else { - // set w=0:h=0 for vpp_qsv to keep the original dimensions, otherwise it will fail. - filters.Add(string.Format(CultureInfo.InvariantCulture, "{0}format=nv12", qsv_or_vaapi ? "vpp_qsv=w=0:h=0:" : "scale_vaapi=")); + filters.Add( + string.Format( + CultureInfo.InvariantCulture, + "{0}=format=nv12{1}", + qsv_or_vaapi ? "vpp_qsv" : "scale_vaapi", + (qsv_or_vaapi && state.DeInterlace("h264", true)) ? ":deinterlace=1" : string.Empty)); } } else if ((videoDecoder ?? string.Empty).IndexOf("cuvid", StringComparison.OrdinalIgnoreCase) != -1 @@ -1998,8 +2043,6 @@ namespace MediaBrowser.Controller.MediaEncoding var inputHeight = videoStream?.Height; var threeDFormat = state.MediaSource.Video3DFormat; - var hasTextSubs = state.SubtitleStream != null && state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode; - // When the input may or may not be hardware VAAPI decodable if (string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase)) { @@ -2010,11 +2053,8 @@ namespace MediaBrowser.Controller.MediaEncoding // When the input may or may not be hardware QSV decodable else if (string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase)) { - if (!hasTextSubs) - { - filters.Add("format=nv12|qsv"); - filters.Add("hwupload=extra_hw_frames=64"); - } + filters.Add("format=nv12|qsv"); + filters.Add("hwupload=extra_hw_frames=64"); } // If we're hardware VAAPI decoding and software encoding, download frames from the decoder first @@ -2022,8 +2062,10 @@ namespace MediaBrowser.Controller.MediaEncoding && string.Equals(outputVideoCodec, "libx264", StringComparison.OrdinalIgnoreCase)) { var codec = videoStream.Codec.ToLowerInvariant(); - var isColorDepth10 = !string.IsNullOrEmpty(videoStream.Profile) && (videoStream.Profile.Contains("Main 10", StringComparison.OrdinalIgnoreCase) - || videoStream.Profile.Contains("High 10", StringComparison.OrdinalIgnoreCase)); + var isColorDepth10 = !string.IsNullOrEmpty(videoStream.Profile) + && (videoStream.Profile.Contains("Main 10", StringComparison.OrdinalIgnoreCase) + || videoStream.Profile.Contains("High 10", StringComparison.OrdinalIgnoreCase) + || videoStream.Profile.Contains("Profile 2", StringComparison.OrdinalIgnoreCase)); // Assert 10-bit hardware VAAPI decodable if (isColorDepth10 && (string.Equals(codec, "hevc", StringComparison.OrdinalIgnoreCase) @@ -2054,31 +2096,32 @@ namespace MediaBrowser.Controller.MediaEncoding { filters.Add(string.Format(CultureInfo.InvariantCulture, "deinterlace_vaapi")); } - else if (string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase)) - { - if (!hasTextSubs) - { - filters.Add(string.Format(CultureInfo.InvariantCulture, "deinterlace_qsv")); - } - } } // Add software deinterlace filter before scaling filter - if (((state.DeInterlace("h264", true) || state.DeInterlace("h265", true) || state.DeInterlace("hevc", true)) - && !string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase) - && !string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase)) - || (hasTextSubs && state.DeInterlace("h264", true) && string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase))) + if (state.DeInterlace("h264", true) || state.DeInterlace("h265", true) || state.DeInterlace("hevc", true)) { + var deintParam = string.Empty; 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) { - filters.Add("yadif=1:-1:0"); + deintParam = "yadif=1:-1:0"; } else { - filters.Add("yadif=0:-1:0"); + deintParam = "yadif=0:-1:0"; + } + + if (!string.IsNullOrEmpty(deintParam)) + { + if (!string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase) + && !string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase) + && videoDecoder.IndexOf("h264_cuvid", StringComparison.OrdinalIgnoreCase) == -1) + { + filters.Add(deintParam); + } } } @@ -2303,11 +2346,19 @@ namespace MediaBrowser.Controller.MediaEncoding && width.HasValue && height.HasValue) { - inputModifier += string.Format( - CultureInfo.InvariantCulture, - " -resize {0}x{1}", - width.Value, - height.Value); + if (width.HasValue && height.HasValue) + { + inputModifier += string.Format( + CultureInfo.InvariantCulture, + " -resize {0}x{1}", + width.Value, + height.Value); + } + + if (state.DeInterlace("h264", true)) + { + inputModifier += " -deint 1"; + } } } } @@ -2554,7 +2605,9 @@ namespace MediaBrowser.Controller.MediaEncoding if (!string.IsNullOrEmpty(videoStream.Codec) && !string.IsNullOrEmpty(encodingOptions.HardwareAccelerationType)) { var isColorDepth10 = !string.IsNullOrEmpty(videoStream.Profile) - && (videoStream.Profile.Contains("Main 10", StringComparison.OrdinalIgnoreCase) || videoStream.Profile.Contains("High 10", StringComparison.OrdinalIgnoreCase)); + && (videoStream.Profile.Contains("Main 10", StringComparison.OrdinalIgnoreCase) + || videoStream.Profile.Contains("High 10", StringComparison.OrdinalIgnoreCase) + || videoStream.Profile.Contains("Profile 2", StringComparison.OrdinalIgnoreCase)); // Only hevc and vp9 formats have 10-bit hardware decoder support now. if (isColorDepth10 && !(string.Equals(videoStream.Codec, "hevc", StringComparison.OrdinalIgnoreCase) -- cgit v1.2.3 From c1c1a2f7515edf157022a3ba421b5d66889aa525 Mon Sep 17 00:00:00 2001 From: Nyanmisaka <nst799610810@gmail.com> Date: Fri, 17 Jul 2020 01:30:35 +0800 Subject: Match the size of subtitle stream and video stream --- .../MediaEncoding/EncodingHelper.cs | 41 +++++++--------------- 1 file changed, 13 insertions(+), 28 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 62811c323..ffe2bcf28 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -1625,45 +1625,31 @@ namespace MediaBrowser.Controller.MediaEncoding var videoSizeParam = string.Empty; var videoDecoder = GetHardwareAcceleratedVideoDecoder(state, options) ?? string.Empty; + var isWindows = Environment.OSVersion.Platform == PlatformID.Win32NT; // Setup subtitle scaling if (state.VideoStream != null && state.VideoStream.Width.HasValue && state.VideoStream.Height.HasValue) { - videoSizeParam = string.Format( + // Adjust the size of graphical subtitles to fit the video stream. + var videoStream = state.VideoStream; + var inputWidth = videoStream?.Width; + var inputHeight = videoStream?.Height; + var (width, height) = GetFixedOutputSize(inputWidth, inputHeight, request.Width, request.Height, request.MaxWidth, request.MaxHeight); + + if (width.HasValue && height.HasValue) + { + videoSizeParam = string.Format( CultureInfo.InvariantCulture, "scale={0}x{1}", - state.VideoStream.Width.Value, - state.VideoStream.Height.Value); + width.Value, + height.Value); + } // For QSV, feed it into hardware encoder now - var isWindows = Environment.OSVersion.Platform == PlatformID.Win32NT; if (!isWindows && string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase)) { videoSizeParam += ",hwupload=extra_hw_frames=64"; } - - // For VAAPI and NVDEC decoder - // these encoders cannot automatically adjust the size of graphical subtitles to fit the output video, - // thus needs to be manually adjusted. - if (videoDecoder.IndexOf("cuvid", StringComparison.OrdinalIgnoreCase) != -1 - || (IsVaapiSupported(state) && string.Equals(options.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase) - && (videoDecoder.IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1 - || outputVideoCodec.IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1))) - { - var videoStream = state.VideoStream; - var inputWidth = videoStream?.Width; - var inputHeight = videoStream?.Height; - var (width, height) = GetFixedOutputSize(inputWidth, inputHeight, request.Width, request.Height, request.MaxWidth, request.MaxHeight); - - if (width.HasValue && height.HasValue) - { - videoSizeParam = string.Format( - CultureInfo.InvariantCulture, - "scale={0}x{1}", - width.Value, - height.Value); - } - } } var mapPrefix = state.SubtitleStream.IsExternal ? @@ -1710,7 +1696,6 @@ namespace MediaBrowser.Controller.MediaEncoding with fixed frame size. Currently only supports linux. */ - var isWindows = Environment.OSVersion.Platform == PlatformID.Win32NT; if (!isWindows) { retStr = !string.IsNullOrEmpty(outputSizeParam) ? -- cgit v1.2.3 From e1ba1fcebea0df71239bbc379ab436327488b9a8 Mon Sep 17 00:00:00 2001 From: Nyanmisaka <nst799610810@gmail.com> Date: Fri, 17 Jul 2020 01:41:24 +0800 Subject: fix indent --- MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index ffe2bcf28..6b3bbc34a 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -1639,10 +1639,10 @@ namespace MediaBrowser.Controller.MediaEncoding if (width.HasValue && height.HasValue) { videoSizeParam = string.Format( - CultureInfo.InvariantCulture, - "scale={0}x{1}", - width.Value, - height.Value); + CultureInfo.InvariantCulture, + "scale={0}x{1}", + width.Value, + height.Value); } // For QSV, feed it into hardware encoder now -- cgit v1.2.3 From 77f9417d84b30a56226497329c59e0e1e50e61a4 Mon Sep 17 00:00:00 2001 From: Nyanmisaka <nst799610810@gmail.com> Date: Fri, 17 Jul 2020 19:32:15 +0800 Subject: enhance platform check and 10bit detect --- .../MediaEncoding/EncodingHelper.cs | 155 +++++++++++++-------- 1 file changed, 95 insertions(+), 60 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 6b3bbc34a..ffbda42c3 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; +using System.Runtime.InteropServices; using System.Text; using System.Threading; using Jellyfin.Data.Enums; @@ -449,60 +450,66 @@ namespace MediaBrowser.Controller.MediaEncoding var arg = new StringBuilder(); var videoDecoder = GetHardwareAcceleratedVideoDecoder(state, encodingOptions) ?? string.Empty; var outputVideoCodec = GetVideoEncoder(state, encodingOptions) ?? string.Empty; - bool isVaapiDecoder = videoDecoder.IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1; - bool isVaapiEncoder = outputVideoCodec.IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1; - bool isQsvDecoder = videoDecoder.IndexOf("qsv", StringComparison.OrdinalIgnoreCase) != -1; - bool isQsvEncoder = outputVideoCodec.IndexOf("qsv", StringComparison.OrdinalIgnoreCase) != -1; + var isVaapiDecoder = videoDecoder.IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1; + var isVaapiEncoder = outputVideoCodec.IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1; + var isQsvDecoder = videoDecoder.IndexOf("qsv", StringComparison.OrdinalIgnoreCase) != -1; + var isQsvEncoder = outputVideoCodec.IndexOf("qsv", StringComparison.OrdinalIgnoreCase) != -1; + var isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); + var isLinux = RuntimeInformation.IsOSPlatform(OSPlatform.Linux); - if (state.IsVideoRequest - && string.Equals(encodingOptions.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase)) + if (!IsCopyCodec(outputVideoCodec)) { - if (isVaapiDecoder) + if (state.IsVideoRequest + && IsVaapiSupported(state) + && string.Equals(encodingOptions.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase)) { - arg.Append("-hwaccel_output_format vaapi ") - .Append("-vaapi_device ") - .Append(encodingOptions.VaapiDevice) - .Append(" "); - } - else if (!isVaapiDecoder && isVaapiEncoder) - { - arg.Append("-vaapi_device ") - .Append(encodingOptions.VaapiDevice) - .Append(" "); + if (isVaapiDecoder) + { + arg.Append("-hwaccel_output_format vaapi ") + .Append("-vaapi_device ") + .Append(encodingOptions.VaapiDevice) + .Append(" "); + } + else if (!isVaapiDecoder && isVaapiEncoder) + { + arg.Append("-vaapi_device ") + .Append(encodingOptions.VaapiDevice) + .Append(" "); + } } - } - if (state.IsVideoRequest - && string.Equals(encodingOptions.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase)) - { - var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode; - var isWindows = Environment.OSVersion.Platform == PlatformID.Win32NT; - - if (isQsvEncoder) + if (state.IsVideoRequest + && string.Equals(encodingOptions.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase)) { - if (isQsvDecoder) + var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode; + + if (isQsvEncoder) { - if (!isWindows) + if (isQsvDecoder) { - if (hasGraphicalSubs) + if (isLinux) { - arg.Append("-init_hw_device qsv=hw -filter_hw_device hw "); + if (hasGraphicalSubs) + { + arg.Append("-init_hw_device qsv=hw -filter_hw_device hw "); + } + else + { + arg.Append("-hwaccel qsv -init_hw_device qsv=hw "); + } } - else + + if (isWindows) { arg.Append("-hwaccel qsv -init_hw_device qsv=hw "); } } + // While using SW decoder else { - arg.Append("-hwaccel qsv -init_hw_device qsv=hw "); + arg.Append("-init_hw_device qsv=hw -filter_hw_device hw "); } } - // While using SW decoder - else - { - arg.Append("-init_hw_device qsv=hw -filter_hw_device hw "); - } } } @@ -1625,7 +1632,7 @@ namespace MediaBrowser.Controller.MediaEncoding var videoSizeParam = string.Empty; var videoDecoder = GetHardwareAcceleratedVideoDecoder(state, options) ?? string.Empty; - var isWindows = Environment.OSVersion.Platform == PlatformID.Win32NT; + var isLinux = RuntimeInformation.IsOSPlatform(OSPlatform.Linux); // Setup subtitle scaling if (state.VideoStream != null && state.VideoStream.Width.HasValue && state.VideoStream.Height.HasValue) @@ -1646,7 +1653,7 @@ namespace MediaBrowser.Controller.MediaEncoding } // For QSV, feed it into hardware encoder now - if (!isWindows && string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase)) + if (isLinux && string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase)) { videoSizeParam += ",hwupload=extra_hw_frames=64"; } @@ -1696,7 +1703,7 @@ namespace MediaBrowser.Controller.MediaEncoding with fixed frame size. Currently only supports linux. */ - if (!isWindows) + if (isLinux) { retStr = !string.IsNullOrEmpty(outputSizeParam) ? " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}]{3}[base];[base][sub]overlay_qsv\"" : @@ -2043,14 +2050,11 @@ namespace MediaBrowser.Controller.MediaEncoding } // If we're hardware VAAPI decoding and software encoding, download frames from the decoder first - else if (videoDecoder.IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1 + else if (IsVaapiSupported(state) && videoDecoder.IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1 && string.Equals(outputVideoCodec, "libx264", StringComparison.OrdinalIgnoreCase)) { var codec = videoStream.Codec.ToLowerInvariant(); - var isColorDepth10 = !string.IsNullOrEmpty(videoStream.Profile) - && (videoStream.Profile.Contains("Main 10", StringComparison.OrdinalIgnoreCase) - || videoStream.Profile.Contains("High 10", StringComparison.OrdinalIgnoreCase) - || videoStream.Profile.Contains("Profile 2", StringComparison.OrdinalIgnoreCase)); + var isColorDepth10 = IsColorDepth10(state); // Assert 10-bit hardware VAAPI decodable if (isColorDepth10 && (string.Equals(codec, "hevc", StringComparison.OrdinalIgnoreCase) @@ -2318,7 +2322,8 @@ namespace MediaBrowser.Controller.MediaEncoding { inputModifier += " " + videoDecoder; - if ((videoDecoder ?? string.Empty).IndexOf("cuvid", StringComparison.OrdinalIgnoreCase) != -1) + if (!IsCopyCodec(state.OutputVideoCodec) + && (videoDecoder ?? string.Empty).IndexOf("cuvid", StringComparison.OrdinalIgnoreCase) != -1) { var videoStream = state.VideoStream; var inputWidth = videoStream?.Width; @@ -2589,10 +2594,7 @@ namespace MediaBrowser.Controller.MediaEncoding if (!string.IsNullOrEmpty(videoStream.Codec) && !string.IsNullOrEmpty(encodingOptions.HardwareAccelerationType)) { - var isColorDepth10 = !string.IsNullOrEmpty(videoStream.Profile) - && (videoStream.Profile.Contains("Main 10", StringComparison.OrdinalIgnoreCase) - || videoStream.Profile.Contains("High 10", StringComparison.OrdinalIgnoreCase) - || videoStream.Profile.Contains("Profile 2", StringComparison.OrdinalIgnoreCase)); + var isColorDepth10 = IsColorDepth10(state); // Only hevc and vp9 formats have 10-bit hardware decoder support now. if (isColorDepth10 && !(string.Equals(videoStream.Codec, "hevc", StringComparison.OrdinalIgnoreCase) @@ -2669,13 +2671,6 @@ namespace MediaBrowser.Controller.MediaEncoding case "h264": if (_mediaEncoder.SupportsDecoder("h264_cuvid") && encodingOptions.HardwareDecodingCodecs.Contains("h264", StringComparer.OrdinalIgnoreCase)) { - // cuvid decoder does not support 10-bit input. - if ((videoStream.BitDepth ?? 8) > 8) - { - encodingOptions.HardwareDecodingCodecs = Array.Empty<string>(); - return null; - } - return "-c:v h264_cuvid"; } @@ -2942,21 +2937,24 @@ namespace MediaBrowser.Controller.MediaEncoding /// </summary> public string GetHwaccelType(EncodingJobInfo state, EncodingOptions options, string videoCodec) { - var isWindows = Environment.OSVersion.Platform == PlatformID.Win32NT; + var isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); + var isLinux = RuntimeInformation.IsOSPlatform(OSPlatform.Linux); var isWindows8orLater = Environment.OSVersion.Version.Major > 6 || (Environment.OSVersion.Version.Major == 6 && Environment.OSVersion.Version.Minor > 1); var isDxvaSupported = _mediaEncoder.SupportsHwaccel("dxva2") || _mediaEncoder.SupportsHwaccel("d3d11va"); if ((isDxvaSupported || IsVaapiSupported(state)) && options.HardwareDecodingCodecs.Contains(videoCodec, StringComparer.OrdinalIgnoreCase)) { - if (!isWindows) + if (isLinux) { return "-hwaccel vaapi"; } - else if (isWindows8orLater) + + if (isWindows && isWindows8orLater) { return "-hwaccel d3d11va"; } - else + + if (isWindows && !isWindows8orLater) { return "-hwaccel dxva2"; } @@ -3225,5 +3223,42 @@ namespace MediaBrowser.Controller.MediaEncoding { return string.Equals(codec, "copy", StringComparison.OrdinalIgnoreCase); } + + public static bool IsColorDepth10(EncodingJobInfo state) + { + var result = false; + var videoStream = state.VideoStream; + + if (videoStream != null) + { + if (!string.IsNullOrEmpty(videoStream.PixelFormat)) + { + result = videoStream.PixelFormat.Contains("p10", StringComparison.OrdinalIgnoreCase); + if (result) + { + return true; + } + } + + if (!string.IsNullOrEmpty(videoStream.Profile)) + { + result = videoStream.Profile.Contains("Main 10", StringComparison.OrdinalIgnoreCase) + || videoStream.Profile.Contains("High 10", StringComparison.OrdinalIgnoreCase) + || videoStream.Profile.Contains("Profile 2", StringComparison.OrdinalIgnoreCase); + if (result) + { + return true; + } + } + + result = (videoStream.BitDepth ?? 8) == 10; + if (result) + { + return true; + } + } + + return result; + } } } -- cgit v1.2.3 From ab396225eaf486932fdb2f23eefa1cbfecbb27f4 Mon Sep 17 00:00:00 2001 From: Patrick Barron <barronpm@gmail.com> Date: Tue, 30 Jun 2020 21:44:41 -0400 Subject: Migrate Display Preferences to EF Core --- Emby.Dlna/ContentDirectory/ControlHandler.cs | 1 + Emby.Server.Implementations/ApplicationHost.cs | 3 - .../Channels/ChannelManager.cs | 1 + .../Data/SqliteDisplayPreferencesRepository.cs | 225 ------------ .../Data/SqliteItemRepository.cs | 1 + .../Emby.Server.Implementations.csproj | 2 +- .../Images/CollectionFolderImageProvider.cs | 2 +- .../Images/FolderImageProvider.cs | 2 +- .../Images/GenreImageProvider.cs | 1 + .../Library/LibraryManager.cs | 1 - .../Library/MusicManager.cs | 2 +- .../Library/SearchEngine.cs | 2 +- .../LiveTv/EmbyTV/EmbyTV.cs | 1 + Jellyfin.Data/Entities/DisplayPreferences.cs | 72 ++++ Jellyfin.Data/Entities/HomeSection.cs | 21 ++ Jellyfin.Data/Entities/User.cs | 5 + Jellyfin.Data/Enums/HomeSectionType.cs | 53 +++ Jellyfin.Data/Enums/IndexingKind.cs | 20 + Jellyfin.Data/Enums/ScrollDirection.cs | 18 + Jellyfin.Data/Enums/SortOrder.cs | 18 + Jellyfin.Data/Enums/ViewType.cs | 38 ++ .../DisplayPreferencesManager.cs | 49 +++ Jellyfin.Server.Implementations/JellyfinDb.cs | 2 + ...0200630170339_AddDisplayPreferences.Designer.cs | 403 +++++++++++++++++++++ .../20200630170339_AddDisplayPreferences.cs | 92 +++++ .../Migrations/JellyfinDbModelSnapshot.cs | 93 ++++- Jellyfin.Server/CoreAppHost.cs | 2 + Jellyfin.Server/Migrations/MigrationRunner.cs | 3 +- .../Routines/MigrateDisplayPreferencesDb.cs | 118 ++++++ MediaBrowser.Api/ChannelService.cs | 2 +- MediaBrowser.Api/DisplayPreferencesService.cs | 92 ++++- MediaBrowser.Api/Movies/MoviesService.cs | 1 + MediaBrowser.Api/SuggestionsService.cs | 1 + MediaBrowser.Api/TvShowsService.cs | 1 + MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs | 5 +- .../Entities/UserViewBuilder.cs | 1 + .../IDisplayPreferencesManager.cs | 25 ++ MediaBrowser.Controller/Library/ILibraryManager.cs | 1 + .../Persistence/IDisplayPreferencesRepository.cs | 53 --- MediaBrowser.Controller/Playlists/Playlist.cs | 1 + MediaBrowser.Model/Dlna/SortCriteria.cs | 2 +- MediaBrowser.Model/Entities/DisplayPreferences.cs | 111 ------ .../Entities/DisplayPreferencesDto.cs | 107 ++++++ MediaBrowser.Model/Entities/ScrollDirection.cs | 18 - MediaBrowser.Model/Entities/SortOrder.cs | 18 - MediaBrowser.Model/LiveTv/LiveTvChannelQuery.cs | 2 +- MediaBrowser.Model/LiveTv/SeriesTimerQuery.cs | 2 +- 47 files changed, 1232 insertions(+), 462 deletions(-) delete mode 100644 Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs create mode 100644 Jellyfin.Data/Entities/DisplayPreferences.cs create mode 100644 Jellyfin.Data/Entities/HomeSection.cs create mode 100644 Jellyfin.Data/Enums/HomeSectionType.cs create mode 100644 Jellyfin.Data/Enums/IndexingKind.cs create mode 100644 Jellyfin.Data/Enums/ScrollDirection.cs create mode 100644 Jellyfin.Data/Enums/SortOrder.cs create mode 100644 Jellyfin.Data/Enums/ViewType.cs create mode 100644 Jellyfin.Server.Implementations/DisplayPreferencesManager.cs create mode 100644 Jellyfin.Server.Implementations/Migrations/20200630170339_AddDisplayPreferences.Designer.cs create mode 100644 Jellyfin.Server.Implementations/Migrations/20200630170339_AddDisplayPreferences.cs create mode 100644 Jellyfin.Server/Migrations/Routines/MigrateDisplayPreferencesDb.cs create mode 100644 MediaBrowser.Controller/IDisplayPreferencesManager.cs delete mode 100644 MediaBrowser.Controller/Persistence/IDisplayPreferencesRepository.cs delete mode 100644 MediaBrowser.Model/Entities/DisplayPreferences.cs create mode 100644 MediaBrowser.Model/Entities/DisplayPreferencesDto.cs delete mode 100644 MediaBrowser.Model/Entities/ScrollDirection.cs delete mode 100644 MediaBrowser.Model/Entities/SortOrder.cs (limited to 'MediaBrowser.Controller') diff --git a/Emby.Dlna/ContentDirectory/ControlHandler.cs b/Emby.Dlna/ContentDirectory/ControlHandler.cs index 291de5245..00821bf78 100644 --- a/Emby.Dlna/ContentDirectory/ControlHandler.cs +++ b/Emby.Dlna/ContentDirectory/ControlHandler.cs @@ -11,6 +11,7 @@ using System.Xml; using Emby.Dlna.Didl; using Emby.Dlna.Service; using Jellyfin.Data.Entities; +using Jellyfin.Data.Enums; using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Drawing; diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index f6077400d..f6f10beb0 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -554,8 +554,6 @@ namespace Emby.Server.Implementations serviceCollection.AddSingleton<IUserDataRepository, SqliteUserDataRepository>(); serviceCollection.AddSingleton<IUserDataManager, UserDataManager>(); - serviceCollection.AddSingleton<IDisplayPreferencesRepository, SqliteDisplayPreferencesRepository>(); - serviceCollection.AddSingleton<IItemRepository, SqliteItemRepository>(); serviceCollection.AddSingleton<IAuthenticationRepository, AuthenticationRepository>(); @@ -650,7 +648,6 @@ namespace Emby.Server.Implementations _httpServer = Resolve<IHttpServer>(); _httpClient = Resolve<IHttpClient>(); - ((SqliteDisplayPreferencesRepository)Resolve<IDisplayPreferencesRepository>()).Initialize(); ((AuthenticationRepository)Resolve<IAuthenticationRepository>()).Initialize(); SetStaticProperties(); diff --git a/Emby.Server.Implementations/Channels/ChannelManager.cs b/Emby.Server.Implementations/Channels/ChannelManager.cs index c803d9d82..2a7cddd87 100644 --- a/Emby.Server.Implementations/Channels/ChannelManager.cs +++ b/Emby.Server.Implementations/Channels/ChannelManager.cs @@ -7,6 +7,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using Jellyfin.Data.Entities; +using Jellyfin.Data.Enums; using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Progress; using MediaBrowser.Controller.Channels; diff --git a/Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs b/Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs deleted file mode 100644 index 5597155a8..000000000 --- a/Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs +++ /dev/null @@ -1,225 +0,0 @@ -#pragma warning disable CS1591 - -using System; -using System.Collections.Generic; -using System.Globalization; -using System.IO; -using System.Text.Json; -using System.Threading; -using MediaBrowser.Common.Configuration; -using MediaBrowser.Common.Extensions; -using MediaBrowser.Common.Json; -using MediaBrowser.Controller.Persistence; -using MediaBrowser.Model.Entities; -using MediaBrowser.Model.IO; -using Microsoft.Extensions.Logging; -using SQLitePCL.pretty; - -namespace Emby.Server.Implementations.Data -{ - /// <summary> - /// Class SQLiteDisplayPreferencesRepository. - /// </summary> - public class SqliteDisplayPreferencesRepository : BaseSqliteRepository, IDisplayPreferencesRepository - { - private readonly IFileSystem _fileSystem; - - private readonly JsonSerializerOptions _jsonOptions; - - public SqliteDisplayPreferencesRepository(ILogger<SqliteDisplayPreferencesRepository> logger, IApplicationPaths appPaths, IFileSystem fileSystem) - : base(logger) - { - _fileSystem = fileSystem; - - _jsonOptions = JsonDefaults.GetOptions(); - - DbFilePath = Path.Combine(appPaths.DataPath, "displaypreferences.db"); - } - - /// <summary> - /// Gets the name of the repository. - /// </summary> - /// <value>The name.</value> - public string Name => "SQLite"; - - public void Initialize() - { - try - { - InitializeInternal(); - } - catch (Exception ex) - { - Logger.LogError(ex, "Error loading database file. Will reset and retry."); - - _fileSystem.DeleteFile(DbFilePath); - - InitializeInternal(); - } - } - - /// <summary> - /// Opens the connection to the database. - /// </summary> - /// <returns>Task.</returns> - private void InitializeInternal() - { - string[] queries = - { - "create table if not exists userdisplaypreferences (id GUID NOT NULL, userId GUID NOT NULL, client text NOT NULL, data BLOB NOT NULL)", - "create unique index if not exists userdisplaypreferencesindex on userdisplaypreferences (id, userId, client)" - }; - - using (var connection = GetConnection()) - { - connection.RunQueries(queries); - } - } - - /// <summary> - /// Save the display preferences associated with an item in the repo. - /// </summary> - /// <param name="displayPreferences">The display preferences.</param> - /// <param name="userId">The user id.</param> - /// <param name="client">The client.</param> - /// <param name="cancellationToken">The cancellation token.</param> - /// <exception cref="ArgumentNullException">item</exception> - public void SaveDisplayPreferences(DisplayPreferences displayPreferences, Guid userId, string client, CancellationToken cancellationToken) - { - if (displayPreferences == null) - { - throw new ArgumentNullException(nameof(displayPreferences)); - } - - if (string.IsNullOrEmpty(displayPreferences.Id)) - { - throw new ArgumentException("Display preferences has an invalid Id", nameof(displayPreferences)); - } - - cancellationToken.ThrowIfCancellationRequested(); - - using (var connection = GetConnection()) - { - connection.RunInTransaction( - db => SaveDisplayPreferences(displayPreferences, userId, client, db), - TransactionMode); - } - } - - private void SaveDisplayPreferences(DisplayPreferences displayPreferences, Guid userId, string client, IDatabaseConnection connection) - { - var serialized = JsonSerializer.SerializeToUtf8Bytes(displayPreferences, _jsonOptions); - - using (var statement = connection.PrepareStatement("replace into userdisplaypreferences (id, userid, client, data) values (@id, @userId, @client, @data)")) - { - statement.TryBind("@id", new Guid(displayPreferences.Id).ToByteArray()); - statement.TryBind("@userId", userId.ToByteArray()); - statement.TryBind("@client", client); - statement.TryBind("@data", serialized); - - statement.MoveNext(); - } - } - - /// <summary> - /// Save all display preferences associated with a user in the repo. - /// </summary> - /// <param name="displayPreferences">The display preferences.</param> - /// <param name="userId">The user id.</param> - /// <param name="cancellationToken">The cancellation token.</param> - /// <exception cref="ArgumentNullException">item</exception> - public void SaveAllDisplayPreferences(IEnumerable<DisplayPreferences> displayPreferences, Guid userId, CancellationToken cancellationToken) - { - if (displayPreferences == null) - { - throw new ArgumentNullException(nameof(displayPreferences)); - } - - cancellationToken.ThrowIfCancellationRequested(); - - using (var connection = GetConnection()) - { - connection.RunInTransaction( - db => - { - foreach (var displayPreference in displayPreferences) - { - SaveDisplayPreferences(displayPreference, userId, displayPreference.Client, db); - } - }, - TransactionMode); - } - } - - /// <summary> - /// Gets the display preferences. - /// </summary> - /// <param name="displayPreferencesId">The display preferences id.</param> - /// <param name="userId">The user id.</param> - /// <param name="client">The client.</param> - /// <returns>Task{DisplayPreferences}.</returns> - /// <exception cref="ArgumentNullException">item</exception> - public DisplayPreferences GetDisplayPreferences(string displayPreferencesId, Guid userId, string client) - { - if (string.IsNullOrEmpty(displayPreferencesId)) - { - throw new ArgumentNullException(nameof(displayPreferencesId)); - } - - var guidId = displayPreferencesId.GetMD5(); - - using (var connection = GetConnection(true)) - { - using (var statement = connection.PrepareStatement("select data from userdisplaypreferences where id = @id and userId=@userId and client=@client")) - { - statement.TryBind("@id", guidId.ToByteArray()); - statement.TryBind("@userId", userId.ToByteArray()); - statement.TryBind("@client", client); - - foreach (var row in statement.ExecuteQuery()) - { - return Get(row); - } - } - } - - return new DisplayPreferences - { - Id = guidId.ToString("N", CultureInfo.InvariantCulture) - }; - } - - /// <summary> - /// Gets all display preferences for the given user. - /// </summary> - /// <param name="userId">The user id.</param> - /// <returns>Task{DisplayPreferences}.</returns> - /// <exception cref="ArgumentNullException">item</exception> - public IEnumerable<DisplayPreferences> GetAllDisplayPreferences(Guid userId) - { - var list = new List<DisplayPreferences>(); - - using (var connection = GetConnection(true)) - using (var statement = connection.PrepareStatement("select data from userdisplaypreferences where userId=@userId")) - { - statement.TryBind("@userId", userId.ToByteArray()); - - foreach (var row in statement.ExecuteQuery()) - { - list.Add(Get(row)); - } - } - - return list; - } - - private DisplayPreferences Get(IReadOnlyList<IResultSetValue> row) - => JsonSerializer.Deserialize<DisplayPreferences>(row[0].ToBlob(), _jsonOptions); - - public void SaveDisplayPreferences(DisplayPreferences displayPreferences, string userId, string client, CancellationToken cancellationToken) - => SaveDisplayPreferences(displayPreferences, new Guid(userId), client, cancellationToken); - - public DisplayPreferences GetDisplayPreferences(string displayPreferencesId, string userId, string client) - => GetDisplayPreferences(displayPreferencesId, new Guid(userId), client); - } -} diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index a6390b1ef..04e5e570f 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -9,6 +9,7 @@ using System.Text; using System.Text.Json; using System.Threading; using Emby.Server.Implementations.Playlists; +using Jellyfin.Data.Enums; using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Json; using MediaBrowser.Controller; diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj index f7ad59c10..548dc7085 100644 --- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj +++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj @@ -54,7 +54,7 @@ <TargetFramework>netstandard2.1</TargetFramework> <GenerateAssemblyInfo>false</GenerateAssemblyInfo> <GenerateDocumentationFile>true</GenerateDocumentationFile> - <TreatWarningsAsErrors Condition=" '$(Configuration)' == 'Release'" >true</TreatWarningsAsErrors> + <TreatWarningsAsErrors Condition=" '$(Configuration)' == 'Release'">true</TreatWarningsAsErrors> </PropertyGroup> <!-- Code Analyzers--> diff --git a/Emby.Server.Implementations/Images/CollectionFolderImageProvider.cs b/Emby.Server.Implementations/Images/CollectionFolderImageProvider.cs index da88b8d8a..161b4c452 100644 --- a/Emby.Server.Implementations/Images/CollectionFolderImageProvider.cs +++ b/Emby.Server.Implementations/Images/CollectionFolderImageProvider.cs @@ -3,7 +3,7 @@ using System; using System.Collections.Generic; using System.IO; -using Emby.Server.Implementations.Images; +using Jellyfin.Data.Enums; using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Dto; diff --git a/Emby.Server.Implementations/Images/FolderImageProvider.cs b/Emby.Server.Implementations/Images/FolderImageProvider.cs index e9523386e..0224ab32a 100644 --- a/Emby.Server.Implementations/Images/FolderImageProvider.cs +++ b/Emby.Server.Implementations/Images/FolderImageProvider.cs @@ -1,7 +1,7 @@ #pragma warning disable CS1591 using System.Collections.Generic; -using Emby.Server.Implementations.Images; +using Jellyfin.Data.Enums; using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Dto; diff --git a/Emby.Server.Implementations/Images/GenreImageProvider.cs b/Emby.Server.Implementations/Images/GenreImageProvider.cs index d2aeccdb2..1cd4cd66b 100644 --- a/Emby.Server.Implementations/Images/GenreImageProvider.cs +++ b/Emby.Server.Implementations/Images/GenreImageProvider.cs @@ -1,6 +1,7 @@ #pragma warning disable CS1591 using System.Collections.Generic; +using Jellyfin.Data.Enums; using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Dto; diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index 77d44e131..4690f2094 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -50,7 +50,6 @@ using Microsoft.Extensions.Logging; using Episode = MediaBrowser.Controller.Entities.TV.Episode; using Genre = MediaBrowser.Controller.Entities.Genre; using Person = MediaBrowser.Controller.Entities.Person; -using SortOrder = MediaBrowser.Model.Entities.SortOrder; using VideoResolver = Emby.Naming.Video.VideoResolver; namespace Emby.Server.Implementations.Library diff --git a/Emby.Server.Implementations/Library/MusicManager.cs b/Emby.Server.Implementations/Library/MusicManager.cs index 0bdc59914..877fdec86 100644 --- a/Emby.Server.Implementations/Library/MusicManager.cs +++ b/Emby.Server.Implementations/Library/MusicManager.cs @@ -4,12 +4,12 @@ using System; using System.Collections.Generic; using System.Linq; using Jellyfin.Data.Entities; +using Jellyfin.Data.Enums; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Playlists; -using MediaBrowser.Model.Entities; using MediaBrowser.Model.Querying; using MusicAlbum = MediaBrowser.Controller.Entities.Audio.MusicAlbum; diff --git a/Emby.Server.Implementations/Library/SearchEngine.cs b/Emby.Server.Implementations/Library/SearchEngine.cs index 3df9cc06f..e3e554824 100644 --- a/Emby.Server.Implementations/Library/SearchEngine.cs +++ b/Emby.Server.Implementations/Library/SearchEngine.cs @@ -4,12 +4,12 @@ using System; using System.Collections.Generic; using System.Linq; using Jellyfin.Data.Entities; +using Jellyfin.Data.Enums; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Extensions; using MediaBrowser.Controller.Library; -using MediaBrowser.Model.Entities; using MediaBrowser.Model.Querying; using MediaBrowser.Model.Search; using Microsoft.Extensions.Logging; diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index 7b0fcbc9e..80e09f0a3 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -12,6 +12,7 @@ using System.Threading; using System.Threading.Tasks; using System.Xml; using Emby.Server.Implementations.Library; +using Jellyfin.Data.Enums; using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Net; diff --git a/Jellyfin.Data/Entities/DisplayPreferences.cs b/Jellyfin.Data/Entities/DisplayPreferences.cs new file mode 100644 index 000000000..668030149 --- /dev/null +++ b/Jellyfin.Data/Entities/DisplayPreferences.cs @@ -0,0 +1,72 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using Jellyfin.Data.Enums; + +namespace Jellyfin.Data.Entities +{ + public class DisplayPreferences + { + public DisplayPreferences(string client, Guid userId) + { + RememberIndexing = false; + ShowBackdrop = true; + Client = client; + UserId = userId; + + HomeSections = new HashSet<HomeSection>(); + } + + protected DisplayPreferences() + { + } + + [Required] + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int Id { get; protected set; } + + [Required] + public Guid UserId { get; set; } + + /// <summary> + /// Gets or sets the id of the associated item. + /// </summary> + /// <remarks> + /// This is currently unused. In the future, this will allow us to have users set + /// display preferences per item. + /// </remarks> + public Guid? ItemId { get; set; } + + [Required] + [MaxLength(64)] + [StringLength(64)] + public string Client { get; set; } + + [Required] + public bool RememberIndexing { get; set; } + + [Required] + public bool RememberSorting { get; set; } + + [Required] + public SortOrder SortOrder { get; set; } + + [Required] + public bool ShowSidebar { get; set; } + + [Required] + public bool ShowBackdrop { get; set; } + + public string SortBy { get; set; } + + public ViewType? ViewType { get; set; } + + [Required] + public ScrollDirection ScrollDirection { get; set; } + + public IndexingKind? IndexBy { get; set; } + + public virtual ICollection<HomeSection> HomeSections { get; protected set; } + } +} diff --git a/Jellyfin.Data/Entities/HomeSection.cs b/Jellyfin.Data/Entities/HomeSection.cs new file mode 100644 index 000000000..f39956a54 --- /dev/null +++ b/Jellyfin.Data/Entities/HomeSection.cs @@ -0,0 +1,21 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using Jellyfin.Data.Enums; + +namespace Jellyfin.Data.Entities +{ + public class HomeSection + { + [Key] + [Required] + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int Id { get; protected set; } + + public int DisplayPreferencesId { get; set; } + + public int Order { get; set; } + + public HomeSectionType Type { get; set; } + } +} diff --git a/Jellyfin.Data/Entities/User.cs b/Jellyfin.Data/Entities/User.cs index b89b0a8f4..d93144e3a 100644 --- a/Jellyfin.Data/Entities/User.cs +++ b/Jellyfin.Data/Entities/User.cs @@ -349,6 +349,11 @@ namespace Jellyfin.Data.Entities /// </summary> public virtual ICollection<AccessSchedule> AccessSchedules { get; protected set; } + /// <summary> + /// Gets or sets the list of item display preferences. + /// </summary> + public virtual ICollection<DisplayPreferences> DisplayPreferences { get; protected set; } + /* /// <summary> /// Gets or sets the list of groups this user is a member of. diff --git a/Jellyfin.Data/Enums/HomeSectionType.cs b/Jellyfin.Data/Enums/HomeSectionType.cs new file mode 100644 index 000000000..be764c592 --- /dev/null +++ b/Jellyfin.Data/Enums/HomeSectionType.cs @@ -0,0 +1,53 @@ +namespace Jellyfin.Data.Enums +{ + /// <summary> + /// An enum representing the different options for the home screen sections. + /// </summary> + public enum HomeSectionType + { + /// <summary> + /// My Media. + /// </summary> + SmallLibraryTiles = 0, + + /// <summary> + /// My Media Small. + /// </summary> + LibraryButtons = 1, + + /// <summary> + /// Active Recordings. + /// </summary> + ActiveRecordings = 2, + + /// <summary> + /// Continue Watching. + /// </summary> + Resume = 3, + + /// <summary> + /// Continue Listening. + /// </summary> + ResumeAudio = 4, + + /// <summary> + /// Latest Media. + /// </summary> + LatestMedia = 5, + + /// <summary> + /// Next Up. + /// </summary> + NextUp = 6, + + /// <summary> + /// Live TV. + /// </summary> + LiveTv = 7, + + /// <summary> + /// None. + /// </summary> + None = 8 + } +} diff --git a/Jellyfin.Data/Enums/IndexingKind.cs b/Jellyfin.Data/Enums/IndexingKind.cs new file mode 100644 index 000000000..c4d8e70ca --- /dev/null +++ b/Jellyfin.Data/Enums/IndexingKind.cs @@ -0,0 +1,20 @@ +namespace Jellyfin.Data.Enums +{ + public enum IndexingKind + { + /// <summary> + /// Index by the premiere date. + /// </summary> + PremiereDate, + + /// <summary> + /// Index by the production year. + /// </summary> + ProductionYear, + + /// <summary> + /// Index by the community rating. + /// </summary> + CommunityRating + } +} diff --git a/Jellyfin.Data/Enums/ScrollDirection.cs b/Jellyfin.Data/Enums/ScrollDirection.cs new file mode 100644 index 000000000..382f585ba --- /dev/null +++ b/Jellyfin.Data/Enums/ScrollDirection.cs @@ -0,0 +1,18 @@ +namespace Jellyfin.Data.Enums +{ + /// <summary> + /// An enum representing the axis that should be scrolled. + /// </summary> + public enum ScrollDirection + { + /// <summary> + /// Horizontal scrolling direction. + /// </summary> + Horizontal, + + /// <summary> + /// Vertical scrolling direction. + /// </summary> + Vertical + } +} diff --git a/Jellyfin.Data/Enums/SortOrder.cs b/Jellyfin.Data/Enums/SortOrder.cs new file mode 100644 index 000000000..309fa7877 --- /dev/null +++ b/Jellyfin.Data/Enums/SortOrder.cs @@ -0,0 +1,18 @@ +namespace Jellyfin.Data.Enums +{ + /// <summary> + /// An enum representing the sorting order. + /// </summary> + public enum SortOrder + { + /// <summary> + /// Sort in increasing order. + /// </summary> + Ascending, + + /// <summary> + /// Sort in decreasing order. + /// </summary> + Descending + } +} diff --git a/Jellyfin.Data/Enums/ViewType.cs b/Jellyfin.Data/Enums/ViewType.cs new file mode 100644 index 000000000..595429ab1 --- /dev/null +++ b/Jellyfin.Data/Enums/ViewType.cs @@ -0,0 +1,38 @@ +namespace Jellyfin.Data.Enums +{ + /// <summary> + /// An enum representing the type of view for a library or collection. + /// </summary> + public enum ViewType + { + /// <summary> + /// Shows banners. + /// </summary> + Banner = 0, + + /// <summary> + /// Shows a list of content. + /// </summary> + List = 1, + + /// <summary> + /// Shows poster artwork. + /// </summary> + Poster = 2, + + /// <summary> + /// Shows poster artwork with a card containing the name and year. + /// </summary> + PosterCard = 3, + + /// <summary> + /// Shows a thumbnail. + /// </summary> + Thumb = 4, + + /// <summary> + /// Shows a thumbnail with a card containing the name and year. + /// </summary> + ThumbCard = 5 + } +} diff --git a/Jellyfin.Server.Implementations/DisplayPreferencesManager.cs b/Jellyfin.Server.Implementations/DisplayPreferencesManager.cs new file mode 100644 index 000000000..132e74c6a --- /dev/null +++ b/Jellyfin.Server.Implementations/DisplayPreferencesManager.cs @@ -0,0 +1,49 @@ +using System; +using System.Linq; +using Jellyfin.Data.Entities; +using MediaBrowser.Controller; + +namespace Jellyfin.Server.Implementations +{ + /// <summary> + /// Manages the storage and retrieval of display preferences through Entity Framework. + /// </summary> + public class DisplayPreferencesManager : IDisplayPreferencesManager + { + private readonly JellyfinDbProvider _dbProvider; + + /// <summary> + /// Initializes a new instance of the <see cref="DisplayPreferencesManager"/> class. + /// </summary> + /// <param name="dbProvider">The Jellyfin db provider.</param> + public DisplayPreferencesManager(JellyfinDbProvider dbProvider) + { + _dbProvider = dbProvider; + } + + /// <inheritdoc /> + public DisplayPreferences GetDisplayPreferences(Guid userId, string client) + { + var dbContext = _dbProvider.CreateContext(); + var user = dbContext.Users.Find(userId); +#pragma warning disable CA1307 + var prefs = user.DisplayPreferences.FirstOrDefault(pref => string.Equals(pref.Client, client)); + + if (prefs == null) + { + prefs = new DisplayPreferences(client, userId); + user.DisplayPreferences.Add(prefs); + } + + return prefs; + } + + /// <inheritdoc /> + public void SaveChanges(DisplayPreferences preferences) + { + var dbContext = _dbProvider.CreateContext(); + dbContext.Update(preferences); + dbContext.SaveChanges(); + } + } +} diff --git a/Jellyfin.Server.Implementations/JellyfinDb.cs b/Jellyfin.Server.Implementations/JellyfinDb.cs index 53120a763..774970e94 100644 --- a/Jellyfin.Server.Implementations/JellyfinDb.cs +++ b/Jellyfin.Server.Implementations/JellyfinDb.cs @@ -27,6 +27,8 @@ namespace Jellyfin.Server.Implementations public virtual DbSet<ActivityLog> ActivityLogs { get; set; } + public virtual DbSet<DisplayPreferences> DisplayPreferences { get; set; } + public virtual DbSet<ImageInfo> ImageInfos { get; set; } public virtual DbSet<Permission> Permissions { get; set; } diff --git a/Jellyfin.Server.Implementations/Migrations/20200630170339_AddDisplayPreferences.Designer.cs b/Jellyfin.Server.Implementations/Migrations/20200630170339_AddDisplayPreferences.Designer.cs new file mode 100644 index 000000000..75f9bb7a3 --- /dev/null +++ b/Jellyfin.Server.Implementations/Migrations/20200630170339_AddDisplayPreferences.Designer.cs @@ -0,0 +1,403 @@ +#pragma warning disable CS1591 + +// <auto-generated /> +using System; +using Jellyfin.Server.Implementations; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +namespace Jellyfin.Server.Implementations.Migrations +{ + [DbContext(typeof(JellyfinDb))] + [Migration("20200630170339_AddDisplayPreferences")] + partial class AddDisplayPreferences + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasDefaultSchema("jellyfin") + .HasAnnotation("ProductVersion", "3.1.5"); + + modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property<int>("DayOfWeek") + .HasColumnType("INTEGER"); + + b.Property<double>("EndHour") + .HasColumnType("REAL"); + + b.Property<double>("StartHour") + .HasColumnType("REAL"); + + b.Property<Guid>("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AccessSchedules"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ActivityLog", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property<DateTime>("DateCreated") + .HasColumnType("TEXT"); + + b.Property<string>("ItemId") + .HasColumnType("TEXT") + .HasMaxLength(256); + + b.Property<int>("LogSeverity") + .HasColumnType("INTEGER"); + + b.Property<string>("Name") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(512); + + b.Property<string>("Overview") + .HasColumnType("TEXT") + .HasMaxLength(512); + + b.Property<uint>("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property<string>("ShortOverview") + .HasColumnType("TEXT") + .HasMaxLength(512); + + b.Property<string>("Type") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(256); + + b.Property<Guid>("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("ActivityLogs"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property<string>("Client") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(64); + + b.Property<int?>("IndexBy") + .HasColumnType("INTEGER"); + + b.Property<Guid?>("ItemId") + .HasColumnType("TEXT"); + + b.Property<bool>("RememberIndexing") + .HasColumnType("INTEGER"); + + b.Property<bool>("RememberSorting") + .HasColumnType("INTEGER"); + + b.Property<int>("ScrollDirection") + .HasColumnType("INTEGER"); + + b.Property<bool>("ShowBackdrop") + .HasColumnType("INTEGER"); + + b.Property<bool>("ShowSidebar") + .HasColumnType("INTEGER"); + + b.Property<string>("SortBy") + .HasColumnType("TEXT"); + + b.Property<int>("SortOrder") + .HasColumnType("INTEGER"); + + b.Property<Guid>("UserId") + .HasColumnType("TEXT"); + + b.Property<int?>("ViewType") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("DisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property<int>("DisplayPreferencesId") + .HasColumnType("INTEGER"); + + b.Property<int>("Order") + .HasColumnType("INTEGER"); + + b.Property<int>("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("DisplayPreferencesId"); + + b.ToTable("HomeSection"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property<DateTime>("LastModified") + .HasColumnType("TEXT"); + + b.Property<string>("Path") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(512); + + b.Property<Guid?>("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("ImageInfos"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property<int>("Kind") + .HasColumnType("INTEGER"); + + b.Property<Guid?>("Permission_Permissions_Guid") + .HasColumnType("TEXT"); + + b.Property<uint>("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property<bool>("Value") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("Permission_Permissions_Guid"); + + b.ToTable("Permissions"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property<int>("Kind") + .HasColumnType("INTEGER"); + + b.Property<Guid?>("Preference_Preferences_Guid") + .HasColumnType("TEXT"); + + b.Property<uint>("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property<string>("Value") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(65535); + + b.HasKey("Id"); + + b.HasIndex("Preference_Preferences_Guid"); + + b.ToTable("Preferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.User", b => + { + b.Property<Guid>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property<string>("AudioLanguagePreference") + .HasColumnType("TEXT") + .HasMaxLength(255); + + b.Property<string>("AuthenticationProviderId") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(255); + + b.Property<bool>("DisplayCollectionsView") + .HasColumnType("INTEGER"); + + b.Property<bool>("DisplayMissingEpisodes") + .HasColumnType("INTEGER"); + + b.Property<string>("EasyPassword") + .HasColumnType("TEXT") + .HasMaxLength(65535); + + b.Property<bool>("EnableAutoLogin") + .HasColumnType("INTEGER"); + + b.Property<bool>("EnableLocalPassword") + .HasColumnType("INTEGER"); + + b.Property<bool>("EnableNextEpisodeAutoPlay") + .HasColumnType("INTEGER"); + + b.Property<bool>("EnableUserPreferenceAccess") + .HasColumnType("INTEGER"); + + b.Property<bool>("HidePlayedInLatest") + .HasColumnType("INTEGER"); + + b.Property<long>("InternalId") + .HasColumnType("INTEGER"); + + b.Property<int>("InvalidLoginAttemptCount") + .HasColumnType("INTEGER"); + + b.Property<DateTime?>("LastActivityDate") + .HasColumnType("TEXT"); + + b.Property<DateTime?>("LastLoginDate") + .HasColumnType("TEXT"); + + b.Property<int?>("LoginAttemptsBeforeLockout") + .HasColumnType("INTEGER"); + + b.Property<int?>("MaxParentalAgeRating") + .HasColumnType("INTEGER"); + + b.Property<bool>("MustUpdatePassword") + .HasColumnType("INTEGER"); + + b.Property<string>("Password") + .HasColumnType("TEXT") + .HasMaxLength(65535); + + b.Property<string>("PasswordResetProviderId") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(255); + + b.Property<bool>("PlayDefaultAudioTrack") + .HasColumnType("INTEGER"); + + b.Property<bool>("RememberAudioSelections") + .HasColumnType("INTEGER"); + + b.Property<bool>("RememberSubtitleSelections") + .HasColumnType("INTEGER"); + + b.Property<int?>("RemoteClientBitrateLimit") + .HasColumnType("INTEGER"); + + b.Property<uint>("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property<string>("SubtitleLanguagePreference") + .HasColumnType("TEXT") + .HasMaxLength(255); + + b.Property<int>("SubtitleMode") + .HasColumnType("INTEGER"); + + b.Property<int>("SyncPlayAccess") + .HasColumnType("INTEGER"); + + b.Property<string>("Username") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(255); + + b.HasKey("Id"); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("AccessSchedules") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("DisplayPreferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => + { + b.HasOne("Jellyfin.Data.Entities.DisplayPreferences", null) + .WithMany("HomeSections") + .HasForeignKey("DisplayPreferencesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithOne("ProfileImage") + .HasForeignKey("Jellyfin.Data.Entities.ImageInfo", "UserId"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("Permissions") + .HasForeignKey("Permission_Permissions_Guid"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("Preferences") + .HasForeignKey("Preference_Preferences_Guid"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Jellyfin.Server.Implementations/Migrations/20200630170339_AddDisplayPreferences.cs b/Jellyfin.Server.Implementations/Migrations/20200630170339_AddDisplayPreferences.cs new file mode 100644 index 000000000..e9a493d9d --- /dev/null +++ b/Jellyfin.Server.Implementations/Migrations/20200630170339_AddDisplayPreferences.cs @@ -0,0 +1,92 @@ +#pragma warning disable CS1591 +#pragma warning disable SA1601 + +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace Jellyfin.Server.Implementations.Migrations +{ + public partial class AddDisplayPreferences : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "DisplayPreferences", + schema: "jellyfin", + columns: table => new + { + Id = table.Column<int>(nullable: false) + .Annotation("Sqlite:Autoincrement", true), + UserId = table.Column<Guid>(nullable: false), + ItemId = table.Column<Guid>(nullable: true), + Client = table.Column<string>(maxLength: 64, nullable: false), + RememberIndexing = table.Column<bool>(nullable: false), + RememberSorting = table.Column<bool>(nullable: false), + SortOrder = table.Column<int>(nullable: false), + ShowSidebar = table.Column<bool>(nullable: false), + ShowBackdrop = table.Column<bool>(nullable: false), + SortBy = table.Column<string>(nullable: true), + ViewType = table.Column<int>(nullable: true), + ScrollDirection = table.Column<int>(nullable: false), + IndexBy = table.Column<int>(nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_DisplayPreferences", x => x.Id); + table.ForeignKey( + name: "FK_DisplayPreferences_Users_UserId", + column: x => x.UserId, + principalSchema: "jellyfin", + principalTable: "Users", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "HomeSection", + schema: "jellyfin", + columns: table => new + { + Id = table.Column<int>(nullable: false) + .Annotation("Sqlite:Autoincrement", true), + DisplayPreferencesId = table.Column<int>(nullable: false), + Order = table.Column<int>(nullable: false), + Type = table.Column<int>(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_HomeSection", x => x.Id); + table.ForeignKey( + name: "FK_HomeSection_DisplayPreferences_DisplayPreferencesId", + column: x => x.DisplayPreferencesId, + principalSchema: "jellyfin", + principalTable: "DisplayPreferences", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_DisplayPreferences_UserId", + schema: "jellyfin", + table: "DisplayPreferences", + column: "UserId"); + + migrationBuilder.CreateIndex( + name: "IX_HomeSection_DisplayPreferencesId", + schema: "jellyfin", + table: "HomeSection", + column: "DisplayPreferencesId"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "HomeSection", + schema: "jellyfin"); + + migrationBuilder.DropTable( + name: "DisplayPreferences", + schema: "jellyfin"); + } + } +} diff --git a/Jellyfin.Server.Implementations/Migrations/JellyfinDbModelSnapshot.cs b/Jellyfin.Server.Implementations/Migrations/JellyfinDbModelSnapshot.cs index 51fad8224..69b544e5b 100644 --- a/Jellyfin.Server.Implementations/Migrations/JellyfinDbModelSnapshot.cs +++ b/Jellyfin.Server.Implementations/Migrations/JellyfinDbModelSnapshot.cs @@ -15,7 +15,7 @@ namespace Jellyfin.Server.Implementations.Migrations #pragma warning disable 612, 618 modelBuilder .HasDefaultSchema("jellyfin") - .HasAnnotation("ProductVersion", "3.1.4"); + .HasAnnotation("ProductVersion", "3.1.5"); modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => { @@ -88,6 +88,79 @@ namespace Jellyfin.Server.Implementations.Migrations b.ToTable("ActivityLogs"); }); + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property<string>("Client") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(64); + + b.Property<int?>("IndexBy") + .HasColumnType("INTEGER"); + + b.Property<Guid?>("ItemId") + .HasColumnType("TEXT"); + + b.Property<bool>("RememberIndexing") + .HasColumnType("INTEGER"); + + b.Property<bool>("RememberSorting") + .HasColumnType("INTEGER"); + + b.Property<int>("ScrollDirection") + .HasColumnType("INTEGER"); + + b.Property<bool>("ShowBackdrop") + .HasColumnType("INTEGER"); + + b.Property<bool>("ShowSidebar") + .HasColumnType("INTEGER"); + + b.Property<string>("SortBy") + .HasColumnType("TEXT"); + + b.Property<int>("SortOrder") + .HasColumnType("INTEGER"); + + b.Property<Guid>("UserId") + .HasColumnType("TEXT"); + + b.Property<int?>("ViewType") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("DisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property<int>("DisplayPreferencesId") + .HasColumnType("INTEGER"); + + b.Property<int>("Order") + .HasColumnType("INTEGER"); + + b.Property<int>("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("DisplayPreferencesId"); + + b.ToTable("HomeSection"); + }); + modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => { b.Property<int>("Id") @@ -282,6 +355,24 @@ namespace Jellyfin.Server.Implementations.Migrations .IsRequired(); }); + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("DisplayPreferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => + { + b.HasOne("Jellyfin.Data.Entities.DisplayPreferences", null) + .WithMany("HomeSections") + .HasForeignKey("DisplayPreferencesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => { b.HasOne("Jellyfin.Data.Entities.User", null) diff --git a/Jellyfin.Server/CoreAppHost.cs b/Jellyfin.Server/CoreAppHost.cs index 207eaa98d..c5a7368aa 100644 --- a/Jellyfin.Server/CoreAppHost.cs +++ b/Jellyfin.Server/CoreAppHost.cs @@ -9,6 +9,7 @@ using Jellyfin.Server.Implementations; using Jellyfin.Server.Implementations.Activity; using Jellyfin.Server.Implementations.Users; using MediaBrowser.Common.Net; +using MediaBrowser.Controller; using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Library; using MediaBrowser.Model.Activity; @@ -73,6 +74,7 @@ namespace Jellyfin.Server serviceCollection.AddSingleton<IActivityManager, ActivityManager>(); serviceCollection.AddSingleton<IUserManager, UserManager>(); + serviceCollection.AddSingleton<IDisplayPreferencesManager, DisplayPreferencesManager>(); base.RegisterServices(serviceCollection); } diff --git a/Jellyfin.Server/Migrations/MigrationRunner.cs b/Jellyfin.Server/Migrations/MigrationRunner.cs index d633c554d..7f208952c 100644 --- a/Jellyfin.Server/Migrations/MigrationRunner.cs +++ b/Jellyfin.Server/Migrations/MigrationRunner.cs @@ -21,7 +21,8 @@ namespace Jellyfin.Server.Migrations typeof(Routines.MigrateActivityLogDb), typeof(Routines.RemoveDuplicateExtras), typeof(Routines.AddDefaultPluginRepository), - typeof(Routines.MigrateUserDb) + typeof(Routines.MigrateUserDb), + typeof(Routines.MigrateDisplayPreferencesDb) }; /// <summary> diff --git a/Jellyfin.Server/Migrations/Routines/MigrateDisplayPreferencesDb.cs b/Jellyfin.Server/Migrations/Routines/MigrateDisplayPreferencesDb.cs new file mode 100644 index 000000000..1ed23fe8e --- /dev/null +++ b/Jellyfin.Server/Migrations/Routines/MigrateDisplayPreferencesDb.cs @@ -0,0 +1,118 @@ +using System; +using System.IO; +using System.Text.Json; +using System.Text.Json.Serialization; +using Jellyfin.Data.Entities; +using Jellyfin.Data.Enums; +using Jellyfin.Server.Implementations; +using MediaBrowser.Controller; +using MediaBrowser.Model.Entities; +using Microsoft.Extensions.Logging; +using SQLitePCL.pretty; + +namespace Jellyfin.Server.Migrations.Routines +{ + /// <summary> + /// The migration routine for migrating the display preferences database to EF Core. + /// </summary> + public class MigrateDisplayPreferencesDb : IMigrationRoutine + { + private const string DbFilename = "displaypreferences.db"; + + private readonly ILogger<MigrateDisplayPreferencesDb> _logger; + private readonly IServerApplicationPaths _paths; + private readonly JellyfinDbProvider _provider; + private readonly JsonSerializerOptions _jsonOptions; + + /// <summary> + /// Initializes a new instance of the <see cref="MigrateDisplayPreferencesDb"/> class. + /// </summary> + /// <param name="logger">The logger.</param> + /// <param name="paths">The server application paths.</param> + /// <param name="provider">The database provider.</param> + public MigrateDisplayPreferencesDb(ILogger<MigrateDisplayPreferencesDb> logger, IServerApplicationPaths paths, JellyfinDbProvider provider) + { + _logger = logger; + _paths = paths; + _provider = provider; + _jsonOptions = new JsonSerializerOptions(); + _jsonOptions.Converters.Add(new JsonStringEnumConverter()); + } + + /// <inheritdoc /> + public Guid Id => Guid.Parse("06387815-C3CC-421F-A888-FB5F9992BEA8"); + + /// <inheritdoc /> + public string Name => "MigrateDisplayPreferencesDatabase"; + + /// <inheritdoc /> + public void Perform() + { + HomeSectionType[] defaults = + { + HomeSectionType.SmallLibraryTiles, + HomeSectionType.Resume, + HomeSectionType.ResumeAudio, + HomeSectionType.LiveTv, + HomeSectionType.NextUp, + HomeSectionType.LatestMedia, + HomeSectionType.None, + }; + + var dbFilePath = Path.Combine(_paths.DataPath, DbFilename); + using (var connection = SQLite3.Open(dbFilePath, ConnectionFlags.ReadOnly, null)) + { + var dbContext = _provider.CreateContext(); + + var results = connection.Query("SELECT * FROM userdisplaypreferences"); + foreach (var result in results) + { + var dto = JsonSerializer.Deserialize<DisplayPreferencesDto>(result[3].ToString(), _jsonOptions); + + var displayPreferences = new DisplayPreferences(result[2].ToString(), new Guid(result[1].ToBlob())) + { + ViewType = Enum.TryParse<ViewType>(dto.ViewType, true, out var viewType) ? viewType : (ViewType?)null, + IndexBy = Enum.TryParse<IndexingKind>(dto.IndexBy, true, out var indexBy) ? indexBy : (IndexingKind?)null, + ShowBackdrop = dto.ShowBackdrop, + ShowSidebar = dto.ShowSidebar, + SortBy = dto.SortBy, + SortOrder = dto.SortOrder, + RememberIndexing = dto.RememberIndexing, + RememberSorting = dto.RememberSorting, + ScrollDirection = dto.ScrollDirection + }; + + for (int i = 0; i < 7; i++) + { + dto.CustomPrefs.TryGetValue("homesection" + i, out var homeSection); + + displayPreferences.HomeSections.Add(new HomeSection + { + Order = i, + Type = Enum.TryParse<HomeSectionType>(homeSection, true, out var type) ? type : defaults[i] + }); + } + + dbContext.Add(displayPreferences); + } + + dbContext.SaveChanges(); + } + + try + { + File.Move(dbFilePath, dbFilePath + ".old"); + + var journalPath = dbFilePath + "-journal"; + if (File.Exists(journalPath)) + { + File.Move(journalPath, dbFilePath + ".old-journal"); + } + } + catch (IOException e) + { + _logger.LogError(e, "Error renaming legacy display preferences database to 'displaypreferences.db.old'"); + } + } + } +} diff --git a/MediaBrowser.Api/ChannelService.cs b/MediaBrowser.Api/ChannelService.cs index 8c336b1c9..8d3a9ee5a 100644 --- a/MediaBrowser.Api/ChannelService.cs +++ b/MediaBrowser.Api/ChannelService.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; +using Jellyfin.Data.Enums; using MediaBrowser.Api.UserLibrary; using MediaBrowser.Controller.Channels; using MediaBrowser.Controller.Configuration; @@ -11,7 +12,6 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Net; using MediaBrowser.Model.Channels; using MediaBrowser.Model.Dto; -using MediaBrowser.Model.Entities; using MediaBrowser.Model.Querying; using MediaBrowser.Model.Services; using Microsoft.Extensions.Logging; diff --git a/MediaBrowser.Api/DisplayPreferencesService.cs b/MediaBrowser.Api/DisplayPreferencesService.cs index c3ed40ad3..e5dd03807 100644 --- a/MediaBrowser.Api/DisplayPreferencesService.cs +++ b/MediaBrowser.Api/DisplayPreferencesService.cs @@ -1,9 +1,10 @@ -using System.Threading; +using System; +using Jellyfin.Data.Entities; +using Jellyfin.Data.Enums; +using MediaBrowser.Controller; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Net; -using MediaBrowser.Controller.Persistence; using MediaBrowser.Model.Entities; -using MediaBrowser.Model.Serialization; using MediaBrowser.Model.Services; using Microsoft.Extensions.Logging; @@ -13,7 +14,7 @@ namespace MediaBrowser.Api /// Class UpdateDisplayPreferences. /// </summary> [Route("/DisplayPreferences/{DisplayPreferencesId}", "POST", Summary = "Updates a user's display preferences for an item")] - public class UpdateDisplayPreferences : DisplayPreferences, IReturnVoid + public class UpdateDisplayPreferences : DisplayPreferencesDto, IReturnVoid { /// <summary> /// Gets or sets the id. @@ -27,7 +28,7 @@ namespace MediaBrowser.Api } [Route("/DisplayPreferences/{Id}", "GET", Summary = "Gets a user's display preferences for an item")] - public class GetDisplayPreferences : IReturn<DisplayPreferences> + public class GetDisplayPreferences : IReturn<DisplayPreferencesDto> { /// <summary> /// Gets or sets the id. @@ -50,28 +51,21 @@ namespace MediaBrowser.Api public class DisplayPreferencesService : BaseApiService { /// <summary> - /// The _display preferences manager. + /// The user manager. /// </summary> - private readonly IDisplayPreferencesRepository _displayPreferencesManager; - /// <summary> - /// The _json serializer. - /// </summary> - private readonly IJsonSerializer _jsonSerializer; + private readonly IDisplayPreferencesManager _displayPreferencesManager; /// <summary> /// Initializes a new instance of the <see cref="DisplayPreferencesService" /> class. /// </summary> - /// <param name="jsonSerializer">The json serializer.</param> /// <param name="displayPreferencesManager">The display preferences manager.</param> public DisplayPreferencesService( ILogger<DisplayPreferencesService> logger, IServerConfigurationManager serverConfigurationManager, IHttpResultFactory httpResultFactory, - IJsonSerializer jsonSerializer, - IDisplayPreferencesRepository displayPreferencesManager) + IDisplayPreferencesManager displayPreferencesManager) : base(logger, serverConfigurationManager, httpResultFactory) { - _jsonSerializer = jsonSerializer; _displayPreferencesManager = displayPreferencesManager; } @@ -81,9 +75,34 @@ namespace MediaBrowser.Api /// <param name="request">The request.</param> public object Get(GetDisplayPreferences request) { - var result = _displayPreferencesManager.GetDisplayPreferences(request.Id, request.UserId, request.Client); + var result = _displayPreferencesManager.GetDisplayPreferences(Guid.Parse(request.UserId), request.Client); + + if (result == null) + { + return null; + } + + var dto = new DisplayPreferencesDto + { + Client = result.Client, + Id = result.UserId.ToString(), + ViewType = result.ViewType?.ToString(), + SortBy = result.SortBy, + SortOrder = result.SortOrder, + IndexBy = result.IndexBy?.ToString(), + RememberIndexing = result.RememberIndexing, + RememberSorting = result.RememberSorting, + ScrollDirection = result.ScrollDirection, + ShowBackdrop = result.ShowBackdrop, + ShowSidebar = result.ShowSidebar + }; - return ToOptimizedResult(result); + foreach (var homeSection in result.HomeSections) + { + dto.CustomPrefs["homesection" + homeSection.Order] = homeSection.Type.ToString().ToLowerInvariant(); + } + + return ToOptimizedResult(dto); } /// <summary> @@ -92,10 +111,43 @@ namespace MediaBrowser.Api /// <param name="request">The request.</param> public void Post(UpdateDisplayPreferences request) { - // Serialize to json and then back so that the core doesn't see the request dto type - var displayPreferences = _jsonSerializer.DeserializeFromString<DisplayPreferences>(_jsonSerializer.SerializeToString(request)); + HomeSectionType[] defaults = + { + HomeSectionType.SmallLibraryTiles, + HomeSectionType.Resume, + HomeSectionType.ResumeAudio, + HomeSectionType.LiveTv, + HomeSectionType.NextUp, + HomeSectionType.LatestMedia, + HomeSectionType.None, + }; + + var prefs = _displayPreferencesManager.GetDisplayPreferences(Guid.Parse(request.UserId), request.Client); + + prefs.ViewType = Enum.TryParse<ViewType>(request.ViewType, true, out var viewType) ? viewType : (ViewType?)null; + prefs.IndexBy = Enum.TryParse<IndexingKind>(request.IndexBy, true, out var indexBy) ? indexBy : (IndexingKind?)null; + prefs.ShowBackdrop = request.ShowBackdrop; + prefs.ShowSidebar = request.ShowSidebar; + prefs.SortBy = request.SortBy; + prefs.SortOrder = request.SortOrder; + prefs.RememberIndexing = request.RememberIndexing; + prefs.RememberSorting = request.RememberSorting; + prefs.ScrollDirection = request.ScrollDirection; + prefs.HomeSections.Clear(); + + for (int i = 0; i < 7; i++) + { + if (request.CustomPrefs.TryGetValue("homesection" + i, out var homeSection)) + { + prefs.HomeSections.Add(new HomeSection + { + Order = i, + Type = Enum.TryParse<HomeSectionType>(homeSection, true, out var type) ? type : defaults[i] + }); + } + } - _displayPreferencesManager.SaveDisplayPreferences(displayPreferences, request.UserId, request.Client, CancellationToken.None); + _displayPreferencesManager.SaveChanges(prefs); } } } diff --git a/MediaBrowser.Api/Movies/MoviesService.cs b/MediaBrowser.Api/Movies/MoviesService.cs index 34cccffa3..2ff322d29 100644 --- a/MediaBrowser.Api/Movies/MoviesService.cs +++ b/MediaBrowser.Api/Movies/MoviesService.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; using Jellyfin.Data.Entities; +using Jellyfin.Data.Enums; using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Dto; diff --git a/MediaBrowser.Api/SuggestionsService.cs b/MediaBrowser.Api/SuggestionsService.cs index 17afa8e79..b42e822e8 100644 --- a/MediaBrowser.Api/SuggestionsService.cs +++ b/MediaBrowser.Api/SuggestionsService.cs @@ -1,6 +1,7 @@ using System; using System.Linq; using Jellyfin.Data.Entities; +using Jellyfin.Data.Enums; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; diff --git a/MediaBrowser.Api/TvShowsService.cs b/MediaBrowser.Api/TvShowsService.cs index 165abd613..799cea648 100644 --- a/MediaBrowser.Api/TvShowsService.cs +++ b/MediaBrowser.Api/TvShowsService.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Globalization; using System.Linq; +using Jellyfin.Data.Enums; using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Dto; diff --git a/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs b/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs index 344861a49..fc19575b3 100644 --- a/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs +++ b/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs @@ -1,5 +1,6 @@ using System; using System.Linq; +using Jellyfin.Data.Enums; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Querying; using MediaBrowser.Model.Services; @@ -466,8 +467,8 @@ namespace MediaBrowser.Api.UserLibrary var sortOrderValue = sortOrders.Length > sortOrderIndex ? sortOrders[sortOrderIndex] : null; var sortOrder = string.Equals(sortOrderValue, "Descending", StringComparison.OrdinalIgnoreCase) - ? MediaBrowser.Model.Entities.SortOrder.Descending - : MediaBrowser.Model.Entities.SortOrder.Ascending; + ? Jellyfin.Data.Enums.SortOrder.Descending + : Jellyfin.Data.Enums.SortOrder.Ascending; result[i] = new ValueTuple<string, SortOrder>(vals[i], sortOrder); } diff --git a/MediaBrowser.Controller/Entities/UserViewBuilder.cs b/MediaBrowser.Controller/Entities/UserViewBuilder.cs index cb35d6e32..22bb7fd55 100644 --- a/MediaBrowser.Controller/Entities/UserViewBuilder.cs +++ b/MediaBrowser.Controller/Entities/UserViewBuilder.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; using Jellyfin.Data.Entities; +using Jellyfin.Data.Enums; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Library; diff --git a/MediaBrowser.Controller/IDisplayPreferencesManager.cs b/MediaBrowser.Controller/IDisplayPreferencesManager.cs new file mode 100644 index 000000000..e27b0ec7c --- /dev/null +++ b/MediaBrowser.Controller/IDisplayPreferencesManager.cs @@ -0,0 +1,25 @@ +using System; +using Jellyfin.Data.Entities; + +namespace MediaBrowser.Controller +{ + /// <summary> + /// Manages the storage and retrieval of display preferences. + /// </summary> + public interface IDisplayPreferencesManager + { + /// <summary> + /// Gets the display preferences for the user and client. + /// </summary> + /// <param name="userId">The user's id.</param> + /// <param name="client">The client string.</param> + /// <returns>The associated display preferences.</returns> + DisplayPreferences GetDisplayPreferences(Guid userId, string client); + + /// <summary> + /// Saves changes to the provided display preferences. + /// </summary> + /// <param name="preferences">The display preferences to save.</param> + void SaveChanges(DisplayPreferences preferences); + } +} diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs index 9d6646857..b5eec1846 100644 --- a/MediaBrowser.Controller/Library/ILibraryManager.cs +++ b/MediaBrowser.Controller/Library/ILibraryManager.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using Jellyfin.Data.Entities; +using Jellyfin.Data.Enums; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; diff --git a/MediaBrowser.Controller/Persistence/IDisplayPreferencesRepository.cs b/MediaBrowser.Controller/Persistence/IDisplayPreferencesRepository.cs deleted file mode 100644 index c2dcb66d7..000000000 --- a/MediaBrowser.Controller/Persistence/IDisplayPreferencesRepository.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Threading; -using MediaBrowser.Model.Entities; - -namespace MediaBrowser.Controller.Persistence -{ - /// <summary> - /// Interface IDisplayPreferencesRepository. - /// </summary> - public interface IDisplayPreferencesRepository : IRepository - { - /// <summary> - /// Saves display preferences for an item. - /// </summary> - /// <param name="displayPreferences">The display preferences.</param> - /// <param name="userId">The user id.</param> - /// <param name="client">The client.</param> - /// <param name="cancellationToken">The cancellation token.</param> - void SaveDisplayPreferences( - DisplayPreferences displayPreferences, - string userId, - string client, - CancellationToken cancellationToken); - - /// <summary> - /// Saves all display preferences for a user. - /// </summary> - /// <param name="displayPreferences">The display preferences.</param> - /// <param name="userId">The user id.</param> - /// <param name="cancellationToken">The cancellation token.</param> - void SaveAllDisplayPreferences( - IEnumerable<DisplayPreferences> displayPreferences, - Guid userId, - CancellationToken cancellationToken); - - /// <summary> - /// Gets the display preferences. - /// </summary> - /// <param name="displayPreferencesId">The display preferences id.</param> - /// <param name="userId">The user id.</param> - /// <param name="client">The client.</param> - /// <returns>Task{DisplayPreferences}.</returns> - DisplayPreferences GetDisplayPreferences(string displayPreferencesId, string userId, string client); - - /// <summary> - /// Gets all display preferences for the given user. - /// </summary> - /// <param name="userId">The user id.</param> - /// <returns>Task{DisplayPreferences}.</returns> - IEnumerable<DisplayPreferences> GetAllDisplayPreferences(Guid userId); - } -} diff --git a/MediaBrowser.Controller/Playlists/Playlist.cs b/MediaBrowser.Controller/Playlists/Playlist.cs index b1a638883..0fd63770f 100644 --- a/MediaBrowser.Controller/Playlists/Playlist.cs +++ b/MediaBrowser.Controller/Playlists/Playlist.cs @@ -6,6 +6,7 @@ using System.Text.Json.Serialization; using System.Threading; using System.Threading.Tasks; using Jellyfin.Data.Entities; +using Jellyfin.Data.Enums; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; diff --git a/MediaBrowser.Model/Dlna/SortCriteria.cs b/MediaBrowser.Model/Dlna/SortCriteria.cs index 1f7fa76ad..53e4540cb 100644 --- a/MediaBrowser.Model/Dlna/SortCriteria.cs +++ b/MediaBrowser.Model/Dlna/SortCriteria.cs @@ -1,6 +1,6 @@ #pragma warning disable CS1591 -using MediaBrowser.Model.Entities; +using Jellyfin.Data.Enums; namespace MediaBrowser.Model.Dlna { diff --git a/MediaBrowser.Model/Entities/DisplayPreferences.cs b/MediaBrowser.Model/Entities/DisplayPreferences.cs deleted file mode 100644 index 7e5c5be3b..000000000 --- a/MediaBrowser.Model/Entities/DisplayPreferences.cs +++ /dev/null @@ -1,111 +0,0 @@ -#nullable disable -using System.Collections.Generic; - -namespace MediaBrowser.Model.Entities -{ - /// <summary> - /// Defines the display preferences for any item that supports them (usually Folders). - /// </summary> - public class DisplayPreferences - { - /// <summary> - /// The image scale. - /// </summary> - private const double ImageScale = .9; - - /// <summary> - /// Initializes a new instance of the <see cref="DisplayPreferences" /> class. - /// </summary> - public DisplayPreferences() - { - RememberIndexing = false; - PrimaryImageHeight = 250; - PrimaryImageWidth = 250; - ShowBackdrop = true; - CustomPrefs = new Dictionary<string, string>(); - } - - /// <summary> - /// Gets or sets the user id. - /// </summary> - /// <value>The user id.</value> - public string Id { get; set; } - - /// <summary> - /// Gets or sets the type of the view. - /// </summary> - /// <value>The type of the view.</value> - public string ViewType { get; set; } - - /// <summary> - /// Gets or sets the sort by. - /// </summary> - /// <value>The sort by.</value> - public string SortBy { get; set; } - - /// <summary> - /// Gets or sets the index by. - /// </summary> - /// <value>The index by.</value> - public string IndexBy { get; set; } - - /// <summary> - /// Gets or sets a value indicating whether [remember indexing]. - /// </summary> - /// <value><c>true</c> if [remember indexing]; otherwise, <c>false</c>.</value> - public bool RememberIndexing { get; set; } - - /// <summary> - /// Gets or sets the height of the primary image. - /// </summary> - /// <value>The height of the primary image.</value> - public int PrimaryImageHeight { get; set; } - - /// <summary> - /// Gets or sets the width of the primary image. - /// </summary> - /// <value>The width of the primary image.</value> - public int PrimaryImageWidth { get; set; } - - /// <summary> - /// Gets or sets the custom prefs. - /// </summary> - /// <value>The custom prefs.</value> - public Dictionary<string, string> CustomPrefs { get; set; } - - /// <summary> - /// Gets or sets the scroll direction. - /// </summary> - /// <value>The scroll direction.</value> - public ScrollDirection ScrollDirection { get; set; } - - /// <summary> - /// Gets or sets a value indicating whether to show backdrops on this item. - /// </summary> - /// <value><c>true</c> if showing backdrops; otherwise, <c>false</c>.</value> - public bool ShowBackdrop { get; set; } - - /// <summary> - /// Gets or sets a value indicating whether [remember sorting]. - /// </summary> - /// <value><c>true</c> if [remember sorting]; otherwise, <c>false</c>.</value> - public bool RememberSorting { get; set; } - - /// <summary> - /// Gets or sets the sort order. - /// </summary> - /// <value>The sort order.</value> - public SortOrder SortOrder { get; set; } - - /// <summary> - /// Gets or sets a value indicating whether [show sidebar]. - /// </summary> - /// <value><c>true</c> if [show sidebar]; otherwise, <c>false</c>.</value> - public bool ShowSidebar { get; set; } - - /// <summary> - /// Gets or sets the client. - /// </summary> - public string Client { get; set; } - } -} diff --git a/MediaBrowser.Model/Entities/DisplayPreferencesDto.cs b/MediaBrowser.Model/Entities/DisplayPreferencesDto.cs new file mode 100644 index 000000000..1f7fe3030 --- /dev/null +++ b/MediaBrowser.Model/Entities/DisplayPreferencesDto.cs @@ -0,0 +1,107 @@ +#nullable disable +using System.Collections.Generic; +using Jellyfin.Data.Enums; + +namespace MediaBrowser.Model.Entities +{ + /// <summary> + /// Defines the display preferences for any item that supports them (usually Folders). + /// </summary> + public class DisplayPreferencesDto + { + /// <summary> + /// Initializes a new instance of the <see cref="DisplayPreferencesDto" /> class. + /// </summary> + public DisplayPreferencesDto() + { + RememberIndexing = false; + PrimaryImageHeight = 250; + PrimaryImageWidth = 250; + ShowBackdrop = true; + CustomPrefs = new Dictionary<string, string>(); + } + + /// <summary> + /// Gets or sets the user id. + /// </summary> + /// <value>The user id.</value> + public string Id { get; set; } + + /// <summary> + /// Gets or sets the type of the view. + /// </summary> + /// <value>The type of the view.</value> + public string ViewType { get; set; } + + /// <summary> + /// Gets or sets the sort by. + /// </summary> + /// <value>The sort by.</value> + public string SortBy { get; set; } + + /// <summary> + /// Gets or sets the index by. + /// </summary> + /// <value>The index by.</value> + public string IndexBy { get; set; } + + /// <summary> + /// Gets or sets a value indicating whether [remember indexing]. + /// </summary> + /// <value><c>true</c> if [remember indexing]; otherwise, <c>false</c>.</value> + public bool RememberIndexing { get; set; } + + /// <summary> + /// Gets or sets the height of the primary image. + /// </summary> + /// <value>The height of the primary image.</value> + public int PrimaryImageHeight { get; set; } + + /// <summary> + /// Gets or sets the width of the primary image. + /// </summary> + /// <value>The width of the primary image.</value> + public int PrimaryImageWidth { get; set; } + + /// <summary> + /// Gets or sets the custom prefs. + /// </summary> + /// <value>The custom prefs.</value> + public Dictionary<string, string> CustomPrefs { get; set; } + + /// <summary> + /// Gets or sets the scroll direction. + /// </summary> + /// <value>The scroll direction.</value> + public ScrollDirection ScrollDirection { get; set; } + + /// <summary> + /// Gets or sets a value indicating whether to show backdrops on this item. + /// </summary> + /// <value><c>true</c> if showing backdrops; otherwise, <c>false</c>.</value> + public bool ShowBackdrop { get; set; } + + /// <summary> + /// Gets or sets a value indicating whether [remember sorting]. + /// </summary> + /// <value><c>true</c> if [remember sorting]; otherwise, <c>false</c>.</value> + public bool RememberSorting { get; set; } + + /// <summary> + /// Gets or sets the sort order. + /// </summary> + /// <value>The sort order.</value> + public SortOrder SortOrder { get; set; } + + /// <summary> + /// Gets or sets a value indicating whether [show sidebar]. + /// </summary> + /// <value><c>true</c> if [show sidebar]; otherwise, <c>false</c>.</value> + public bool ShowSidebar { get; set; } + + /// <summary> + /// Gets or sets the client. + /// </summary> + public string Client { get; set; } + } +} diff --git a/MediaBrowser.Model/Entities/ScrollDirection.cs b/MediaBrowser.Model/Entities/ScrollDirection.cs deleted file mode 100644 index a1de0edcb..000000000 --- a/MediaBrowser.Model/Entities/ScrollDirection.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace MediaBrowser.Model.Entities -{ - /// <summary> - /// Enum ScrollDirection. - /// </summary> - public enum ScrollDirection - { - /// <summary> - /// The horizontal. - /// </summary> - Horizontal, - - /// <summary> - /// The vertical. - /// </summary> - Vertical - } -} diff --git a/MediaBrowser.Model/Entities/SortOrder.cs b/MediaBrowser.Model/Entities/SortOrder.cs deleted file mode 100644 index f3abc06f3..000000000 --- a/MediaBrowser.Model/Entities/SortOrder.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace MediaBrowser.Model.Entities -{ - /// <summary> - /// Enum SortOrder. - /// </summary> - public enum SortOrder - { - /// <summary> - /// The ascending. - /// </summary> - Ascending, - - /// <summary> - /// The descending. - /// </summary> - Descending - } -} diff --git a/MediaBrowser.Model/LiveTv/LiveTvChannelQuery.cs b/MediaBrowser.Model/LiveTv/LiveTvChannelQuery.cs index 2b2377fda..ab74aff28 100644 --- a/MediaBrowser.Model/LiveTv/LiveTvChannelQuery.cs +++ b/MediaBrowser.Model/LiveTv/LiveTvChannelQuery.cs @@ -2,7 +2,7 @@ #pragma warning disable CS1591 using System; -using MediaBrowser.Model.Entities; +using Jellyfin.Data.Enums; namespace MediaBrowser.Model.LiveTv { diff --git a/MediaBrowser.Model/LiveTv/SeriesTimerQuery.cs b/MediaBrowser.Model/LiveTv/SeriesTimerQuery.cs index b899a464b..dae885775 100644 --- a/MediaBrowser.Model/LiveTv/SeriesTimerQuery.cs +++ b/MediaBrowser.Model/LiveTv/SeriesTimerQuery.cs @@ -1,6 +1,6 @@ #pragma warning disable CS1591 -using MediaBrowser.Model.Entities; +using Jellyfin.Data.Enums; namespace MediaBrowser.Model.LiveTv { -- cgit v1.2.3 From 4742ddbb711e9c7b0141b592b9b005f85e85c0df Mon Sep 17 00:00:00 2001 From: Patrick Barron <barronpm@gmail.com> Date: Fri, 17 Jul 2020 19:48:11 -0400 Subject: Update .NET Core to 3.1.6 --- Emby.Server.Implementations/Emby.Server.Implementations.csproj | 8 ++++---- Jellyfin.Api/Jellyfin.Api.csproj | 2 +- Jellyfin.Data/Jellyfin.Data.csproj | 4 ++-- .../Jellyfin.Server.Implementations.csproj | 4 ++-- Jellyfin.Server/Jellyfin.Server.csproj | 4 ++-- MediaBrowser.Common/MediaBrowser.Common.csproj | 4 ++-- MediaBrowser.Controller/MediaBrowser.Controller.csproj | 4 ++-- MediaBrowser.Model/MediaBrowser.Model.csproj | 2 +- MediaBrowser.Providers/MediaBrowser.Providers.csproj | 4 ++-- tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj | 2 +- tests/MediaBrowser.Api.Tests/MediaBrowser.Api.Tests.csproj | 2 +- 11 files changed, 20 insertions(+), 20 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj index f7ad59c10..4351b9aa5 100644 --- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj +++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj @@ -34,10 +34,10 @@ <PackageReference Include="Microsoft.AspNetCore.ResponseCompression" Version="2.2.0" /> <PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="2.2.0" /> <PackageReference Include="Microsoft.AspNetCore.WebSockets" Version="2.2.1" /> - <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.1.5" /> - <PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="3.1.5" /> - <PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.1.5" /> - <PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="3.1.5" /> + <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.1.6" /> + <PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="3.1.6" /> + <PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.1.6" /> + <PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="3.1.6" /> <PackageReference Include="Mono.Nat" Version="2.0.1" /> <PackageReference Include="prometheus-net.DotNetRuntime" Version="3.3.1" /> <PackageReference Include="ServiceStack.Text.Core" Version="5.9.0" /> diff --git a/Jellyfin.Api/Jellyfin.Api.csproj b/Jellyfin.Api/Jellyfin.Api.csproj index 93c4612b6..3693d5122 100644 --- a/Jellyfin.Api/Jellyfin.Api.csproj +++ b/Jellyfin.Api/Jellyfin.Api.csproj @@ -14,7 +14,7 @@ <ItemGroup> <PackageReference Include="Microsoft.AspNetCore.Authentication" Version="2.2.0" /> - <PackageReference Include="Microsoft.AspNetCore.Authorization" Version="3.1.5" /> + <PackageReference Include="Microsoft.AspNetCore.Authorization" Version="3.1.6" /> <PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.2.0" /> <PackageReference Include="Swashbuckle.AspNetCore" Version="5.5.1" /> </ItemGroup> diff --git a/Jellyfin.Data/Jellyfin.Data.csproj b/Jellyfin.Data/Jellyfin.Data.csproj index 58d1ba2f3..8ce0f3848 100644 --- a/Jellyfin.Data/Jellyfin.Data.csproj +++ b/Jellyfin.Data/Jellyfin.Data.csproj @@ -19,8 +19,8 @@ </ItemGroup> <ItemGroup> - <PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="3.1.5" /> - <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="3.1.5" /> + <PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="3.1.6" /> + <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="3.1.6" /> </ItemGroup> </Project> diff --git a/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj b/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj index dcac1b34b..21748ca19 100644 --- a/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj +++ b/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj @@ -24,11 +24,11 @@ </ItemGroup> <ItemGroup> - <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="3.1.5"> + <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="3.1.6"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> </PackageReference> - <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="3.1.5"> + <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="3.1.6"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> </PackageReference> diff --git a/Jellyfin.Server/Jellyfin.Server.csproj b/Jellyfin.Server/Jellyfin.Server.csproj index 6a2d252ab..b1bd38cff 100644 --- a/Jellyfin.Server/Jellyfin.Server.csproj +++ b/Jellyfin.Server/Jellyfin.Server.csproj @@ -41,8 +41,8 @@ <ItemGroup> <PackageReference Include="CommandLineParser" Version="2.8.0" /> - <PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="3.1.5" /> - <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="3.1.5" /> + <PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="3.1.6" /> + <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="3.1.6" /> <PackageReference Include="prometheus-net" Version="3.6.0" /> <PackageReference Include="prometheus-net.AspNetCore" Version="3.6.0" /> <PackageReference Include="Serilog.AspNetCore" Version="3.2.0" /> diff --git a/MediaBrowser.Common/MediaBrowser.Common.csproj b/MediaBrowser.Common/MediaBrowser.Common.csproj index c9ca153c7..7380f39fd 100644 --- a/MediaBrowser.Common/MediaBrowser.Common.csproj +++ b/MediaBrowser.Common/MediaBrowser.Common.csproj @@ -17,8 +17,8 @@ </ItemGroup> <ItemGroup> - <PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.1.5" /> - <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="3.1.5" /> + <PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.1.6" /> + <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="3.1.6" /> <PackageReference Include="Microsoft.Net.Http.Headers" Version="2.2.8" /> </ItemGroup> diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index 73e966344..67f17f7a5 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -13,8 +13,8 @@ </PropertyGroup> <ItemGroup> - <PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.1.5" /> - <PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="3.1.5" /> + <PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.1.6" /> + <PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="3.1.6" /> </ItemGroup> <ItemGroup> diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj index 83bd0c07e..902e29b20 100644 --- a/MediaBrowser.Model/MediaBrowser.Model.csproj +++ b/MediaBrowser.Model/MediaBrowser.Model.csproj @@ -23,7 +23,7 @@ <ItemGroup> <PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.2.0" /> - <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="3.1.5" /> + <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="3.1.6" /> <PackageReference Include="System.Globalization" Version="4.3.0" /> <PackageReference Include="System.Text.Json" Version="4.7.2" /> </ItemGroup> diff --git a/MediaBrowser.Providers/MediaBrowser.Providers.csproj b/MediaBrowser.Providers/MediaBrowser.Providers.csproj index 446e27df6..42c7cec53 100644 --- a/MediaBrowser.Providers/MediaBrowser.Providers.csproj +++ b/MediaBrowser.Providers/MediaBrowser.Providers.csproj @@ -16,8 +16,8 @@ </ItemGroup> <ItemGroup> - <PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.1.5" /> - <PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="3.1.5" /> + <PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.1.6" /> + <PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="3.1.6" /> <PackageReference Include="OptimizedPriorityQueue" Version="4.2.0" /> <PackageReference Include="PlaylistsNET" Version="1.0.6" /> <PackageReference Include="TvDbSharper" Version="3.2.0" /> diff --git a/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj b/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj index 219020888..132050e7b 100644 --- a/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj +++ b/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj @@ -16,7 +16,7 @@ <PackageReference Include="AutoFixture" Version="4.13.0" /> <PackageReference Include="AutoFixture.AutoMoq" Version="4.12.0" /> <PackageReference Include="AutoFixture.Xunit2" Version="4.12.0" /> - <PackageReference Include="Microsoft.Extensions.Options" Version="3.1.5" /> + <PackageReference Include="Microsoft.Extensions.Options" Version="3.1.6" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.6.1" /> <PackageReference Include="xunit" Version="2.4.1" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" /> diff --git a/tests/MediaBrowser.Api.Tests/MediaBrowser.Api.Tests.csproj b/tests/MediaBrowser.Api.Tests/MediaBrowser.Api.Tests.csproj index a767c0039..8309faebd 100644 --- a/tests/MediaBrowser.Api.Tests/MediaBrowser.Api.Tests.csproj +++ b/tests/MediaBrowser.Api.Tests/MediaBrowser.Api.Tests.csproj @@ -8,7 +8,7 @@ </PropertyGroup> <ItemGroup> - <PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="3.1.5" /> + <PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="3.1.6" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.6.1" /> <PackageReference Include="xunit" Version="2.4.1" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" /> -- cgit v1.2.3 From 3514813eb4eda997a0ea722cc2ed41979419c6dd Mon Sep 17 00:00:00 2001 From: David <daullmer@gmail.com> Date: Sun, 12 Jul 2020 11:14:38 +0200 Subject: Continute work --- Emby.Server.Implementations/ApplicationHost.cs | 3 + Jellyfin.Api/Controllers/AudioController.cs | 350 ++++++++--- Jellyfin.Api/Controllers/PlaystateController.cs | 12 +- Jellyfin.Api/Helpers/FileStreamResponseHelpers.cs | 236 +++++++ Jellyfin.Api/Helpers/StreamingHelpers.cs | 681 +++++++++++++++++++-- Jellyfin.Api/Helpers/TranscodingJobHelper.cs | 453 +++++++++++++- Jellyfin.Api/Models/StreamState.cs | 145 ----- Jellyfin.Api/Models/StreamingDtos/StreamState.cs | 207 +++++++ .../Playback/Progressive/AudioService.cs | 4 - .../MediaEncoding/EncodingHelper.cs | 11 + 10 files changed, 1801 insertions(+), 301 deletions(-) create mode 100644 Jellyfin.Api/Helpers/FileStreamResponseHelpers.cs delete mode 100644 Jellyfin.Api/Models/StreamState.cs create mode 100644 Jellyfin.Api/Models/StreamingDtos/StreamState.cs (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index 25ee7e9ec..c177537b8 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -46,6 +46,7 @@ using Emby.Server.Implementations.Session; using Emby.Server.Implementations.TV; using Emby.Server.Implementations.Updates; using Emby.Server.Implementations.SyncPlay; +using Jellyfin.Api.Helpers; using MediaBrowser.Api; using MediaBrowser.Common; using MediaBrowser.Common.Configuration; @@ -637,6 +638,8 @@ namespace Emby.Server.Implementations serviceCollection.AddSingleton<EncodingHelper>(); serviceCollection.AddSingleton<IAttachmentExtractor, MediaBrowser.MediaEncoding.Attachments.AttachmentExtractor>(); + + serviceCollection.AddSingleton<TranscodingJobHelper>(); } /// <summary> diff --git a/Jellyfin.Api/Controllers/AudioController.cs b/Jellyfin.Api/Controllers/AudioController.cs index 39df1e1b1..4d29d3880 100644 --- a/Jellyfin.Api/Controllers/AudioController.cs +++ b/Jellyfin.Api/Controllers/AudioController.cs @@ -3,97 +3,277 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using Jellyfin.Api.Helpers; +using MediaBrowser.Common.Configuration; +using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Devices; using MediaBrowser.Controller.Dlna; +using MediaBrowser.Controller.Library; using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Controller.Net; +using MediaBrowser.Model.Dlna; +using MediaBrowser.Model.IO; using MediaBrowser.Model.MediaInfo; using MediaBrowser.Model.Net; +using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.Logging; -using Microsoft.Net.Http.Headers; +using Microsoft.Extensions.Configuration; namespace Jellyfin.Api.Controllers { - /// <summary> /// The audio controller. /// </summary> + // TODO: In order to autheneticate this in the future, Dlna playback will require updating public class AudioController : BaseJellyfinApiController { private readonly IDlnaManager _dlnaManager; - private readonly ILogger _logger; + private readonly IAuthorizationContext _authContext; + private readonly IUserManager _userManager; + private readonly ILibraryManager _libraryManager; + private readonly IMediaSourceManager _mediaSourceManager; + private readonly IServerConfigurationManager _serverConfigurationManager; + private readonly IMediaEncoder _mediaEncoder; + private readonly IStreamHelper _streamHelper; + private readonly IFileSystem _fileSystem; + private readonly ISubtitleEncoder _subtitleEncoder; + private readonly IConfiguration _configuration; + private readonly IDeviceManager _deviceManager; + private readonly TranscodingJobHelper _transcodingJobHelper; + + private readonly TranscodingJobType _transcodingJobType = TranscodingJobType.Progressive; /// <summary> /// Initializes a new instance of the <see cref="AudioController"/> class. /// </summary> /// <param name="dlnaManager">Instance of the <see cref="IDlnaManager"/> interface.</param> - /// <param name="logger">Instance of the <see cref="ILogger{AuidoController}"/> interface.</param> - public AudioController(IDlnaManager dlnaManager, ILogger<AudioController> logger) + /// <param name="userManger">Instance of the <see cref="IUserManager"/> interface.</param> + /// <param name="authorizationContext">Instance of the <see cref="IAuthorizationContext"/> interface.</param> + /// <param name="libraryManager">Instance of the <see cref="ILibraryManager"/> interface.</param> + /// <param name="mediaSourceManager">Instance of the <see cref="IMediaSourceManager"/> interface.</param> + /// <param name="serverConfigurationManager">Instance of the <see cref="IServerConfigurationManager"/> interface.</param> + /// <param name="mediaEncoder">Instance of the <see cref="IMediaEncoder"/> interface.</param> + /// <param name="streamHelper">Instance of the <see cref="IStreamHelper"/> interface.</param> + /// <param name="fileSystem">Instance of the <see cref="IFileSystem"/> interface.</param> + /// <param name="subtitleEncoder">Instance of the <see cref="ISubtitleEncoder"/> interface.</param> + /// <param name="configuration">Instance of the <see cref="IConfiguration"/> interface.</param> + /// <param name="deviceManager">Instance of the <see cref="IDeviceManager"/> interface.</param> + /// <param name="transcodingJobHelper">The <see cref="TranscodingJobHelper"/> singleton.</param> + public AudioController( + IDlnaManager dlnaManager, + IUserManager userManger, + IAuthorizationContext authorizationContext, + ILibraryManager libraryManager, + IMediaSourceManager mediaSourceManager, + IServerConfigurationManager serverConfigurationManager, + IMediaEncoder mediaEncoder, + IStreamHelper streamHelper, + IFileSystem fileSystem, + ISubtitleEncoder subtitleEncoder, + IConfiguration configuration, + IDeviceManager deviceManager, + TranscodingJobHelper transcodingJobHelper) { _dlnaManager = dlnaManager; - _logger = logger; + _authContext = authorizationContext; + _userManager = userManger; + _libraryManager = libraryManager; + _mediaSourceManager = mediaSourceManager; + _serverConfigurationManager = serverConfigurationManager; + _mediaEncoder = mediaEncoder; + _streamHelper = streamHelper; + _fileSystem = fileSystem; + _subtitleEncoder = subtitleEncoder; + _configuration = configuration; + _deviceManager = deviceManager; + _transcodingJobHelper = transcodingJobHelper; } - [HttpGet("{id}/stream.{container}")] - [HttpGet("{id}/stream")] - [HttpHead("{id}/stream.{container}")] - [HttpGet("{id}/stream")] + /// <summary> + /// Gets an audio stream. + /// </summary> + /// <param name="itemId">The item id.</param> + /// <param name="container">The audio container.</param> + /// <param name="static">Optional. If true, the original file will be streamed statically without any encoding. Use either no url extension or the original file extension. true/false.</param> + /// <param name="params">The streaming parameters.</param> + /// <param name="tag">The tag.</param> + /// <param name="deviceProfileId">Optional. The dlna device profile id to utilize.</param> + /// <param name="playSessionId">The play session id.</param> + /// <param name="segmentContainer">The segment container.</param> + /// <param name="segmentLength">The segment lenght.</param> + /// <param name="minSegments">The minimum number of segments.</param> + /// <param name="mediaSourceId">The media version id, if playing an alternate version.</param> + /// <param name="deviceId">The device id of the client requesting. Used to stop encoding processes when needed.</param> + /// <param name="audioCodec">Optional. Specify a audio codec to encode to, e.g. mp3. If omitted the server will auto-select using the url's extension. Options: aac, mp3, vorbis, wma.</param> + /// <param name="enableAutoStreamCopy">Whether or not to allow automatic stream copy if requested values match the original source. Defaults to true.</param> + /// <param name="allowVideoStreamCopy">Whether or not to allow copying of the video stream url.</param> + /// <param name="allowAudioStreamCopy">Whether or not to allow copying of the audio stream url.</param> + /// <param name="breakOnNonKeyFrames">Optional. Whether to break on non key frames.</param> + /// <param name="audioSampleRate">Optional. Specify a specific audio sample rate, e.g. 44100.</param> + /// <param name="maxAudioBitDepth">Optional. The maximum audio bit depth.</param> + /// <param name="audioBitRate">Optional. Specify an audio bitrate to encode to, e.g. 128000. If omitted this will be left to encoder defaults.</param> + /// <param name="audioChannels">Optional. Specify a specific number of audio channels to encode to, e.g. 2.</param> + /// <param name="maxAudioChannels">Optional. Specify a maximum number of audio channels to encode to, e.g. 2.</param> + /// <param name="profile">Optional. Specify a specific an encoder profile (varies by encoder), e.g. main, baseline, high.</param> + /// <param name="level">Optional. Specify a level for the encoder profile (varies by encoder), e.g. 3, 3.1.</param> + /// <param name="framerate">Optional. A specific video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements.</param> + /// <param name="maxFramerate">Optional. A specific maximum video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements.</param> + /// <param name="copyTimestamps">Whether or not to copy timestamps when transcoding with an offset. Defaults to false.</param> + /// <param name="startTimeTicks">Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms.</param> + /// <param name="width">Optional. The fixed horizontal resolution of the encoded video.</param> + /// <param name="height">Optional. The fixed vertical resolution of the encoded video.</param> + /// <param name="videoBitRate">Optional. Specify a video bitrate to encode to, e.g. 500000. If omitted this will be left to encoder defaults.</param> + /// <param name="subtitleStreamIndex">Optional. The index of the subtitle stream to use. If omitted no subtitles will be used.</param> + /// <param name="subtitleMethod">Optional. Specify the subtitle delivery method.</param> + /// <param name="maxRefFrames">Optional.</param> + /// <param name="maxVideoBitDepth">Optional. The maximum video bit depth.</param> + /// <param name="requireAvc">Optional. Whether to require avc.</param> + /// <param name="deInterlace">Optional. Whether to deinterlace the video.</param> + /// <param name="requireNonAnamorphic">Optional. Whether to require a non anamporphic stream.</param> + /// <param name="transcodingMaxAudioChannels">Optional. The maximum number of audio channels to transcode.</param> + /// <param name="cpuCoreLimit">Optional. The limit of how many cpu cores to use.</param> + /// <param name="liveStreamId">The live stream id.</param> + /// <param name="enableMpegtsM2TsMode">Optional. Whether to enable the MpegtsM2Ts mode.</param> + /// <param name="videoCodec">Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vpx, wmv.</param> + /// <param name="subtitleCodec">Optional. Specify a subtitle codec to encode to.</param> + /// <param name="transcodingReasons">Optional. The transcoding reason.</param> + /// <param name="audioStreamIndex">Optional. The index of the audio stream to use. If omitted the first audio stream will be used.</param> + /// <param name="videoStreamIndex">Optional. The index of the video stream to use. If omitted the first video stream will be used.</param> + /// <param name="context">Optional. The <see cref="EncodingContext"/>.</param> + /// <param name="streamOptions">Optional. The streaming options.</param> + /// <returns>A <see cref="FileResult"/> containing the audio file.</returns> + [HttpGet("{itemId}/stream.{container}")] + [HttpGet("{itemId}/stream")] + [HttpHead("{itemId}/stream.{container}")] + [HttpGet("{itemId}/stream")] + [ProducesResponseType(StatusCodes.Status200OK)] public async Task<ActionResult> GetAudioStream( - [FromRoute] string id, - [FromRoute] string container, - [FromQuery] bool Static, - [FromQuery] string tag) + [FromRoute] Guid itemId, + [FromRoute] string? container, + [FromQuery] bool? @static, + [FromQuery] string? @params, + [FromQuery] string? tag, + [FromQuery] string? deviceProfileId, + [FromQuery] string? playSessionId, + [FromQuery] string? segmentContainer, + [FromQuery] int? segmentLength, + [FromQuery] int? minSegments, + [FromQuery] string? mediaSourceId, + [FromQuery] string? deviceId, + [FromQuery] string? audioCodec, + [FromQuery] bool? enableAutoStreamCopy, + [FromQuery] bool? allowVideoStreamCopy, + [FromQuery] bool? allowAudioStreamCopy, + [FromQuery] bool? breakOnNonKeyFrames, + [FromQuery] int? audioSampleRate, + [FromQuery] int? maxAudioBitDepth, + [FromQuery] int? audioBitRate, + [FromQuery] int? audioChannels, + [FromQuery] int? maxAudioChannels, + [FromQuery] string? profile, + [FromQuery] string? level, + [FromQuery] float? framerate, + [FromQuery] float? maxFramerate, + [FromQuery] bool? copyTimestamps, + [FromQuery] long? startTimeTicks, + [FromQuery] int? width, + [FromQuery] int? height, + [FromQuery] int? videoBitRate, + [FromQuery] int? subtitleStreamIndex, + [FromQuery] SubtitleDeliveryMethod subtitleMethod, + [FromQuery] int? maxRefFrames, + [FromQuery] int? maxVideoBitDepth, + [FromQuery] bool? requireAvc, + [FromQuery] bool? deInterlace, + [FromQuery] bool? requireNonAnamorphic, + [FromQuery] int? transcodingMaxAudioChannels, + [FromQuery] int? cpuCoreLimit, + [FromQuery] string? liveStreamId, + [FromQuery] bool? enableMpegtsM2TsMode, + [FromQuery] string? videoCodec, + [FromQuery] string? subtitleCodec, + [FromQuery] string? transcodingReasons, + [FromQuery] int? audioStreamIndex, + [FromQuery] int? videoStreamIndex, + [FromQuery] EncodingContext context, + [FromQuery] Dictionary<string, string> streamOptions) { bool isHeadRequest = Request.Method == System.Net.WebRequestMethods.Http.Head; var cancellationTokenSource = new CancellationTokenSource(); - var state = await GetState(request, cancellationTokenSource.Token).ConfigureAwait(false); + var state = await StreamingHelpers.GetStreamingState( + itemId, + startTimeTicks, + audioCodec, + subtitleCodec, + videoCodec, + @params, + @static, + container, + liveStreamId, + playSessionId, + mediaSourceId, + deviceId, + deviceProfileId, + audioBitRate, + Request, + _authContext, + _mediaSourceManager, + _userManager, + _libraryManager, + _serverConfigurationManager, + _mediaEncoder, + _fileSystem, + _subtitleEncoder, + _configuration, + _dlnaManager, + _deviceManager, + _transcodingJobHelper, + _transcodingJobType, + false, + cancellationTokenSource.Token) + .ConfigureAwait(false); - if (Static && state.DirectStreamProvider != null) + if (@static.HasValue && @static.Value && state.DirectStreamProvider != null) { - StreamingHelpers.AddDlnaHeaders(state, Response.Headers, true, Request, _dlnaManager); + StreamingHelpers.AddDlnaHeaders(state, Response.Headers, true, startTimeTicks, Request, _dlnaManager); using (state) { - var outputHeaders = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); - - // TODO: Don't hardcode this - outputHeaders[HeaderNames.ContentType] = MimeTypes.GetMimeType("file.ts"); + // TODO AllowEndOfFile = false + await new ProgressiveFileCopier(_streamHelper, state.DirectStreamProvider).WriteToAsync(Response.Body, CancellationToken.None).ConfigureAwait(false); - return new ProgressiveFileCopier(state.DirectStreamProvider, outputHeaders, null, _logger, CancellationToken.None) - { - AllowEndOfFile = false - }; + // TODO (moved from MediaBrowser.Api): Don't hardcode contentType + return File(Response.Body, MimeTypes.GetMimeType("file.ts")!); } } // Static remote stream - if (Static && state.InputProtocol == MediaProtocol.Http) + if (@static.HasValue && @static.Value && state.InputProtocol == MediaProtocol.Http) { - StreamingHelpers.AddDlnaHeaders(state, Response.Headers, true, Request, _dlnaManager); + StreamingHelpers.AddDlnaHeaders(state, Response.Headers, true, startTimeTicks, Request, _dlnaManager); using (state) { - return await GetStaticRemoteStreamResult(state, responseHeaders, isHeadRequest, cancellationTokenSource).ConfigureAwait(false); + return await FileStreamResponseHelpers.GetStaticRemoteStreamResult(state, isHeadRequest, this, cancellationTokenSource).ConfigureAwait(false); } } - if (Static && state.InputProtocol != MediaProtocol.File) + if (@static.HasValue && @static.Value && state.InputProtocol != MediaProtocol.File) { - throw new ArgumentException(string.Format($"Input protocol {state.InputProtocol} cannot be streamed statically.")); + return BadRequest($"Input protocol {state.InputProtocol} cannot be streamed statically"); } var outputPath = state.OutputFilePath; - var outputPathExists = File.Exists(outputPath); + var outputPathExists = System.IO.File.Exists(outputPath); - var transcodingJob = TranscodingJobHelper.GetTranscodingJob(outputPath, TranscodingJobType.Progressive); + var transcodingJob = _transcodingJobHelper.GetTranscodingJob(outputPath, TranscodingJobType.Progressive); var isTranscodeCached = outputPathExists && transcodingJob != null; - StreamingHelpers.AddDlnaHeaders(state, Response.Headers, Static || isTranscodeCached, Request, _dlnaManager); + StreamingHelpers.AddDlnaHeaders(state, Response.Headers, (@static.HasValue && @static.Value) || isTranscodeCached, startTimeTicks, Request, _dlnaManager); // Static stream - if (Static) + if (@static.HasValue && @static.Value) { var contentType = state.GetMimeType("." + state.OutputContainer, false) ?? state.GetMimeType(state.MediaPath); @@ -101,16 +281,10 @@ namespace Jellyfin.Api.Controllers { if (state.MediaSource.IsInfiniteStream) { - var outputHeaders = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase) - { - [HeaderNames.ContentType] = contentType - }; - + // TODO AllowEndOfFile = false + await new ProgressiveFileCopier(_streamHelper, state.MediaPath).WriteToAsync(Response.Body, CancellationToken.None).ConfigureAwait(false); - return new ProgressiveFileCopier(FileSystem, state.MediaPath, outputHeaders, null, _logger, CancellationToken.None) - { - AllowEndOfFile = false - }; + return File(Response.Body, contentType); } TimeSpan? cacheDuration = null; @@ -120,57 +294,65 @@ namespace Jellyfin.Api.Controllers cacheDuration = TimeSpan.FromDays(365); } + return FileStreamResponseHelpers.GetStaticFileResult( + state.MediaPath, + contentType, + _fileSystem.GetLastWriteTimeUtc(state.MediaPath), + cacheDuration, + isHeadRequest, + this); + } + } + + /* + // Not static but transcode cache file exists + if (isTranscodeCached && state.VideoRequest == null) + { + var contentType = state.GetMimeType(outputPath) + try + { + if (transcodingJob != null) + { + ApiEntryPoint.Instance.OnTranscodeBeginRequest(transcodingJob); + } return await ResultFactory.GetStaticFileResult(Request, new StaticFileResultOptions { ResponseHeaders = responseHeaders, ContentType = contentType, IsHeadRequest = isHeadRequest, - Path = state.MediaPath, - CacheDuration = cacheDuration - + Path = outputPath, + FileShare = FileShare.ReadWrite, + OnComplete = () => + { + if (transcodingJob != null) + { + ApiEntryPoint.Instance.OnTranscodeEndRequest(transcodingJob); + } }).ConfigureAwait(false); } + finally + { + state.Dispose(); + } } + */ - //// Not static but transcode cache file exists - //if (isTranscodeCached && state.VideoRequest == null) - //{ - // var contentType = state.GetMimeType(outputPath); - - // try - // { - // if (transcodingJob != null) - // { - // ApiEntryPoint.Instance.OnTranscodeBeginRequest(transcodingJob); - // } - - // return await ResultFactory.GetStaticFileResult(Request, new StaticFileResultOptions - // { - // ResponseHeaders = responseHeaders, - // ContentType = contentType, - // IsHeadRequest = isHeadRequest, - // Path = outputPath, - // FileShare = FileShare.ReadWrite, - // OnComplete = () => - // { - // if (transcodingJob != null) - // { - // ApiEntryPoint.Instance.OnTranscodeEndRequest(transcodingJob); - // } - // } - - // }).ConfigureAwait(false); - // } - // finally - // { - // state.Dispose(); - // } - //} - - // Need to start ffmpeg + // Need to start ffmpeg (because media can't be returned directly) try { - return await GetStreamResult(request, state, responseHeaders, isHeadRequest, cancellationTokenSource).ConfigureAwait(false); + var encodingOptions = _serverConfigurationManager.GetEncodingOptions(); + var encodingHelper = new EncodingHelper(_mediaEncoder, _fileSystem, _subtitleEncoder, _configuration); + var ffmpegCommandLineArguments = encodingHelper.GetProgressiveAudioFullCommandLine(state, encodingOptions, outputPath); + return await FileStreamResponseHelpers.GetTranscodedFile( + state, + isHeadRequest, + _streamHelper, + this, + _transcodingJobHelper, + ffmpegCommandLineArguments, + Request, + _transcodingJobType, + cancellationTokenSource).ConfigureAwait(false); } catch { diff --git a/Jellyfin.Api/Controllers/PlaystateController.cs b/Jellyfin.Api/Controllers/PlaystateController.cs index 05a6edf4e..da69ca72c 100644 --- a/Jellyfin.Api/Controllers/PlaystateController.cs +++ b/Jellyfin.Api/Controllers/PlaystateController.cs @@ -8,7 +8,6 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Net; using MediaBrowser.Controller.Session; using MediaBrowser.Model.Dto; -using MediaBrowser.Model.IO; using MediaBrowser.Model.Session; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; @@ -40,8 +39,7 @@ namespace Jellyfin.Api.Controllers /// <param name="sessionManager">Instance of the <see cref="ISessionManager"/> interface.</param> /// <param name="authContext">Instance of the <see cref="IAuthorizationContext"/> interface.</param> /// <param name="loggerFactory">Instance of the <see cref="ILoggerFactory"/> interface.</param> - /// <param name="mediaSourceManager">Instance of the <see cref="IMediaSourceManager"/> interface.</param> - /// <param name="fileSystem">Instance of the <see cref="IFileSystem"/> interface.</param> + /// <param name="transcodingJobHelper">Th <see cref="TranscodingJobHelper"/> singleton.</param> public PlaystateController( IUserManager userManager, IUserDataManager userDataRepository, @@ -49,8 +47,7 @@ namespace Jellyfin.Api.Controllers ISessionManager sessionManager, IAuthorizationContext authContext, ILoggerFactory loggerFactory, - IMediaSourceManager mediaSourceManager, - IFileSystem fileSystem) + TranscodingJobHelper transcodingJobHelper) { _userManager = userManager; _userDataRepository = userDataRepository; @@ -59,10 +56,7 @@ namespace Jellyfin.Api.Controllers _authContext = authContext; _logger = loggerFactory.CreateLogger<PlaystateController>(); - _transcodingJobHelper = new TranscodingJobHelper( - loggerFactory.CreateLogger<TranscodingJobHelper>(), - mediaSourceManager, - fileSystem); + _transcodingJobHelper = transcodingJobHelper; } /// <summary> diff --git a/Jellyfin.Api/Helpers/FileStreamResponseHelpers.cs b/Jellyfin.Api/Helpers/FileStreamResponseHelpers.cs new file mode 100644 index 000000000..e03cafe35 --- /dev/null +++ b/Jellyfin.Api/Helpers/FileStreamResponseHelpers.cs @@ -0,0 +1,236 @@ +using System; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using Jellyfin.Api.Models.StreamingDtos; +using MediaBrowser.Controller.MediaEncoding; +using MediaBrowser.Model.IO; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Primitives; +using Microsoft.Net.Http.Headers; + +namespace Jellyfin.Api.Helpers +{ + /// <summary> + /// The stream response helpers. + /// </summary> + public static class FileStreamResponseHelpers + { + /// <summary> + /// Returns a static file from a remote source. + /// </summary> + /// <param name="state">The current <see cref="StreamState"/>.</param> + /// <param name="isHeadRequest">Whether the current request is a HTTP HEAD request so only the headers get returned.</param> + /// <param name="controller">The <see cref="ControllerBase"/> managing the response.</param> + /// <param name="cancellationTokenSource">The <see cref="CancellationTokenSource"/>.</param> + /// <returns>A <see cref="Task{ActionResult}"/> containing the API response.</returns> + public static async Task<ActionResult> GetStaticRemoteStreamResult( + StreamState state, + bool isHeadRequest, + ControllerBase controller, + CancellationTokenSource cancellationTokenSource) + { + HttpClient httpClient = new HttpClient(); + var responseHeaders = controller.Response.Headers; + + if (state.RemoteHttpHeaders.TryGetValue(HeaderNames.UserAgent, out var useragent)) + { + httpClient.DefaultRequestHeaders.Add(HeaderNames.UserAgent, useragent); + } + + var response = await httpClient.GetAsync(state.MediaPath).ConfigureAwait(false); + var contentType = response.Content.Headers.ContentType.ToString(); + + responseHeaders[HeaderNames.AcceptRanges] = "none"; + + // Seeing cases of -1 here + if (response.Content.Headers.ContentLength.HasValue && response.Content.Headers.ContentLength.Value >= 0) + { + responseHeaders[HeaderNames.ContentLength] = response.Content.Headers.ContentLength.Value.ToString(CultureInfo.InvariantCulture); + } + + if (isHeadRequest) + { + using (response) + { + return controller.File(Array.Empty<byte>(), contentType); + } + } + + return controller.File(await response.Content.ReadAsStreamAsync().ConfigureAwait(false), contentType); + } + + /// <summary> + /// Returns a static file from the server. + /// </summary> + /// <param name="path">The path to the file.</param> + /// <param name="contentType">The content type of the file.</param> + /// <param name="dateLastModified">The <see cref="DateTime"/> of the last modification of the file.</param> + /// <param name="cacheDuration">The cache duration of the file.</param> + /// <param name="isHeadRequest">Whether the current request is a HTTP HEAD request so only the headers get returned.</param> + /// <param name="controller">The <see cref="ControllerBase"/> managing the response.</param> + /// <returns>An <see cref="ActionResult"/> the file.</returns> + // TODO: caching doesn't work + public static ActionResult GetStaticFileResult( + string path, + string contentType, + DateTime dateLastModified, + TimeSpan? cacheDuration, + bool isHeadRequest, + ControllerBase controller) + { + bool disableCaching = false; + if (controller.Request.Headers.TryGetValue(HeaderNames.CacheControl, out StringValues headerValue)) + { + disableCaching = headerValue.FirstOrDefault().Contains("no-cache", StringComparison.InvariantCulture); + } + + bool parsingSuccessful = DateTime.TryParseExact(controller.Request.Headers[HeaderNames.IfModifiedSince], "ddd, dd MMM yyyy HH:mm:ss \"GMT\"", new CultureInfo("en-US", false), DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal, out DateTime ifModifiedSinceHeader); + + // if the parsing of the IfModifiedSince header was not successfull, disable caching + if (!parsingSuccessful) + { + disableCaching = true; + } + + controller.Response.ContentType = contentType; + controller.Response.Headers.Add(HeaderNames.Age, Convert.ToInt64((DateTime.UtcNow - dateLastModified).TotalSeconds).ToString(CultureInfo.InvariantCulture)); + controller.Response.Headers.Add(HeaderNames.Vary, HeaderNames.Accept); + + if (disableCaching) + { + controller.Response.Headers.Add(HeaderNames.CacheControl, "no-cache, no-store, must-revalidate"); + controller.Response.Headers.Add(HeaderNames.Pragma, "no-cache, no-store, must-revalidate"); + } + else + { + if (cacheDuration.HasValue) + { + controller.Response.Headers.Add(HeaderNames.CacheControl, "public, max-age=" + cacheDuration.Value.TotalSeconds); + } + else + { + controller.Response.Headers.Add(HeaderNames.CacheControl, "public"); + } + + controller.Response.Headers.Add(HeaderNames.LastModified, dateLastModified.ToUniversalTime().ToString("ddd, dd MMM yyyy HH:mm:ss \"GMT\"", new CultureInfo("en-US", false))); + + // if the image was not modified since "ifModifiedSinceHeader"-header, return a HTTP status code 304 not modified + if (!(dateLastModified > ifModifiedSinceHeader)) + { + if (ifModifiedSinceHeader.Add(cacheDuration!.Value) < DateTime.UtcNow) + { + controller.Response.StatusCode = StatusCodes.Status304NotModified; + return new ContentResult(); + } + } + } + + // if the request is a head request, return a NoContent result with the same headers as it would with a GET request + if (isHeadRequest) + { + return controller.NoContent(); + } + + var stream = new FileStream(path, FileMode.Open, FileAccess.Read); + return controller.File(stream, contentType); + } + + /// <summary> + /// Returns a transcoded file from the server. + /// </summary> + /// <param name="state">The current <see cref="StreamState"/>.</param> + /// <param name="isHeadRequest">Whether the current request is a HTTP HEAD request so only the headers get returned.</param> + /// <param name="streamHelper">Instance of the <see cref="IStreamHelper"/> interface.</param> + /// <param name="controller">The <see cref="ControllerBase"/> managing the response.</param> + /// <param name="transcodingJobHelper">The <see cref="TranscodingJobHelper"/> singleton.</param> + /// <param name="ffmpegCommandLineArguments">The command line arguments to start ffmpeg.</param> + /// <param name="request">The <see cref="HttpRequest"/> starting the transcoding.</param> + /// <param name="transcodingJobType">The <see cref="TranscodingJobType"/>.</param> + /// <param name="cancellationTokenSource">The <see cref="CancellationTokenSource"/>.</param> + /// <returns>A <see cref="Task{ActionResult}"/> containing the transcoded file.</returns> + public static async Task<ActionResult> GetTranscodedFile( + StreamState state, + bool isHeadRequest, + IStreamHelper streamHelper, + ControllerBase controller, + TranscodingJobHelper transcodingJobHelper, + string ffmpegCommandLineArguments, + HttpRequest request, + TranscodingJobType transcodingJobType, + CancellationTokenSource cancellationTokenSource) + { + IHeaderDictionary responseHeaders = controller.Response.Headers; + // Use the command line args with a dummy playlist path + var outputPath = state.OutputFilePath; + + responseHeaders[HeaderNames.AcceptRanges] = "none"; + + var contentType = state.GetMimeType(outputPath); + + // TODO: The isHeadRequest is only here because ServiceStack will add Content-Length=0 to the response + // TODO (from api-migration): Investigate if this is still neccessary as we migrated away from ServiceStack + var contentLength = state.EstimateContentLength || isHeadRequest ? GetEstimatedContentLength(state) : null; + + if (contentLength.HasValue) + { + responseHeaders[HeaderNames.ContentLength] = contentLength.Value.ToString(CultureInfo.InvariantCulture); + } + else + { + responseHeaders.Remove(HeaderNames.ContentLength); + } + + // Headers only + if (isHeadRequest) + { + return controller.File(Array.Empty<byte>(), contentType); + } + + var transcodingLock = transcodingJobHelper.GetTranscodingLock(outputPath); + await transcodingLock.WaitAsync(cancellationTokenSource.Token).ConfigureAwait(false); + try + { + if (!File.Exists(outputPath)) + { + await transcodingJobHelper.StartFfMpeg(state, outputPath, ffmpegCommandLineArguments, request, transcodingJobType, cancellationTokenSource).ConfigureAwait(false); + } + else + { + transcodingJobHelper.OnTranscodeBeginRequest(outputPath, TranscodingJobType.Progressive); + state.Dispose(); + } + + Stream stream = new MemoryStream(); + + await new ProgressiveFileCopier(streamHelper, outputPath).WriteToAsync(stream, CancellationToken.None).ConfigureAwait(false); + return controller.File(stream, contentType); + } + finally + { + transcodingLock.Release(); + } + } + + /// <summary> + /// Gets the length of the estimated content. + /// </summary> + /// <param name="state">The state.</param> + /// <returns>System.Nullable{System.Int64}.</returns> + private static long? GetEstimatedContentLength(StreamState state) + { + var totalBitrate = state.TotalOutputBitrate ?? 0; + + if (totalBitrate > 0 && state.RunTimeTicks.HasValue) + { + return Convert.ToInt64(totalBitrate * TimeSpan.FromTicks(state.RunTimeTicks.Value).TotalSeconds / 8); + } + + return null; + } + } +} diff --git a/Jellyfin.Api/Helpers/StreamingHelpers.cs b/Jellyfin.Api/Helpers/StreamingHelpers.cs index 4cebf40f6..c88ec0b2f 100644 --- a/Jellyfin.Api/Helpers/StreamingHelpers.cs +++ b/Jellyfin.Api/Helpers/StreamingHelpers.cs @@ -1,32 +1,255 @@ using System; using System.Collections.Generic; using System.Globalization; +using System.IO; using System.Linq; -using Jellyfin.Api.Models; +using System.Threading; +using System.Threading.Tasks; +using Jellyfin.Api.Models.StreamingDtos; +using MediaBrowser.Common.Configuration; +using MediaBrowser.Common.Extensions; +using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Devices; using MediaBrowser.Controller.Dlna; +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.MediaEncoding; +using MediaBrowser.Controller.Net; using MediaBrowser.Model.Dlna; +using MediaBrowser.Model.Dto; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.IO; using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Primitives; +using Microsoft.Net.Http.Headers; namespace Jellyfin.Api.Helpers { /// <summary> - /// The streaming helpers + /// The streaming helpers. /// </summary> - public class StreamingHelpers + public static class StreamingHelpers { + public static async Task<StreamState> GetStreamingState( + Guid itemId, + long? startTimeTicks, + string? audioCodec, + string? subtitleCodec, + string? videoCodec, + string? @params, + bool? @static, + string? container, + string? liveStreamId, + string? playSessionId, + string? mediaSourceId, + string? deviceId, + string? deviceProfileId, + int? audioBitRate, + HttpRequest request, + IAuthorizationContext authorizationContext, + IMediaSourceManager mediaSourceManager, + IUserManager userManager, + ILibraryManager libraryManager, + IServerConfigurationManager serverConfigurationManager, + IMediaEncoder mediaEncoder, + IFileSystem fileSystem, + ISubtitleEncoder subtitleEncoder, + IConfiguration configuration, + IDlnaManager dlnaManager, + IDeviceManager deviceManager, + TranscodingJobHelper transcodingJobHelper, + TranscodingJobType transcodingJobType, + bool isVideoRequest, + CancellationToken cancellationToken) + { + EncodingHelper encodingHelper = new EncodingHelper(mediaEncoder, fileSystem, subtitleEncoder, configuration); + // Parse the DLNA time seek header + if (!startTimeTicks.HasValue) + { + var timeSeek = request.Headers["TimeSeekRange.dlna.org"]; + + startTimeTicks = ParseTimeSeekHeader(timeSeek); + } + + if (!string.IsNullOrWhiteSpace(@params)) + { + // What is this? + ParseParams(request); + } + + var streamOptions = ParseStreamOptions(request.Query); + + var url = request.Path.Value.Split('.').Last(); + + if (string.IsNullOrEmpty(audioCodec)) + { + audioCodec = encodingHelper.InferAudioCodec(url); + } + + var enableDlnaHeaders = !string.IsNullOrWhiteSpace(@params) || + string.Equals(request.Headers["GetContentFeatures.DLNA.ORG"], "1", StringComparison.OrdinalIgnoreCase); + + var state = new StreamState(mediaSourceManager, transcodingJobType, transcodingJobHelper) + { + // TODO request was the StreamingRequest living in MediaBrowser.Api.Playback.Progressive + Request = request, + RequestedUrl = url, + UserAgent = request.Headers[HeaderNames.UserAgent], + EnableDlnaHeaders = enableDlnaHeaders + }; + + var auth = authorizationContext.GetAuthorizationInfo(request); + if (!auth.UserId.Equals(Guid.Empty)) + { + state.User = userManager.GetUserById(auth.UserId); + } + + /* + if ((Request.UserAgent ?? string.Empty).IndexOf("iphone", StringComparison.OrdinalIgnoreCase) != -1 || + (Request.UserAgent ?? string.Empty).IndexOf("ipad", StringComparison.OrdinalIgnoreCase) != -1 || + (Request.UserAgent ?? string.Empty).IndexOf("ipod", StringComparison.OrdinalIgnoreCase) != -1) + { + state.SegmentLength = 6; + } + */ + + if (state.VideoRequest != null && !string.IsNullOrWhiteSpace(state.VideoRequest.VideoCodec)) + { + state.SupportedVideoCodecs = state.VideoRequest.VideoCodec.Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToArray(); + state.VideoRequest.VideoCodec = state.SupportedVideoCodecs.FirstOrDefault(); + } + + if (!string.IsNullOrWhiteSpace(audioCodec)) + { + state.SupportedAudioCodecs = audioCodec.Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToArray(); + state.Request.AudioCodec = state.SupportedAudioCodecs.FirstOrDefault(i => mediaEncoder.CanEncodeToAudioCodec(i)) + ?? state.SupportedAudioCodecs.FirstOrDefault(); + } + + if (!string.IsNullOrWhiteSpace(subtitleCodec)) + { + state.SupportedSubtitleCodecs = subtitleCodec.Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToArray(); + state.Request.SubtitleCodec = state.SupportedSubtitleCodecs.FirstOrDefault(i => mediaEncoder.CanEncodeToSubtitleCodec(i)) + ?? state.SupportedSubtitleCodecs.FirstOrDefault(); + } + + var item = libraryManager.GetItemById(itemId); + + state.IsInputVideo = string.Equals(item.MediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase); + + /* + var primaryImage = item.GetImageInfo(ImageType.Primary, 0) ?? + item.Parents.Select(i => i.GetImageInfo(ImageType.Primary, 0)).FirstOrDefault(i => i != null); + if (primaryImage != null) + { + state.AlbumCoverPath = primaryImage.Path; + } + */ + + MediaSourceInfo? mediaSource = null; + if (string.IsNullOrWhiteSpace(liveStreamId)) + { + var currentJob = !string.IsNullOrWhiteSpace(playSessionId) + ? transcodingJobHelper.GetTranscodingJob(playSessionId) + : null; + + if (currentJob != null) + { + mediaSource = currentJob.MediaSource; + } + + if (mediaSource == null) + { + var mediaSources = await mediaSourceManager.GetPlaybackMediaSources(libraryManager.GetItemById(itemId), null, false, false, cancellationToken).ConfigureAwait(false); + + mediaSource = string.IsNullOrEmpty(mediaSourceId) + ? mediaSources[0] + : mediaSources.Find(i => string.Equals(i.Id, mediaSourceId, StringComparison.InvariantCulture)); + + if (mediaSource == null && Guid.Parse(mediaSourceId) == itemId) + { + mediaSource = mediaSources[0]; + } + } + } + else + { + var liveStreamInfo = await mediaSourceManager.GetLiveStreamWithDirectStreamProvider(liveStreamId, cancellationToken).ConfigureAwait(false); + mediaSource = liveStreamInfo.Item1; + state.DirectStreamProvider = liveStreamInfo.Item2; + } + + encodingHelper.AttachMediaSourceInfo(state, mediaSource, url); + + var containerInternal = Path.GetExtension(state.RequestedUrl); + + if (string.IsNullOrEmpty(container)) + { + containerInternal = container; + } + + if (string.IsNullOrEmpty(containerInternal)) + { + containerInternal = (@static.HasValue && @static.Value) ? StreamBuilder.NormalizeMediaSourceFormatIntoSingleContainer(state.InputContainer, state.MediaPath, null, DlnaProfileType.Audio) : GetOutputFileExtension(state); + } + + state.OutputContainer = (containerInternal ?? string.Empty).TrimStart('.'); + + state.OutputAudioBitrate = encodingHelper.GetAudioBitrateParam(audioBitRate, state.AudioStream); + + state.OutputAudioCodec = audioCodec; + + state.OutputAudioChannels = encodingHelper.GetNumAudioChannelsParam(state, state.AudioStream, state.OutputAudioCodec); + + if (isVideoRequest) + { + state.OutputVideoCodec = state.VideoRequest.VideoCodec; + state.OutputVideoBitrate = EncodingHelper.GetVideoBitrateParamValue(state.VideoRequest, state.VideoStream, state.OutputVideoCodec); + + encodingHelper.TryStreamCopy(state); + + if (state.OutputVideoBitrate.HasValue && !EncodingHelper.IsCopyCodec(state.OutputVideoCodec)) + { + var resolution = ResolutionNormalizer.Normalize( + state.VideoStream?.BitRate, + state.VideoStream?.Width, + state.VideoStream?.Height, + state.OutputVideoBitrate.Value, + state.VideoStream?.Codec, + state.OutputVideoCodec, + videoRequest.MaxWidth, + videoRequest.MaxHeight); + + videoRequest.MaxWidth = resolution.MaxWidth; + videoRequest.MaxHeight = resolution.MaxHeight; + } + } + + ApplyDeviceProfileSettings(state, dlnaManager, deviceManager, request, deviceProfileId, @static); + + var ext = string.IsNullOrWhiteSpace(state.OutputContainer) + ? GetOutputFileExtension(state) + : ('.' + state.OutputContainer); + + state.OutputFilePath = GetOutputFilePath(state, ext!, serverConfigurationManager, deviceId, playSessionId); + + return state; + } + /// <summary> /// Adds the dlna headers. /// </summary> /// <param name="state">The state.</param> /// <param name="responseHeaders">The response headers.</param> /// <param name="isStaticallyStreamed">if set to <c>true</c> [is statically streamed].</param> + /// <param name="startTimeTicks">The start time in ticks.</param> /// <param name="request">The <see cref="HttpRequest"/>.</param> /// <param name="dlnaManager">Instance of the <see cref="IDlnaManager"/> interface.</param> public static void AddDlnaHeaders( StreamState state, IHeaderDictionary responseHeaders, bool isStaticallyStreamed, + long? startTimeTicks, HttpRequest request, IDlnaManager dlnaManager) { @@ -54,7 +277,7 @@ namespace Jellyfin.Api.Helpers if (!isStaticallyStreamed && profile != null) { - AddTimeSeekResponseHeaders(state, responseHeaders); + AddTimeSeekResponseHeaders(state, responseHeaders, startTimeTicks); } } @@ -82,51 +305,18 @@ namespace Jellyfin.Api.Helpers { var videoCodec = state.ActualOutputVideoCodec; - responseHeaders.Add("contentFeatures.dlna.org", new ContentFeatureBuilder(profile).BuildVideoHeader( - state.OutputContainer, - videoCodec, - audioCodec, - state.OutputWidth, - state.OutputHeight, - state.TargetVideoBitDepth, - state.OutputVideoBitrate, - state.TargetTimestamp, - isStaticallyStreamed, - state.RunTimeTicks, - state.TargetVideoProfile, - state.TargetVideoLevel, - state.TargetFramerate, - state.TargetPacketLength, - state.TranscodeSeekInfo, - state.IsTargetAnamorphic, - state.IsTargetInterlaced, - state.TargetRefFrames, - state.TargetVideoStreamCount, - state.TargetAudioStreamCount, - state.TargetVideoCodecTag, - state.IsTargetAVC).FirstOrDefault() ?? string.Empty); - } - } - - /// <summary> - /// Parses the dlna headers. - /// </summary> - /// <param name="startTimeTicks">The start time ticks.</param> - /// <param name="request">The <see cref="HttpRequest"/>.</param> - public void ParseDlnaHeaders(long? startTimeTicks, HttpRequest request) - { - if (!startTimeTicks.HasValue) - { - var timeSeek = request.Headers["TimeSeekRange.dlna.org"]; - - startTimeTicks = ParseTimeSeekHeader(timeSeek); + responseHeaders.Add( + "contentFeatures.dlna.org", + new ContentFeatureBuilder(profile).BuildVideoHeader(state.OutputContainer, videoCodec, audioCodec, state.OutputWidth, state.OutputHeight, state.TargetVideoBitDepth, state.OutputVideoBitrate, state.TargetTimestamp, isStaticallyStreamed, state.RunTimeTicks, state.TargetVideoProfile, state.TargetVideoLevel, state.TargetFramerate, state.TargetPacketLength, state.TranscodeSeekInfo, state.IsTargetAnamorphic, state.IsTargetInterlaced, state.TargetRefFrames, state.TargetVideoStreamCount, state.TargetAudioStreamCount, state.TargetVideoCodecTag, state.IsTargetAVC).FirstOrDefault() ?? string.Empty); } } /// <summary> /// Parses the time seek header. /// </summary> - public long? ParseTimeSeekHeader(string value) + /// <param name="value">The time seek header string.</param> + /// <returns>A nullable <see cref="long"/> representing the seek time in ticks.</returns> + public static long? ParseTimeSeekHeader(string value) { if (string.IsNullOrWhiteSpace(value)) { @@ -138,12 +328,13 @@ namespace Jellyfin.Api.Helpers { throw new ArgumentException("Invalid timeseek header"); } - int index = value.IndexOf('-'); + + int index = value.IndexOf('-', StringComparison.InvariantCulture); value = index == -1 ? value.Substring(Npt.Length) : value.Substring(Npt.Length, index - Npt.Length); - if (value.IndexOf(':') == -1) + if (value.IndexOf(':', StringComparison.InvariantCulture) == -1) { // Parses npt times in the format of '417.33' if (double.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out var seconds)) @@ -169,15 +360,45 @@ namespace Jellyfin.Api.Helpers { throw new ArgumentException("Invalid timeseek header"); } + timeFactor /= 60; } + return TimeSpan.FromSeconds(secondsSum).Ticks; } - public void AddTimeSeekResponseHeaders(StreamState state, IHeaderDictionary responseHeaders) + /// <summary> + /// Parses query parameters as StreamOptions. + /// </summary> + /// <param name="queryString">The query string.</param> + /// <returns>A <see cref="Dictionary{String,String}"/> containing the stream options.</returns> + public static Dictionary<string, string> ParseStreamOptions(IQueryCollection queryString) { - var runtimeSeconds = TimeSpan.FromTicks(state.RunTimeTicks.Value).TotalSeconds.ToString(CultureInfo.InvariantCulture); - var startSeconds = TimeSpan.FromTicks(state.Request.StartTimeTicks ?? 0).TotalSeconds.ToString(CultureInfo.InvariantCulture); + Dictionary<string, string> streamOptions = new Dictionary<string, string>(); + foreach (var param in queryString) + { + if (char.IsLower(param.Key[0])) + { + // This was probably not parsed initially and should be a StreamOptions + // or the generated URL should correctly serialize it + // TODO: This should be incorporated either in the lower framework for parsing requests + streamOptions[param.Key] = param.Value; + } + } + + return streamOptions; + } + + /// <summary> + /// Adds the dlna time seek headers to the response. + /// </summary> + /// <param name="state">The current <see cref="StreamState"/>.</param> + /// <param name="responseHeaders">The <see cref="IHeaderDictionary"/> of the response.</param> + /// <param name="startTimeTicks">The start time in ticks.</param> + public static void AddTimeSeekResponseHeaders(StreamState state, IHeaderDictionary responseHeaders, long? startTimeTicks) + { + var runtimeSeconds = TimeSpan.FromTicks(state.RunTimeTicks!.Value).TotalSeconds.ToString(CultureInfo.InvariantCulture); + var startSeconds = TimeSpan.FromTicks(startTimeTicks ?? 0).TotalSeconds.ToString(CultureInfo.InvariantCulture); responseHeaders.Add("TimeSeekRange.dlna.org", string.Format( CultureInfo.InvariantCulture, @@ -190,5 +411,369 @@ namespace Jellyfin.Api.Helpers startSeconds, runtimeSeconds)); } + + /// <summary> + /// Gets the output file extension. + /// </summary> + /// <param name="state">The state.</param> + /// <returns>System.String.</returns> + public static string? GetOutputFileExtension(StreamState state) + { + var ext = Path.GetExtension(state.RequestedUrl); + + if (!string.IsNullOrEmpty(ext)) + { + return ext; + } + + var isVideoRequest = state.VideoRequest != null; + + // Try to infer based on the desired video codec + if (isVideoRequest) + { + var videoCodec = state.VideoRequest.VideoCodec; + + if (string.Equals(videoCodec, "h264", StringComparison.OrdinalIgnoreCase) || + string.Equals(videoCodec, "h265", StringComparison.OrdinalIgnoreCase)) + { + return ".ts"; + } + + if (string.Equals(videoCodec, "theora", StringComparison.OrdinalIgnoreCase)) + { + return ".ogv"; + } + + if (string.Equals(videoCodec, "vpx", StringComparison.OrdinalIgnoreCase)) + { + return ".webm"; + } + + if (string.Equals(videoCodec, "wmv", StringComparison.OrdinalIgnoreCase)) + { + return ".asf"; + } + } + + // Try to infer based on the desired audio codec + if (!isVideoRequest) + { + var audioCodec = state.Request.AudioCodec; + + if (string.Equals("aac", audioCodec, StringComparison.OrdinalIgnoreCase)) + { + return ".aac"; + } + + if (string.Equals("mp3", audioCodec, StringComparison.OrdinalIgnoreCase)) + { + return ".mp3"; + } + + if (string.Equals("vorbis", audioCodec, StringComparison.OrdinalIgnoreCase)) + { + return ".ogg"; + } + + if (string.Equals("wma", audioCodec, StringComparison.OrdinalIgnoreCase)) + { + return ".wma"; + } + } + + return null; + } + + /// <summary> + /// Gets the output file path for transcoding. + /// </summary> + /// <param name="state">The current <see cref="StreamState"/>.</param> + /// <param name="outputFileExtension">The file extension of the output file.</param> + /// <param name="serverConfigurationManager">Instance of the <see cref="IServerConfigurationManager"/> interface.</param> + /// <param name="deviceId">The device id.</param> + /// <param name="playSessionId">The play session id.</param> + /// <returns>The complete file path, including the folder, for the transcoding file.</returns> + private static string GetOutputFilePath(StreamState state, string outputFileExtension, IServerConfigurationManager serverConfigurationManager, string? deviceId, string? playSessionId) + { + var data = $"{state.MediaPath}-{state.UserAgent}-{deviceId!}-{playSessionId!}"; + + var filename = data.GetMD5().ToString("N", CultureInfo.InvariantCulture); + var ext = outputFileExtension?.ToLowerInvariant(); + var folder = serverConfigurationManager.GetTranscodePath(); + + return Path.Combine(folder, filename + ext); + } + + private static void ApplyDeviceProfileSettings(StreamState state, IDlnaManager dlnaManager, IDeviceManager deviceManager, HttpRequest request, string? deviceProfileId, bool? @static) + { + var headers = request.Headers; + + if (!string.IsNullOrWhiteSpace(deviceProfileId)) + { + state.DeviceProfile = dlnaManager.GetProfile(deviceProfileId); + } + else if (!string.IsNullOrWhiteSpace(deviceProfileId)) + { + var caps = deviceManager.GetCapabilities(deviceProfileId); + + state.DeviceProfile = caps == null ? dlnaManager.GetProfile(headers) : caps.DeviceProfile; + } + + var profile = state.DeviceProfile; + + if (profile == null) + { + // Don't use settings from the default profile. + // Only use a specific profile if it was requested. + return; + } + + var audioCodec = state.ActualOutputAudioCodec; + var videoCodec = state.ActualOutputVideoCodec; + + var mediaProfile = state.VideoRequest == null + ? profile.GetAudioMediaProfile(state.OutputContainer, audioCodec, state.OutputAudioChannels, state.OutputAudioBitrate, state.OutputAudioSampleRate, state.OutputAudioBitDepth) + : profile.GetVideoMediaProfile( + state.OutputContainer, + audioCodec, + videoCodec, + state.OutputWidth, + state.OutputHeight, + state.TargetVideoBitDepth, + state.OutputVideoBitrate, + state.TargetVideoProfile, + state.TargetVideoLevel, + state.TargetFramerate, + state.TargetPacketLength, + state.TargetTimestamp, + state.IsTargetAnamorphic, + state.IsTargetInterlaced, + state.TargetRefFrames, + state.TargetVideoStreamCount, + state.TargetAudioStreamCount, + state.TargetVideoCodecTag, + state.IsTargetAVC); + + if (mediaProfile != null) + { + state.MimeType = mediaProfile.MimeType; + } + + if (!(@static.HasValue && @static.Value)) + { + var transcodingProfile = state.VideoRequest == null ? profile.GetAudioTranscodingProfile(state.OutputContainer, audioCodec) : profile.GetVideoTranscodingProfile(state.OutputContainer, audioCodec, videoCodec); + + if (transcodingProfile != null) + { + state.EstimateContentLength = transcodingProfile.EstimateContentLength; + // state.EnableMpegtsM2TsMode = transcodingProfile.EnableMpegtsM2TsMode; + state.TranscodeSeekInfo = transcodingProfile.TranscodeSeekInfo; + + if (state.VideoRequest != null) + { + state.VideoRequest.CopyTimestamps = transcodingProfile.CopyTimestamps; + state.VideoRequest.EnableSubtitlesInManifest = transcodingProfile.EnableSubtitlesInManifest; + } + } + } + } + + /// <summary> + /// Parses the parameters. + /// </summary> + /// <param name="request">The request.</param> + private void ParseParams(StreamRequest request) + { + var vals = request.Params.Split(';'); + + var videoRequest = request as VideoStreamRequest; + + for (var i = 0; i < vals.Length; i++) + { + var val = vals[i]; + + if (string.IsNullOrWhiteSpace(val)) + { + continue; + } + + switch (i) + { + case 0: + request.DeviceProfileId = val; + break; + case 1: + request.DeviceId = val; + break; + case 2: + request.MediaSourceId = val; + break; + case 3: + request.Static = string.Equals("true", val, StringComparison.OrdinalIgnoreCase); + break; + case 4: + if (videoRequest != null) + { + videoRequest.VideoCodec = val; + } + + break; + case 5: + request.AudioCodec = val; + break; + case 6: + if (videoRequest != null) + { + videoRequest.AudioStreamIndex = int.Parse(val, CultureInfo.InvariantCulture); + } + + break; + case 7: + if (videoRequest != null) + { + videoRequest.SubtitleStreamIndex = int.Parse(val, CultureInfo.InvariantCulture); + } + + break; + case 8: + if (videoRequest != null) + { + videoRequest.VideoBitRate = int.Parse(val, CultureInfo.InvariantCulture); + } + + break; + case 9: + request.AudioBitRate = int.Parse(val, CultureInfo.InvariantCulture); + break; + case 10: + request.MaxAudioChannels = int.Parse(val, CultureInfo.InvariantCulture); + break; + case 11: + if (videoRequest != null) + { + videoRequest.MaxFramerate = float.Parse(val, CultureInfo.InvariantCulture); + } + + break; + case 12: + if (videoRequest != null) + { + videoRequest.MaxWidth = int.Parse(val, CultureInfo.InvariantCulture); + } + + break; + case 13: + if (videoRequest != null) + { + videoRequest.MaxHeight = int.Parse(val, CultureInfo.InvariantCulture); + } + + break; + case 14: + request.StartTimeTicks = long.Parse(val, CultureInfo.InvariantCulture); + break; + case 15: + if (videoRequest != null) + { + videoRequest.Level = val; + } + + break; + case 16: + if (videoRequest != null) + { + videoRequest.MaxRefFrames = int.Parse(val, CultureInfo.InvariantCulture); + } + + break; + case 17: + if (videoRequest != null) + { + videoRequest.MaxVideoBitDepth = int.Parse(val, CultureInfo.InvariantCulture); + } + + break; + case 18: + if (videoRequest != null) + { + videoRequest.Profile = val; + } + + break; + case 19: + // cabac no longer used + break; + case 20: + request.PlaySessionId = val; + break; + case 21: + // api_key + break; + case 22: + request.LiveStreamId = val; + break; + case 23: + // Duplicating ItemId because of MediaMonkey + break; + case 24: + if (videoRequest != null) + { + videoRequest.CopyTimestamps = string.Equals("true", val, StringComparison.OrdinalIgnoreCase); + } + + break; + case 25: + if (!string.IsNullOrWhiteSpace(val) && videoRequest != null) + { + if (Enum.TryParse(val, out SubtitleDeliveryMethod method)) + { + videoRequest.SubtitleMethod = method; + } + } + + break; + case 26: + request.TranscodingMaxAudioChannels = int.Parse(val, CultureInfo.InvariantCulture); + break; + case 27: + if (videoRequest != null) + { + videoRequest.EnableSubtitlesInManifest = string.Equals("true", val, StringComparison.OrdinalIgnoreCase); + } + + break; + case 28: + request.Tag = val; + break; + case 29: + if (videoRequest != null) + { + videoRequest.RequireAvc = string.Equals("true", val, StringComparison.OrdinalIgnoreCase); + } + + break; + case 30: + request.SubtitleCodec = val; + break; + case 31: + if (videoRequest != null) + { + videoRequest.RequireNonAnamorphic = string.Equals("true", val, StringComparison.OrdinalIgnoreCase); + } + + break; + case 32: + if (videoRequest != null) + { + videoRequest.DeInterlace = string.Equals("true", val, StringComparison.OrdinalIgnoreCase); + } + + break; + case 33: + request.TranscodeReasons = val; + break; + } + } + } } } diff --git a/Jellyfin.Api/Helpers/TranscodingJobHelper.cs b/Jellyfin.Api/Helpers/TranscodingJobHelper.cs index 7db75387a..9fbd5ec2d 100644 --- a/Jellyfin.Api/Helpers/TranscodingJobHelper.cs +++ b/Jellyfin.Api/Helpers/TranscodingJobHelper.cs @@ -1,16 +1,28 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Globalization; using System.IO; using System.Linq; +using System.Text; +using System.Text.Json; using System.Threading; using System.Threading.Tasks; -using Jellyfin.Api.Models; using Jellyfin.Api.Models.PlaybackDtos; +using Jellyfin.Api.Models.StreamingDtos; +using Jellyfin.Data.Enums; +using MediaBrowser.Common.Configuration; +using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.MediaEncoding; +using MediaBrowser.Controller.Net; +using MediaBrowser.Controller.Session; +using MediaBrowser.Model.Entities; using MediaBrowser.Model.IO; +using MediaBrowser.Model.MediaInfo; using MediaBrowser.Model.Session; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; namespace Jellyfin.Api.Helpers @@ -30,9 +42,17 @@ namespace Jellyfin.Api.Helpers /// </summary> private static readonly Dictionary<string, SemaphoreSlim> _transcodingLocks = new Dictionary<string, SemaphoreSlim>(); + private readonly IAuthorizationContext _authorizationContext; + private readonly EncodingHelper _encodingHelper; + private readonly IFileSystem _fileSystem; + private readonly IIsoManager _isoManager; + private readonly ILogger<TranscodingJobHelper> _logger; + private readonly IMediaEncoder _mediaEncoder; private readonly IMediaSourceManager _mediaSourceManager; - private readonly IFileSystem _fileSystem; + private readonly IServerConfigurationManager _serverConfigurationManager; + private readonly ISessionManager _sessionManager; + private readonly ILoggerFactory _loggerFactory; /// <summary> /// Initializes a new instance of the <see cref="TranscodingJobHelper"/> class. @@ -40,14 +60,40 @@ namespace Jellyfin.Api.Helpers /// <param name="logger">Instance of the <see cref="ILogger{TranscodingJobHelpers}"/> interface.</param> /// <param name="mediaSourceManager">Instance of the <see cref="IMediaSourceManager"/> interface.</param> /// <param name="fileSystem">Instance of the <see cref="IFileSystem"/> interface.</param> + /// <param name="mediaEncoder">Instance of the <see cref="IMediaEncoder"/> interface.</param> + /// <param name="serverConfigurationManager">Instance of the <see cref="IServerConfigurationManager"/> interface.</param> + /// <param name="sessionManager">Instance of the <see cref="ISessionManager"/> interface.</param> + /// <param name="authorizationContext">Instance of the <see cref="IAuthorizationContext"/> interface.</param> + /// <param name="isoManager">Instance of the <see cref="IIsoManager"/> interface.</param> + /// <param name="subtitleEncoder">Instance of the <see cref="ISubtitleEncoder"/> interface.</param> + /// <param name="configuration">Instance of the <see cref="IConfiguration"/> interface.</param> + /// <param name="loggerFactory">Instance of the <see cref="ILoggerFactory"/> interface.</param> public TranscodingJobHelper( ILogger<TranscodingJobHelper> logger, IMediaSourceManager mediaSourceManager, - IFileSystem fileSystem) + IFileSystem fileSystem, + IMediaEncoder mediaEncoder, + IServerConfigurationManager serverConfigurationManager, + ISessionManager sessionManager, + IAuthorizationContext authorizationContext, + IIsoManager isoManager, + ISubtitleEncoder subtitleEncoder, + IConfiguration configuration, + ILoggerFactory loggerFactory) { _logger = logger; _mediaSourceManager = mediaSourceManager; _fileSystem = fileSystem; + _mediaEncoder = mediaEncoder; + _serverConfigurationManager = serverConfigurationManager; + _sessionManager = sessionManager; + _authorizationContext = authorizationContext; + _isoManager = isoManager; + _loggerFactory = loggerFactory; + + _encodingHelper = new EncodingHelper(mediaEncoder, fileSystem, subtitleEncoder, configuration); + + DeleteEncodedMediaCache(); } /// <summary> @@ -63,7 +109,13 @@ namespace Jellyfin.Api.Helpers } } - public static TranscodingJobDto GetTranscodingJob(string path, TranscodingJobType type) + /// <summary> + /// Get transcoding job. + /// </summary> + /// <param name="path">Path to the transcoding file.</param> + /// <param name="type">The <see cref="TranscodingJobType"/>.</param> + /// <returns>The transcoding job.</returns> + public TranscodingJobDto GetTranscodingJob(string path, TranscodingJobType type) { lock (_activeTranscodingJobs) { @@ -361,14 +413,24 @@ namespace Jellyfin.Api.Helpers } } + /// <summary> + /// Report the transcoding progress to the session manager. + /// </summary> + /// <param name="job">The <see cref="TranscodingJobDto"/> of which the progress will be reported.</param> + /// <param name="state">The <see cref="StreamState"/> of the current transcoding job.</param> + /// <param name="transcodingPosition">The current transcoding position.</param> + /// <param name="framerate">The framerate of the transcoding job.</param> + /// <param name="percentComplete">The completion percentage of the transcode.</param> + /// <param name="bytesTranscoded">The number of bytes transcoded.</param> + /// <param name="bitRate">The bitrate of the transcoding job.</param> public void ReportTranscodingProgress( - TranscodingJob job, - StreamState state, - TimeSpan? transcodingPosition, - float? framerate, - double? percentComplete, - long? bytesTranscoded, - int? bitRate) + TranscodingJobDto job, + StreamState state, + TimeSpan? transcodingPosition, + float? framerate, + double? percentComplete, + long? bytesTranscoded, + int? bitRate) { var ticks = transcodingPosition?.Ticks; @@ -405,5 +467,374 @@ namespace Jellyfin.Api.Helpers }); } } + + /// <summary> + /// Starts the FFMPEG. + /// </summary> + /// <param name="state">The state.</param> + /// <param name="outputPath">The output path.</param> + /// <param name="commandLineArguments">The command line arguments for ffmpeg.</param> + /// <param name="request">The <see cref="HttpRequest"/>.</param> + /// <param name="transcodingJobType">The <see cref="TranscodingJobType"/>.</param> + /// <param name="cancellationTokenSource">The cancellation token source.</param> + /// <param name="workingDirectory">The working directory.</param> + /// <returns>Task.</returns> + public async Task<TranscodingJobDto> StartFfMpeg( + StreamState state, + string outputPath, + string commandLineArguments, + HttpRequest request, + TranscodingJobType transcodingJobType, + CancellationTokenSource cancellationTokenSource, + string workingDirectory = null) + { + Directory.CreateDirectory(Path.GetDirectoryName(outputPath)); + + await AcquireResources(state, cancellationTokenSource).ConfigureAwait(false); + + if (state.VideoRequest != null && !EncodingHelper.IsCopyCodec(state.OutputVideoCodec)) + { + var auth = _authorizationContext.GetAuthorizationInfo(request); + if (auth.User != null && !auth.User.HasPermission(PermissionKind.EnableVideoPlaybackTranscoding)) + { + this.OnTranscodeFailedToStart(outputPath, transcodingJobType, state); + + throw new ArgumentException("User does not have access to video transcoding"); + } + } + + var process = new Process() + { + StartInfo = new ProcessStartInfo() + { + WindowStyle = ProcessWindowStyle.Hidden, + CreateNoWindow = true, + UseShellExecute = false, + + // Must consume both stdout and stderr or deadlocks may occur + // RedirectStandardOutput = true, + RedirectStandardError = true, + RedirectStandardInput = true, + FileName = _mediaEncoder.EncoderPath, + Arguments = commandLineArguments, + WorkingDirectory = string.IsNullOrWhiteSpace(workingDirectory) ? null : workingDirectory, + ErrorDialog = false + }, + EnableRaisingEvents = true + }; + + var transcodingJob = this.OnTranscodeBeginning( + outputPath, + state.Request.PlaySessionId, + state.MediaSource.LiveStreamId, + Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture), + transcodingJobType, + process, + state.Request.DeviceId, + state, + cancellationTokenSource); + + var commandLineLogMessage = process.StartInfo.FileName + " " + process.StartInfo.Arguments; + _logger.LogInformation(commandLineLogMessage); + + var logFilePrefix = "ffmpeg-transcode"; + if (state.VideoRequest != null + && EncodingHelper.IsCopyCodec(state.OutputVideoCodec)) + { + logFilePrefix = EncodingHelper.IsCopyCodec(state.OutputAudioCodec) + ? "ffmpeg-remux" + : "ffmpeg-directstream"; + } + + var logFilePath = Path.Combine(_serverConfigurationManager.ApplicationPaths.LogDirectoryPath, logFilePrefix + "-" + Guid.NewGuid() + ".txt"); + + // FFMpeg writes debug/error info to stderr. This is useful when debugging so let's put it in the log directory. + Stream logStream = new FileStream(logFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, IODefaults.FileStreamBufferSize, true); + + var commandLineLogMessageBytes = Encoding.UTF8.GetBytes(request.Path + Environment.NewLine + Environment.NewLine + JsonSerializer.Serialize(state.MediaSource) + Environment.NewLine + Environment.NewLine + commandLineLogMessage + Environment.NewLine + Environment.NewLine); + await logStream.WriteAsync(commandLineLogMessageBytes, 0, commandLineLogMessageBytes.Length, cancellationTokenSource.Token).ConfigureAwait(false); + + process.Exited += (sender, args) => OnFfMpegProcessExited(process, transcodingJob, state); + + try + { + process.Start(); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error starting ffmpeg"); + + this.OnTranscodeFailedToStart(outputPath, transcodingJobType, state); + + throw; + } + + _logger.LogDebug("Launched ffmpeg process"); + state.TranscodingJob = transcodingJob; + + // Important - don't await the log task or we won't be able to kill ffmpeg when the user stops playback + _ = new JobLogger(_logger).StartStreamingLog(state, process.StandardError.BaseStream, logStream); + + // Wait for the file to exist before proceeeding + var ffmpegTargetFile = state.WaitForPath ?? outputPath; + _logger.LogDebug("Waiting for the creation of {0}", ffmpegTargetFile); + while (!File.Exists(ffmpegTargetFile) && !transcodingJob.HasExited) + { + await Task.Delay(100, cancellationTokenSource.Token).ConfigureAwait(false); + } + + _logger.LogDebug("File {0} created or transcoding has finished", ffmpegTargetFile); + + if (state.IsInputVideo && transcodingJob.Type == TranscodingJobType.Progressive && !transcodingJob.HasExited) + { + await Task.Delay(1000, cancellationTokenSource.Token).ConfigureAwait(false); + + if (state.ReadInputAtNativeFramerate && !transcodingJob.HasExited) + { + await Task.Delay(1500, cancellationTokenSource.Token).ConfigureAwait(false); + } + } + + if (!transcodingJob.HasExited) + { + StartThrottler(state, transcodingJob); + } + + _logger.LogDebug("StartFfMpeg() finished successfully"); + + return transcodingJob; + } + + private void StartThrottler(StreamState state, TranscodingJobDto transcodingJob) + { + if (EnableThrottling(state)) + { + transcodingJob.TranscodingThrottler = state.TranscodingThrottler = new TranscodingThrottler(transcodingJob, new Logger<TranscodingThrottler>(new LoggerFactory()), _serverConfigurationManager, _fileSystem); + state.TranscodingThrottler.Start(); + } + } + + private bool EnableThrottling(StreamState state) + { + var encodingOptions = _serverConfigurationManager.GetEncodingOptions(); + + // enable throttling when NOT using hardware acceleration + if (string.IsNullOrEmpty(encodingOptions.HardwareAccelerationType)) + { + return state.InputProtocol == MediaProtocol.File && + state.RunTimeTicks.HasValue && + state.RunTimeTicks.Value >= TimeSpan.FromMinutes(5).Ticks && + state.IsInputVideo && + state.VideoType == VideoType.VideoFile && + !EncodingHelper.IsCopyCodec(state.OutputVideoCodec); + } + + return false; + } + + /// <summary> + /// Called when [transcode beginning]. + /// </summary> + /// <param name="path">The path.</param> + /// <param name="playSessionId">The play session identifier.</param> + /// <param name="liveStreamId">The live stream identifier.</param> + /// <param name="transcodingJobId">The transcoding job identifier.</param> + /// <param name="type">The type.</param> + /// <param name="process">The process.</param> + /// <param name="deviceId">The device id.</param> + /// <param name="state">The state.</param> + /// <param name="cancellationTokenSource">The cancellation token source.</param> + /// <returns>TranscodingJob.</returns> + public TranscodingJobDto OnTranscodeBeginning( + string path, + string playSessionId, + string liveStreamId, + string transcodingJobId, + TranscodingJobType type, + Process process, + string deviceId, + StreamState state, + CancellationTokenSource cancellationTokenSource) + { + lock (_activeTranscodingJobs) + { + var job = new TranscodingJobDto(_loggerFactory.CreateLogger<TranscodingJobDto>()) + { + Type = type, + Path = path, + Process = process, + ActiveRequestCount = 1, + DeviceId = deviceId, + CancellationTokenSource = cancellationTokenSource, + Id = transcodingJobId, + PlaySessionId = playSessionId, + LiveStreamId = liveStreamId, + MediaSource = state.MediaSource + }; + + _activeTranscodingJobs.Add(job); + + ReportTranscodingProgress(job, state, null, null, null, null, null); + + return job; + } + } + + /// <summary> + /// <summary> + /// The progressive + /// </summary> + /// Called when [transcode failed to start]. + /// </summary> + /// <param name="path">The path.</param> + /// <param name="type">The type.</param> + /// <param name="state">The state.</param> + public void OnTranscodeFailedToStart(string path, TranscodingJobType type, StreamState state) + { + lock (_activeTranscodingJobs) + { + var job = _activeTranscodingJobs.FirstOrDefault(j => j.Type == type && string.Equals(j.Path, path, StringComparison.OrdinalIgnoreCase)); + + if (job != null) + { + _activeTranscodingJobs.Remove(job); + } + } + + lock (_transcodingLocks) + { + _transcodingLocks.Remove(path); + } + + if (!string.IsNullOrWhiteSpace(state.Request.DeviceId)) + { + _sessionManager.ClearTranscodingInfo(state.Request.DeviceId); + } + } + + /// <summary> + /// Processes the exited. + /// </summary> + /// <param name="process">The process.</param> + /// <param name="job">The job.</param> + /// <param name="state">The state.</param> + private void OnFfMpegProcessExited(Process process, TranscodingJobDto job, StreamState state) + { + if (job != null) + { + job.HasExited = true; + } + + _logger.LogDebug("Disposing stream resources"); + state.Dispose(); + + if (process.ExitCode == 0) + { + _logger.LogInformation("FFMpeg exited with code 0"); + } + else + { + _logger.LogError("FFMpeg exited with code {0}", process.ExitCode); + } + + process.Dispose(); + } + + private async Task AcquireResources(StreamState state, CancellationTokenSource cancellationTokenSource) + { + if (state.VideoType == VideoType.Iso && state.IsoType.HasValue && _isoManager.CanMount(state.MediaPath)) + { + state.IsoMount = await _isoManager.Mount(state.MediaPath, cancellationTokenSource.Token).ConfigureAwait(false); + } + + if (state.MediaSource.RequiresOpening && string.IsNullOrWhiteSpace(state.Request.LiveStreamId)) + { + var liveStreamResponse = await _mediaSourceManager.OpenLiveStream( + new LiveStreamRequest { OpenToken = state.MediaSource.OpenToken }, + cancellationTokenSource.Token) + .ConfigureAwait(false); + + _encodingHelper.AttachMediaSourceInfo(state, liveStreamResponse.MediaSource, state.RequestedUrl); + + if (state.VideoRequest != null) + { + _encodingHelper.TryStreamCopy(state); + } + } + + if (state.MediaSource.BufferMs.HasValue) + { + await Task.Delay(state.MediaSource.BufferMs.Value, cancellationTokenSource.Token).ConfigureAwait(false); + } + } + + /// <summary> + /// Called when [transcode begin request]. + /// </summary> + /// <param name="path">The path.</param> + /// <param name="type">The type.</param> + /// <returns>The <see cref="TranscodingJobDto"/>.</returns> + public TranscodingJobDto? OnTranscodeBeginRequest(string path, TranscodingJobType type) + { + lock (_activeTranscodingJobs) + { + var job = _activeTranscodingJobs.FirstOrDefault(j => j.Type == type && string.Equals(j.Path, path, StringComparison.OrdinalIgnoreCase)); + + if (job == null) + { + return null; + } + + OnTranscodeBeginRequest(job); + + return job; + } + } + + private void OnTranscodeBeginRequest(TranscodingJobDto job) + { + job.ActiveRequestCount++; + + if (string.IsNullOrWhiteSpace(job.PlaySessionId) || job.Type == TranscodingJobType.Progressive) + { + job.StopKillTimer(); + } + } + + /// <summary> + /// Gets the transcoding lock. + /// </summary> + /// <param name="outputPath">The output path of the transcoded file.</param> + /// <returns>A <see cref="SemaphoreSlim"/>.</returns> + public SemaphoreSlim GetTranscodingLock(string outputPath) + { + lock (_transcodingLocks) + { + if (!_transcodingLocks.TryGetValue(outputPath, out SemaphoreSlim result)) + { + result = new SemaphoreSlim(1, 1); + _transcodingLocks[outputPath] = result; + } + + return result; + } + } + + /// <summary> + /// Deletes the encoded media cache. + /// </summary> + private void DeleteEncodedMediaCache() + { + var path = _serverConfigurationManager.GetTranscodePath(); + if (!Directory.Exists(path)) + { + return; + } + + foreach (var file in _fileSystem.GetFilePaths(path, true)) + { + _fileSystem.DeleteFile(file); + } + } } } diff --git a/Jellyfin.Api/Models/StreamState.cs b/Jellyfin.Api/Models/StreamState.cs deleted file mode 100644 index 9fe5f52c3..000000000 --- a/Jellyfin.Api/Models/StreamState.cs +++ /dev/null @@ -1,145 +0,0 @@ -using System; -using Jellyfin.Api.Helpers; -using Jellyfin.Api.Models.PlaybackDtos; -using MediaBrowser.Controller.Library; -using MediaBrowser.Controller.MediaEncoding; -using MediaBrowser.Model.Dlna; - -namespace Jellyfin.Api.Models -{ - public class StreamState : EncodingJobInfo, IDisposable - { - private readonly IMediaSourceManager _mediaSourceManager; - private bool _disposed = false; - - public string RequestedUrl { get; set; } - - public StreamRequest Request - { - get => (StreamRequest)BaseRequest; - set - { - BaseRequest = value; - - IsVideoRequest = VideoRequest != null; - } - } - - public TranscodingThrottler TranscodingThrottler { get; set; } - - public VideoStreamRequest VideoRequest => Request as VideoStreamRequest; - - public IDirectStreamProvider DirectStreamProvider { get; set; } - - public string WaitForPath { get; set; } - - public bool IsOutputVideo => Request is VideoStreamRequest; - - public int SegmentLength - { - get - { - if (Request.SegmentLength.HasValue) - { - return Request.SegmentLength.Value; - } - - if (EncodingHelper.IsCopyCodec(OutputVideoCodec)) - { - var userAgent = UserAgent ?? string.Empty; - - if (userAgent.IndexOf("AppleTV", StringComparison.OrdinalIgnoreCase) != -1 || - userAgent.IndexOf("cfnetwork", StringComparison.OrdinalIgnoreCase) != -1 || - userAgent.IndexOf("ipad", StringComparison.OrdinalIgnoreCase) != -1 || - userAgent.IndexOf("iphone", StringComparison.OrdinalIgnoreCase) != -1 || - userAgent.IndexOf("ipod", StringComparison.OrdinalIgnoreCase) != -1) - { - if (IsSegmentedLiveStream) - { - return 6; - } - - return 6; - } - - if (IsSegmentedLiveStream) - { - return 3; - } - - return 6; - } - - return 3; - } - } - - public int MinSegments - { - get - { - if (Request.MinSegments.HasValue) - { - return Request.MinSegments.Value; - } - - return SegmentLength >= 10 ? 2 : 3; - } - } - - public string UserAgent { get; set; } - - public bool EstimateContentLength { get; set; } - - public TranscodeSeekInfo TranscodeSeekInfo { get; set; } - - public bool EnableDlnaHeaders { get; set; } - - public DeviceProfile DeviceProfile { get; set; } - - public TranscodingJobDto TranscodingJob { get; set; } - - public StreamState(IMediaSourceManager mediaSourceManager, TranscodingJobType transcodingType) - : base(transcodingType) - { - _mediaSourceManager = mediaSourceManager; - } - - public override void ReportTranscodingProgress(TimeSpan? transcodingPosition, float? framerate, double? percentComplete, long? bytesTranscoded, int? bitRate) - { - TranscodingJobHelper.ReportTranscodingProgress(TranscodingJob, this, transcodingPosition, framerate, percentComplete, bytesTranscoded, bitRate); - } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - protected virtual void Dispose(bool disposing) - { - if (_disposed) - { - return; - } - - if (disposing) - { - // REVIEW: Is this the right place for this? - if (MediaSource.RequiresClosing - && string.IsNullOrWhiteSpace(Request.LiveStreamId) - && !string.IsNullOrWhiteSpace(MediaSource.LiveStreamId)) - { - _mediaSourceManager.CloseLiveStream(MediaSource.LiveStreamId).GetAwaiter().GetResult(); - } - - TranscodingThrottler?.Dispose(); - } - - TranscodingThrottler = null; - TranscodingJob = null; - - _disposed = true; - } - } -} diff --git a/Jellyfin.Api/Models/StreamingDtos/StreamState.cs b/Jellyfin.Api/Models/StreamingDtos/StreamState.cs new file mode 100644 index 000000000..b962e0ac7 --- /dev/null +++ b/Jellyfin.Api/Models/StreamingDtos/StreamState.cs @@ -0,0 +1,207 @@ +using System; +using Jellyfin.Api.Helpers; +using Jellyfin.Api.Models.PlaybackDtos; +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.MediaEncoding; +using MediaBrowser.Model.Dlna; + +namespace Jellyfin.Api.Models.StreamingDtos +{ + /// <summary> + /// The stream state dto. + /// </summary> + public class StreamState : EncodingJobInfo, IDisposable + { + private readonly IMediaSourceManager _mediaSourceManager; + private readonly TranscodingJobHelper _transcodingJobHelper; + private bool _disposed; + + /// <summary> + /// Initializes a new instance of the <see cref="StreamState" /> class. + /// </summary> + /// <param name="mediaSourceManager">Instance of the <see cref="mediaSourceManager" /> interface.</param> + /// <param name="transcodingType">The <see cref="TranscodingJobType" />.</param> + /// <param name="transcodingJobHelper">The <see cref="TranscodingJobHelper" /> singleton.</param> + public StreamState(IMediaSourceManager mediaSourceManager, TranscodingJobType transcodingType, TranscodingJobHelper transcodingJobHelper) + : base(transcodingType) + { + _mediaSourceManager = mediaSourceManager; + _transcodingJobHelper = transcodingJobHelper; + } + + /// <summary> + /// Gets or sets the requested url. + /// </summary> + public string? RequestedUrl { get; set; } + + // /// <summary> + // /// Gets or sets the request. + // /// </summary> + // public StreamRequest Request + // { + // get => (StreamRequest)BaseRequest; + // set + // { + // BaseRequest = value; + // + // IsVideoRequest = VideoRequest != null; + // } + // } + + /// <summary> + /// Gets or sets the transcoding throttler. + /// </summary> + public TranscodingThrottler? TranscodingThrottler { get; set; } + + /// <summary> + /// Gets the video request. + /// </summary> + public VideoStreamRequest VideoRequest => Request as VideoStreamRequest; + + /// <summary> + /// Gets or sets the direct stream provicer. + /// </summary> + public IDirectStreamProvider? DirectStreamProvider { get; set; } + + /// <summary> + /// Gets or sets the path to wait for. + /// </summary> + public string? WaitForPath { get; set; } + + /// <summary> + /// Gets a value indicating whether the request outputs video. + /// </summary> + public bool IsOutputVideo => Request is VideoStreamRequest; + + /// <summary> + /// Gets the segment length. + /// </summary> + public int SegmentLength + { + get + { + if (Request.SegmentLength.HasValue) + { + return Request.SegmentLength.Value; + } + + if (EncodingHelper.IsCopyCodec(OutputVideoCodec)) + { + var userAgent = UserAgent ?? string.Empty; + + if (userAgent.IndexOf("AppleTV", StringComparison.OrdinalIgnoreCase) != -1 || + userAgent.IndexOf("cfnetwork", StringComparison.OrdinalIgnoreCase) != -1 || + userAgent.IndexOf("ipad", StringComparison.OrdinalIgnoreCase) != -1 || + userAgent.IndexOf("iphone", StringComparison.OrdinalIgnoreCase) != -1 || + userAgent.IndexOf("ipod", StringComparison.OrdinalIgnoreCase) != -1) + { + if (IsSegmentedLiveStream) + { + return 6; + } + + return 6; + } + + if (IsSegmentedLiveStream) + { + return 3; + } + + return 6; + } + + return 3; + } + } + + /// <summary> + /// Gets the minimum number of segments. + /// </summary> + public int MinSegments + { + get + { + if (Request.MinSegments.HasValue) + { + return Request.MinSegments.Value; + } + + return SegmentLength >= 10 ? 2 : 3; + } + } + + /// <summary> + /// Gets or sets the user agent. + /// </summary> + public string? UserAgent { get; set; } + + /// <summary> + /// Gets or sets a value indicating whether to estimate the content length. + /// </summary> + public bool EstimateContentLength { get; set; } + + /// <summary> + /// Gets or sets the transcode seek info. + /// </summary> + public TranscodeSeekInfo TranscodeSeekInfo { get; set; } + + /// <summary> + /// Gets or sets a value indicating whether to enable dlna headers. + /// </summary> + public bool EnableDlnaHeaders { get; set; } + + /// <summary> + /// Gets or sets the device profile. + /// </summary> + public DeviceProfile? DeviceProfile { get; set; } + + /// <summary> + /// Gets or sets the transcoding job. + /// </summary> + public TranscodingJobDto? TranscodingJob { get; set; } + + /// <inheritdoc /> + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + /// <inheritdoc /> + public override void ReportTranscodingProgress(TimeSpan? transcodingPosition, float? framerate, double? percentComplete, long? bytesTranscoded, int? bitRate) + { + _transcodingJobHelper.ReportTranscodingProgress(TranscodingJob!, this, transcodingPosition, framerate, percentComplete, bytesTranscoded, bitRate); + } + + /// <summary> + /// Disposes the stream state. + /// </summary> + /// <param name="disposing">Whether the object is currently beeing disposed.</param> + protected virtual void Dispose(bool disposing) + { + if (_disposed) + { + return; + } + + if (disposing) + { + // REVIEW: Is this the right place for this? + if (MediaSource.RequiresClosing + && string.IsNullOrWhiteSpace(Request.LiveStreamId) + && !string.IsNullOrWhiteSpace(MediaSource.LiveStreamId)) + { + _mediaSourceManager.CloseLiveStream(MediaSource.LiveStreamId).GetAwaiter().GetResult(); + } + + TranscodingThrottler?.Dispose(); + } + + TranscodingThrottler = null; + TranscodingJob = null; + + _disposed = true; + } + } +} diff --git a/MediaBrowser.Api/Playback/Progressive/AudioService.cs b/MediaBrowser.Api/Playback/Progressive/AudioService.cs index 34c7986ca..ef639851b 100644 --- a/MediaBrowser.Api/Playback/Progressive/AudioService.cs +++ b/MediaBrowser.Api/Playback/Progressive/AudioService.cs @@ -17,10 +17,6 @@ namespace MediaBrowser.Api.Playback.Progressive /// <summary> /// Class GetAudioStream /// </summary> - [Route("/Audio/{Id}/stream.{Container}", "GET", Summary = "Gets an audio stream")] - [Route("/Audio/{Id}/stream", "GET", Summary = "Gets an audio stream")] - [Route("/Audio/{Id}/stream.{Container}", "HEAD", Summary = "Gets an audio stream")] - [Route("/Audio/{Id}/stream", "HEAD", Summary = "Gets an audio stream")] public class GetAudioStream : StreamRequest { } diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 8ce106469..8cfe562b3 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -1263,6 +1263,17 @@ namespace MediaBrowser.Controller.MediaEncoding return null; } + public int? GetAudioBitrateParam(int? audioBitRate, MediaStream audioStream) + { + if (audioBitRate.HasValue) + { + // Don't encode any higher than this + return Math.Min(384000, audioBitRate.Value); + } + + return null; + } + public string GetAudioFilterParam(EncodingJobInfo state, EncodingOptions encodingOptions, bool isHls) { var channels = state.OutputAudioChannels; -- cgit v1.2.3 From 7324b44c4371b2c9543bc834e665daf6e764b554 Mon Sep 17 00:00:00 2001 From: Bond_009 <Bond.009@outlook.com> Date: Mon, 20 Jul 2020 11:01:37 +0200 Subject: Fix warnings --- .../Library/CoreResolutionIgnoreRule.cs | 2 +- .../Library/ExclusiveLiveStream.cs | 24 +-- .../Library/LibraryManager.cs | 214 ++++++++++----------- .../Library/LiveStreamHelper.cs | 24 +-- .../Library/MediaSourceManager.cs | 17 +- .../Library/MediaStreamSelector.cs | 2 +- .../Library/SearchEngine.cs | 18 +- MediaBrowser.Controller/Library/ILibraryManager.cs | 2 +- 8 files changed, 144 insertions(+), 159 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/Library/CoreResolutionIgnoreRule.cs b/Emby.Server.Implementations/Library/CoreResolutionIgnoreRule.cs index 77b2c0a69..3380e29d4 100644 --- a/Emby.Server.Implementations/Library/CoreResolutionIgnoreRule.cs +++ b/Emby.Server.Implementations/Library/CoreResolutionIgnoreRule.cs @@ -77,7 +77,7 @@ namespace Emby.Server.Implementations.Library if (parent != null) { // Don't resolve these into audio files - if (string.Equals(Path.GetFileNameWithoutExtension(filename), BaseItem.ThemeSongFilename) + if (string.Equals(Path.GetFileNameWithoutExtension(filename), BaseItem.ThemeSongFilename, StringComparison.Ordinal) && _libraryManager.IsAudioFile(filename)) { return true; diff --git a/Emby.Server.Implementations/Library/ExclusiveLiveStream.cs b/Emby.Server.Implementations/Library/ExclusiveLiveStream.cs index ab39a7223..236453e80 100644 --- a/Emby.Server.Implementations/Library/ExclusiveLiveStream.cs +++ b/Emby.Server.Implementations/Library/ExclusiveLiveStream.cs @@ -11,6 +11,17 @@ namespace Emby.Server.Implementations.Library { public class ExclusiveLiveStream : ILiveStream { + private readonly Func<Task> _closeFn; + + public ExclusiveLiveStream(MediaSourceInfo mediaSource, Func<Task> closeFn) + { + MediaSource = mediaSource; + EnableStreamSharing = false; + _closeFn = closeFn; + ConsumerCount = 1; + UniqueId = Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture); + } + public int ConsumerCount { get; set; } public string OriginalStreamId { get; set; } @@ -21,18 +32,7 @@ namespace Emby.Server.Implementations.Library public MediaSourceInfo MediaSource { get; set; } - public string UniqueId { get; private set; } - - private Func<Task> _closeFn; - - public ExclusiveLiveStream(MediaSourceInfo mediaSource, Func<Task> closeFn) - { - MediaSource = mediaSource; - EnableStreamSharing = false; - _closeFn = closeFn; - ConsumerCount = 1; - UniqueId = Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture); - } + public string UniqueId { get; } public Task Close() { diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index c27b73c74..10e6119e9 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -60,6 +60,8 @@ namespace Emby.Server.Implementations.Library /// </summary> public class LibraryManager : ILibraryManager { + private const string ShortcutFileExtension = ".mblink"; + private readonly ILogger<LibraryManager> _logger; private readonly ITaskManager _taskManager; private readonly IUserManager _userManager; @@ -75,63 +77,24 @@ namespace Emby.Server.Implementations.Library private readonly ConcurrentDictionary<Guid, BaseItem> _libraryItemsCache; private readonly IImageProcessor _imageProcessor; - private NamingOptions _namingOptions; - private string[] _videoFileExtensions; - - private ILibraryMonitor LibraryMonitor => _libraryMonitorFactory.Value; - - private IProviderManager ProviderManager => _providerManagerFactory.Value; - - private IUserViewManager UserViewManager => _userviewManagerFactory.Value; - - /// <summary> - /// Gets or sets the postscan tasks. - /// </summary> - /// <value>The postscan tasks.</value> - private ILibraryPostScanTask[] PostscanTasks { get; set; } - - /// <summary> - /// Gets or sets the intro providers. - /// </summary> - /// <value>The intro providers.</value> - private IIntroProvider[] IntroProviders { get; set; } - - /// <summary> - /// Gets or sets the list of entity resolution ignore rules. - /// </summary> - /// <value>The entity resolution ignore rules.</value> - private IResolverIgnoreRule[] EntityResolutionIgnoreRules { get; set; } - - /// <summary> - /// Gets or sets the list of currently registered entity resolvers. - /// </summary> - /// <value>The entity resolvers enumerable.</value> - private IItemResolver[] EntityResolvers { get; set; } - - private IMultiItemResolver[] MultiItemResolvers { get; set; } - /// <summary> - /// Gets or sets the comparers. + /// The _root folder sync lock. /// </summary> - /// <value>The comparers.</value> - private IBaseItemComparer[] Comparers { get; set; } + private readonly object _rootFolderSyncLock = new object(); + private readonly object _userRootFolderSyncLock = new object(); - /// <summary> - /// Occurs when [item added]. - /// </summary> - public event EventHandler<ItemChangeEventArgs> ItemAdded; + private readonly TimeSpan _viewRefreshInterval = TimeSpan.FromHours(24); - /// <summary> - /// Occurs when [item updated]. - /// </summary> - public event EventHandler<ItemChangeEventArgs> ItemUpdated; + private NamingOptions _namingOptions; + private string[] _videoFileExtensions; /// <summary> - /// Occurs when [item removed]. + /// The _root folder. /// </summary> - public event EventHandler<ItemChangeEventArgs> ItemRemoved; + private volatile AggregateFolder _rootFolder; + private volatile UserRootFolder _userRootFolder; - public bool IsScanRunning { get; private set; } + private bool _wizardCompleted; /// <summary> /// Initializes a new instance of the <see cref="LibraryManager" /> class. @@ -186,37 +149,19 @@ namespace Emby.Server.Implementations.Library } /// <summary> - /// Adds the parts. + /// Occurs when [item added]. /// </summary> - /// <param name="rules">The rules.</param> - /// <param name="resolvers">The resolvers.</param> - /// <param name="introProviders">The intro providers.</param> - /// <param name="itemComparers">The item comparers.</param> - /// <param name="postscanTasks">The post scan tasks.</param> - public void AddParts( - IEnumerable<IResolverIgnoreRule> rules, - IEnumerable<IItemResolver> resolvers, - IEnumerable<IIntroProvider> introProviders, - IEnumerable<IBaseItemComparer> itemComparers, - IEnumerable<ILibraryPostScanTask> postscanTasks) - { - EntityResolutionIgnoreRules = rules.ToArray(); - EntityResolvers = resolvers.OrderBy(i => i.Priority).ToArray(); - MultiItemResolvers = EntityResolvers.OfType<IMultiItemResolver>().ToArray(); - IntroProviders = introProviders.ToArray(); - Comparers = itemComparers.ToArray(); - PostscanTasks = postscanTasks.ToArray(); - } + public event EventHandler<ItemChangeEventArgs> ItemAdded; /// <summary> - /// The _root folder. + /// Occurs when [item updated]. /// </summary> - private volatile AggregateFolder _rootFolder; + public event EventHandler<ItemChangeEventArgs> ItemUpdated; /// <summary> - /// The _root folder sync lock. + /// Occurs when [item removed]. /// </summary> - private readonly object _rootFolderSyncLock = new object(); + public event EventHandler<ItemChangeEventArgs> ItemRemoved; /// <summary> /// Gets the root folder. @@ -241,7 +186,68 @@ namespace Emby.Server.Implementations.Library } } - private bool _wizardCompleted; + private ILibraryMonitor LibraryMonitor => _libraryMonitorFactory.Value; + + private IProviderManager ProviderManager => _providerManagerFactory.Value; + + private IUserViewManager UserViewManager => _userviewManagerFactory.Value; + + /// <summary> + /// Gets or sets the postscan tasks. + /// </summary> + /// <value>The postscan tasks.</value> + private ILibraryPostScanTask[] PostscanTasks { get; set; } + + /// <summary> + /// Gets or sets the intro providers. + /// </summary> + /// <value>The intro providers.</value> + private IIntroProvider[] IntroProviders { get; set; } + + /// <summary> + /// Gets or sets the list of entity resolution ignore rules. + /// </summary> + /// <value>The entity resolution ignore rules.</value> + private IResolverIgnoreRule[] EntityResolutionIgnoreRules { get; set; } + + /// <summary> + /// Gets or sets the list of currently registered entity resolvers. + /// </summary> + /// <value>The entity resolvers enumerable.</value> + private IItemResolver[] EntityResolvers { get; set; } + + private IMultiItemResolver[] MultiItemResolvers { get; set; } + + /// <summary> + /// Gets or sets the comparers. + /// </summary> + /// <value>The comparers.</value> + private IBaseItemComparer[] Comparers { get; set; } + + public bool IsScanRunning { get; private set; } + + /// <summary> + /// Adds the parts. + /// </summary> + /// <param name="rules">The rules.</param> + /// <param name="resolvers">The resolvers.</param> + /// <param name="introProviders">The intro providers.</param> + /// <param name="itemComparers">The item comparers.</param> + /// <param name="postscanTasks">The post scan tasks.</param> + public void AddParts( + IEnumerable<IResolverIgnoreRule> rules, + IEnumerable<IItemResolver> resolvers, + IEnumerable<IIntroProvider> introProviders, + IEnumerable<IBaseItemComparer> itemComparers, + IEnumerable<ILibraryPostScanTask> postscanTasks) + { + EntityResolutionIgnoreRules = rules.ToArray(); + EntityResolvers = resolvers.OrderBy(i => i.Priority).ToArray(); + MultiItemResolvers = EntityResolvers.OfType<IMultiItemResolver>().ToArray(); + IntroProviders = introProviders.ToArray(); + Comparers = itemComparers.ToArray(); + PostscanTasks = postscanTasks.ToArray(); + } /// <summary> /// Records the configuration values. @@ -512,7 +518,7 @@ namespace Emby.Server.Implementations.Library // Try to normalize paths located underneath program-data in an attempt to make them more portable key = key.Substring(_configurationManager.ApplicationPaths.ProgramDataPath.Length) .TrimStart(new[] { '/', '\\' }) - .Replace("/", "\\"); + .Replace('/', '\\'); } if (forceCaseInsensitive || !_configurationManager.Configuration.EnableCaseSensitiveItemIds) @@ -775,14 +781,11 @@ namespace Emby.Server.Implementations.Library return rootFolder; } - private volatile UserRootFolder _userRootFolder; - private readonly object _syncLock = new object(); - public Folder GetUserRootFolder() { if (_userRootFolder == null) { - lock (_syncLock) + lock (_userRootFolderSyncLock) { if (_userRootFolder == null) { @@ -1332,7 +1335,7 @@ namespace Emby.Server.Implementations.Library return new QueryResult<BaseItem> { - Items = _itemRepository.GetItemList(query).ToArray() + Items = _itemRepository.GetItemList(query) }; } @@ -1463,11 +1466,9 @@ namespace Emby.Server.Implementations.Library return _itemRepository.GetItems(query); } - var list = _itemRepository.GetItemList(query); - return new QueryResult<BaseItem> { - Items = list + Items = _itemRepository.GetItemList(query) }; } @@ -1945,12 +1946,9 @@ namespace Emby.Server.Implementations.Library /// <summary> /// Updates the item. /// </summary> - public void UpdateItems(IEnumerable<BaseItem> items, BaseItem parent, ItemUpdateType updateReason, CancellationToken cancellationToken) + public void UpdateItems(IReadOnlyList<BaseItem> items, BaseItem parent, ItemUpdateType updateReason, CancellationToken cancellationToken) { - // Don't iterate multiple times - var itemsList = items.ToList(); - - foreach (var item in itemsList) + foreach (var item in items) { if (item.IsFileProtocol) { @@ -1962,11 +1960,11 @@ namespace Emby.Server.Implementations.Library UpdateImages(item, updateReason >= ItemUpdateType.ImageUpdate); } - _itemRepository.SaveItems(itemsList, cancellationToken); + _itemRepository.SaveItems(items, cancellationToken); if (ItemUpdated != null) { - foreach (var item in itemsList) + foreach (var item in items) { // With the live tv guide this just creates too much noise if (item.SourceType != SourceType.Library) @@ -2189,8 +2187,6 @@ namespace Emby.Server.Implementations.Library .FirstOrDefault(i => !string.IsNullOrEmpty(i)); } - private readonly TimeSpan _viewRefreshInterval = TimeSpan.FromHours(24); - public UserView GetNamedView( User user, string name, @@ -2488,14 +2484,9 @@ namespace Emby.Server.Implementations.Library var isFolder = episode.VideoType == VideoType.BluRay || episode.VideoType == VideoType.Dvd; - var episodeInfo = episode.IsFileProtocol ? - resolver.Resolve(episode.Path, isFolder, null, null, isAbsoluteNaming) : - new Naming.TV.EpisodeInfo(); - - if (episodeInfo == null) - { - episodeInfo = new Naming.TV.EpisodeInfo(); - } + var episodeInfo = episode.IsFileProtocol + ? resolver.Resolve(episode.Path, isFolder, null, null, isAbsoluteNaming) ?? new Naming.TV.EpisodeInfo() + : new Naming.TV.EpisodeInfo(); try { @@ -2503,11 +2494,13 @@ namespace Emby.Server.Implementations.Library if (libraryOptions.EnableEmbeddedEpisodeInfos && string.Equals(episodeInfo.Container, "mp4", StringComparison.OrdinalIgnoreCase)) { // Read from metadata - var mediaInfo = _mediaEncoder.GetMediaInfo(new MediaInfoRequest - { - MediaSource = episode.GetMediaSources(false)[0], - MediaType = DlnaProfileType.Video - }, CancellationToken.None).GetAwaiter().GetResult(); + var mediaInfo = _mediaEncoder.GetMediaInfo( + new MediaInfoRequest + { + MediaSource = episode.GetMediaSources(false)[0], + MediaType = DlnaProfileType.Video + }, + CancellationToken.None).GetAwaiter().GetResult(); if (mediaInfo.ParentIndexNumber > 0) { episodeInfo.SeasonNumber = mediaInfo.ParentIndexNumber; @@ -2665,7 +2658,7 @@ namespace Emby.Server.Implementations.Library var videos = videoListResolver.Resolve(fileSystemChildren); - var currentVideo = videos.FirstOrDefault(i => string.Equals(owner.Path, i.Files.First().Path, StringComparison.OrdinalIgnoreCase)); + var currentVideo = videos.FirstOrDefault(i => string.Equals(owner.Path, i.Files[0].Path, StringComparison.OrdinalIgnoreCase)); if (currentVideo != null) { @@ -2682,9 +2675,7 @@ namespace Emby.Server.Implementations.Library .Select(video => { // Try to retrieve it from the db. If we don't find it, use the resolved version - var dbItem = GetItemById(video.Id) as Trailer; - - if (dbItem != null) + if (GetItemById(video.Id) is Trailer dbItem) { video = dbItem; } @@ -3011,8 +3002,6 @@ namespace Emby.Server.Implementations.Library }); } - private const string ShortcutFileExtension = ".mblink"; - public void AddMediaPath(string virtualFolderName, MediaPathInfo pathInfo) { AddMediaPathInternal(virtualFolderName, pathInfo, true); @@ -3206,7 +3195,8 @@ namespace Emby.Server.Implementations.Library if (!Directory.Exists(virtualFolderPath)) { - throw new FileNotFoundException(string.Format("The media collection {0} does not exist", virtualFolderName)); + throw new FileNotFoundException( + string.Format(CultureInfo.InvariantCulture, "The media collection {0} does not exist", virtualFolderName)); } var shortcut = _fileSystem.GetFilePaths(virtualFolderPath, true) diff --git a/Emby.Server.Implementations/Library/LiveStreamHelper.cs b/Emby.Server.Implementations/Library/LiveStreamHelper.cs index 9b9f53049..041619d1e 100644 --- a/Emby.Server.Implementations/Library/LiveStreamHelper.cs +++ b/Emby.Server.Implementations/Library/LiveStreamHelper.cs @@ -23,9 +23,8 @@ namespace Emby.Server.Implementations.Library { private readonly IMediaEncoder _mediaEncoder; private readonly ILogger _logger; - - private IJsonSerializer _json; - private IApplicationPaths _appPaths; + private readonly IJsonSerializer _json; + private readonly IApplicationPaths _appPaths; public LiveStreamHelper(IMediaEncoder mediaEncoder, ILogger logger, IJsonSerializer json, IApplicationPaths appPaths) { @@ -72,13 +71,14 @@ namespace Emby.Server.Implementations.Library mediaSource.AnalyzeDurationMs = 3000; - mediaInfo = await _mediaEncoder.GetMediaInfo(new MediaInfoRequest - { - MediaSource = mediaSource, - MediaType = isAudio ? DlnaProfileType.Audio : DlnaProfileType.Video, - ExtractChapters = false - - }, cancellationToken).ConfigureAwait(false); + mediaInfo = await _mediaEncoder.GetMediaInfo( + new MediaInfoRequest + { + MediaSource = mediaSource, + MediaType = isAudio ? DlnaProfileType.Audio : DlnaProfileType.Video, + ExtractChapters = false + }, + cancellationToken).ConfigureAwait(false); if (cacheFilePath != null) { @@ -126,7 +126,7 @@ namespace Emby.Server.Implementations.Library mediaSource.RunTimeTicks = null; } - var audioStream = mediaStreams.FirstOrDefault(i => i.Type == MediaBrowser.Model.Entities.MediaStreamType.Audio); + var audioStream = mediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Audio); if (audioStream == null || audioStream.Index == -1) { @@ -137,7 +137,7 @@ namespace Emby.Server.Implementations.Library mediaSource.DefaultAudioStreamIndex = audioStream.Index; } - var videoStream = mediaStreams.FirstOrDefault(i => i.Type == MediaBrowser.Model.Entities.MediaStreamType.Video); + var videoStream = mediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Video); if (videoStream != null) { if (!videoStream.BitRate.HasValue) diff --git a/Emby.Server.Implementations/Library/MediaSourceManager.cs b/Emby.Server.Implementations/Library/MediaSourceManager.cs index ceb36b389..4e1316abf 100644 --- a/Emby.Server.Implementations/Library/MediaSourceManager.cs +++ b/Emby.Server.Implementations/Library/MediaSourceManager.cs @@ -29,6 +29,9 @@ namespace Emby.Server.Implementations.Library { public class MediaSourceManager : IMediaSourceManager, IDisposable { + // Do not use a pipe here because Roku http requests to the server will fail, without any explicit error message. + private const char LiveStreamIdDelimeter = '_'; + private readonly IItemRepository _itemRepo; private readonly IUserManager _userManager; private readonly ILibraryManager _libraryManager; @@ -40,6 +43,11 @@ namespace Emby.Server.Implementations.Library private readonly ILocalizationManager _localizationManager; private readonly IApplicationPaths _appPaths; + private readonly Dictionary<string, ILiveStream> _openStreams = new Dictionary<string, ILiveStream>(StringComparer.OrdinalIgnoreCase); + private readonly SemaphoreSlim _liveStreamSemaphore = new SemaphoreSlim(1, 1); + + private readonly object _disposeLock = new object(); + private IMediaSourceProvider[] _providers; public MediaSourceManager( @@ -368,7 +376,6 @@ namespace Emby.Server.Implementations.Library } } - var preferredSubs = string.IsNullOrEmpty(user.SubtitleLanguagePreference) ? Array.Empty<string>() : NormalizeLanguage(user.SubtitleLanguagePreference); @@ -451,9 +458,6 @@ namespace Emby.Server.Implementations.Library .ToList(); } - private readonly Dictionary<string, ILiveStream> _openStreams = new Dictionary<string, ILiveStream>(StringComparer.OrdinalIgnoreCase); - private readonly SemaphoreSlim _liveStreamSemaphore = new SemaphoreSlim(1, 1); - public async Task<Tuple<LiveStreamResponse, IDirectStreamProvider>> OpenLiveStreamInternal(LiveStreamRequest request, CancellationToken cancellationToken) { await _liveStreamSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); @@ -855,9 +859,6 @@ namespace Emby.Server.Implementations.Library } } - // Do not use a pipe here because Roku http requests to the server will fail, without any explicit error message. - private const char LiveStreamIdDelimeter = '_'; - private Tuple<IMediaSourceProvider, string> GetProvider(string key) { if (string.IsNullOrEmpty(key)) @@ -881,9 +882,9 @@ namespace Emby.Server.Implementations.Library public void Dispose() { Dispose(true); + GC.SuppressFinalize(this); } - private readonly object _disposeLock = new object(); /// <summary> /// Releases unmanaged and - optionally - managed resources. /// </summary> diff --git a/Emby.Server.Implementations/Library/MediaStreamSelector.cs b/Emby.Server.Implementations/Library/MediaStreamSelector.cs index ca904c4ec..179e0ed98 100644 --- a/Emby.Server.Implementations/Library/MediaStreamSelector.cs +++ b/Emby.Server.Implementations/Library/MediaStreamSelector.cs @@ -89,7 +89,7 @@ namespace Emby.Server.Implementations.Library } // load forced subs if we have found no suitable full subtitles - stream = stream ?? streams.FirstOrDefault(s => s.IsForced && string.Equals(s.Language, audioTrackLanguage, StringComparison.OrdinalIgnoreCase)); + stream ??= streams.FirstOrDefault(s => s.IsForced && string.Equals(s.Language, audioTrackLanguage, StringComparison.OrdinalIgnoreCase)); if (stream != null) { diff --git a/Emby.Server.Implementations/Library/SearchEngine.cs b/Emby.Server.Implementations/Library/SearchEngine.cs index 3df9cc06f..d67c9e542 100644 --- a/Emby.Server.Implementations/Library/SearchEngine.cs +++ b/Emby.Server.Implementations/Library/SearchEngine.cs @@ -20,13 +20,11 @@ namespace Emby.Server.Implementations.Library { public class SearchEngine : ISearchEngine { - private readonly ILogger<SearchEngine> _logger; private readonly ILibraryManager _libraryManager; private readonly IUserManager _userManager; - public SearchEngine(ILogger<SearchEngine> logger, ILibraryManager libraryManager, IUserManager userManager) + public SearchEngine(ILibraryManager libraryManager, IUserManager userManager) { - _logger = logger; _libraryManager = libraryManager; _userManager = userManager; } @@ -34,11 +32,7 @@ namespace Emby.Server.Implementations.Library public QueryResult<SearchHintInfo> GetSearchHints(SearchQuery query) { User user = null; - - if (query.UserId.Equals(Guid.Empty)) - { - } - else + if (query.UserId != Guid.Empty) { user = _userManager.GetUserById(query.UserId); } @@ -48,19 +42,19 @@ namespace Emby.Server.Implementations.Library if (query.StartIndex.HasValue) { - results = results.Skip(query.StartIndex.Value).ToList(); + results = results.GetRange(query.StartIndex.Value, totalRecordCount - query.StartIndex.Value); } if (query.Limit.HasValue) { - results = results.Take(query.Limit.Value).ToList(); + results = results.GetRange(0, query.Limit.Value); } return new QueryResult<SearchHintInfo> { TotalRecordCount = totalRecordCount, - Items = results.ToArray() + Items = results }; } @@ -85,7 +79,7 @@ namespace Emby.Server.Implementations.Library if (string.IsNullOrEmpty(searchTerm)) { - throw new ArgumentNullException("SearchTerm can't be empty.", nameof(searchTerm)); + throw new ArgumentException("SearchTerm can't be empty.", nameof(query)); } searchTerm = searchTerm.Trim().RemoveDiacritics(); diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs index 9d6646857..bb56c83c2 100644 --- a/MediaBrowser.Controller/Library/ILibraryManager.cs +++ b/MediaBrowser.Controller/Library/ILibraryManager.cs @@ -199,7 +199,7 @@ namespace MediaBrowser.Controller.Library /// <summary> /// Updates the item. /// </summary> - void UpdateItems(IEnumerable<BaseItem> items, BaseItem parent, ItemUpdateType updateReason, CancellationToken cancellationToken); + void UpdateItems(IReadOnlyList<BaseItem> items, BaseItem parent, ItemUpdateType updateReason, CancellationToken cancellationToken); void UpdateItem(BaseItem item, BaseItem parent, ItemUpdateType updateReason, CancellationToken cancellationToken); -- cgit v1.2.3 From 5f89e813062323c168adddb3fe143c470859e04c Mon Sep 17 00:00:00 2001 From: Nyanmisaka <nst799610810@gmail.com> Date: Mon, 20 Jul 2020 20:48:20 +0800 Subject: fix qsv device creation on Comet Lake reddit: https://www.reddit.com/r/jellyfin/comments/huct4x/jellyfin_1060_released/fyn30ds --- .../MediaEncoding/EncodingHelper.cs | 82 ++++++++++++++-------- 1 file changed, 53 insertions(+), 29 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index ffbda42c3..81ad3769a 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -495,13 +495,13 @@ namespace MediaBrowser.Controller.MediaEncoding } else { - arg.Append("-hwaccel qsv -init_hw_device qsv=hw "); + arg.Append("-hwaccel qsv "); } } if (isWindows) { - arg.Append("-hwaccel qsv -init_hw_device qsv=hw "); + arg.Append("-hwaccel qsv "); } } // While using SW decoder @@ -1606,25 +1606,41 @@ namespace MediaBrowser.Controller.MediaEncoding } else { - index = outputSizeParam.IndexOf("format", StringComparison.OrdinalIgnoreCase); + index = outputSizeParam.IndexOf("hwupload=extra_hw_frames", StringComparison.OrdinalIgnoreCase); if (index != -1) { outputSizeParam = outputSizeParam.Substring(index); } else { - index = outputSizeParam.IndexOf("yadif", StringComparison.OrdinalIgnoreCase); + index = outputSizeParam.IndexOf("format", StringComparison.OrdinalIgnoreCase); if (index != -1) { outputSizeParam = outputSizeParam.Substring(index); } else { - index = outputSizeParam.IndexOf("scale", StringComparison.OrdinalIgnoreCase); + index = outputSizeParam.IndexOf("yadif", StringComparison.OrdinalIgnoreCase); if (index != -1) { outputSizeParam = outputSizeParam.Substring(index); } + else + { + index = outputSizeParam.IndexOf("scale", StringComparison.OrdinalIgnoreCase); + if (index != -1) + { + outputSizeParam = outputSizeParam.Substring(index); + } + else + { + index = outputSizeParam.IndexOf("vpp", StringComparison.OrdinalIgnoreCase); + if (index != -1) + { + outputSizeParam = outputSizeParam.Substring(index); + } + } + } } } } @@ -1790,6 +1806,10 @@ namespace MediaBrowser.Controller.MediaEncoding var outputWidth = width.Value; var outputHeight = height.Value; var qsv_or_vaapi = string.Equals(videoEncoder, "h264_qsv", StringComparison.OrdinalIgnoreCase); + var isDeintEnabled = state.DeInterlace("h264", true) + || state.DeInterlace("avc", true) + || state.DeInterlace("h265", true) + || state.DeInterlace("hevc", true); if (!videoWidth.HasValue || outputWidth != videoWidth.Value @@ -1805,7 +1825,7 @@ namespace MediaBrowser.Controller.MediaEncoding qsv_or_vaapi ? "vpp_qsv" : "scale_vaapi", outputWidth, outputHeight, - (qsv_or_vaapi && state.DeInterlace("h264", true)) ? ":deinterlace=1" : string.Empty)); + (qsv_or_vaapi && isDeintEnabled) ? ":deinterlace=1" : string.Empty)); } else { @@ -1814,7 +1834,7 @@ namespace MediaBrowser.Controller.MediaEncoding CultureInfo.InvariantCulture, "{0}=format=nv12{1}", qsv_or_vaapi ? "vpp_qsv" : "scale_vaapi", - (qsv_or_vaapi && state.DeInterlace("h264", true)) ? ":deinterlace=1" : string.Empty)); + (qsv_or_vaapi && isDeintEnabled) ? ":deinterlace=1" : string.Empty)); } } else if ((videoDecoder ?? string.Empty).IndexOf("cuvid", StringComparison.OrdinalIgnoreCase) != -1 @@ -2026,7 +2046,6 @@ namespace MediaBrowser.Controller.MediaEncoding // http://sonnati.wordpress.com/2012/10/19/ffmpeg-the-swiss-army-knife-of-internet-streaming-part-vi/ var request = state.BaseRequest; - var videoStream = state.VideoStream; var filters = new List<string>(); @@ -2035,23 +2054,31 @@ namespace MediaBrowser.Controller.MediaEncoding var inputHeight = videoStream?.Height; var threeDFormat = state.MediaSource.Video3DFormat; + var isVaapiDecoder = videoDecoder.IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1; + var isVaapiH264Encoder = outputVideoCodec.IndexOf("h264_vaapi", StringComparison.OrdinalIgnoreCase) != -1; + var isQsvH264Encoder = outputVideoCodec.IndexOf("h264_qsv", StringComparison.OrdinalIgnoreCase) != -1; + var isNvdecH264Decoder = videoDecoder.IndexOf("h264_cuvid", StringComparison.OrdinalIgnoreCase) != -1; + var isLibX264Encoder = outputVideoCodec.IndexOf("libx264", StringComparison.OrdinalIgnoreCase) != -1; + var isLinux = RuntimeInformation.IsOSPlatform(OSPlatform.Linux); + + var hasTextSubs = state.SubtitleStream != null && state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode; + var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode; + // When the input may or may not be hardware VAAPI decodable - if (string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase)) + if (isVaapiH264Encoder) { filters.Add("format=nv12|vaapi"); filters.Add("hwupload"); } - // When the input may or may not be hardware QSV decodable - else if (string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase)) + // When burning in graphical subtitles using overlay_qsv, upload videostream to the same qsv context + else if (isLinux && hasGraphicalSubs && isQsvH264Encoder) { - filters.Add("format=nv12|qsv"); filters.Add("hwupload=extra_hw_frames=64"); } // If we're hardware VAAPI decoding and software encoding, download frames from the decoder first - else if (IsVaapiSupported(state) && videoDecoder.IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1 - && string.Equals(outputVideoCodec, "libx264", StringComparison.OrdinalIgnoreCase)) + else if (IsVaapiSupported(state) && isVaapiDecoder && isLibX264Encoder) { var codec = videoStream.Codec.ToLowerInvariant(); var isColorDepth10 = IsColorDepth10(state); @@ -2079,16 +2106,19 @@ namespace MediaBrowser.Controller.MediaEncoding } // Add hardware deinterlace filter before scaling filter - if (state.DeInterlace("h264", true)) + if (state.DeInterlace("h264", true) || state.DeInterlace("avc", true)) { - if (string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase)) + if (isVaapiH264Encoder) { filters.Add(string.Format(CultureInfo.InvariantCulture, "deinterlace_vaapi")); } } // Add software deinterlace filter before scaling filter - if (state.DeInterlace("h264", 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)) { var deintParam = string.Empty; var inputFramerate = videoStream?.RealFrameRate; @@ -2105,9 +2135,7 @@ namespace MediaBrowser.Controller.MediaEncoding if (!string.IsNullOrEmpty(deintParam)) { - if (!string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase) - && !string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase) - && videoDecoder.IndexOf("h264_cuvid", StringComparison.OrdinalIgnoreCase) == -1) + if (!isVaapiH264Encoder && !isQsvH264Encoder && !isNvdecH264Decoder) { filters.Add(deintParam); } @@ -2117,12 +2145,10 @@ namespace MediaBrowser.Controller.MediaEncoding // Add scaling filter: scale_*=format=nv12 or scale_*=w=*:h=*:format=nv12 or scale=expr filters.AddRange(GetScalingFilters(state, inputWidth, inputHeight, threeDFormat, videoDecoder, outputVideoCodec, request.Width, request.Height, request.MaxWidth, request.MaxHeight)); - // Add parameters to use VAAPI with burn-in text subttiles (GH issue #642) - if (string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase)) + // Add parameters to use VAAPI with burn-in text subtitles (GH issue #642) + if (isVaapiH264Encoder) { - if (state.SubtitleStream != null - && state.SubtitleStream.IsTextSubtitleStream - && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode) + if (hasTextSubs) { // Test passed on Intel and AMD gfx filters.Add("hwmap=mode=read+write"); @@ -2132,9 +2158,7 @@ namespace MediaBrowser.Controller.MediaEncoding var output = string.Empty; - if (state.SubtitleStream != null - && state.SubtitleStream.IsTextSubtitleStream - && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode) + if (hasTextSubs) { var subParam = GetTextSubtitleParam(state); @@ -2142,7 +2166,7 @@ namespace MediaBrowser.Controller.MediaEncoding // Ensure proper filters are passed to ffmpeg in case of hardware acceleration via VA-API // Reference: https://trac.ffmpeg.org/wiki/Hardware/VAAPI - if (string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase)) + if (isVaapiH264Encoder) { filters.Add("hwmap"); } -- cgit v1.2.3 From d4c6415f9908715f8cd6f90fd754d300d007c06f Mon Sep 17 00:00:00 2001 From: Nyanmisaka <nst799610810@gmail.com> Date: Tue, 21 Jul 2020 11:41:28 +0800 Subject: minor changes --- MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 81ad3769a..04d03080b 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -460,7 +460,7 @@ namespace MediaBrowser.Controller.MediaEncoding if (!IsCopyCodec(outputVideoCodec)) { if (state.IsVideoRequest - && IsVaapiSupported(state) + && _mediaEncoder.SupportsHwaccel("vaapi") && string.Equals(encodingOptions.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase)) { if (isVaapiDecoder) @@ -1701,7 +1701,7 @@ namespace MediaBrowser.Controller.MediaEncoding } // If we're hardware VAAPI decoding and software encoding, download frames from the decoder first - else if (IsVaapiSupported(state) && videoDecoder.IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1 + else if (_mediaEncoder.SupportsHwaccel("vaapi") && videoDecoder.IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1 && string.Equals(outputVideoCodec, "libx264", StringComparison.OrdinalIgnoreCase)) { /* -- cgit v1.2.3 From febb6bced6d2eb0941ed30205558ff8cf045720b Mon Sep 17 00:00:00 2001 From: Bond_009 <Bond.009@outlook.com> Date: Wed, 22 Jul 2020 13:34:51 +0200 Subject: Review usage of string.Substring (part 1) Reduced allocations by replacing string.Substring with ReadOnlySpan<char>.Slice --- Emby.Dlna/Didl/DidlBuilder.cs | 3 +- Emby.Dlna/DlnaManager.cs | 6 ++-- Emby.Drawing/ImageProcessor.cs | 14 ++++----- Emby.Naming/TV/SeasonPathParser.cs | 2 +- .../Library/LibraryManager.cs | 4 +-- .../Library/MediaSourceManager.cs | 3 +- .../LiveTv/Listings/SchedulesDirect.cs | 4 +-- .../LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs | 9 ++++-- .../LiveTv/TunerHosts/M3uParser.cs | 25 ++++++++------- .../Localization/LocalizationManager.cs | 8 ++--- .../Networking/NetworkManager.cs | 2 +- .../Services/ServiceExec.cs | 8 ++++- .../Services/ServiceHandler.cs | 17 +++++----- .../Services/ServicePath.cs | 2 +- MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs | 2 +- MediaBrowser.Controller/Entities/BaseItem.cs | 16 +++++----- .../MediaEncoding/EncodingHelper.cs | 23 +++++++------- MediaBrowser.MediaEncoding/Subtitles/AssParser.cs | 4 +-- .../Subtitles/ParserValues.cs | 5 ++- MediaBrowser.MediaEncoding/Subtitles/SrtParser.cs | 11 ++++--- MediaBrowser.MediaEncoding/Subtitles/SrtWriter.cs | 4 +++ MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs | 36 +++++++++------------- .../Subtitles/SubtitleEncoder.cs | 4 ++- MediaBrowser.MediaEncoding/Subtitles/TtmlWriter.cs | 9 ++++-- MediaBrowser.MediaEncoding/Subtitles/VttWriter.cs | 2 +- 25 files changed, 124 insertions(+), 99 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Dlna/Didl/DidlBuilder.cs b/Emby.Dlna/Didl/DidlBuilder.cs index 66baa9512..70e358019 100644 --- a/Emby.Dlna/Didl/DidlBuilder.cs +++ b/Emby.Dlna/Didl/DidlBuilder.cs @@ -364,7 +364,8 @@ namespace Emby.Dlna.Didl writer.WriteAttributeString("bitrate", totalBitrate.Value.ToString(_usCulture)); } - var mediaProfile = _profile.GetVideoMediaProfile(streamInfo.Container, + var mediaProfile = _profile.GetVideoMediaProfile( + streamInfo.Container, streamInfo.TargetAudioCodec.FirstOrDefault(), streamInfo.TargetVideoCodec.FirstOrDefault(), streamInfo.TargetAudioBitrate, diff --git a/Emby.Dlna/DlnaManager.cs b/Emby.Dlna/DlnaManager.cs index 5911a73ef..1e20ff92b 100644 --- a/Emby.Dlna/DlnaManager.cs +++ b/Emby.Dlna/DlnaManager.cs @@ -387,7 +387,7 @@ namespace Emby.Dlna foreach (var name in _assembly.GetManifestResourceNames()) { - if (!name.StartsWith(namespaceName)) + if (!name.StartsWith(namespaceName, StringComparison.Ordinal)) { continue; } @@ -406,7 +406,7 @@ namespace Emby.Dlna using (var fileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read)) { - await stream.CopyToAsync(fileStream); + await stream.CopyToAsync(fileStream).ConfigureAwait(false); } } } @@ -509,7 +509,7 @@ namespace Emby.Dlna return _jsonSerializer.DeserializeFromString<DeviceProfile>(json); } - class InternalProfileInfo + private class InternalProfileInfo { internal DeviceProfileInfo Info { get; set; } diff --git a/Emby.Drawing/ImageProcessor.cs b/Emby.Drawing/ImageProcessor.cs index 8696cb280..f585b90ca 100644 --- a/Emby.Drawing/ImageProcessor.cs +++ b/Emby.Drawing/ImageProcessor.cs @@ -448,21 +448,21 @@ namespace Emby.Drawing /// or /// filename. /// </exception> - public string GetCachePath(string path, string filename) + public string GetCachePath(ReadOnlySpan<char> path, ReadOnlySpan<char> filename) { - if (string.IsNullOrEmpty(path)) + if (path.IsEmpty) { - throw new ArgumentNullException(nameof(path)); + throw new ArgumentException("Path can't be empty.", nameof(path)); } - if (string.IsNullOrEmpty(filename)) + if (path.IsEmpty) { - throw new ArgumentNullException(nameof(filename)); + throw new ArgumentException("Filename can't be empty.", nameof(filename)); } - var prefix = filename.Substring(0, 1); + var prefix = filename.Slice(0, 1); - return Path.Combine(path, prefix, filename); + return Path.Join(path, prefix, filename); } /// <inheritdoc /> diff --git a/Emby.Naming/TV/SeasonPathParser.cs b/Emby.Naming/TV/SeasonPathParser.cs index 2fa6b4353..d2e324dda 100644 --- a/Emby.Naming/TV/SeasonPathParser.cs +++ b/Emby.Naming/TV/SeasonPathParser.cs @@ -77,7 +77,7 @@ namespace Emby.Naming.TV if (filename.StartsWith("s", StringComparison.OrdinalIgnoreCase)) { - var testFilename = filename.Substring(1); + var testFilename = filename.AsSpan().Slice(1); if (int.TryParse(testFilename, NumberStyles.Integer, CultureInfo.InvariantCulture, out var val)) { diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index c27b73c74..302d2a092 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -511,8 +511,8 @@ namespace Emby.Server.Implementations.Library { // Try to normalize paths located underneath program-data in an attempt to make them more portable key = key.Substring(_configurationManager.ApplicationPaths.ProgramDataPath.Length) - .TrimStart(new[] { '/', '\\' }) - .Replace("/", "\\"); + .TrimStart('/', '\\') + .Replace('/', '\\'); } if (forceCaseInsensitive || !_configurationManager.Configuration.EnableCaseSensitiveItemIds) diff --git a/Emby.Server.Implementations/Library/MediaSourceManager.cs b/Emby.Server.Implementations/Library/MediaSourceManager.cs index ceb36b389..e5df20622 100644 --- a/Emby.Server.Implementations/Library/MediaSourceManager.cs +++ b/Emby.Server.Implementations/Library/MediaSourceManager.cs @@ -869,7 +869,7 @@ namespace Emby.Server.Implementations.Library var provider = _providers.FirstOrDefault(i => string.Equals(i.GetType().FullName.GetMD5().ToString("N", CultureInfo.InvariantCulture), keys[0], StringComparison.OrdinalIgnoreCase)); - var splitIndex = key.IndexOf(LiveStreamIdDelimeter); + var splitIndex = key.IndexOf(LiveStreamIdDelimeter, StringComparison.Ordinal); var keyId = key.Substring(splitIndex + 1); return new Tuple<IMediaSourceProvider, string>(provider, keyId); @@ -881,6 +881,7 @@ namespace Emby.Server.Implementations.Library public void Dispose() { Dispose(true); + GC.SuppressFinalize(this); } private readonly object _disposeLock = new object(); diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs index 3709f8fe4..77a7069eb 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs @@ -461,7 +461,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings private async Task<List<ScheduleDirect.ShowImages>> GetImageForPrograms( ListingsProviderInfo info, List<string> programIds, - CancellationToken cancellationToken) + CancellationToken cancellationToken) { if (programIds.Count == 0) { @@ -474,7 +474,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings { var imageId = i.Substring(0, 10); - if (!imageIdString.Contains(imageId)) + if (!imageIdString.Contains(imageId, StringComparison.Ordinal)) { imageIdString += "\"" + imageId + "\","; } diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs index 2e2488e6e..00420bd2a 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs @@ -195,7 +195,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun while (!sr.EndOfStream) { string line = StripXML(sr.ReadLine()); - if (line.Contains("Channel")) + if (line.Contains("Channel", StringComparison.Ordinal)) { LiveTvTunerStatus status; var index = line.IndexOf("Channel", StringComparison.OrdinalIgnoreCase); @@ -226,6 +226,11 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun private static string StripXML(string source) { + if (string.IsNullOrEmpty(source)) + { + return string.Empty; + } + char[] buffer = new char[source.Length]; int bufferIndex = 0; bool inside = false; @@ -270,7 +275,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun for (int i = 0; i < model.TunerCount; ++i) { - var name = string.Format("Tuner {0}", i + 1); + var name = string.Format(CultureInfo.InvariantCulture, "Tuner {0}", i + 1); var currentChannel = "none"; // @todo Get current channel and map back to Station Id var isAvailable = await manager.CheckTunerAvailability(ipInfo, i, cancellationToken).ConfigureAwait(false); var status = isAvailable ? LiveTvTunerStatus.Available : LiveTvTunerStatus.LiveTv; diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs index c798c0a85..875977219 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs @@ -158,15 +158,14 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts private string GetChannelNumber(string extInf, Dictionary<string, string> attributes, string mediaUrl) { var nameParts = extInf.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); - var nameInExtInf = nameParts.Length > 1 ? nameParts[nameParts.Length - 1].Trim() : null; + var nameInExtInf = nameParts.Length > 1 ? nameParts[^1].AsSpan().Trim() : ReadOnlySpan<char>.Empty; string numberString = null; string attributeValue; - double doubleValue; if (attributes.TryGetValue("tvg-chno", out attributeValue)) { - if (double.TryParse(attributeValue, NumberStyles.Any, CultureInfo.InvariantCulture, out doubleValue)) + if (double.TryParse(attributeValue, NumberStyles.Any, CultureInfo.InvariantCulture, out _)) { numberString = attributeValue; } @@ -176,36 +175,36 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts { if (attributes.TryGetValue("tvg-id", out attributeValue)) { - if (double.TryParse(attributeValue, NumberStyles.Any, CultureInfo.InvariantCulture, out doubleValue)) + if (double.TryParse(attributeValue, NumberStyles.Any, CultureInfo.InvariantCulture, out _)) { numberString = attributeValue; } else if (attributes.TryGetValue("channel-id", out attributeValue)) { - if (double.TryParse(attributeValue, NumberStyles.Any, CultureInfo.InvariantCulture, out doubleValue)) + if (double.TryParse(attributeValue, NumberStyles.Any, CultureInfo.InvariantCulture, out _)) { numberString = attributeValue; } } } - if (String.IsNullOrWhiteSpace(numberString)) + if (string.IsNullOrWhiteSpace(numberString)) { // Using this as a fallback now as this leads to Problems with channels like "5 USA" // where 5 isnt ment to be the channel number // Check for channel number with the format from SatIp // #EXTINF:0,84. VOX Schweiz // #EXTINF:0,84.0 - VOX Schweiz - if (!string.IsNullOrWhiteSpace(nameInExtInf)) + if (!nameInExtInf.IsEmpty && !nameInExtInf.IsWhiteSpace()) { var numberIndex = nameInExtInf.IndexOf(' '); if (numberIndex > 0) { - var numberPart = nameInExtInf.Substring(0, numberIndex).Trim(new[] { ' ', '.' }); + var numberPart = nameInExtInf.Slice(0, numberIndex).Trim(new[] { ' ', '.' }); - if (double.TryParse(numberPart, NumberStyles.Any, CultureInfo.InvariantCulture, out var number)) + if (double.TryParse(numberPart, NumberStyles.Any, CultureInfo.InvariantCulture, out _)) { - numberString = numberPart; + numberString = numberPart.ToString(); } } } @@ -231,7 +230,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts { try { - numberString = Path.GetFileNameWithoutExtension(mediaUrl.Split('/').Last()); + numberString = Path.GetFileNameWithoutExtension(mediaUrl.Split('/')[^1]); if (!IsValidChannelNumber(numberString)) { @@ -258,7 +257,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts return false; } - if (!double.TryParse(numberString, NumberStyles.Any, CultureInfo.InvariantCulture, out var value)) + if (!double.TryParse(numberString, NumberStyles.Any, CultureInfo.InvariantCulture, out _)) { return false; } @@ -281,7 +280,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts { var numberPart = nameInExtInf.Substring(0, numberIndex).Trim(new[] { ' ', '.' }); - if (double.TryParse(numberPart, NumberStyles.Any, CultureInfo.InvariantCulture, out var number)) + if (double.TryParse(numberPart, NumberStyles.Any, CultureInfo.InvariantCulture, out _)) { // channel.Number = number.ToString(); nameInExtInf = nameInExtInf.Substring(numberIndex + 1).Trim(new[] { ' ', '-' }); diff --git a/Emby.Server.Implementations/Localization/LocalizationManager.cs b/Emby.Server.Implementations/Localization/LocalizationManager.cs index 62a23118f..90e2766b8 100644 --- a/Emby.Server.Implementations/Localization/LocalizationManager.cs +++ b/Emby.Server.Implementations/Localization/LocalizationManager.cs @@ -247,7 +247,7 @@ namespace Emby.Server.Implementations.Localization } // Try splitting by : to handle "Germany: FSK 18" - var index = rating.IndexOf(':'); + var index = rating.IndexOf(':', StringComparison.Ordinal); if (index != -1) { rating = rating.Substring(index).TrimStart(':').Trim(); @@ -312,12 +312,12 @@ namespace Emby.Server.Implementations.Localization throw new ArgumentNullException(nameof(culture)); } - const string prefix = "Core"; - var key = prefix + culture; + const string Prefix = "Core"; + var key = Prefix + culture; return _dictionaries.GetOrAdd( key, - f => GetDictionary(prefix, culture, DefaultCulture + ".json").GetAwaiter().GetResult()); + f => GetDictionary(Prefix, culture, DefaultCulture + ".json").GetAwaiter().GetResult()); } private async Task<Dictionary<string, string>> GetDictionary(string prefix, string culture, string baseFilename) diff --git a/Emby.Server.Implementations/Networking/NetworkManager.cs b/Emby.Server.Implementations/Networking/NetworkManager.cs index 50cb44b28..ff95302ee 100644 --- a/Emby.Server.Implementations/Networking/NetworkManager.cs +++ b/Emby.Server.Implementations/Networking/NetworkManager.cs @@ -390,7 +390,7 @@ namespace Emby.Server.Implementations.Networking var host = uri.DnsSafeHost; _logger.LogDebug("Resolving host {0}", host); - address = GetIpAddresses(host).Result.FirstOrDefault(); + address = GetIpAddresses(host).GetAwaiter().GetResult().FirstOrDefault(); if (address != null) { diff --git a/Emby.Server.Implementations/Services/ServiceExec.cs b/Emby.Server.Implementations/Services/ServiceExec.cs index cbc4b754d..947a5cbf8 100644 --- a/Emby.Server.Implementations/Services/ServiceExec.cs +++ b/Emby.Server.Implementations/Services/ServiceExec.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Linq.Expressions; using System.Reflection; @@ -105,7 +106,12 @@ namespace Emby.Server.Implementations.Services } var expectedMethodName = actionName.Substring(0, 1) + actionName.Substring(1).ToLowerInvariant(); - throw new NotImplementedException(string.Format("Could not find method named {1}({0}) or Any({0}) on Service {2}", requestDto.GetType().GetMethodName(), expectedMethodName, serviceType.GetMethodName())); + throw new NotImplementedException( + string.Format( + CultureInfo.InvariantCulture, + "Could not find method named {1}({0}) or Any({0}) on Service {2}", + requestDto.GetType().GetMethodName(), + expectedMethodName, serviceType.GetMethodName())); } private static async Task<object> GetTaskResult(Task task) diff --git a/Emby.Server.Implementations/Services/ServiceHandler.cs b/Emby.Server.Implementations/Services/ServiceHandler.cs index a42f88ea0..e63a80cee 100644 --- a/Emby.Server.Implementations/Services/ServiceHandler.cs +++ b/Emby.Server.Implementations/Services/ServiceHandler.cs @@ -44,7 +44,7 @@ namespace Emby.Server.Implementations.Services var pos = pathInfo.LastIndexOf('.'); if (pos != -1) { - var format = pathInfo.Substring(pos + 1); + var format = pathInfo.AsSpan().Slice(pos + 1); contentType = GetFormatContentType(format); if (contentType != null) { @@ -55,15 +55,18 @@ namespace Emby.Server.Implementations.Services return pathInfo; } - private static string GetFormatContentType(string format) + private static string GetFormatContentType(ReadOnlySpan<char> format) { - // built-in formats - switch (format) + if (format.Equals("json", StringComparison.Ordinal)) { - case "json": return "application/json"; - case "xml": return "application/xml"; - default: return null; + return "application/json"; } + else if (format.Equals("xml", StringComparison.Ordinal)) + { + return "application/xml"; + } + + return null; } public async Task ProcessRequestAsync(HttpListenerHost httpHost, IRequest httpReq, HttpResponse httpRes, ILogger logger, CancellationToken cancellationToken) diff --git a/Emby.Server.Implementations/Services/ServicePath.cs b/Emby.Server.Implementations/Services/ServicePath.cs index 89538ae72..69c6844f8 100644 --- a/Emby.Server.Implementations/Services/ServicePath.cs +++ b/Emby.Server.Implementations/Services/ServicePath.cs @@ -156,7 +156,7 @@ namespace Emby.Server.Implementations.Services { var component = components[i]; - if (component.StartsWith(VariablePrefix)) + if (component.StartsWith(VariablePrefix, StringComparison.Ordinal)) { var variableName = component.Substring(1, component.Length - 2); if (variableName[variableName.Length - 1] == WildCardChar) diff --git a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs index fe5f980b1..6ff96ac56 100644 --- a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs +++ b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs @@ -369,7 +369,7 @@ namespace MediaBrowser.Api.Playback.Hls var playlistFilename = Path.GetFileNameWithoutExtension(playlist); - var indexString = Path.GetFileNameWithoutExtension(file.Name).Substring(playlistFilename.Length); + var indexString = Path.GetFileNameWithoutExtension(file.Name).AsSpan().Slice(playlistFilename.Length); return int.Parse(indexString, NumberStyles.Integer, CultureInfo.InvariantCulture); } diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 90f62e153..f34309c40 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -675,11 +675,11 @@ namespace MediaBrowser.Controller.Entities return System.IO.Path.Combine(basePath, "channels", ChannelId.ToString("N", CultureInfo.InvariantCulture), Id.ToString("N", CultureInfo.InvariantCulture)); } - var idString = Id.ToString("N", CultureInfo.InvariantCulture); + ReadOnlySpan<char> idString = Id.ToString("N", CultureInfo.InvariantCulture); basePath = System.IO.Path.Combine(basePath, "library"); - return System.IO.Path.Combine(basePath, idString.Substring(0, 2), idString); + return System.IO.Path.Join(basePath, idString.Slice(0, 2), idString); } /// <summary> @@ -702,26 +702,27 @@ namespace MediaBrowser.Controller.Entities foreach (var removeChar in ConfigurationManager.Configuration.SortRemoveCharacters) { - sortable = sortable.Replace(removeChar, string.Empty); + sortable = sortable.Replace(removeChar, string.Empty, StringComparison.Ordinal); } foreach (var replaceChar in ConfigurationManager.Configuration.SortReplaceCharacters) { - sortable = sortable.Replace(replaceChar, " "); + sortable = sortable.Replace(replaceChar, " ", StringComparison.Ordinal); } foreach (var search in ConfigurationManager.Configuration.SortRemoveWords) { // Remove from beginning if a space follows - if (sortable.StartsWith(search + " ")) + if (sortable.StartsWith(search + " ", StringComparison.Ordinal)) { sortable = sortable.Remove(0, search.Length + 1); } + // Remove from middle if surrounded by spaces - sortable = sortable.Replace(" " + search + " ", " "); + sortable = sortable.Replace(" " + search + " ", " ", StringComparison.Ordinal); // Remove from end if followed by a space - if (sortable.EndsWith(" " + search)) + if (sortable.EndsWith(" " + search, StringComparison.Ordinal)) { sortable = sortable.Remove(sortable.Length - (search.Length + 1)); } @@ -751,6 +752,7 @@ namespace MediaBrowser.Controller.Entities builder.Append(chunkBuilder); } + // logger.LogDebug("ModifySortChunks Start: {0} End: {1}", name, builder.ToString()); return builder.ToString().RemoveDiacritics(); } diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index ffbda42c3..18fd53ad6 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -1588,7 +1588,7 @@ namespace MediaBrowser.Controller.MediaEncoding { outputVideoCodec ??= string.Empty; - var outputSizeParam = string.Empty; + var outputSizeParam = ReadOnlySpan<char>.Empty; var request = state.BaseRequest; // Add resolution params, if specified @@ -1602,28 +1602,28 @@ namespace MediaBrowser.Controller.MediaEncoding var index = outputSizeParam.IndexOf("hwdownload", StringComparison.OrdinalIgnoreCase); if (index != -1) { - outputSizeParam = outputSizeParam.Substring(index); + outputSizeParam = outputSizeParam.Slice(index); } else { index = outputSizeParam.IndexOf("format", StringComparison.OrdinalIgnoreCase); if (index != -1) { - outputSizeParam = outputSizeParam.Substring(index); + outputSizeParam = outputSizeParam.Slice(index); } else { index = outputSizeParam.IndexOf("yadif", StringComparison.OrdinalIgnoreCase); if (index != -1) { - outputSizeParam = outputSizeParam.Substring(index); + outputSizeParam = outputSizeParam.Slice(index); } else { index = outputSizeParam.IndexOf("scale", StringComparison.OrdinalIgnoreCase); if (index != -1) { - outputSizeParam = outputSizeParam.Substring(index); + outputSizeParam = outputSizeParam.Slice(index); } } } @@ -1669,9 +1669,9 @@ namespace MediaBrowser.Controller.MediaEncoding // Setup default filtergraph utilizing FFMpeg overlay() and FFMpeg scale() (see the return of this function for index reference) // Always put the scaler before the overlay for better performance - var retStr = !string.IsNullOrEmpty(outputSizeParam) ? - " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}]{3}[base];[base][sub]overlay\"" : - " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}][sub]overlay\""; + var retStr = !outputSizeParam.IsEmpty + ? " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}]{3}[base];[base][sub]overlay\"" + : " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}][sub]overlay\""; // When the input may or may not be hardware VAAPI decodable if (string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase)) @@ -1705,7 +1705,7 @@ namespace MediaBrowser.Controller.MediaEncoding */ if (isLinux) { - retStr = !string.IsNullOrEmpty(outputSizeParam) ? + retStr = !outputSizeParam.IsEmpty ? " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}]{3}[base];[base][sub]overlay_qsv\"" : " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}][sub]overlay_qsv\""; } @@ -1717,7 +1717,7 @@ namespace MediaBrowser.Controller.MediaEncoding mapPrefix, subtitleStreamIndex, state.VideoStream.Index, - outputSizeParam, + outputSizeParam.ToString(), videoSizeParam); } @@ -2090,7 +2090,7 @@ namespace MediaBrowser.Controller.MediaEncoding // Add software deinterlace filter before scaling filter if (state.DeInterlace("h264", true) || state.DeInterlace("h265", true) || state.DeInterlace("hevc", true)) { - var deintParam = string.Empty; + 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 @@ -2159,7 +2159,6 @@ namespace MediaBrowser.Controller.MediaEncoding return output; } - /// <summary> /// Gets the number of threads. /// </summary> diff --git a/MediaBrowser.MediaEncoding/Subtitles/AssParser.cs b/MediaBrowser.MediaEncoding/Subtitles/AssParser.cs index 0e2d70017..43a45291c 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/AssParser.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/AssParser.cs @@ -35,7 +35,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles continue; } - if (line.StartsWith("[")) + if (line[0] == '[') { break; } @@ -62,7 +62,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles return trackInfo; } - long GetTicks(string time) + private long GetTicks(ReadOnlySpan<char> time) { return TimeSpan.TryParseExact(time, @"h\:mm\:ss\.ff", _usCulture, out var span) ? span.Ticks : 0; diff --git a/MediaBrowser.MediaEncoding/Subtitles/ParserValues.cs b/MediaBrowser.MediaEncoding/Subtitles/ParserValues.cs index bf8808eb8..dca5c1e8a 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/ParserValues.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/ParserValues.cs @@ -1,6 +1,9 @@ +#nullable enable +#pragma warning disable CS1591 + namespace MediaBrowser.MediaEncoding.Subtitles { - public class ParserValues + public static class ParserValues { public const string NewLine = "\r\n"; } diff --git a/MediaBrowser.MediaEncoding/Subtitles/SrtParser.cs b/MediaBrowser.MediaEncoding/Subtitles/SrtParser.cs index 728efa788..cc35efb3f 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SrtParser.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SrtParser.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using System.Globalization; @@ -20,6 +22,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles _logger = logger; } + /// <inheritdoc /> public SubtitleTrackInfo Parse(Stream stream, CancellationToken cancellationToken) { var trackInfo = new SubtitleTrackInfo(); @@ -55,11 +58,11 @@ namespace MediaBrowser.MediaEncoding.Subtitles } subEvent.StartPositionTicks = GetTicks(time[0]); - var endTime = time[1]; - var idx = endTime.IndexOf(" ", StringComparison.Ordinal); + var endTime = time[1].AsSpan(); + var idx = endTime.IndexOf(' '); if (idx > 0) { - endTime = endTime.Substring(0, idx); + endTime = endTime.Slice(0, idx); } subEvent.EndPositionTicks = GetTicks(endTime); @@ -88,7 +91,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles return trackInfo; } - long GetTicks(string time) + private long GetTicks(ReadOnlySpan<char> time) { return TimeSpan.TryParseExact(time, @"hh\:mm\:ss\.fff", _usCulture, out var span) ? span.Ticks diff --git a/MediaBrowser.MediaEncoding/Subtitles/SrtWriter.cs b/MediaBrowser.MediaEncoding/Subtitles/SrtWriter.cs index 45b317b2e..143c010b7 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SrtWriter.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SrtWriter.cs @@ -8,8 +8,12 @@ using MediaBrowser.Model.MediaInfo; namespace MediaBrowser.MediaEncoding.Subtitles { + /// <summary> + /// SRT subtitle writer. + /// </summary> public class SrtWriter : ISubtitleWriter { + /// <inheritdoc /> public void Write(SubtitleTrackInfo info, Stream stream, CancellationToken cancellationToken) { using (var writer = new StreamWriter(stream, Encoding.UTF8, 1024, true)) diff --git a/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs b/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs index 77033c6b4..bd330f568 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs @@ -12,6 +12,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles /// </summary> public class SsaParser : ISubtitleParser { + /// <inheritdoc /> public SubtitleTrackInfo Parse(Stream stream, CancellationToken cancellationToken) { var trackInfo = new SubtitleTrackInfo(); @@ -45,7 +46,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles header.AppendLine(line); } - if (line.Trim().ToLowerInvariant() == "[events]") + if (string.Equals(line.Trim(), "[events]", StringComparison.OrdinalIgnoreCase)) { eventsStarted = true; } @@ -63,27 +64,27 @@ namespace MediaBrowser.MediaEncoding.Subtitles format = line.ToLowerInvariant().Substring(8).Split(','); for (int i = 0; i < format.Length; i++) { - if (format[i].Trim().ToLowerInvariant() == "layer") + if (string.Equals(format[i].Trim(), "layer", StringComparison.OrdinalIgnoreCase)) { indexLayer = i; } - else if (format[i].Trim().ToLowerInvariant() == "start") + else if (string.Equals(format[i].Trim(), "start", StringComparison.OrdinalIgnoreCase)) { indexStart = i; } - else if (format[i].Trim().ToLowerInvariant() == "end") + else if (string.Equals(format[i].Trim(), "end", StringComparison.OrdinalIgnoreCase)) { indexEnd = i; } - else if (format[i].Trim().ToLowerInvariant() == "text") + else if (string.Equals(format[i].Trim(), "text", StringComparison.OrdinalIgnoreCase)) { indexText = i; } - else if (format[i].Trim().ToLowerInvariant() == "effect") + else if (string.Equals(format[i].Trim(), "effect", StringComparison.OrdinalIgnoreCase)) { indexEffect = i; } - else if (format[i].Trim().ToLowerInvariant() == "style") + else if (string.Equals(format[i].Trim(), "style", StringComparison.OrdinalIgnoreCase)) { indexStyle = i; } @@ -184,12 +185,10 @@ namespace MediaBrowser.MediaEncoding.Subtitles int.Parse(timeCode[3]) * 10).Ticks; } - public static string GetFormattedText(string text) + private static string GetFormattedText(string text) { text = text.Replace("\\n", ParserValues.NewLine, StringComparison.OrdinalIgnoreCase); - bool italic = false; - for (int i = 0; i < 10; i++) // just look ten times... { if (text.Contains(@"{\fn")) @@ -200,7 +199,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles { string fontName = text.Substring(start + 4, end - (start + 4)); string extraTags = string.Empty; - CheckAndAddSubTags(ref fontName, ref extraTags, out italic); + CheckAndAddSubTags(ref fontName, ref extraTags, out bool italic); text = text.Remove(start, end - start + 1); if (italic) { @@ -231,7 +230,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles { string fontSize = text.Substring(start + 4, end - (start + 4)); string extraTags = string.Empty; - CheckAndAddSubTags(ref fontSize, ref extraTags, out italic); + CheckAndAddSubTags(ref fontSize, ref extraTags, out bool italic); if (IsInteger(fontSize)) { text = text.Remove(start, end - start + 1); @@ -265,7 +264,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles { string color = text.Substring(start + 4, end - (start + 4)); string extraTags = string.Empty; - CheckAndAddSubTags(ref color, ref extraTags, out italic); + CheckAndAddSubTags(ref color, ref extraTags, out bool italic); color = color.Replace("&", string.Empty).TrimStart('H'); color = color.PadLeft(6, '0'); @@ -303,7 +302,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles { string color = text.Substring(start + 5, end - (start + 5)); string extraTags = string.Empty; - CheckAndAddSubTags(ref color, ref extraTags, out italic); + CheckAndAddSubTags(ref color, ref extraTags, out bool italic); color = color.Replace("&", string.Empty).TrimStart('H'); color = color.PadLeft(6, '0'); @@ -354,14 +353,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles } private static bool IsInteger(string s) - { - if (int.TryParse(s, out var i)) - { - return true; - } - - return false; - } + => int.TryParse(s, out _); private static int CountTagInText(string text, string tag) { diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs index f1aa8ea5f..969ad1b33 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Concurrent; using System.Diagnostics; @@ -365,7 +367,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles /// <returns>System.Object.</returns> private SemaphoreSlim GetLock(string filename) { - return _semaphoreLocks.GetOrAdd(filename, key => new SemaphoreSlim(1, 1)); + return _semaphoreLocks.GetOrAdd(filename, _ => new SemaphoreSlim(1, 1)); } /// <summary> diff --git a/MediaBrowser.MediaEncoding/Subtitles/TtmlWriter.cs b/MediaBrowser.MediaEncoding/Subtitles/TtmlWriter.cs index 7d3e18578..e5c785bc5 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/TtmlWriter.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/TtmlWriter.cs @@ -6,8 +6,12 @@ using MediaBrowser.Model.MediaInfo; namespace MediaBrowser.MediaEncoding.Subtitles { + /// <summary> + /// TTML subtitle writer. + /// </summary> public class TtmlWriter : ISubtitleWriter { + /// <inheritdoc /> public void Write(SubtitleTrackInfo info, Stream stream, CancellationToken cancellationToken) { // Example: https://github.com/zmalltalker/ttml2vtt/blob/master/data/sample.xml @@ -36,9 +40,10 @@ namespace MediaBrowser.MediaEncoding.Subtitles text = Regex.Replace(text, @"\\n", "<br/>", RegexOptions.IgnoreCase); - writer.WriteLine("<p begin=\"{0}\" dur=\"{1}\">{2}</p>", + writer.WriteLine( + "<p begin=\"{0}\" dur=\"{1}\">{2}</p>", trackEvent.StartPositionTicks, - (trackEvent.EndPositionTicks - trackEvent.StartPositionTicks), + trackEvent.EndPositionTicks - trackEvent.StartPositionTicks, text); } diff --git a/MediaBrowser.MediaEncoding/Subtitles/VttWriter.cs b/MediaBrowser.MediaEncoding/Subtitles/VttWriter.cs index de35acbba..ad32cb794 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/VttWriter.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/VttWriter.cs @@ -47,7 +47,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles text = Regex.Replace(text, @"\\n", " ", RegexOptions.IgnoreCase); writer.WriteLine(text); - writer.WriteLine(string.Empty); + writer.WriteLine(); } } } -- cgit v1.2.3 From 4d681e3cad3e74fa99dae4a483c7e258e345b001 Mon Sep 17 00:00:00 2001 From: Bond_009 <Bond.009@outlook.com> Date: Wed, 22 Jul 2020 14:34:51 +0200 Subject: Optimize StringBuilder.Append calls --- Emby.Dlna/Eventing/EventManager.cs | 14 +++++++++----- Emby.Server.Implementations/Data/SqliteItemRepository.cs | 14 +++++++++----- Emby.Server.Implementations/Services/ServicePath.cs | 6 ++++-- MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs | 6 +++--- 4 files changed, 25 insertions(+), 15 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Dlna/Eventing/EventManager.cs b/Emby.Dlna/Eventing/EventManager.cs index 56c90c8b3..7d02f5e96 100644 --- a/Emby.Dlna/Eventing/EventManager.cs +++ b/Emby.Dlna/Eventing/EventManager.cs @@ -152,11 +152,15 @@ namespace Emby.Dlna.Eventing builder.Append("<e:propertyset xmlns:e=\"urn:schemas-upnp-org:event-1-0\">"); foreach (var key in stateVariables.Keys) { - builder.Append("<e:property>"); - builder.Append("<" + key + ">"); - builder.Append(stateVariables[key]); - builder.Append("</" + key + ">"); - builder.Append("</e:property>"); + builder.Append("<e:property>") + .Append('<') + .Append(key) + .Append('>') + .Append(stateVariables[key]) + .Append("</") + .Append(key) + .Append('>') + .Append("</e:property>"); } builder.Append("</e:propertyset>"); diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index a6390b1ef..9f5566424 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -1110,7 +1110,8 @@ namespace Emby.Server.Implementations.Data continue; } - str.Append(ToValueString(i) + "|"); + str.Append(ToValueString(i)) + .Append('|'); } str.Length -= 1; // Remove last | @@ -2471,7 +2472,7 @@ namespace Emby.Server.Implementations.Data var item = query.SimilarTo; var builder = new StringBuilder(); - builder.Append("("); + builder.Append('('); if (string.IsNullOrEmpty(item.OfficialRating)) { @@ -2509,7 +2510,7 @@ namespace Emby.Server.Implementations.Data if (!string.IsNullOrEmpty(query.SearchTerm)) { var builder = new StringBuilder(); - builder.Append("("); + builder.Append('('); builder.Append("((CleanName like @SearchTermStartsWith or (OriginalTitle not null and OriginalTitle like @SearchTermStartsWith)) * 10)"); @@ -5238,7 +5239,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type { if (i > 0) { - insertText.Append(","); + insertText.Append(','); } insertText.AppendFormat("(@ItemId, @AncestorId{0}, @AncestorIdText{0})", i.ToString(CultureInfo.InvariantCulture)); @@ -6331,7 +6332,10 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type foreach (var column in _mediaAttachmentSaveColumns.Skip(1)) { - insertText.Append("@" + column + index + ","); + insertText.Append('@') + .Append(column) + .Append(index) + .Append(','); } insertText.Length -= 1; diff --git a/Emby.Server.Implementations/Services/ServicePath.cs b/Emby.Server.Implementations/Services/ServicePath.cs index 89538ae72..bdda7c089 100644 --- a/Emby.Server.Implementations/Services/ServicePath.cs +++ b/Emby.Server.Implementations/Services/ServicePath.cs @@ -488,7 +488,8 @@ namespace Emby.Server.Implementations.Services sb.Append(value); for (var j = pathIx + 1; j < requestComponents.Length; j++) { - sb.Append(PathSeperatorChar + requestComponents[j]); + sb.Append(PathSeperatorChar) + .Append(requestComponents[j]); } value = sb.ToString(); @@ -505,7 +506,8 @@ namespace Emby.Server.Implementations.Services pathIx++; while (!string.Equals(requestComponents[pathIx], stopLiteral, StringComparison.OrdinalIgnoreCase)) { - sb.Append(PathSeperatorChar + requestComponents[pathIx++]); + sb.Append(PathSeperatorChar) + .Append(requestComponents[pathIx++]); } value = sb.ToString(); diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index ffbda42c3..74ebab6a7 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -372,7 +372,7 @@ namespace MediaBrowser.Controller.MediaEncoding public int GetVideoProfileScore(string profile) { // strip spaces because they may be stripped out on the query string - profile = profile.Replace(" ", ""); + profile = profile.Replace(" ", string.Empty, CultureInfo.InvariantCulture); return Array.FindIndex(_videoProfiles, x => string.Equals(x, profile, StringComparison.OrdinalIgnoreCase)); } @@ -468,13 +468,13 @@ namespace MediaBrowser.Controller.MediaEncoding arg.Append("-hwaccel_output_format vaapi ") .Append("-vaapi_device ") .Append(encodingOptions.VaapiDevice) - .Append(" "); + .Append(' '); } else if (!isVaapiDecoder && isVaapiEncoder) { arg.Append("-vaapi_device ") .Append(encodingOptions.VaapiDevice) - .Append(" "); + .Append(' '); } } -- cgit v1.2.3 From b9004a0246d4df800ad8a601d4b7c21a78792982 Mon Sep 17 00:00:00 2001 From: Bond_009 <Bond.009@outlook.com> Date: Wed, 22 Jul 2020 14:56:58 +0200 Subject: Fix build --- MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 74ebab6a7..5894abb0d 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -372,7 +372,7 @@ namespace MediaBrowser.Controller.MediaEncoding public int GetVideoProfileScore(string profile) { // strip spaces because they may be stripped out on the query string - profile = profile.Replace(" ", string.Empty, CultureInfo.InvariantCulture); + profile = profile.Replace(" ", string.Empty, StringComparison.Ordinal); return Array.FindIndex(_videoProfiles, x => string.Equals(x, profile, StringComparison.OrdinalIgnoreCase)); } -- cgit v1.2.3 From 6cbfae209d5e4621624d9cc249c601f46c3721c5 Mon Sep 17 00:00:00 2001 From: Bond_009 <Bond.009@outlook.com> Date: Wed, 22 Jul 2020 20:57:29 +0200 Subject: Make CreateUser async --- Jellyfin.Api/Controllers/StartupController.cs | 8 ++--- .../Users/UserManager.cs | 42 +++++++++++++--------- MediaBrowser.Api/UserService.cs | 2 +- MediaBrowser.Controller/Library/IUserManager.cs | 4 +-- 4 files changed, 31 insertions(+), 25 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Jellyfin.Api/Controllers/StartupController.cs b/Jellyfin.Api/Controllers/StartupController.cs index 04f134b8b..93fb22c4e 100644 --- a/Jellyfin.Api/Controllers/StartupController.cs +++ b/Jellyfin.Api/Controllers/StartupController.cs @@ -46,14 +46,12 @@ namespace Jellyfin.Api.Controllers [HttpGet("Configuration")] public StartupConfigurationDto GetStartupConfiguration() { - var result = new StartupConfigurationDto + return new StartupConfigurationDto { UICulture = _config.Configuration.UICulture, MetadataCountryCode = _config.Configuration.MetadataCountryCode, PreferredMetadataLanguage = _config.Configuration.PreferredMetadataLanguage }; - - return result; } /// <summary> @@ -92,10 +90,10 @@ namespace Jellyfin.Api.Controllers /// </summary> /// <returns>The first user.</returns> [HttpGet("User")] - public StartupUserDto GetFirstUser() + public async Task<StartupUserDto> GetFirstUser() { // TODO: Remove this method when startup wizard no longer requires an existing user. - _userManager.Initialize(); + await _userManager.InitializeAsync().ConfigureAwait(false); var user = _userManager.Users.First(); return new StartupUserDto { diff --git a/Jellyfin.Server.Implementations/Users/UserManager.cs b/Jellyfin.Server.Implementations/Users/UserManager.cs index 343f452c7..5d72ff938 100644 --- a/Jellyfin.Server.Implementations/Users/UserManager.cs +++ b/Jellyfin.Server.Implementations/Users/UserManager.cs @@ -188,8 +188,24 @@ namespace Jellyfin.Server.Implementations.Users await dbContext.SaveChangesAsync().ConfigureAwait(false); } + internal async Task<User> CreateUserInternalAsync(string name, JellyfinDb dbContext) + { + // TODO: Remove after user item data is migrated. + var max = await dbContext.Users.AnyAsync().ConfigureAwait(false) + ? await dbContext.Users.Select(u => u.InternalId).MaxAsync().ConfigureAwait(false) + : 0; + + return new User( + name, + _defaultAuthenticationProvider.GetType().FullName, + _defaultPasswordResetProvider.GetType().FullName) + { + InternalId = max + 1 + }; + } + /// <inheritdoc/> - public User CreateUser(string name) + public async Task<User> CreateUserAsync(string name) { if (!IsValidUsername(name)) { @@ -198,18 +214,10 @@ namespace Jellyfin.Server.Implementations.Users using var dbContext = _dbProvider.CreateContext(); - // TODO: Remove after user item data is migrated. - var max = dbContext.Users.Any() ? dbContext.Users.Select(u => u.InternalId).Max() : 0; + var newUser = await CreateUserInternalAsync(name, dbContext).ConfigureAwait(false); - var newUser = new User( - name, - _defaultAuthenticationProvider.GetType().FullName, - _defaultPasswordResetProvider.GetType().FullName) - { - InternalId = max + 1 - }; - dbContext.Users.Add(newUser); - dbContext.SaveChanges(); + await dbContext.Users.AddAsync(newUser).ConfigureAwait(false); + await dbContext.SaveChangesAsync().ConfigureAwait(false); OnUserCreated?.Invoke(this, new GenericEventArgs<User>(newUser)); @@ -572,12 +580,12 @@ namespace Jellyfin.Server.Implementations.Users } /// <inheritdoc /> - public void Initialize() + public async Task InitializeAsync() { // TODO: Refactor the startup wizard so that it doesn't require a user to already exist. using var dbContext = _dbProvider.CreateContext(); - if (dbContext.Users.Any()) + if (await dbContext.Users.AnyAsync().ConfigureAwait(false)) { return; } @@ -595,13 +603,13 @@ namespace Jellyfin.Server.Implementations.Users throw new ArgumentException("Provided username is not valid!", defaultName); } - var newUser = CreateUser(defaultName); + var newUser = await CreateUserInternalAsync(defaultName, dbContext).ConfigureAwait(false); newUser.SetPermission(PermissionKind.IsAdministrator, true); newUser.SetPermission(PermissionKind.EnableContentDeletion, true); newUser.SetPermission(PermissionKind.EnableRemoteControlOfOtherUsers, true); - dbContext.Users.Update(newUser); - dbContext.SaveChanges(); + await dbContext.Users.AddAsync(newUser).ConfigureAwait(false); + await dbContext.SaveChangesAsync().ConfigureAwait(false); } /// <inheritdoc/> diff --git a/MediaBrowser.Api/UserService.cs b/MediaBrowser.Api/UserService.cs index 6e9d788dc..440d1840d 100644 --- a/MediaBrowser.Api/UserService.cs +++ b/MediaBrowser.Api/UserService.cs @@ -525,7 +525,7 @@ namespace MediaBrowser.Api /// <returns>System.Object.</returns> public async Task<object> Post(CreateUserByName request) { - var newUser = _userManager.CreateUser(request.Name); + var newUser = await _userManager.CreateUserAsync(request.Name).ConfigureAwait(false); // no need to authenticate password for new user if (request.Password != null) diff --git a/MediaBrowser.Controller/Library/IUserManager.cs b/MediaBrowser.Controller/Library/IUserManager.cs index e73fe7120..a2ff0c1bc 100644 --- a/MediaBrowser.Controller/Library/IUserManager.cs +++ b/MediaBrowser.Controller/Library/IUserManager.cs @@ -55,7 +55,7 @@ namespace MediaBrowser.Controller.Library /// <summary> /// Initializes the user manager and ensures that a user exists. /// </summary> - void Initialize(); + Task InitializeAsync(); /// <summary> /// Gets a user by Id. @@ -106,7 +106,7 @@ namespace MediaBrowser.Controller.Library /// <returns>The created user.</returns> /// <exception cref="ArgumentNullException">name</exception> /// <exception cref="ArgumentException"></exception> - User CreateUser(string name); + Task<User> CreateUserAsync(string name); /// <summary> /// Deletes the specified user. -- cgit v1.2.3 From cbe47325b328b70e5a49dc231a70d3709f71dbbd Mon Sep 17 00:00:00 2001 From: Bond_009 <Bond.009@outlook.com> Date: Thu, 23 Jul 2020 13:18:47 +0200 Subject: Make UNIX socket configurable --- .../ConfigurationOptions.cs | 4 ++-- Jellyfin.Server/Program.cs | 21 +++++++++++++---- .../Extensions/ConfigurationExtensions.cs | 26 ++++++++++++++++++++++ 3 files changed, 45 insertions(+), 6 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/ConfigurationOptions.cs b/Emby.Server.Implementations/ConfigurationOptions.cs index ff7ee085f..9a4693db0 100644 --- a/Emby.Server.Implementations/ConfigurationOptions.cs +++ b/Emby.Server.Implementations/ConfigurationOptions.cs @@ -1,6 +1,5 @@ using System.Collections.Generic; using Emby.Server.Implementations.HttpServer; -using Emby.Server.Implementations.Updates; using static MediaBrowser.Controller.Extensions.ConfigurationExtensions; namespace Emby.Server.Implementations @@ -19,7 +18,8 @@ namespace Emby.Server.Implementations { HttpListenerHost.DefaultRedirectKey, "web/index.html" }, { FfmpegProbeSizeKey, "1G" }, { FfmpegAnalyzeDurationKey, "200M" }, - { PlaylistsAllowDuplicatesKey, bool.TrueString } + { PlaylistsAllowDuplicatesKey, bool.TrueString }, + { BindToUnixSocketKey, bool.TrueString } }; } } diff --git a/Jellyfin.Server/Program.cs b/Jellyfin.Server/Program.cs index 444a91c02..f3ee339d1 100644 --- a/Jellyfin.Server/Program.cs +++ b/Jellyfin.Server/Program.cs @@ -344,11 +344,24 @@ namespace Jellyfin.Server } } - // Bind to unix socket (only on OSX and Linux) - if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + // Bind to unix socket (only on macOS and Linux) + if (startupConfig.UseUnixSocket() && !RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { - // TODO: allow configuration of socket path - var socketPath = $"{appPaths.DataPath}/socket.sock"; + var socketPath = startupConfig.GetUnixSocketPath(); + if (string.IsNullOrEmpty(socketPath)) + { + var xdgRuntimeDir = Environment.GetEnvironmentVariable("XDG_RUNTIME_DIR"); + if (xdgRuntimeDir == null) + { + // Fall back to config dir + socketPath = Path.Join(appPaths.ConfigurationDirectoryPath, "socket.sock"); + } + else + { + socketPath = Path.Join(xdgRuntimeDir, "jellyfin-socket"); + } + } + // Workaround for https://github.com/aspnet/AspNetCore/issues/14134 if (File.Exists(socketPath)) { diff --git a/MediaBrowser.Controller/Extensions/ConfigurationExtensions.cs b/MediaBrowser.Controller/Extensions/ConfigurationExtensions.cs index c2932cc4c..ae02c1cee 100644 --- a/MediaBrowser.Controller/Extensions/ConfigurationExtensions.cs +++ b/MediaBrowser.Controller/Extensions/ConfigurationExtensions.cs @@ -33,6 +33,16 @@ namespace MediaBrowser.Controller.Extensions /// </summary> public const string PlaylistsAllowDuplicatesKey = "playlists:allowDuplicates"; + /// <summary> + /// The key for a setting that indicates whether kestrel should bind to a unix socket. + /// </summary> + public const string BindToUnixSocketKey = "kerstrel:socket"; + + /// <summary> + /// The key for the unix socket path. + /// </summary> + public const string UnixSocketPathKey = "kerstrel:socketPath"; + /// <summary> /// Gets a value indicating whether the application should host static web content from the <see cref="IConfiguration"/>. /// </summary> @@ -65,5 +75,21 @@ namespace MediaBrowser.Controller.Extensions /// <returns>True if playlists should allow duplicates, otherwise false.</returns> public static bool DoPlaylistsAllowDuplicates(this IConfiguration configuration) => configuration.GetValue<bool>(PlaylistsAllowDuplicatesKey); + + /// <summary> + /// Gets a value indicating whether kestrel should bind to a unix socket from the <see cref="IConfiguration" />. + /// </summary> + /// <param name="configuration">The configuration to read the setting from.</param> + /// <returns><c>true</c> if kestrel should bind to a unix socket, otherwise <c>false</c>.</returns> + public static bool UseUnixSocket(this IConfiguration configuration) + => configuration.GetValue<bool>(BindToUnixSocketKey); + + /// <summary> + /// Gets the path for the unix socket from the <see cref="IConfiguration" />. + /// </summary> + /// <param name="configuration">The configuration to read the setting from.</param> + /// <returns>The unix socket path.</returns> + public static string GetUnixSocketPath(this IConfiguration configuration) + => configuration[FfmpegAnalyzeDurationKey]; } } -- cgit v1.2.3 From 1cc62d6afa121607abf5c68a088de790f105f917 Mon Sep 17 00:00:00 2001 From: Bond-009 <bond.009@outlook.com> Date: Fri, 24 Jul 2020 09:36:18 +0200 Subject: Update MediaBrowser.Controller/Extensions/ConfigurationExtensions.cs Co-authored-by: David Mouse <dmouse10462@gmail.com> --- MediaBrowser.Controller/Extensions/ConfigurationExtensions.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/Extensions/ConfigurationExtensions.cs b/MediaBrowser.Controller/Extensions/ConfigurationExtensions.cs index ae02c1cee..425b39fd9 100644 --- a/MediaBrowser.Controller/Extensions/ConfigurationExtensions.cs +++ b/MediaBrowser.Controller/Extensions/ConfigurationExtensions.cs @@ -36,12 +36,12 @@ namespace MediaBrowser.Controller.Extensions /// <summary> /// The key for a setting that indicates whether kestrel should bind to a unix socket. /// </summary> - public const string BindToUnixSocketKey = "kerstrel:socket"; + public const string BindToUnixSocketKey = "kestrel:socket"; /// <summary> /// The key for the unix socket path. /// </summary> - public const string UnixSocketPathKey = "kerstrel:socketPath"; + public const string UnixSocketPathKey = "kestrel:socketPath"; /// <summary> /// Gets a value indicating whether the application should host static web content from the <see cref="IConfiguration"/>. -- cgit v1.2.3 From 928bc6c7875c4523ee158aabc0e2ffc46c691383 Mon Sep 17 00:00:00 2001 From: Bond_009 <Bond.009@outlook.com> Date: Fri, 24 Jul 2020 16:42:28 +0200 Subject: Fix build --- MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 3f85f3ecf..c20c9c2c4 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -1630,14 +1630,14 @@ namespace MediaBrowser.Controller.MediaEncoding index = outputSizeParam.IndexOf("scale", StringComparison.OrdinalIgnoreCase); if (index != -1) { - outputSizeParam = outputSizeParam.Substring(index); + outputSizeParam = outputSizeParam.Slice(index); } else { index = outputSizeParam.IndexOf("vpp", StringComparison.OrdinalIgnoreCase); if (index != -1) { - outputSizeParam = outputSizeParam.Substring(index); + outputSizeParam = outputSizeParam.Slice(index); } } } -- cgit v1.2.3 From 7b862bba5aad345f0bc8d76bfb950590471ae232 Mon Sep 17 00:00:00 2001 From: nyanmisaka <nst799610810@gmail.com> Date: Sat, 25 Jul 2020 00:57:34 +0800 Subject: add Tonemapping relaying on nvdec and ocl --- .../MediaEncoding/EncodingHelper.cs | 109 +++++++++++++++++++-- .../Probing/MediaStreamInfo.cs | 14 +++ .../Probing/ProbeResultNormalizer.cs | 10 ++ .../Configuration/EncodingOptions.cs | 29 +++++- MediaBrowser.Model/Entities/MediaStream.cs | 18 ++-- 5 files changed, 166 insertions(+), 14 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 0242338b7..4a33f22e6 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -454,6 +454,7 @@ namespace MediaBrowser.Controller.MediaEncoding var isVaapiEncoder = outputVideoCodec.IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1; var isQsvDecoder = videoDecoder.IndexOf("qsv", StringComparison.OrdinalIgnoreCase) != -1; var isQsvEncoder = outputVideoCodec.IndexOf("qsv", StringComparison.OrdinalIgnoreCase) != -1; + var isNvencHevcDecoder = videoDecoder.IndexOf("hevc_cuvid", StringComparison.OrdinalIgnoreCase) != -1; var isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); var isLinux = RuntimeInformation.IsOSPlatform(OSPlatform.Linux); @@ -511,6 +512,25 @@ namespace MediaBrowser.Controller.MediaEncoding } } } + + if (state.IsVideoRequest + && string.Equals(encodingOptions.HardwareAccelerationType, "nvenc", StringComparison.OrdinalIgnoreCase)) + { + var codec = state.VideoStream.Codec.ToLowerInvariant(); + var isColorDepth10 = IsColorDepth10(state); + + if (isNvencHevcDecoder && isColorDepth10 + && _mediaEncoder.SupportsHwaccel("opencl") + && encodingOptions.EnableTonemapping + && !string.IsNullOrEmpty(state.VideoStream.VideoRange) + && state.VideoStream.VideoRange.Contains("HDR", StringComparison.OrdinalIgnoreCase)) + { + arg.Append("-init_hw_device opencl=ocl:") + .Append(encodingOptions.OpenclDevice) + .Append(' ') + .Append("-filter_hw_device ocl "); + } + } } arg.Append("-i ") @@ -994,11 +1014,33 @@ namespace MediaBrowser.Controller.MediaEncoding if (!string.Equals(videoEncoder, "h264_omx", StringComparison.OrdinalIgnoreCase) && !string.Equals(videoEncoder, "h264_qsv", StringComparison.OrdinalIgnoreCase) && !string.Equals(videoEncoder, "h264_vaapi", StringComparison.OrdinalIgnoreCase) + && !string.Equals(videoEncoder, "h264_nvenc", StringComparison.OrdinalIgnoreCase) && !string.Equals(videoEncoder, "h264_v4l2m2m", StringComparison.OrdinalIgnoreCase)) { param = "-pix_fmt yuv420p " + param; } + if (string.Equals(videoEncoder, "h264_nvenc", StringComparison.OrdinalIgnoreCase)) + { + var videoDecoder = GetHardwareAcceleratedVideoDecoder(state, encodingOptions) ?? string.Empty; + var videoStream = state.VideoStream; + var isColorDepth10 = IsColorDepth10(state); + + if (videoDecoder.IndexOf("hevc_cuvid", StringComparison.OrdinalIgnoreCase) != -1 + && isColorDepth10 + && _mediaEncoder.SupportsHwaccel("opencl") + && encodingOptions.EnableTonemapping + && !string.IsNullOrEmpty(videoStream.VideoRange) + && videoStream.VideoRange.Contains("HDR", StringComparison.OrdinalIgnoreCase)) + { + param = "-pix_fmt nv12 " + param; + } + else + { + param = "-pix_fmt yuv420p " + param; + } + } + if (string.Equals(videoEncoder, "h264_v4l2m2m", StringComparison.OrdinalIgnoreCase)) { param = "-pix_fmt nv21 " + param; @@ -1599,46 +1641,54 @@ namespace MediaBrowser.Controller.MediaEncoding { outputSizeParam = GetOutputSizeParam(state, options, outputVideoCodec).TrimEnd('"'); - var index = outputSizeParam.IndexOf("hwdownload", StringComparison.OrdinalIgnoreCase); + var index = outputSizeParam.IndexOf("hwupload,tonemap_opencl", StringComparison.OrdinalIgnoreCase); if (index != -1) { outputSizeParam = outputSizeParam.Substring(index); } else { - index = outputSizeParam.IndexOf("hwupload=extra_hw_frames", StringComparison.OrdinalIgnoreCase); + index = outputSizeParam.IndexOf("hwdownload", StringComparison.OrdinalIgnoreCase); if (index != -1) { outputSizeParam = outputSizeParam.Substring(index); } else { - index = outputSizeParam.IndexOf("format", StringComparison.OrdinalIgnoreCase); + index = outputSizeParam.IndexOf("hwupload=extra_hw_frames", StringComparison.OrdinalIgnoreCase); if (index != -1) { outputSizeParam = outputSizeParam.Substring(index); } else { - index = outputSizeParam.IndexOf("yadif", StringComparison.OrdinalIgnoreCase); + index = outputSizeParam.IndexOf("format", StringComparison.OrdinalIgnoreCase); if (index != -1) { outputSizeParam = outputSizeParam.Substring(index); } else { - index = outputSizeParam.IndexOf("scale", StringComparison.OrdinalIgnoreCase); + index = outputSizeParam.IndexOf("yadif", StringComparison.OrdinalIgnoreCase); if (index != -1) { outputSizeParam = outputSizeParam.Substring(index); } else { - index = outputSizeParam.IndexOf("vpp", StringComparison.OrdinalIgnoreCase); + index = outputSizeParam.IndexOf("scale", StringComparison.OrdinalIgnoreCase); if (index != -1) { outputSizeParam = outputSizeParam.Substring(index); } + else + { + index = outputSizeParam.IndexOf("vpp", StringComparison.OrdinalIgnoreCase); + if (index != -1) + { + outputSizeParam = outputSizeParam.Substring(index); + } + } } } } @@ -2058,12 +2108,58 @@ namespace MediaBrowser.Controller.MediaEncoding var isVaapiH264Encoder = outputVideoCodec.IndexOf("h264_vaapi", StringComparison.OrdinalIgnoreCase) != -1; var isQsvH264Encoder = outputVideoCodec.IndexOf("h264_qsv", StringComparison.OrdinalIgnoreCase) != -1; var isNvdecH264Decoder = videoDecoder.IndexOf("h264_cuvid", StringComparison.OrdinalIgnoreCase) != -1; + var isNvdecHevcDecoder = videoDecoder.IndexOf("hevc_cuvid", StringComparison.OrdinalIgnoreCase) != -1; var isLibX264Encoder = outputVideoCodec.IndexOf("libx264", StringComparison.OrdinalIgnoreCase) != -1; var isLinux = RuntimeInformation.IsOSPlatform(OSPlatform.Linux); + var isColorDepth10 = IsColorDepth10(state); var hasTextSubs = state.SubtitleStream != null && state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode; var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode; + // Currently only with the use of NVENC decoder can we get a decent performance. + // Currently only the HEVC/H265 format is supported. + // NVIDIA Pascal and Turing or higher are recommended. + if (isNvdecHevcDecoder && isColorDepth10 + && _mediaEncoder.SupportsHwaccel("opencl") + && options.EnableTonemapping + && !string.IsNullOrEmpty(videoStream.VideoRange) + && videoStream.VideoRange.Contains("HDR", StringComparison.OrdinalIgnoreCase)) + { + var parameters = "tonemap_opencl=format=nv12:primaries=bt709:transfer=bt709:matrix=bt709:tonemap={0}:desat={1}:threshold={2}:peak={3}"; + + if (options.TonemappingParam != 0) + { + parameters += ":param={4}"; + } + + if (!string.Equals(options.TonemappingRange, "auto", StringComparison.OrdinalIgnoreCase)) + { + parameters += ":range={5}"; + } + + // Upload the HDR10 or HLG data to the OpenCL device, + // use tonemap_opencl filter for tone mapping, + // and then download the SDR data to memory. + filters.Add("hwupload"); + filters.Add( + string.Format( + CultureInfo.InvariantCulture, + parameters, + options.TonemappingAlgorithm, + options.TonemappingDesat, + options.TonemappingThreshold, + options.TonemappingPeak, + options.TonemappingParam, + options.TonemappingRange)); + filters.Add("hwdownload"); + + if (hasGraphicalSubs || state.DeInterlace("h265", true) || state.DeInterlace("hevc", true) + || string.Equals(outputVideoCodec, "libx264", StringComparison.OrdinalIgnoreCase)) + { + filters.Add("format=nv12"); + } + } + // When the input may or may not be hardware VAAPI decodable if (isVaapiH264Encoder) { @@ -2081,7 +2177,6 @@ namespace MediaBrowser.Controller.MediaEncoding else if (IsVaapiSupported(state) && isVaapiDecoder && isLibX264Encoder) { var codec = videoStream.Codec.ToLowerInvariant(); - var isColorDepth10 = IsColorDepth10(state); // Assert 10-bit hardware VAAPI decodable if (isColorDepth10 && (string.Equals(codec, "hevc", StringComparison.OrdinalIgnoreCase) diff --git a/MediaBrowser.MediaEncoding/Probing/MediaStreamInfo.cs b/MediaBrowser.MediaEncoding/Probing/MediaStreamInfo.cs index a2ea0766a..d9658cba2 100644 --- a/MediaBrowser.MediaEncoding/Probing/MediaStreamInfo.cs +++ b/MediaBrowser.MediaEncoding/Probing/MediaStreamInfo.cs @@ -279,6 +279,20 @@ namespace MediaBrowser.MediaEncoding.Probing [JsonPropertyName("disposition")] public IReadOnlyDictionary<string, int> Disposition { get; set; } + /// <summary> + /// Gets or sets the color range. + /// </summary> + /// <value>The color range.</value> + [JsonPropertyName("color_range")] + public string ColorRange { get; set; } + + /// <summary> + /// Gets or sets the color space. + /// </summary> + /// <value>The color space.</value> + [JsonPropertyName("color_space")] + public string ColorSpace { get; set; } + /// <summary> /// Gets or sets the color transfer. /// </summary> diff --git a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs index c85d963ed..3815e00d4 100644 --- a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs +++ b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs @@ -703,6 +703,16 @@ namespace MediaBrowser.MediaEncoding.Probing stream.RefFrames = streamInfo.Refs; } + if (!string.IsNullOrEmpty(streamInfo.ColorRange)) + { + stream.ColorRange = streamInfo.ColorRange; + } + + if (!string.IsNullOrEmpty(streamInfo.ColorSpace)) + { + stream.ColorSpace = streamInfo.ColorSpace; + } + if (!string.IsNullOrEmpty(streamInfo.ColorTransfer)) { stream.ColorTransfer = streamInfo.ColorTransfer; diff --git a/MediaBrowser.Model/Configuration/EncodingOptions.cs b/MediaBrowser.Model/Configuration/EncodingOptions.cs index 9a30f7e9f..843ff3ff9 100644 --- a/MediaBrowser.Model/Configuration/EncodingOptions.cs +++ b/MediaBrowser.Model/Configuration/EncodingOptions.cs @@ -29,6 +29,22 @@ namespace MediaBrowser.Model.Configuration public string VaapiDevice { get; set; } + public string OpenclDevice { get; set; } + + public bool EnableTonemapping { get; set; } + + public string TonemappingAlgorithm { get; set; } + + public string TonemappingRange { get; set; } + + public double TonemappingDesat { get; set; } + + public double TonemappingThreshold { get; set; } + + public double TonemappingPeak { get; set; } + + public double TonemappingParam { get; set; } + public int H264Crf { get; set; } public int H265Crf { get; set; } @@ -53,8 +69,19 @@ namespace MediaBrowser.Model.Configuration EnableThrottling = false; ThrottleDelaySeconds = 180; EncodingThreadCount = -1; - // This is a DRM device that is almost guaranteed to be there on every intel platform, plus it's the default one in ffmpeg if you don't specify anything + // This is a DRM device that is almost guaranteed to be there on every intel platform, + // plus it's the default one in ffmpeg if you don't specify anything VaapiDevice = "/dev/dri/renderD128"; + // This is the OpenCL device that is used for tonemapping. + // The left side of the dot is the platform number, and the right side is the device number on the platform. + OpenclDevice = "0.0"; + EnableTonemapping = false; + TonemappingAlgorithm = "reinhard"; + TonemappingRange = "auto"; + TonemappingDesat = 0; + TonemappingThreshold = 0.8; + TonemappingPeak = 0; + TonemappingParam = 0; H264Crf = 23; H265Crf = 28; DeinterlaceMethod = "yadif"; diff --git a/MediaBrowser.Model/Entities/MediaStream.cs b/MediaBrowser.Model/Entities/MediaStream.cs index 1b37cfc93..19eb79acc 100644 --- a/MediaBrowser.Model/Entities/MediaStream.cs +++ b/MediaBrowser.Model/Entities/MediaStream.cs @@ -35,6 +35,18 @@ namespace MediaBrowser.Model.Entities /// <value>The language.</value> public string Language { get; set; } + /// <summary> + /// Gets or sets the color range. + /// </summary> + /// <value>The color range.</value> + public string ColorRange { get; set; } + + /// <summary> + /// Gets or sets the color space. + /// </summary> + /// <value>The color space.</value> + public string ColorSpace { get; set; } + /// <summary> /// Gets or sets the color transfer. /// </summary> @@ -47,12 +59,6 @@ namespace MediaBrowser.Model.Entities /// <value>The color primaries.</value> public string ColorPrimaries { get; set; } - /// <summary> - /// Gets or sets the color space. - /// </summary> - /// <value>The color space.</value> - public string ColorSpace { get; set; } - /// <summary> /// Gets or sets the comment. /// </summary> -- cgit v1.2.3 From 5716453542172443124db43790d4fde0f0abff10 Mon Sep 17 00:00:00 2001 From: nyanmisaka <nst799610810@gmail.com> Date: Sat, 25 Jul 2020 01:03:34 +0800 Subject: minor changes --- MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 668411342..42b89be02 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -1686,7 +1686,7 @@ namespace MediaBrowser.Controller.MediaEncoding index = outputSizeParam.IndexOf("vpp", StringComparison.OrdinalIgnoreCase); if (index != -1) { - outputSizeParam = outputSizeParam.Substring(index); + outputSizeParam = outputSizeParam.Slice(index); } } } @@ -1771,9 +1771,9 @@ namespace MediaBrowser.Controller.MediaEncoding */ if (isLinux) { - retStr = !outputSizeParam.IsEmpty ? - " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}]{3}[base];[base][sub]overlay_qsv\"" : - " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}][sub]overlay_qsv\""; + retStr = !outputSizeParam.IsEmpty + ? " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}]{3}[base];[base][sub]overlay_qsv\"" + : " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}][sub]overlay_qsv\""; } } -- cgit v1.2.3 From 95b961c8647b9db98d52631561cfc98224b905f7 Mon Sep 17 00:00:00 2001 From: Nyanmisaka <nst799610810@gmail.com> Date: Sun, 26 Jul 2020 12:38:57 +0800 Subject: remove unused line --- MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs | 1 - 1 file changed, 1 deletion(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 42b89be02..1cdc8b736 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -516,7 +516,6 @@ namespace MediaBrowser.Controller.MediaEncoding if (state.IsVideoRequest && string.Equals(encodingOptions.HardwareAccelerationType, "nvenc", StringComparison.OrdinalIgnoreCase)) { - var codec = state.VideoStream.Codec.ToLowerInvariant(); var isColorDepth10 = IsColorDepth10(state); if (isNvencHevcDecoder && isColorDepth10 -- cgit v1.2.3 From d5dcb12407f785ee6f06f5cd91bbda4d398aaf58 Mon Sep 17 00:00:00 2001 From: 不帅你报警 <yrjyrj123@qq.com> Date: Sun, 26 Jul 2020 23:47:29 +0800 Subject: Update EncodingHelper.cs Fix the problem that hardware decoding cannot be used on macOS. --- MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index c20c9c2c4..8321e82f4 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -456,7 +456,8 @@ namespace MediaBrowser.Controller.MediaEncoding var isQsvEncoder = outputVideoCodec.IndexOf("qsv", StringComparison.OrdinalIgnoreCase) != -1; var isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); var isLinux = RuntimeInformation.IsOSPlatform(OSPlatform.Linux); - + var isMacOS = RuntimeInformation.IsOSPlatform(OSPlatform.OSX); + if (!IsCopyCodec(outputVideoCodec)) { if (state.IsVideoRequest @@ -511,6 +512,12 @@ namespace MediaBrowser.Controller.MediaEncoding } } } + + if (state.IsVideoRequest + && string.Equals(encodingOptions.HardwareAccelerationType, "videotoolbox", StringComparison.OrdinalIgnoreCase)) + { + arg.Append("-hwaccel videotoolbox "); + } } arg.Append("-i ") -- cgit v1.2.3 From 30bfa5536fecc2a9ccb428eb55e124ba27c44cc0 Mon Sep 17 00:00:00 2001 From: 不帅你报警 <yrjyrj123@qq.com> Date: Mon, 27 Jul 2020 01:34:36 +0800 Subject: Update MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs Co-authored-by: Nyanmisaka <nst799610810@gmail.com> --- MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs | 1 - 1 file changed, 1 deletion(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 8321e82f4..383a589ca 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -457,7 +457,6 @@ namespace MediaBrowser.Controller.MediaEncoding var isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); var isLinux = RuntimeInformation.IsOSPlatform(OSPlatform.Linux); var isMacOS = RuntimeInformation.IsOSPlatform(OSPlatform.OSX); - if (!IsCopyCodec(outputVideoCodec)) { if (state.IsVideoRequest -- cgit v1.2.3 From 3e556328075b09cc214598fc3db4dfa6b9cd09c7 Mon Sep 17 00:00:00 2001 From: Nyanmisaka <nst799610810@gmail.com> Date: Mon, 27 Jul 2020 01:41:27 +0800 Subject: remove spaces --- MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 383a589ca..913e171f1 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -457,6 +457,7 @@ namespace MediaBrowser.Controller.MediaEncoding var isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); var isLinux = RuntimeInformation.IsOSPlatform(OSPlatform.Linux); var isMacOS = RuntimeInformation.IsOSPlatform(OSPlatform.OSX); + if (!IsCopyCodec(outputVideoCodec)) { if (state.IsVideoRequest @@ -511,7 +512,7 @@ namespace MediaBrowser.Controller.MediaEncoding } } } - + if (state.IsVideoRequest && string.Equals(encodingOptions.HardwareAccelerationType, "videotoolbox", StringComparison.OrdinalIgnoreCase)) { -- cgit v1.2.3 From 3c91aa0c3d4af3c3d11b4c732ea14c7e641ba662 Mon Sep 17 00:00:00 2001 From: Matt Montgomery <33811686+ConfusedPolarBear@users.noreply.github.com> Date: Sun, 26 Jul 2020 23:13:14 -0500 Subject: Code cleanup --- .../QuickConnect/QuickConnectManager.cs | 25 +++++++++++----------- .../QuickConnect/QuickConnectService.cs | 2 +- .../QuickConnect/IQuickConnect.cs | 6 +++--- 3 files changed, 16 insertions(+), 17 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/QuickConnect/QuickConnectManager.cs b/Emby.Server.Implementations/QuickConnect/QuickConnectManager.cs index a69ea2267..23e94afd7 100644 --- a/Emby.Server.Implementations/QuickConnect/QuickConnectManager.cs +++ b/Emby.Server.Implementations/QuickConnect/QuickConnectManager.cs @@ -14,6 +14,7 @@ using MediaBrowser.Model.Services; using MediaBrowser.Common; using Microsoft.Extensions.Logging; using MediaBrowser.Common.Extensions; +using MediaBrowser.Controller.Authentication; namespace Emby.Server.Implementations.QuickConnect { @@ -83,13 +84,13 @@ namespace Emby.Server.Implementations.QuickConnect public void Activate() { DateActivated = DateTime.Now; - SetEnabled(QuickConnectState.Active); + SetState(QuickConnectState.Active); } /// <inheritdoc/> - public void SetEnabled(QuickConnectState newState) + public void SetState(QuickConnectState newState) { - _logger.LogDebug("Changed quick connect state from {0} to {1}", State, newState); + _logger.LogDebug("Changed quick connect state from {State} to {newState}", State, newState); ExpireRequests(true); @@ -107,12 +108,8 @@ namespace Emby.Server.Implementations.QuickConnect if (State != QuickConnectState.Active) { - _logger.LogDebug("Refusing quick connect initiation request, current state is {0}", State); - - return new QuickConnectResult() - { - Error = "Quick connect is not active on this server" - }; + _logger.LogDebug("Refusing quick connect initiation request, current state is {State}", State); + throw new AuthenticationException("Quick connect is not active on this server"); } _logger.LogDebug("Got new quick connect request from {friendlyName}", friendlyName); @@ -200,7 +197,7 @@ namespace Emby.Server.Implementations.QuickConnect UserId = auth.UserId }); - _logger.LogInformation("Allowing device {0} to login as user {1} with quick connect code {2}", result.FriendlyName, auth.User.Username, result.Code); + _logger.LogInformation("Allowing device {FriendlyName} to login as user {Username} with quick connect code {Code}", result.FriendlyName, auth.User.Username, result.Code); return true; } @@ -216,13 +213,15 @@ namespace Emby.Server.Implementations.QuickConnect var tokens = raw.Items.Where(x => x.AppName.StartsWith(TokenNamePrefix, StringComparison.CurrentCulture)); + var removed = 0; foreach (var token in tokens) { _authenticationRepository.Delete(token); - _logger.LogDebug("Deleted token {0}", token.AccessToken); + _logger.LogDebug("Deleted token {AccessToken}", token.AccessToken); + removed++; } - return tokens.Count(); + return removed; } /// <summary> @@ -261,7 +260,7 @@ namespace Emby.Server.Implementations.QuickConnect if (State == QuickConnectState.Active && DateTime.Now > DateActivated.AddMinutes(Timeout) && !expireAll) { _logger.LogDebug("Quick connect time expired, deactivating"); - SetEnabled(QuickConnectState.Available); + SetState(QuickConnectState.Available); expireAll = true; } diff --git a/MediaBrowser.Api/QuickConnect/QuickConnectService.cs b/MediaBrowser.Api/QuickConnect/QuickConnectService.cs index 6298f66e5..7093be990 100644 --- a/MediaBrowser.Api/QuickConnect/QuickConnectService.cs +++ b/MediaBrowser.Api/QuickConnect/QuickConnectService.cs @@ -125,7 +125,7 @@ namespace MediaBrowser.Api.QuickConnect public object Post(Available request) { - _quickConnect.SetEnabled(request.Status); + _quickConnect.SetState(request.Status); return _quickConnect.State; } } diff --git a/MediaBrowser.Controller/QuickConnect/IQuickConnect.cs b/MediaBrowser.Controller/QuickConnect/IQuickConnect.cs index 10ec9e6cb..5518e0385 100644 --- a/MediaBrowser.Controller/QuickConnect/IQuickConnect.cs +++ b/MediaBrowser.Controller/QuickConnect/IQuickConnect.cs @@ -41,16 +41,16 @@ namespace MediaBrowser.Controller.QuickConnect void Activate(); /// <summary> - /// Changes the status of quick connect. + /// Changes the state of quick connect. /// </summary> /// <param name="newState">New state to change to.</param> - void SetEnabled(QuickConnectState newState); + void SetState(QuickConnectState newState); /// <summary> /// Initiates a new quick connect request. /// </summary> /// <param name="friendlyName">Friendly device name to display in the request UI.</param> - /// <returns>A quick connect result with tokens to proceed or a descriptive error message otherwise.</returns> + /// <returns>A quick connect result with tokens to proceed or throws an exception if not active.</returns> QuickConnectResult TryConnect(string friendlyName); /// <summary> -- cgit v1.2.3 From 17527d68dfe2fa6fb7755f819f03ada5165cb23d Mon Sep 17 00:00:00 2001 From: Nyanmisaka <nst799610810@gmail.com> Date: Mon, 27 Jul 2020 14:11:05 +0800 Subject: fix build --- MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs | 1 + 1 file changed, 1 insertion(+) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 323fc5f75..a04ddbaa0 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -530,6 +530,7 @@ namespace MediaBrowser.Controller.MediaEncoding .Append(' ') .Append("-filter_hw_device ocl "); } + } if (state.IsVideoRequest && string.Equals(encodingOptions.HardwareAccelerationType, "videotoolbox", StringComparison.OrdinalIgnoreCase)) -- cgit v1.2.3 From 31d3b1b83aa356221e8af2f316b58584579207fe Mon Sep 17 00:00:00 2001 From: Matt Montgomery <33811686+ConfusedPolarBear@users.noreply.github.com> Date: Mon, 27 Jul 2020 15:40:14 -0500 Subject: Cleanup interfaces --- MediaBrowser.Controller/QuickConnect/IQuickConnect.cs | 10 +++++----- MediaBrowser.Controller/Session/ISessionManager.cs | 7 ++++++- 2 files changed, 11 insertions(+), 6 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/QuickConnect/IQuickConnect.cs b/MediaBrowser.Controller/QuickConnect/IQuickConnect.cs index 5518e0385..993637c8a 100644 --- a/MediaBrowser.Controller/QuickConnect/IQuickConnect.cs +++ b/MediaBrowser.Controller/QuickConnect/IQuickConnect.cs @@ -13,22 +13,22 @@ namespace MediaBrowser.Controller.QuickConnect /// <summary> /// Gets or sets the length of user facing codes. /// </summary> - public int CodeLength { get; set; } + int CodeLength { get; set; } /// <summary> /// Gets or sets the string to prefix internal access tokens with. /// </summary> - public string TokenNamePrefix { get; set; } + string TokenNamePrefix { get; set; } /// <summary> /// Gets the current state of quick connect. /// </summary> - public QuickConnectState State { get; } + QuickConnectState State { get; } /// <summary> /// Gets or sets the time (in minutes) before quick connect will automatically deactivate. /// </summary> - public int Timeout { get; set; } + int Timeout { get; set; } /// <summary> /// Assert that quick connect is currently active and throws an exception if it is not. @@ -72,7 +72,7 @@ namespace MediaBrowser.Controller.QuickConnect /// Expire quick connect requests that are over the time limit. If <paramref name="expireAll"/> is true, all requests are unconditionally expired. /// </summary> /// <param name="expireAll">If true, all requests will be expired.</param> - public void ExpireRequests(bool expireAll = false); + void ExpireRequests(bool expireAll = false); /// <summary> /// Deletes all quick connect access tokens for the provided user. diff --git a/MediaBrowser.Controller/Session/ISessionManager.cs b/MediaBrowser.Controller/Session/ISessionManager.cs index 23230e41e..ffa19fb69 100644 --- a/MediaBrowser.Controller/Session/ISessionManager.cs +++ b/MediaBrowser.Controller/Session/ISessionManager.cs @@ -264,7 +264,12 @@ namespace MediaBrowser.Controller.Session /// <returns>Task{SessionInfo}.</returns> Task<AuthenticationResult> AuthenticateNewSession(AuthenticationRequest request); - public Task<AuthenticationResult> AuthenticateQuickConnect(AuthenticationRequest request, string token); + /// <summary> + /// Authenticates a new session with quick connect. + /// </summary> + /// <param name="request">The request.</param> + /// <returns>Task{SessionInfo}.</returns> + Task<AuthenticationResult> AuthenticateQuickConnect(AuthenticationRequest request, string token); /// <summary> /// Creates the new session. -- cgit v1.2.3 From 68a185fd02844698ac5ecd5618d590ae254d95cf Mon Sep 17 00:00:00 2001 From: Patrick Barron <barronpm@gmail.com> Date: Mon, 27 Jul 2020 20:40:21 -0400 Subject: Serialize/deserialize new entities properly. --- Jellyfin.Data/Entities/ItemDisplayPreferences.cs | 120 +++++++++++++++++++++ .../Entities/LibraryDisplayPreferences.cs | 120 --------------------- Jellyfin.Data/Entities/User.cs | 4 +- Jellyfin.Server.Implementations/JellyfinDb.cs | 2 + .../Users/DisplayPreferencesManager.cs | 39 ++++++- .../Routines/MigrateDisplayPreferencesDb.cs | 33 ++++-- MediaBrowser.Api/DisplayPreferencesService.cs | 70 +++++++----- .../IDisplayPreferencesManager.cs | 24 +++++ 8 files changed, 254 insertions(+), 158 deletions(-) create mode 100644 Jellyfin.Data/Entities/ItemDisplayPreferences.cs delete mode 100644 Jellyfin.Data/Entities/LibraryDisplayPreferences.cs (limited to 'MediaBrowser.Controller') diff --git a/Jellyfin.Data/Entities/ItemDisplayPreferences.cs b/Jellyfin.Data/Entities/ItemDisplayPreferences.cs new file mode 100644 index 000000000..95c08e6c6 --- /dev/null +++ b/Jellyfin.Data/Entities/ItemDisplayPreferences.cs @@ -0,0 +1,120 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using Jellyfin.Data.Enums; + +namespace Jellyfin.Data.Entities +{ + public class ItemDisplayPreferences + { + /// <summary> + /// Initializes a new instance of the <see cref="ItemDisplayPreferences"/> class. + /// </summary> + /// <param name="userId">The user id.</param> + /// <param name="itemId">The item id.</param> + /// <param name="client">The client.</param> + public ItemDisplayPreferences(Guid userId, Guid itemId, string client) + { + UserId = userId; + ItemId = itemId; + Client = client; + + SortBy = "SortName"; + ViewType = ViewType.Poster; + SortOrder = SortOrder.Ascending; + RememberSorting = false; + RememberIndexing = false; + } + + /// <summary> + /// Initializes a new instance of the <see cref="ItemDisplayPreferences"/> class. + /// </summary> + protected ItemDisplayPreferences() + { + } + + /// <summary> + /// Gets or sets the Id. + /// </summary> + /// <remarks> + /// Required. + /// </remarks> + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int Id { get; protected set; } + + /// <summary> + /// Gets or sets the user Id. + /// </summary> + /// <remarks> + /// Required. + /// </remarks> + public Guid UserId { get; set; } + + /// <summary> + /// Gets or sets the id of the associated item. + /// </summary> + /// <remarks> + /// Required. + /// </remarks> + public Guid ItemId { get; set; } + + /// <summary> + /// Gets or sets the client string. + /// </summary> + /// <remarks> + /// Required. Max Length = 32. + /// </remarks> + [Required] + [MaxLength(32)] + [StringLength(32)] + public string Client { get; set; } + + /// <summary> + /// Gets or sets the view type. + /// </summary> + /// <remarks> + /// Required. + /// </remarks> + public ViewType ViewType { get; set; } + + /// <summary> + /// Gets or sets a value indicating whether the indexing should be remembered. + /// </summary> + /// <remarks> + /// Required. + /// </remarks> + public bool RememberIndexing { get; set; } + + /// <summary> + /// Gets or sets what the view should be indexed by. + /// </summary> + public IndexingKind? IndexBy { get; set; } + + /// <summary> + /// Gets or sets a value indicating whether the sorting type should be remembered. + /// </summary> + /// <remarks> + /// Required. + /// </remarks> + public bool RememberSorting { get; set; } + + /// <summary> + /// Gets or sets what the view should be sorted by. + /// </summary> + /// <remarks> + /// Required. + /// </remarks> + [Required] + [MaxLength(64)] + [StringLength(64)] + public string SortBy { get; set; } + + /// <summary> + /// Gets or sets the sort order. + /// </summary> + /// <remarks> + /// Required. + /// </remarks> + public SortOrder SortOrder { get; set; } + } +} diff --git a/Jellyfin.Data/Entities/LibraryDisplayPreferences.cs b/Jellyfin.Data/Entities/LibraryDisplayPreferences.cs deleted file mode 100644 index 87be1c6f7..000000000 --- a/Jellyfin.Data/Entities/LibraryDisplayPreferences.cs +++ /dev/null @@ -1,120 +0,0 @@ -using System; -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; -using Jellyfin.Data.Enums; - -namespace Jellyfin.Data.Entities -{ - public class LibraryDisplayPreferences - { - /// <summary> - /// Initializes a new instance of the <see cref="LibraryDisplayPreferences"/> class. - /// </summary> - /// <param name="userId">The user id.</param> - /// <param name="itemId">The item id.</param> - /// <param name="client">The client.</param> - public LibraryDisplayPreferences(Guid userId, Guid itemId, string client) - { - UserId = userId; - ItemId = itemId; - Client = client; - - SortBy = "SortName"; - ViewType = ViewType.Poster; - SortOrder = SortOrder.Ascending; - RememberSorting = false; - RememberIndexing = false; - } - - /// <summary> - /// Initializes a new instance of the <see cref="LibraryDisplayPreferences"/> class. - /// </summary> - protected LibraryDisplayPreferences() - { - } - - /// <summary> - /// Gets or sets the Id. - /// </summary> - /// <remarks> - /// Required. - /// </remarks> - [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public int Id { get; protected set; } - - /// <summary> - /// Gets or sets the user Id. - /// </summary> - /// <remarks> - /// Required. - /// </remarks> - public Guid UserId { get; set; } - - /// <summary> - /// Gets or sets the id of the associated item. - /// </summary> - /// <remarks> - /// Required. - /// </remarks> - public Guid ItemId { get; set; } - - /// <summary> - /// Gets or sets the client string. - /// </summary> - /// <remarks> - /// Required. Max Length = 32. - /// </remarks> - [Required] - [MaxLength(32)] - [StringLength(32)] - public string Client { get; set; } - - /// <summary> - /// Gets or sets the view type. - /// </summary> - /// <remarks> - /// Required. - /// </remarks> - public ViewType ViewType { get; set; } - - /// <summary> - /// Gets or sets a value indicating whether the indexing should be remembered. - /// </summary> - /// <remarks> - /// Required. - /// </remarks> - public bool RememberIndexing { get; set; } - - /// <summary> - /// Gets or sets what the view should be indexed by. - /// </summary> - public IndexingKind? IndexBy { get; set; } - - /// <summary> - /// Gets or sets a value indicating whether the sorting type should be remembered. - /// </summary> - /// <remarks> - /// Required. - /// </remarks> - public bool RememberSorting { get; set; } - - /// <summary> - /// Gets or sets what the view should be sorted by. - /// </summary> - /// <remarks> - /// Required. - /// </remarks> - [Required] - [MaxLength(64)] - [StringLength(64)] - public string SortBy { get; set; } - - /// <summary> - /// Gets or sets the sort order. - /// </summary> - /// <remarks> - /// Required. - /// </remarks> - public SortOrder SortOrder { get; set; } - } -} diff --git a/Jellyfin.Data/Entities/User.cs b/Jellyfin.Data/Entities/User.cs index dc4bd9979..50810561f 100644 --- a/Jellyfin.Data/Entities/User.cs +++ b/Jellyfin.Data/Entities/User.cs @@ -48,7 +48,7 @@ namespace Jellyfin.Data.Entities PasswordResetProviderId = passwordResetProviderId; AccessSchedules = new HashSet<AccessSchedule>(); - LibraryDisplayPreferences = new HashSet<LibraryDisplayPreferences>(); + ItemDisplayPreferences = new HashSet<ItemDisplayPreferences>(); // Groups = new HashSet<Group>(); Permissions = new HashSet<Permission>(); Preferences = new HashSet<Preference>(); @@ -362,7 +362,7 @@ namespace Jellyfin.Data.Entities /// <summary> /// Gets or sets the list of item display preferences. /// </summary> - public virtual ICollection<LibraryDisplayPreferences> LibraryDisplayPreferences { get; protected set; } + public virtual ICollection<ItemDisplayPreferences> ItemDisplayPreferences { get; protected set; } /* /// <summary> diff --git a/Jellyfin.Server.Implementations/JellyfinDb.cs b/Jellyfin.Server.Implementations/JellyfinDb.cs index 4ad684063..7d864ebc6 100644 --- a/Jellyfin.Server.Implementations/JellyfinDb.cs +++ b/Jellyfin.Server.Implementations/JellyfinDb.cs @@ -32,6 +32,8 @@ namespace Jellyfin.Server.Implementations public virtual DbSet<ImageInfo> ImageInfos { get; set; } + public virtual DbSet<ItemDisplayPreferences> ItemDisplayPreferences { get; set; } + public virtual DbSet<Permission> Permissions { get; set; } public virtual DbSet<Preference> Preferences { get; set; } diff --git a/Jellyfin.Server.Implementations/Users/DisplayPreferencesManager.cs b/Jellyfin.Server.Implementations/Users/DisplayPreferencesManager.cs index b7c65fc2c..7c5c5a3ec 100644 --- a/Jellyfin.Server.Implementations/Users/DisplayPreferencesManager.cs +++ b/Jellyfin.Server.Implementations/Users/DisplayPreferencesManager.cs @@ -1,6 +1,7 @@ #pragma warning disable CA1307 using System; +using System.Collections.Generic; using System.Linq; using Jellyfin.Data.Entities; using MediaBrowser.Controller; @@ -31,17 +32,43 @@ namespace Jellyfin.Server.Implementations.Users var prefs = dbContext.DisplayPreferences .Include(pref => pref.HomeSections) .FirstOrDefault(pref => - pref.UserId == userId && pref.ItemId == null && string.Equals(pref.Client, client)); + pref.UserId == userId && string.Equals(pref.Client, client)); if (prefs == null) { - prefs = new DisplayPreferences(client, userId); + prefs = new DisplayPreferences(userId, client); dbContext.DisplayPreferences.Add(prefs); } return prefs; } + /// <inheritdoc /> + public ItemDisplayPreferences GetItemDisplayPreferences(Guid userId, Guid itemId, string client) + { + using var dbContext = _dbProvider.CreateContext(); + 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); + } + + return prefs; + } + + /// <inheritdoc /> + public IList<ItemDisplayPreferences> ListItemDisplayPreferences(Guid userId, string client) + { + using var dbContext = _dbProvider.CreateContext(); + + return dbContext.ItemDisplayPreferences + .Where(prefs => prefs.UserId == userId && prefs.ItemId != Guid.Empty && string.Equals(prefs.Client, client)) + .ToList(); + } + /// <inheritdoc /> public void SaveChanges(DisplayPreferences preferences) { @@ -49,5 +76,13 @@ namespace Jellyfin.Server.Implementations.Users dbContext.Update(preferences); dbContext.SaveChanges(); } + + /// <inheritdoc /> + public void SaveChanges(ItemDisplayPreferences preferences) + { + using var dbContext = _dbProvider.CreateContext(); + dbContext.Update(preferences); + dbContext.SaveChanges(); + } } } diff --git a/Jellyfin.Server/Migrations/Routines/MigrateDisplayPreferencesDb.cs b/Jellyfin.Server/Migrations/Routines/MigrateDisplayPreferencesDb.cs index d8b081bb2..6a78bff4f 100644 --- a/Jellyfin.Server/Migrations/Routines/MigrateDisplayPreferencesDb.cs +++ b/Jellyfin.Server/Migrations/Routines/MigrateDisplayPreferencesDb.cs @@ -1,6 +1,7 @@ using System; using System.Globalization; using System.IO; +using System.Linq; using System.Text.Json; using System.Text.Json.Serialization; using Jellyfin.Data.Entities; @@ -78,16 +79,11 @@ namespace Jellyfin.Server.Migrations.Routines : ChromecastVersion.Stable : ChromecastVersion.Stable; - var displayPreferences = new DisplayPreferences(result[2].ToString(), new Guid(result[1].ToBlob())) + var displayPreferences = new DisplayPreferences(new Guid(result[1].ToBlob()), result[2].ToString()) { - ViewType = Enum.TryParse<ViewType>(dto.ViewType, true, out var viewType) ? viewType : (ViewType?)null, IndexBy = Enum.TryParse<IndexingKind>(dto.IndexBy, true, out var indexBy) ? indexBy : (IndexingKind?)null, ShowBackdrop = dto.ShowBackdrop, ShowSidebar = dto.ShowSidebar, - SortBy = dto.SortBy, - SortOrder = dto.SortOrder, - RememberIndexing = dto.RememberIndexing, - RememberSorting = dto.RememberSorting, ScrollDirection = dto.ScrollDirection, ChromecastVersion = chromecastVersion, SkipForwardLength = dto.CustomPrefs.TryGetValue("skipForwardLength", out var length) @@ -95,7 +91,7 @@ namespace Jellyfin.Server.Migrations.Routines : 30000, SkipBackwardLength = dto.CustomPrefs.TryGetValue("skipBackLength", out length) ? int.Parse(length, CultureInfo.InvariantCulture) - : 30000, + : 10000, EnableNextVideoInfoOverlay = dto.CustomPrefs.TryGetValue("enableNextVideoInfoOverlay", out var enabled) ? bool.Parse(enabled) : true @@ -112,6 +108,29 @@ namespace Jellyfin.Server.Migrations.Routines }); } + foreach (var key in dto.CustomPrefs.Keys.Where(key => key.StartsWith("landing-", StringComparison.Ordinal))) + { + if (!Guid.TryParse(key.AsSpan().Slice("landing-".Length), out var itemId)) + { + continue; + } + + var libraryDisplayPreferences = new ItemDisplayPreferences(displayPreferences.UserId, itemId, displayPreferences.Client) + { + SortBy = dto.SortBy, + SortOrder = dto.SortOrder, + RememberIndexing = dto.RememberIndexing, + RememberSorting = dto.RememberSorting, + }; + + if (Enum.TryParse<ViewType>(dto.ViewType, true, out var viewType)) + { + libraryDisplayPreferences.ViewType = viewType; + } + + dbContext.ItemDisplayPreferences.Add(libraryDisplayPreferences); + } + dbContext.Add(displayPreferences); } diff --git a/MediaBrowser.Api/DisplayPreferencesService.cs b/MediaBrowser.Api/DisplayPreferencesService.cs index 0f3427e54..416d63100 100644 --- a/MediaBrowser.Api/DisplayPreferencesService.cs +++ b/MediaBrowser.Api/DisplayPreferencesService.cs @@ -76,37 +76,38 @@ namespace MediaBrowser.Api /// <param name="request">The request.</param> public object Get(GetDisplayPreferences request) { - var result = _displayPreferencesManager.GetDisplayPreferences(Guid.Parse(request.UserId), request.Client); - - if (result == null) - { - return null; - } + var displayPreferences = _displayPreferencesManager.GetDisplayPreferences(Guid.Parse(request.UserId), request.Client); + var itemPreferences = _displayPreferencesManager.GetItemDisplayPreferences(displayPreferences.UserId, Guid.Empty, displayPreferences.Client); var dto = new DisplayPreferencesDto { - Client = result.Client, - Id = result.UserId.ToString(), - ViewType = result.ViewType?.ToString(), - SortBy = result.SortBy, - SortOrder = result.SortOrder, - IndexBy = result.IndexBy?.ToString(), - RememberIndexing = result.RememberIndexing, - RememberSorting = result.RememberSorting, - ScrollDirection = result.ScrollDirection, - ShowBackdrop = result.ShowBackdrop, - ShowSidebar = result.ShowSidebar + Client = displayPreferences.Client, + Id = displayPreferences.UserId.ToString(), + ViewType = itemPreferences.ViewType.ToString(), + SortBy = itemPreferences.SortBy, + SortOrder = itemPreferences.SortOrder, + IndexBy = displayPreferences.IndexBy?.ToString(), + RememberIndexing = itemPreferences.RememberIndexing, + RememberSorting = itemPreferences.RememberSorting, + ScrollDirection = displayPreferences.ScrollDirection, + ShowBackdrop = displayPreferences.ShowBackdrop, + ShowSidebar = displayPreferences.ShowSidebar }; - foreach (var homeSection in result.HomeSections) + foreach (var homeSection in displayPreferences.HomeSections) { dto.CustomPrefs["homesection" + homeSection.Order] = homeSection.Type.ToString().ToLowerInvariant(); } - dto.CustomPrefs["chromecastVersion"] = result.ChromecastVersion.ToString().ToLowerInvariant(); - dto.CustomPrefs["skipForwardLength"] = result.SkipForwardLength.ToString(); - dto.CustomPrefs["skipBackLength"] = result.SkipBackwardLength.ToString(); - dto.CustomPrefs["enableNextVideoInfoOverlay"] = result.EnableNextVideoInfoOverlay.ToString(); + foreach (var itemDisplayPreferences in _displayPreferencesManager.ListItemDisplayPreferences(displayPreferences.UserId, displayPreferences.Client)) + { + dto.CustomPrefs["landing-" + itemDisplayPreferences.ItemId] = itemDisplayPreferences.ViewType.ToString().ToLowerInvariant(); + } + + dto.CustomPrefs["chromecastVersion"] = displayPreferences.ChromecastVersion.ToString().ToLowerInvariant(); + dto.CustomPrefs["skipForwardLength"] = displayPreferences.SkipForwardLength.ToString(); + dto.CustomPrefs["skipBackLength"] = displayPreferences.SkipBackwardLength.ToString(); + dto.CustomPrefs["enableNextVideoInfoOverlay"] = displayPreferences.EnableNextVideoInfoOverlay.ToString(); return ToOptimizedResult(dto); } @@ -130,14 +131,10 @@ namespace MediaBrowser.Api var prefs = _displayPreferencesManager.GetDisplayPreferences(Guid.Parse(request.UserId), request.Client); - prefs.ViewType = Enum.TryParse<ViewType>(request.ViewType, true, out var viewType) ? viewType : (ViewType?)null; prefs.IndexBy = Enum.TryParse<IndexingKind>(request.IndexBy, true, out var indexBy) ? indexBy : (IndexingKind?)null; prefs.ShowBackdrop = request.ShowBackdrop; prefs.ShowSidebar = request.ShowSidebar; - prefs.SortBy = request.SortBy; - prefs.SortOrder = request.SortOrder; - prefs.RememberIndexing = request.RememberIndexing; - prefs.RememberSorting = request.RememberSorting; + prefs.ScrollDirection = request.ScrollDirection; prefs.ChromecastVersion = request.CustomPrefs.TryGetValue("chromecastVersion", out var chromecastVersion) ? Enum.Parse<ChromecastVersion>(chromecastVersion, true) @@ -164,7 +161,26 @@ namespace MediaBrowser.Api }); } + foreach (var key in request.CustomPrefs.Keys.Where(key => key.StartsWith("landing-"))) + { + var itemPreferences = _displayPreferencesManager.GetItemDisplayPreferences(prefs.UserId, Guid.Parse(key.Substring("landing-".Length)), prefs.Client); + itemPreferences.ViewType = Enum.Parse<ViewType>(request.ViewType); + _displayPreferencesManager.SaveChanges(itemPreferences); + } + + var itemPrefs = _displayPreferencesManager.GetItemDisplayPreferences(prefs.UserId, Guid.Empty, prefs.Client); + itemPrefs.SortBy = request.SortBy; + itemPrefs.SortOrder = request.SortOrder; + itemPrefs.RememberIndexing = request.RememberIndexing; + itemPrefs.RememberSorting = request.RememberSorting; + + if (Enum.TryParse<ViewType>(request.ViewType, true, out var viewType)) + { + itemPrefs.ViewType = viewType; + } + _displayPreferencesManager.SaveChanges(prefs); + _displayPreferencesManager.SaveChanges(itemPrefs); } } } diff --git a/MediaBrowser.Controller/IDisplayPreferencesManager.cs b/MediaBrowser.Controller/IDisplayPreferencesManager.cs index e27b0ec7c..b6bfed3e5 100644 --- a/MediaBrowser.Controller/IDisplayPreferencesManager.cs +++ b/MediaBrowser.Controller/IDisplayPreferencesManager.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using Jellyfin.Data.Entities; namespace MediaBrowser.Controller @@ -16,10 +17,33 @@ namespace MediaBrowser.Controller /// <returns>The associated display preferences.</returns> DisplayPreferences GetDisplayPreferences(Guid userId, string client); + /// <summary> + /// Gets the default item display preferences for the user and client. + /// </summary> + /// <param name="userId">The user id.</param> + /// <param name="itemId">The item id.</param> + /// <param name="client">The client string.</param> + /// <returns>The item display preferences.</returns> + ItemDisplayPreferences GetItemDisplayPreferences(Guid userId, Guid itemId, string client); + + /// <summary> + /// Gets all of the item display preferences for the user and client. + /// </summary> + /// <param name="userId">The user id.</param> + /// <param name="client">The client string.</param> + /// <returns>A list of item display preferences.</returns> + IList<ItemDisplayPreferences> ListItemDisplayPreferences(Guid userId, string client); + /// <summary> /// Saves changes to the provided display preferences. /// </summary> /// <param name="preferences">The display preferences to save.</param> void SaveChanges(DisplayPreferences preferences); + + /// <summary> + /// Saves changes to the provided item display preferences. + /// </summary> + /// <param name="preferences">The item display preferences to save.</param> + void SaveChanges(ItemDisplayPreferences preferences); } } -- cgit v1.2.3 From 2139e9f8d11597a06839df7bb1b88787bf750305 Mon Sep 17 00:00:00 2001 From: Nyanmisaka <nst799610810@gmail.com> Date: Tue, 28 Jul 2020 17:07:10 +0800 Subject: adjust priority in outputSizeParam cutter --- .../MediaEncoding/EncodingHelper.cs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 913e171f1..18d310a00 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -1606,42 +1606,48 @@ namespace MediaBrowser.Controller.MediaEncoding { outputSizeParam = GetOutputSizeParam(state, options, outputVideoCodec).TrimEnd('"'); - var index = outputSizeParam.IndexOf("hwdownload", StringComparison.OrdinalIgnoreCase); + // hwupload=extra_hw_frames=64,vpp_qsv (for overlay_qsv on linux) + var index = outputSizeParam.IndexOf("hwupload=extra_hw_frames", StringComparison.OrdinalIgnoreCase); if (index != -1) { outputSizeParam = outputSizeParam.Slice(index); } else { - index = outputSizeParam.IndexOf("hwupload=extra_hw_frames", StringComparison.OrdinalIgnoreCase); + // vpp_qsv + index = outputSizeParam.IndexOf("vpp", StringComparison.OrdinalIgnoreCase); if (index != -1) { outputSizeParam = outputSizeParam.Slice(index); } else { - index = outputSizeParam.IndexOf("format", StringComparison.OrdinalIgnoreCase); + // hwdownload,format=p010le (hardware decode + software encode for vaapi) + index = outputSizeParam.IndexOf("hwdownload", StringComparison.OrdinalIgnoreCase); if (index != -1) { outputSizeParam = outputSizeParam.Slice(index); } else { - index = outputSizeParam.IndexOf("yadif", StringComparison.OrdinalIgnoreCase); + // format=nv12|vaapi,hwupload,scale_vaapi + index = outputSizeParam.IndexOf("format", StringComparison.OrdinalIgnoreCase); if (index != -1) { outputSizeParam = outputSizeParam.Slice(index); } else { - index = outputSizeParam.IndexOf("scale", StringComparison.OrdinalIgnoreCase); + // yadif,scale=expr + index = outputSizeParam.IndexOf("yadif", StringComparison.OrdinalIgnoreCase); if (index != -1) { outputSizeParam = outputSizeParam.Slice(index); } else { - index = outputSizeParam.IndexOf("vpp", StringComparison.OrdinalIgnoreCase); + // scale=expr + index = outputSizeParam.IndexOf("scale", StringComparison.OrdinalIgnoreCase); if (index != -1) { outputSizeParam = outputSizeParam.Slice(index); -- cgit v1.2.3 From 7b3f76b81fd92d30ac8783508fb7b6793d32ec95 Mon Sep 17 00:00:00 2001 From: Nyanmisaka <nst799610810@gmail.com> Date: Mon, 3 Aug 2020 14:55:28 +0800 Subject: resolve conflicts --- .../MediaEncoding/EncodingHelper.cs | 63 ++++++---------------- 1 file changed, 16 insertions(+), 47 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index a04ddbaa0..9433d33b4 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -1647,57 +1647,26 @@ namespace MediaBrowser.Controller.MediaEncoding { outputSizeParam = GetOutputSizeParam(state, options, outputVideoCodec).TrimEnd('"'); - var index = outputSizeParam.IndexOf("hwupload,tonemap_opencl", StringComparison.OrdinalIgnoreCase); - if (index != -1) - { - outputSizeParam = outputSizeParam.Slice(index); - } - else + // All possible beginning of video filters + // Don't break the order + string[] beginOfParam = new[] + { + "hwupload,tonemap_opencl", + "hwupload=extra_hw_frames", + "vpp", + "hwdownload", + "format", + "yadif", + "scale" + }; + + for (int i = 0, index = -1; i < beginOfParam.Length; i++) { - index = outputSizeParam.IndexOf("hwdownload", StringComparison.OrdinalIgnoreCase); + index = outputSizeParam.IndexOf(beginOfParam[i], StringComparison.OrdinalIgnoreCase); if (index != -1) { outputSizeParam = outputSizeParam.Slice(index); - } - else - { - index = outputSizeParam.IndexOf("hwupload=extra_hw_frames", StringComparison.OrdinalIgnoreCase); - if (index != -1) - { - outputSizeParam = outputSizeParam.Slice(index); - } - else - { - index = outputSizeParam.IndexOf("format", StringComparison.OrdinalIgnoreCase); - if (index != -1) - { - outputSizeParam = outputSizeParam.Slice(index); - } - else - { - index = outputSizeParam.IndexOf("yadif", StringComparison.OrdinalIgnoreCase); - if (index != -1) - { - outputSizeParam = outputSizeParam.Slice(index); - } - else - { - index = outputSizeParam.IndexOf("scale", StringComparison.OrdinalIgnoreCase); - if (index != -1) - { - outputSizeParam = outputSizeParam.Slice(index); - } - else - { - index = outputSizeParam.IndexOf("vpp", StringComparison.OrdinalIgnoreCase); - if (index != -1) - { - outputSizeParam = outputSizeParam.Slice(index); - } - } - } - } - } + break; } } } -- cgit v1.2.3 From 229a5d9e0bf99f9c6f741f654f1dbe0a7f975872 Mon Sep 17 00:00:00 2001 From: Patrick Barron <barronpm@gmail.com> Date: Sat, 8 Aug 2020 13:39:49 -0400 Subject: Make DisplayPreferencesManager scoped --- .../Controllers/DisplayPreferencesController.cs | 4 +-- .../Users/DisplayPreferencesManager.cs | 36 +++++++--------------- Jellyfin.Server/CoreAppHost.cs | 2 +- .../IDisplayPreferencesManager.cs | 11 ++----- 4 files changed, 15 insertions(+), 38 deletions(-) (limited to 'MediaBrowser.Controller') 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<ViewType>(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.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 /// </summary> public class DisplayPreferencesManager : IDisplayPreferencesManager { - private readonly JellyfinDbProvider _dbProvider; + private readonly JellyfinDb _dbContext; /// <summary> /// Initializes a new instance of the <see cref="DisplayPreferencesManager"/> class. /// </summary> - /// <param name="dbProvider">The Jellyfin db provider.</param> - public DisplayPreferencesManager(JellyfinDbProvider dbProvider) + /// <param name="dbContext">The database context.</param> + public DisplayPreferencesManager(JellyfinDb dbContext) { - _dbProvider = dbProvider; + _dbContext = dbContext; } /// <inheritdoc /> 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 /// <inheritdoc /> 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 /// <inheritdoc /> public IList<ItemDisplayPreferences> 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(); } /// <inheritdoc /> - public void SaveChanges(DisplayPreferences preferences) - { - using var dbContext = _dbProvider.CreateContext(); - dbContext.Update(preferences); - dbContext.SaveChanges(); - } - - /// <inheritdoc /> - public void SaveChanges(ItemDisplayPreferences preferences) + public void SaveChanges() { - 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 7b20bfb5a..6f2434422 100644 --- a/Jellyfin.Server/CoreAppHost.cs +++ b/Jellyfin.Server/CoreAppHost.cs @@ -71,7 +71,7 @@ namespace Jellyfin.Server serviceCollection.AddSingleton<IActivityManager, ActivityManager>(); serviceCollection.AddSingleton<IUserManager, UserManager>(); - serviceCollection.AddSingleton<IDisplayPreferencesManager, DisplayPreferencesManager>(); + serviceCollection.AddScoped<IDisplayPreferencesManager, DisplayPreferencesManager>(); base.RegisterServices(serviceCollection); } diff --git a/MediaBrowser.Controller/IDisplayPreferencesManager.cs b/MediaBrowser.Controller/IDisplayPreferencesManager.cs index b6bfed3e5..4288a2a54 100644 --- a/MediaBrowser.Controller/IDisplayPreferencesManager.cs +++ b/MediaBrowser.Controller/IDisplayPreferencesManager.cs @@ -35,15 +35,8 @@ namespace MediaBrowser.Controller IList<ItemDisplayPreferences> ListItemDisplayPreferences(Guid userId, string client); /// <summary> - /// Saves changes to the provided display preferences. + /// Saves changes made to the database. /// </summary> - /// <param name="preferences">The display preferences to save.</param> - void SaveChanges(DisplayPreferences preferences); - - /// <summary> - /// Saves changes to the provided item display preferences. - /// </summary> - /// <param name="preferences">The item display preferences to save.</param> - void SaveChanges(ItemDisplayPreferences preferences); + void SaveChanges(); } } -- cgit v1.2.3 From 6c92154a9bc78deeafa313c96c1fe474a5976776 Mon Sep 17 00:00:00 2001 From: Bond-009 <bond.009@outlook.com> Date: Sun, 9 Aug 2020 13:55:57 +0200 Subject: Update MediaBrowser.Controller/Extensions/ConfigurationExtensions.cs Co-authored-by: David <davidullmer@outlook.de> --- MediaBrowser.Controller/Extensions/ConfigurationExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/Extensions/ConfigurationExtensions.cs b/MediaBrowser.Controller/Extensions/ConfigurationExtensions.cs index 425b39fd9..4c2209b67 100644 --- a/MediaBrowser.Controller/Extensions/ConfigurationExtensions.cs +++ b/MediaBrowser.Controller/Extensions/ConfigurationExtensions.cs @@ -90,6 +90,6 @@ namespace MediaBrowser.Controller.Extensions /// <param name="configuration">The configuration to read the setting from.</param> /// <returns>The unix socket path.</returns> public static string GetUnixSocketPath(this IConfiguration configuration) - => configuration[FfmpegAnalyzeDurationKey]; + => configuration[UnixSocketPathKey]; } } -- cgit v1.2.3 From 7df2affb238e92c9b03813f5aa11530cb37dcbdc Mon Sep 17 00:00:00 2001 From: Orry Verducci <orry@orryverducci.co.uk> Date: Mon, 10 Aug 2020 22:14:47 +0100 Subject: Add double rate deinterlacing option --- MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs | 3 +++ MediaBrowser.Model/Configuration/EncodingOptions.cs | 3 +++ 2 files changed, 6 insertions(+) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 913e171f1..81606aa0c 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -2071,6 +2071,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) { diff --git a/MediaBrowser.Model/Configuration/EncodingOptions.cs b/MediaBrowser.Model/Configuration/EncodingOptions.cs index 9a30f7e9f..d7785f39c 100644 --- a/MediaBrowser.Model/Configuration/EncodingOptions.cs +++ b/MediaBrowser.Model/Configuration/EncodingOptions.cs @@ -35,6 +35,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; } @@ -57,6 +59,7 @@ namespace MediaBrowser.Model.Configuration VaapiDevice = "/dev/dri/renderD128"; H264Crf = 23; H265Crf = 28; + DeinterlaceDoubleRate = false; DeinterlaceMethod = "yadif"; EnableDecodingColorDepth10Hevc = true; EnableDecodingColorDepth10Vp9 = true; -- cgit v1.2.3 From 9dc95074a3b35d00713cbe38eb982e80913f8ab0 Mon Sep 17 00:00:00 2001 From: Orry Verducci <orry@orryverducci.co.uk> Date: Mon, 10 Aug 2020 22:16:23 +0100 Subject: Add bwdif and simplify software deinterlacing --- .../MediaEncoding/EncodingHelper.cs | 29 ++++++++++------------ 1 file changed, 13 insertions(+), 16 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 81606aa0c..c69d31065 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -2125,30 +2125,27 @@ namespace MediaBrowser.Controller.MediaEncoding } // Add software deinterlace filter before scaling filter - if (state.DeInterlace("h264", 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")); } } -- cgit v1.2.3 From ce51775e7426ff4e037d593715395684ebf9b08a Mon Sep 17 00:00:00 2001 From: Orry Verducci <orry@orryverducci.co.uk> Date: Mon, 10 Aug 2020 22:16:46 +0100 Subject: Apply double rate option to hardware deinterlacers --- MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index c69d31065..9567c90d5 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -2120,7 +2120,11 @@ 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")); } } @@ -2378,6 +2382,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"; + } } } } -- cgit v1.2.3 From 1ae3dc202ce2fbd40565e0d776b2d77abcd0f1f5 Mon Sep 17 00:00:00 2001 From: cvium <clausvium@gmail.com> Date: Tue, 11 Aug 2020 22:04:41 +0200 Subject: Populate ThemeVideoIds and ThemeSongIds --- MediaBrowser.Controller/Entities/BaseItem.cs | 51 +++++++++++++++++++++++++--- 1 file changed, 46 insertions(+), 5 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index f34309c40..32b8cea6c 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -58,8 +58,6 @@ namespace MediaBrowser.Controller.Entities protected BaseItem() { - ThemeSongIds = Array.Empty<Guid>(); - ThemeVideoIds = Array.Empty<Guid>(); Tags = Array.Empty<string>(); Genres = Array.Empty<string>(); Studios = Array.Empty<string>(); @@ -98,12 +96,52 @@ namespace MediaBrowser.Controller.Entities }; [JsonIgnore] - public Guid[] ThemeSongIds { get; set; } + public Guid[] ThemeSongIds + { + get + { + if (_themeSongIds == null) + { + _themeSongIds = GetExtras() + .Where(extra => extra.ExtraType == Model.Entities.ExtraType.ThemeSong) + .Select(song => song.Id) + .ToArray(); + } + + return _themeSongIds; + } + + private set + { + _themeSongIds = value; + } + } + [JsonIgnore] - public Guid[] ThemeVideoIds { get; set; } + public Guid[] ThemeVideoIds + { + get + { + if (_themeVideoIds == null) + { + _themeVideoIds = GetExtras() + .Where(extra => extra.ExtraType == Model.Entities.ExtraType.ThemeVideo) + .Select(song => song.Id) + .ToArray(); + } + + return _themeVideoIds; + } + + private set + { + _themeVideoIds = value; + } + } [JsonIgnore] public string PreferredMetadataCountryCode { get; set; } + [JsonIgnore] public string PreferredMetadataLanguage { get; set; } @@ -633,6 +671,9 @@ namespace MediaBrowser.Controller.Entities } private string _sortName; + private Guid[] _themeSongIds; + private Guid[] _themeVideoIds; + /// <summary> /// Gets the name of the sort. /// </summary> @@ -2909,7 +2950,7 @@ namespace MediaBrowser.Controller.Entities public IEnumerable<BaseItem> GetThemeSongs() { - return ThemeVideoIds.Select(LibraryManager.GetItemById).Where(i => i.ExtraType.Equals(Model.Entities.ExtraType.ThemeSong)).OrderBy(i => i.SortName); + return ThemeSongIds.Select(LibraryManager.GetItemById).Where(i => i.ExtraType.Equals(Model.Entities.ExtraType.ThemeSong)).OrderBy(i => i.SortName); } public IEnumerable<BaseItem> GetThemeVideos() -- cgit v1.2.3 From e10693cbe033652ecd6da66b48ec3a2be23e7a29 Mon Sep 17 00:00:00 2001 From: cvium <clausvium@gmail.com> Date: Wed, 12 Aug 2020 22:14:14 +0200 Subject: Remove some LINQ queries --- MediaBrowser.Controller/Entities/BaseItem.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 32b8cea6c..72574d613 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -2950,12 +2950,12 @@ namespace MediaBrowser.Controller.Entities public IEnumerable<BaseItem> GetThemeSongs() { - return ThemeSongIds.Select(LibraryManager.GetItemById).Where(i => i.ExtraType.Equals(Model.Entities.ExtraType.ThemeSong)).OrderBy(i => i.SortName); + return ThemeSongIds.Select(LibraryManager.GetItemById); } public IEnumerable<BaseItem> GetThemeVideos() { - return ThemeVideoIds.Select(LibraryManager.GetItemById).Where(i => i.ExtraType.Equals(Model.Entities.ExtraType.ThemeVideo)).OrderBy(i => i.SortName); + return ThemeVideoIds.Select(LibraryManager.GetItemById); } /// <summary> -- cgit v1.2.3 From 6709645ec910051ca6427c38836548b4ce164d87 Mon Sep 17 00:00:00 2001 From: crobibero <cody@robibe.ro> Date: Wed, 12 Aug 2020 15:52:29 -0600 Subject: bump deps --- Emby.Server.Implementations/Emby.Server.Implementations.csproj | 8 ++++---- Jellyfin.Api/Jellyfin.Api.csproj | 4 ++-- Jellyfin.Data/Jellyfin.Data.csproj | 4 ++-- .../Jellyfin.Server.Implementations.csproj | 4 ++-- Jellyfin.Server/Jellyfin.Server.csproj | 4 ++-- MediaBrowser.Common/MediaBrowser.Common.csproj | 4 ++-- MediaBrowser.Controller/MediaBrowser.Controller.csproj | 4 ++-- MediaBrowser.Model/MediaBrowser.Model.csproj | 2 +- MediaBrowser.Providers/MediaBrowser.Providers.csproj | 4 ++-- tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj | 8 ++++---- tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj | 2 +- tests/Jellyfin.Controller.Tests/Jellyfin.Controller.Tests.csproj | 2 +- .../Jellyfin.MediaEncoding.Tests.csproj | 2 +- tests/Jellyfin.Naming.Tests/Jellyfin.Naming.Tests.csproj | 2 +- .../Jellyfin.Server.Implementations.Tests.csproj | 4 ++-- tests/MediaBrowser.Api.Tests/MediaBrowser.Api.Tests.csproj | 4 ++-- 16 files changed, 31 insertions(+), 31 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj index 1adef68aa..3245c0c8b 100644 --- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj +++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj @@ -32,10 +32,10 @@ <PackageReference Include="Microsoft.AspNetCore.ResponseCompression" Version="2.2.0" /> <PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="2.2.0" /> <PackageReference Include="Microsoft.AspNetCore.WebSockets" Version="2.2.1" /> - <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.1.6" /> - <PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="3.1.6" /> - <PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.1.6" /> - <PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="3.1.6" /> + <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.1.7" /> + <PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="3.1.7" /> + <PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.1.7" /> + <PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="3.1.7" /> <PackageReference Include="Mono.Nat" Version="2.0.2" /> <PackageReference Include="prometheus-net.DotNetRuntime" Version="3.3.1" /> <PackageReference Include="ServiceStack.Text.Core" Version="5.9.2" /> diff --git a/Jellyfin.Api/Jellyfin.Api.csproj b/Jellyfin.Api/Jellyfin.Api.csproj index 24bc07b66..ca0542b03 100644 --- a/Jellyfin.Api/Jellyfin.Api.csproj +++ b/Jellyfin.Api/Jellyfin.Api.csproj @@ -14,9 +14,9 @@ <ItemGroup> <PackageReference Include="Microsoft.AspNetCore.Authentication" Version="2.2.0" /> - <PackageReference Include="Microsoft.AspNetCore.Authorization" Version="3.1.6" /> + <PackageReference Include="Microsoft.AspNetCore.Authorization" Version="3.1.7" /> <PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.2.0" /> - <PackageReference Include="Microsoft.Extensions.Http" Version="3.1.6" /> + <PackageReference Include="Microsoft.Extensions.Http" Version="3.1.7" /> <PackageReference Include="Swashbuckle.AspNetCore" Version="5.5.1" /> <PackageReference Include="Swashbuckle.AspNetCore.ReDoc" Version="5.5.1" /> </ItemGroup> diff --git a/Jellyfin.Data/Jellyfin.Data.csproj b/Jellyfin.Data/Jellyfin.Data.csproj index 8ce0f3848..367d14769 100644 --- a/Jellyfin.Data/Jellyfin.Data.csproj +++ b/Jellyfin.Data/Jellyfin.Data.csproj @@ -19,8 +19,8 @@ </ItemGroup> <ItemGroup> - <PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="3.1.6" /> - <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="3.1.6" /> + <PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="3.1.7" /> + <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="3.1.7" /> </ItemGroup> </Project> diff --git a/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj b/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj index 21748ca19..30ed3e6af 100644 --- a/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj +++ b/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj @@ -24,11 +24,11 @@ </ItemGroup> <ItemGroup> - <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="3.1.6"> + <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="3.1.7"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> </PackageReference> - <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="3.1.6"> + <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="3.1.7"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> </PackageReference> diff --git a/Jellyfin.Server/Jellyfin.Server.csproj b/Jellyfin.Server/Jellyfin.Server.csproj index 7541707d9..5e85ff4f1 100644 --- a/Jellyfin.Server/Jellyfin.Server.csproj +++ b/Jellyfin.Server/Jellyfin.Server.csproj @@ -41,8 +41,8 @@ <ItemGroup> <PackageReference Include="CommandLineParser" Version="2.8.0" /> - <PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="3.1.6" /> - <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="3.1.6" /> + <PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="3.1.7" /> + <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="3.1.7" /> <PackageReference Include="prometheus-net" Version="3.6.0" /> <PackageReference Include="prometheus-net.AspNetCore" Version="3.6.0" /> <PackageReference Include="Serilog.AspNetCore" Version="3.4.0" /> diff --git a/MediaBrowser.Common/MediaBrowser.Common.csproj b/MediaBrowser.Common/MediaBrowser.Common.csproj index 7380f39fd..e0e271e3e 100644 --- a/MediaBrowser.Common/MediaBrowser.Common.csproj +++ b/MediaBrowser.Common/MediaBrowser.Common.csproj @@ -17,8 +17,8 @@ </ItemGroup> <ItemGroup> - <PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.1.6" /> - <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="3.1.6" /> + <PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.1.7" /> + <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="3.1.7" /> <PackageReference Include="Microsoft.Net.Http.Headers" Version="2.2.8" /> </ItemGroup> diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index 67f17f7a5..da474fcab 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -13,8 +13,8 @@ </PropertyGroup> <ItemGroup> - <PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.1.6" /> - <PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="3.1.6" /> + <PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.1.7" /> + <PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="3.1.7" /> </ItemGroup> <ItemGroup> diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj index 902e29b20..4de932982 100644 --- a/MediaBrowser.Model/MediaBrowser.Model.csproj +++ b/MediaBrowser.Model/MediaBrowser.Model.csproj @@ -23,7 +23,7 @@ <ItemGroup> <PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.2.0" /> - <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="3.1.6" /> + <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="3.1.7" /> <PackageReference Include="System.Globalization" Version="4.3.0" /> <PackageReference Include="System.Text.Json" Version="4.7.2" /> </ItemGroup> diff --git a/MediaBrowser.Providers/MediaBrowser.Providers.csproj b/MediaBrowser.Providers/MediaBrowser.Providers.csproj index 7c0b54250..e2a9172d8 100644 --- a/MediaBrowser.Providers/MediaBrowser.Providers.csproj +++ b/MediaBrowser.Providers/MediaBrowser.Providers.csproj @@ -16,8 +16,8 @@ </ItemGroup> <ItemGroup> - <PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.1.6" /> - <PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="3.1.6" /> + <PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.1.7" /> + <PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="3.1.7" /> <PackageReference Include="OptimizedPriorityQueue" Version="4.2.0" /> <PackageReference Include="PlaylistsNET" Version="1.1.2" /> <PackageReference Include="TvDbSharper" Version="3.2.1" /> diff --git a/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj b/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj index f77eba376..4118594ca 100644 --- a/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj +++ b/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj @@ -14,12 +14,12 @@ <ItemGroup> <PackageReference Include="AutoFixture" Version="4.13.0" /> - <PackageReference Include="AutoFixture.AutoMoq" Version="4.12.0" /> - <PackageReference Include="AutoFixture.Xunit2" Version="4.12.0" /> - <PackageReference Include="Microsoft.Extensions.Options" Version="3.1.6" /> + <PackageReference Include="AutoFixture.AutoMoq" Version="4.13.0" /> + <PackageReference Include="AutoFixture.Xunit2" Version="4.13.0" /> + <PackageReference Include="Microsoft.Extensions.Options" Version="3.1.7" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.0" /> <PackageReference Include="xunit" Version="2.4.1" /> - <PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" /> + <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" /> <PackageReference Include="coverlet.collector" Version="1.3.0" /> <PackageReference Include="Moq" Version="4.14.5" /> </ItemGroup> diff --git a/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj b/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj index 746474044..cc802ccde 100644 --- a/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj +++ b/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj @@ -15,7 +15,7 @@ <ItemGroup> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.0" /> <PackageReference Include="xunit" Version="2.4.1" /> - <PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" /> + <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" /> <PackageReference Include="coverlet.collector" Version="1.3.0" /> </ItemGroup> diff --git a/tests/Jellyfin.Controller.Tests/Jellyfin.Controller.Tests.csproj b/tests/Jellyfin.Controller.Tests/Jellyfin.Controller.Tests.csproj index 1559f70ab..25459287c 100644 --- a/tests/Jellyfin.Controller.Tests/Jellyfin.Controller.Tests.csproj +++ b/tests/Jellyfin.Controller.Tests/Jellyfin.Controller.Tests.csproj @@ -15,7 +15,7 @@ <ItemGroup> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.0" /> <PackageReference Include="xunit" Version="2.4.1" /> - <PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" /> + <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" /> <PackageReference Include="coverlet.collector" Version="1.3.0" /> </ItemGroup> diff --git a/tests/Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj b/tests/Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj index e1a089547..c43323abc 100644 --- a/tests/Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj +++ b/tests/Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj @@ -21,7 +21,7 @@ <ItemGroup> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.0" /> <PackageReference Include="xunit" Version="2.4.1" /> - <PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" /> + <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" /> <PackageReference Include="coverlet.collector" Version="1.3.0" /> </ItemGroup> diff --git a/tests/Jellyfin.Naming.Tests/Jellyfin.Naming.Tests.csproj b/tests/Jellyfin.Naming.Tests/Jellyfin.Naming.Tests.csproj index 0e9e91563..d305a10a8 100644 --- a/tests/Jellyfin.Naming.Tests/Jellyfin.Naming.Tests.csproj +++ b/tests/Jellyfin.Naming.Tests/Jellyfin.Naming.Tests.csproj @@ -15,7 +15,7 @@ <ItemGroup> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.0" /> <PackageReference Include="xunit" Version="2.4.1" /> - <PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" /> + <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" /> <PackageReference Include="coverlet.collector" Version="1.3.0" /> </ItemGroup> diff --git a/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj b/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj index 03187f4b9..2f47d5ffe 100644 --- a/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj +++ b/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj @@ -15,10 +15,10 @@ <ItemGroup> <PackageReference Include="AutoFixture" Version="4.13.0" /> - <PackageReference Include="AutoFixture.AutoMoq" Version="4.12.0" /> + <PackageReference Include="AutoFixture.AutoMoq" Version="4.13.0" /> <PackageReference Include="Moq" Version="4.14.5" /> <PackageReference Include="xunit" Version="2.4.1" /> - <PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" /> + <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" /> <PackageReference Include="coverlet.collector" Version="1.3.0" /> </ItemGroup> diff --git a/tests/MediaBrowser.Api.Tests/MediaBrowser.Api.Tests.csproj b/tests/MediaBrowser.Api.Tests/MediaBrowser.Api.Tests.csproj index a4ef10648..0fea965d2 100644 --- a/tests/MediaBrowser.Api.Tests/MediaBrowser.Api.Tests.csproj +++ b/tests/MediaBrowser.Api.Tests/MediaBrowser.Api.Tests.csproj @@ -8,10 +8,10 @@ </PropertyGroup> <ItemGroup> - <PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="3.1.6" /> + <PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="3.1.7" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.0" /> <PackageReference Include="xunit" Version="2.4.1" /> - <PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" /> + <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" /> <PackageReference Include="coverlet.collector" Version="1.3.0" /> </ItemGroup> -- cgit v1.2.3 From a61f6e3308dfc9f84fe2bdfab0194b75c041d2aa Mon Sep 17 00:00:00 2001 From: David <daullmer@gmail.com> Date: Thu, 13 Aug 2020 15:22:12 +0200 Subject: Fix nuget ci --- .ci/azure-pipelines-package.yml | 6 +++--- Emby.Naming/Emby.Naming.csproj | 1 + Jellyfin.Data/Jellyfin.Data.csproj | 8 ++++++++ MediaBrowser.Common/MediaBrowser.Common.csproj | 1 + .../MediaBrowser.Controller.csproj | 1 + MediaBrowser.Model/MediaBrowser.Model.csproj | 1 + bump_version | 23 ++++++++++++++++++++++ 7 files changed, 38 insertions(+), 3 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/.ci/azure-pipelines-package.yml b/.ci/azure-pipelines-package.yml index 003d5baf0..c80ec7b0e 100644 --- a/.ci/azure-pipelines-package.yml +++ b/.ci/azure-pipelines-package.yml @@ -153,11 +153,11 @@ jobs: vmImage: 'ubuntu-latest' steps: - - task: NuGetCommand@2 + - task: DotNetCoreCLI@2 inputs: command: 'pack' - packagesToPack: Jellyfin.Data/Jellyfin.Data.csproj;MediaBrowser.Common/MediaBrowser.Common.csproj;MediaBrowser.Controller/MediaBrowser.Controller.csproj;MediaBrowser.Model/MediaBrowser.Model.csproj;Emby.Naming/Emby.Naming.csproj - packDestination: '$(Build.ArtifactStagingDirectory)' + packagesToPack: 'Jellyfin.Data/Jellyfin.Data.csproj;MediaBrowser.Common/MediaBrowser.Common.csproj;MediaBrowser.Controller/MediaBrowser.Controller.csproj;MediaBrowser.Model/MediaBrowser.Model.csproj;Emby.Naming/Emby.Naming.csproj' + versioningScheme: 'off' - task: NuGetCommand@2 inputs: diff --git a/Emby.Naming/Emby.Naming.csproj b/Emby.Naming/Emby.Naming.csproj index c017e76c7..410492e67 100644 --- a/Emby.Naming/Emby.Naming.csproj +++ b/Emby.Naming/Emby.Naming.csproj @@ -23,6 +23,7 @@ <PropertyGroup> <Authors>Jellyfin Contributors</Authors> <PackageId>Jellyfin.Naming</PackageId> + <PackageVersion>10.7.0</PackageVersion> <PackageLicenseUrl>https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt</PackageLicenseUrl> <RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl> </PropertyGroup> diff --git a/Jellyfin.Data/Jellyfin.Data.csproj b/Jellyfin.Data/Jellyfin.Data.csproj index 8ce0f3848..979198353 100644 --- a/Jellyfin.Data/Jellyfin.Data.csproj +++ b/Jellyfin.Data/Jellyfin.Data.csproj @@ -6,6 +6,14 @@ <GenerateDocumentationFile>true</GenerateDocumentationFile> </PropertyGroup> + <PropertyGroup> + <Authors>Jellyfin Contributors</Authors> + <PackageId>Jellyfin.Data</PackageId> + <PackageVersion>10.7.0</PackageVersion> + <PackageLicenseUrl>https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt</PackageLicenseUrl> + <RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)' == 'Debug' "> <CodeAnalysisRuleSet>../jellyfin.ruleset</CodeAnalysisRuleSet> </PropertyGroup> diff --git a/MediaBrowser.Common/MediaBrowser.Common.csproj b/MediaBrowser.Common/MediaBrowser.Common.csproj index 7380f39fd..e7f9a5643 100644 --- a/MediaBrowser.Common/MediaBrowser.Common.csproj +++ b/MediaBrowser.Common/MediaBrowser.Common.csproj @@ -8,6 +8,7 @@ <PropertyGroup> <Authors>Jellyfin Contributors</Authors> <PackageId>Jellyfin.Common</PackageId> + <PackageVersion>10.7.0</PackageVersion> <PackageLicenseUrl>https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt</PackageLicenseUrl> <RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl> </PropertyGroup> diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index 67f17f7a5..9686b4a72 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -8,6 +8,7 @@ <PropertyGroup> <Authors>Jellyfin Contributors</Authors> <PackageId>Jellyfin.Controller</PackageId> + <PackageVersion>10.7.0</PackageVersion> <PackageLicenseUrl>https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt</PackageLicenseUrl> <RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl> </PropertyGroup> diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj index 902e29b20..229a75a46 100644 --- a/MediaBrowser.Model/MediaBrowser.Model.csproj +++ b/MediaBrowser.Model/MediaBrowser.Model.csproj @@ -8,6 +8,7 @@ <PropertyGroup> <Authors>Jellyfin Contributors</Authors> <PackageId>Jellyfin.Model</PackageId> + <PackageVersion>10.7.0</PackageVersion> <PackageLicenseUrl>https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt</PackageLicenseUrl> <RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl> </PropertyGroup> diff --git a/bump_version b/bump_version index 1c943f691..1db1f4499 100755 --- a/bump_version +++ b/bump_version @@ -20,6 +20,12 @@ fi shared_version_file="./SharedVersion.cs" build_file="./build.yaml" +# csproj files for nuget packages +mediabrowser_common="MediaBrowser.Common/MediaBrowser.Common.csproj" +jellyfin_data="Jellyfin.Data/Jellyfin.Data.csproj" +mediabrowser_controller="MediaBrowser.Controller/MediaBrowser.Controller.csproj" +mediabrowser_model="MediaBrowser.Model/MediaBrowser.Model.csproj" +emby_naming="Emby.Naming/Emby.Naming.csproj" new_version="$1" @@ -45,6 +51,23 @@ echo $old_version old_version_sed="$( sed 's/\./\\./g' <<<"${old_version}" )" # Escape the '.' chars sed -i "s/${old_version_sed}/${new_version}/g" ${build_file} +# update nuget package version +for f in ${mediabrowser_common} ${jellyfin_data} ${mediabrowser_controller} ${mediabrowser_model} ${emby_naming} +do + code ${f} + echo ${f} + # Parse the version from the *.csproj file + old_version="$( + grep "PackageVersion" ${f} \ + | awk '{$1=$1};1' \ + | sed -E 's/<PackageVersion>([0-9\.]+[-a-z0-9]*)<\/PackageVersion>/\1/' + )" + echo old nuget version: $old_version + + # Set the nuget version to the specified new_version + sed -i "s|${old_version}|${new_version}|g" ${f} +done + if [[ ${new_version} == *"-"* ]]; then new_version_deb="$( sed 's/-/~/g' <<<"${new_version}" )" else -- cgit v1.2.3 From 2be1865b429540a831806832c1313d7d48ad2f45 Mon Sep 17 00:00:00 2001 From: Patrick Barron <barronpm@gmail.com> Date: Thu, 13 Aug 2020 12:50:04 -0400 Subject: Remove unused methods in IDtoService --- Emby.Server.Implementations/Dto/DtoService.cs | 48 +++------------------------ MediaBrowser.Controller/Dto/IDtoService.cs | 24 -------------- 2 files changed, 5 insertions(+), 67 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/Dto/DtoService.cs b/Emby.Server.Implementations/Dto/DtoService.cs index c967e9230..f2c7118fe 100644 --- a/Emby.Server.Implementations/Dto/DtoService.cs +++ b/Emby.Server.Implementations/Dto/DtoService.cs @@ -73,25 +73,6 @@ namespace Emby.Server.Implementations.Dto _livetvManagerFactory = livetvManagerFactory; } - /// <summary> - /// Converts a BaseItem to a DTOBaseItem. - /// </summary> - /// <param name="item">The item.</param> - /// <param name="fields">The fields.</param> - /// <param name="user">The user.</param> - /// <param name="owner">The owner.</param> - /// <returns>Task{DtoBaseItem}.</returns> - /// <exception cref="ArgumentNullException">item</exception> - public BaseItemDto GetBaseItemDto(BaseItem item, ItemFields[] fields, User user = null, BaseItem owner = null) - { - var options = new DtoOptions - { - Fields = fields - }; - - return GetBaseItemDto(item, options, user, owner); - } - /// <inheritdoc /> public IReadOnlyList<BaseItemDto> GetBaseItemDtos(IReadOnlyList<BaseItem> items, DtoOptions options, User user = null, BaseItem owner = null) { @@ -443,17 +424,6 @@ namespace Emby.Server.Implementations.Dto return folder.GetChildCount(user); } - /// <summary> - /// Gets client-side Id of a server-side BaseItem. - /// </summary> - /// <param name="item">The item.</param> - /// <returns>System.String.</returns> - /// <exception cref="ArgumentNullException">item</exception> - public string GetDtoId(BaseItem item) - { - return item.Id.ToString("N", CultureInfo.InvariantCulture); - } - private static void SetBookProperties(BaseItemDto dto, Book item) { dto.SeriesName = item.SeriesName; @@ -484,6 +454,11 @@ namespace Emby.Server.Implementations.Dto } } + private string GetDtoId(BaseItem item) + { + return item.Id.ToString("N", CultureInfo.InvariantCulture); + } + private void SetMusicVideoProperties(BaseItemDto dto, MusicVideo item) { if (!string.IsNullOrEmpty(item.Album)) @@ -513,19 +488,6 @@ namespace Emby.Server.Implementations.Dto .ToArray(); } - private string GetImageCacheTag(BaseItem item, ImageType type) - { - try - { - return _imageProcessor.GetImageCacheTag(item, type); - } - catch (Exception ex) - { - _logger.LogError(ex, "Error getting {type} image info", type); - return null; - } - } - private string GetImageCacheTag(BaseItem item, ItemImageInfo image) { try diff --git a/MediaBrowser.Controller/Dto/IDtoService.cs b/MediaBrowser.Controller/Dto/IDtoService.cs index 0dadc283e..988557f42 100644 --- a/MediaBrowser.Controller/Dto/IDtoService.cs +++ b/MediaBrowser.Controller/Dto/IDtoService.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using Jellyfin.Data.Entities; using MediaBrowser.Controller.Entities; using MediaBrowser.Model.Dto; -using MediaBrowser.Model.Querying; namespace MediaBrowser.Controller.Dto { @@ -11,20 +10,6 @@ namespace MediaBrowser.Controller.Dto /// </summary> public interface IDtoService { - /// <summary> - /// Gets the dto id. - /// </summary> - /// <param name="item">The item.</param> - /// <returns>System.String.</returns> - string GetDtoId(BaseItem item); - - /// <summary> - /// Attaches the primary image aspect ratio. - /// </summary> - /// <param name="dto">The dto.</param> - /// <param name="item">The item.</param> - void AttachPrimaryImageAspectRatio(IItemDto dto, BaseItem item); - /// <summary> /// Gets the primary image aspect ratio. /// </summary> @@ -32,15 +17,6 @@ namespace MediaBrowser.Controller.Dto /// <returns>System.Nullable<System.Double>.</returns> double? GetPrimaryImageAspectRatio(BaseItem item); - /// <summary> - /// Gets the base item dto. - /// </summary> - /// <param name="item">The item.</param> - /// <param name="fields">The fields.</param> - /// <param name="user">The user.</param> - /// <param name="owner">The owner.</param> - BaseItemDto GetBaseItemDto(BaseItem item, ItemFields[] fields, User user = null, BaseItem owner = null); - /// <summary> /// Gets the base item dto. /// </summary> -- cgit v1.2.3 From b92fbe4d69975d077737042d13d4fd935bc3e3c7 Mon Sep 17 00:00:00 2001 From: David <daullmer@gmail.com> Date: Thu, 13 Aug 2020 19:03:24 +0200 Subject: Use VersionPrefix --- Emby.Naming/Emby.Naming.csproj | 2 +- Jellyfin.Data/Jellyfin.Data.csproj | 2 +- MediaBrowser.Common/MediaBrowser.Common.csproj | 2 +- MediaBrowser.Controller/MediaBrowser.Controller.csproj | 2 +- MediaBrowser.Model/MediaBrowser.Model.csproj | 2 +- bump_version | 4 ++-- 6 files changed, 7 insertions(+), 7 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Naming/Emby.Naming.csproj b/Emby.Naming/Emby.Naming.csproj index 410492e67..14aac1a4a 100644 --- a/Emby.Naming/Emby.Naming.csproj +++ b/Emby.Naming/Emby.Naming.csproj @@ -23,7 +23,7 @@ <PropertyGroup> <Authors>Jellyfin Contributors</Authors> <PackageId>Jellyfin.Naming</PackageId> - <PackageVersion>10.7.0</PackageVersion> + <VersionPrefix>10.7.0</VersionPrefix> <PackageLicenseUrl>https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt</PackageLicenseUrl> <RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl> </PropertyGroup> diff --git a/Jellyfin.Data/Jellyfin.Data.csproj b/Jellyfin.Data/Jellyfin.Data.csproj index 979198353..cef75f890 100644 --- a/Jellyfin.Data/Jellyfin.Data.csproj +++ b/Jellyfin.Data/Jellyfin.Data.csproj @@ -9,7 +9,7 @@ <PropertyGroup> <Authors>Jellyfin Contributors</Authors> <PackageId>Jellyfin.Data</PackageId> - <PackageVersion>10.7.0</PackageVersion> + <VersionPrefix>10.7.0</VersionPrefix> <PackageLicenseUrl>https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt</PackageLicenseUrl> <RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl> </PropertyGroup> diff --git a/MediaBrowser.Common/MediaBrowser.Common.csproj b/MediaBrowser.Common/MediaBrowser.Common.csproj index e7f9a5643..04100eba4 100644 --- a/MediaBrowser.Common/MediaBrowser.Common.csproj +++ b/MediaBrowser.Common/MediaBrowser.Common.csproj @@ -8,7 +8,7 @@ <PropertyGroup> <Authors>Jellyfin Contributors</Authors> <PackageId>Jellyfin.Common</PackageId> - <PackageVersion>10.7.0</PackageVersion> + <VersionPrefix>10.7.0</VersionPrefix> <PackageLicenseUrl>https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt</PackageLicenseUrl> <RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl> </PropertyGroup> diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index 9686b4a72..6bfe4e403 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -8,7 +8,7 @@ <PropertyGroup> <Authors>Jellyfin Contributors</Authors> <PackageId>Jellyfin.Controller</PackageId> - <PackageVersion>10.7.0</PackageVersion> + <VersionPrefix>10.7.0</VersionPrefix> <PackageLicenseUrl>https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt</PackageLicenseUrl> <RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl> </PropertyGroup> diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj index 229a75a46..2cb89f77f 100644 --- a/MediaBrowser.Model/MediaBrowser.Model.csproj +++ b/MediaBrowser.Model/MediaBrowser.Model.csproj @@ -8,7 +8,7 @@ <PropertyGroup> <Authors>Jellyfin Contributors</Authors> <PackageId>Jellyfin.Model</PackageId> - <PackageVersion>10.7.0</PackageVersion> + <VersionPrefix>10.7.0</VersionPrefix> <PackageLicenseUrl>https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt</PackageLicenseUrl> <RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl> </PropertyGroup> diff --git a/bump_version b/bump_version index 1db1f4499..226e37eec 100755 --- a/bump_version +++ b/bump_version @@ -58,9 +58,9 @@ do echo ${f} # Parse the version from the *.csproj file old_version="$( - grep "PackageVersion" ${f} \ + grep "VersionPrefix" ${f} \ | awk '{$1=$1};1' \ - | sed -E 's/<PackageVersion>([0-9\.]+[-a-z0-9]*)<\/PackageVersion>/\1/' + | sed -E 's/<VersionPrefix>([0-9\.]+[-a-z0-9]*)<\/VersionPrefix>/\1/' )" echo old nuget version: $old_version -- cgit v1.2.3 From e0c6172d23782a84250a345aa73553fc6f624fe5 Mon Sep 17 00:00:00 2001 From: Patrick Barron <barronpm@gmail.com> Date: Thu, 13 Aug 2020 16:10:26 -0400 Subject: Add ServiceProvider to IServerApplicationHost --- MediaBrowser.Controller/IServerApplicationHost.cs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/IServerApplicationHost.cs b/MediaBrowser.Controller/IServerApplicationHost.cs index abdb0f695..77da54675 100644 --- a/MediaBrowser.Controller/IServerApplicationHost.cs +++ b/MediaBrowser.Controller/IServerApplicationHost.cs @@ -16,13 +16,7 @@ namespace MediaBrowser.Controller { event EventHandler HasUpdateAvailableChanged; - /// <summary> - /// Gets the system info. - /// </summary> - /// <returns>SystemInfo.</returns> - Task<SystemInfo> GetSystemInfo(CancellationToken cancellationToken); - - Task<PublicSystemInfo> GetPublicSystemInfo(CancellationToken cancellationToken); + IServiceProvider ServiceProvider { get; } bool CanLaunchWebBrowser { get; } @@ -55,6 +49,14 @@ namespace MediaBrowser.Controller /// <value>The name of the friendly.</value> string FriendlyName { get; } + /// <summary> + /// Gets the system info. + /// </summary> + /// <returns>SystemInfo.</returns> + Task<SystemInfo> GetSystemInfo(CancellationToken cancellationToken); + + Task<PublicSystemInfo> GetPublicSystemInfo(CancellationToken cancellationToken); + /// <summary> /// 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. -- cgit v1.2.3 From 9438a509760af4024822b1f9adf895fde491e585 Mon Sep 17 00:00:00 2001 From: Orry Verducci <orry@orryverducci.co.uk> Date: Thu, 13 Aug 2020 21:23:12 +0100 Subject: Correct parentheses --- MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 1c42adb03..84a6a461f 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -2089,7 +2089,7 @@ namespace MediaBrowser.Controller.MediaEncoding 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); + var doubleRateDeinterlace = options.DeinterlaceDoubleRate && (videoStream?.RealFrameRate ?? 60) <= 30; // When the input may or may not be hardware VAAPI decodable if (isVaapiH264Encoder) @@ -2150,7 +2150,9 @@ namespace MediaBrowser.Controller.MediaEncoding || state.DeInterlace("avc", true) || state.DeInterlace("h265", true) || state.DeInterlace("hevc", true)) - && (!isVaapiH264Encoder && !isQsvH264Encoder && !isNvdecH264Decoder)) + && !isVaapiH264Encoder + && !isQsvH264Encoder + && !isNvdecH264Decoder) { if (string.Equals(options.DeinterlaceMethod, "bwdif", StringComparison.OrdinalIgnoreCase)) { -- cgit v1.2.3 From 285af300f50c8380ef04974ab29881cf0e5d600b Mon Sep 17 00:00:00 2001 From: Patrick Barron <barronpm@gmail.com> Date: Thu, 13 Aug 2020 20:29:14 -0400 Subject: Create IEventConsumer and IEventManager --- MediaBrowser.Controller/Events/IEventConsumer.cs | 11 +++++++++++ MediaBrowser.Controller/Events/IEventManager.cs | 20 ++++++++++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 MediaBrowser.Controller/Events/IEventConsumer.cs create mode 100644 MediaBrowser.Controller/Events/IEventManager.cs (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/Events/IEventConsumer.cs b/MediaBrowser.Controller/Events/IEventConsumer.cs new file mode 100644 index 000000000..3cefe2f9c --- /dev/null +++ b/MediaBrowser.Controller/Events/IEventConsumer.cs @@ -0,0 +1,11 @@ +using System; +using System.Threading.Tasks; + +namespace MediaBrowser.Controller.Events +{ + public interface IEventConsumer<in T> + where T : EventArgs + { + Task OnEvent(T eventArgs); + } +} diff --git a/MediaBrowser.Controller/Events/IEventManager.cs b/MediaBrowser.Controller/Events/IEventManager.cs new file mode 100644 index 000000000..794a8709e --- /dev/null +++ b/MediaBrowser.Controller/Events/IEventManager.cs @@ -0,0 +1,20 @@ +using System; +using System.Threading.Tasks; + +namespace MediaBrowser.Controller.Events +{ + /// <summary> + /// An interface that handles eventing. + /// </summary> + public interface IEventManager + { + /// <summary> + /// Publishes an event. + /// </summary> + /// <param name="eventArgs">The event arguments.</param> + /// <typeparam name="T">The type of event.</typeparam> + /// <returns>A task representing the publishing of the event.</returns> + Task Publish<T>(T eventArgs) + where T : EventArgs; + } +} -- cgit v1.2.3 From 57e2f7248d5ae96063119246efa059d88a856208 Mon Sep 17 00:00:00 2001 From: Patrick Barron <barronpm@gmail.com> Date: Thu, 13 Aug 2020 20:30:43 -0400 Subject: Remove unused class and rename file. --- .../Subtitles/SubtitleDownloadEventArgs.cs | 27 ---------------------- .../Subtitles/SubtitleDownloadFailureEventArgs.cs | 14 +++++++++++ 2 files changed, 14 insertions(+), 27 deletions(-) delete mode 100644 MediaBrowser.Controller/Subtitles/SubtitleDownloadEventArgs.cs create mode 100644 MediaBrowser.Controller/Subtitles/SubtitleDownloadFailureEventArgs.cs (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/Subtitles/SubtitleDownloadEventArgs.cs b/MediaBrowser.Controller/Subtitles/SubtitleDownloadEventArgs.cs deleted file mode 100644 index 5703aea17..000000000 --- a/MediaBrowser.Controller/Subtitles/SubtitleDownloadEventArgs.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System; -using MediaBrowser.Controller.Entities; - -namespace MediaBrowser.Controller.Subtitles -{ - public class SubtitleDownloadEventArgs - { - public BaseItem Item { get; set; } - - public string Format { get; set; } - - public string Language { get; set; } - - public bool IsForced { get; set; } - - public string Provider { get; set; } - } - - public class SubtitleDownloadFailureEventArgs - { - public BaseItem Item { get; set; } - - public string Provider { get; set; } - - public Exception Exception { get; set; } - } -} diff --git a/MediaBrowser.Controller/Subtitles/SubtitleDownloadFailureEventArgs.cs b/MediaBrowser.Controller/Subtitles/SubtitleDownloadFailureEventArgs.cs new file mode 100644 index 000000000..7687bf5b6 --- /dev/null +++ b/MediaBrowser.Controller/Subtitles/SubtitleDownloadFailureEventArgs.cs @@ -0,0 +1,14 @@ +using System; +using MediaBrowser.Controller.Entities; + +namespace MediaBrowser.Controller.Subtitles +{ + public class SubtitleDownloadFailureEventArgs : EventArgs + { + public BaseItem Item { get; set; } + + public string Provider { get; set; } + + public Exception Exception { get; set; } + } +} -- cgit v1.2.3 From 3e5fe04427d60261bb87df2e124ce7b2e066b88e Mon Sep 17 00:00:00 2001 From: Patrick Barron <barronpm@gmail.com> Date: Thu, 13 Aug 2020 20:31:26 -0400 Subject: Migrate ActivityLogEntryPoint.OnPlaybackStart to IEventConsumer --- .../Activity/ActivityLogEntryPoint.cs | 53 ----------- .../Consumers/Session/PlaybackStartLogger.cs | 105 +++++++++++++++++++++ .../Library/PlaybackStartEventArgs.cs | 6 ++ 3 files changed, 111 insertions(+), 53 deletions(-) create mode 100644 Jellyfin.Server.Implementations/Events/Consumers/Session/PlaybackStartLogger.cs create mode 100644 MediaBrowser.Controller/Library/PlaybackStartEventArgs.cs (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs b/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs index 84bec9201..53b3a6293 100644 --- a/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs +++ b/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Globalization; -using System.Linq; using System.Text; using System.Threading.Tasks; using Jellyfin.Data.Entities; @@ -83,7 +82,6 @@ namespace Emby.Server.Implementations.Activity _sessionManager.AuthenticationFailed += OnAuthenticationFailed; _sessionManager.AuthenticationSucceeded += OnAuthenticationSucceeded; _sessionManager.SessionEnded += OnSessionEnded; - _sessionManager.PlaybackStart += OnPlaybackStart; _sessionManager.PlaybackStopped += OnPlaybackStopped; _subManager.SubtitleDownloadFailure += OnSubtitleDownloadFailure; @@ -161,41 +159,6 @@ namespace Emby.Server.Implementations.Activity .ConfigureAwait(false); } - private async void OnPlaybackStart(object sender, PlaybackProgressEventArgs e) - { - var item = e.MediaInfo; - - if (item == null) - { - _logger.LogWarning("PlaybackStart reported with null media info."); - return; - } - - if (e.Item != null && e.Item.IsThemeMedia) - { - // Don't report theme song or local trailer playback - return; - } - - if (e.Users.Count == 0) - { - return; - } - - var user = e.Users.First(); - - await CreateLogEntry(new ActivityLog( - string.Format( - CultureInfo.InvariantCulture, - _localization.GetLocalizedString("UserStartedPlayingItemWithValues"), - user.Username, - GetItemName(item), - e.DeviceName), - GetPlaybackNotificationType(item.MediaType), - user.Id)) - .ConfigureAwait(false); - } - private static string GetItemName(BaseItemDto item) { var name = item.Name; @@ -213,21 +176,6 @@ namespace Emby.Server.Implementations.Activity return name; } - private static string GetPlaybackNotificationType(string mediaType) - { - if (string.Equals(mediaType, MediaType.Audio, StringComparison.OrdinalIgnoreCase)) - { - return NotificationType.AudioPlayback.ToString(); - } - - if (string.Equals(mediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase)) - { - return NotificationType.VideoPlayback.ToString(); - } - - return null; - } - private static string GetPlaybackStoppedNotificationType(string mediaType) { if (string.Equals(mediaType, MediaType.Audio, StringComparison.OrdinalIgnoreCase)) @@ -494,7 +442,6 @@ namespace Emby.Server.Implementations.Activity _sessionManager.AuthenticationSucceeded -= OnAuthenticationSucceeded; _sessionManager.SessionEnded -= OnSessionEnded; - _sessionManager.PlaybackStart -= OnPlaybackStart; _sessionManager.PlaybackStopped -= OnPlaybackStopped; _subManager.SubtitleDownloadFailure -= OnSubtitleDownloadFailure; diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Session/PlaybackStartLogger.cs b/Jellyfin.Server.Implementations/Events/Consumers/Session/PlaybackStartLogger.cs new file mode 100644 index 000000000..c48683ea3 --- /dev/null +++ b/Jellyfin.Server.Implementations/Events/Consumers/Session/PlaybackStartLogger.cs @@ -0,0 +1,105 @@ +using System; +using System.Globalization; +using System.Linq; +using System.Threading.Tasks; +using Jellyfin.Data.Entities; +using MediaBrowser.Controller.Events; +using MediaBrowser.Controller.Library; +using MediaBrowser.Model.Activity; +using MediaBrowser.Model.Dto; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Globalization; +using MediaBrowser.Model.Notifications; +using Microsoft.Extensions.Logging; + +namespace Jellyfin.Server.Implementations.Events.Consumers.Session +{ + /// <summary> + /// Creates an entry in the activity log whenever a user starts playback. + /// </summary> + public class PlaybackStartLogger : IEventConsumer<PlaybackStartEventArgs> + { + private readonly ILogger<PlaybackStartLogger> _logger; + private readonly ILocalizationManager _localizationManager; + private readonly IActivityManager _activityManager; + + /// <summary> + /// Initializes a new instance of the <see cref="PlaybackStartLogger"/> class. + /// </summary> + /// <param name="logger">The logger.</param> + /// <param name="localizationManager">The localization manager.</param> + /// <param name="activityManager">The activity manager.</param> + public PlaybackStartLogger(ILogger<PlaybackStartLogger> logger, ILocalizationManager localizationManager, IActivityManager activityManager) + { + _logger = logger; + _localizationManager = localizationManager; + _activityManager = activityManager; + } + + /// <inheritdoc /> + public async Task OnEvent(PlaybackStartEventArgs eventArgs) + { + if (eventArgs.MediaInfo == null) + { + _logger.LogWarning("PlaybackStart reported with null media info."); + return; + } + + if (eventArgs.Item != null && eventArgs.Item.IsThemeMedia) + { + // Don't report theme song or local trailer playback + return; + } + + if (eventArgs.Users.Count == 0) + { + return; + } + + var user = eventArgs.Users.First(); + + await _activityManager.CreateAsync(new ActivityLog( + string.Format( + CultureInfo.InvariantCulture, + _localizationManager.GetLocalizedString("UserStartedPlayingItemWithValues"), + user.Username, + GetItemName(eventArgs.MediaInfo), + eventArgs.DeviceName), + GetPlaybackNotificationType(eventArgs.MediaInfo.MediaType), + user.Id)) + .ConfigureAwait(false); + } + + private static string GetItemName(BaseItemDto item) + { + var name = item.Name; + + if (!string.IsNullOrEmpty(item.SeriesName)) + { + name = item.SeriesName + " - " + name; + } + + if (item.Artists != null && item.Artists.Count > 0) + { + name = item.Artists[0] + " - " + name; + } + + return name; + } + + private static string GetPlaybackNotificationType(string mediaType) + { + if (string.Equals(mediaType, MediaType.Audio, StringComparison.OrdinalIgnoreCase)) + { + return NotificationType.AudioPlayback.ToString(); + } + + if (string.Equals(mediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase)) + { + return NotificationType.VideoPlayback.ToString(); + } + + return null; + } + } +} diff --git a/MediaBrowser.Controller/Library/PlaybackStartEventArgs.cs b/MediaBrowser.Controller/Library/PlaybackStartEventArgs.cs new file mode 100644 index 000000000..3aa9c2895 --- /dev/null +++ b/MediaBrowser.Controller/Library/PlaybackStartEventArgs.cs @@ -0,0 +1,6 @@ +namespace MediaBrowser.Controller.Library +{ + public class PlaybackStartEventArgs : PlaybackProgressEventArgs + { + } +} -- cgit v1.2.3 From ca1f15af19e26f8f610a7b56cd6b15a6a308a58f Mon Sep 17 00:00:00 2001 From: Patrick Barron <barronpm@gmail.com> Date: Thu, 13 Aug 2020 20:48:28 -0400 Subject: Move GenericEventArgs to Jellyfin.Data.Events --- Emby.Dlna/PlayTo/PlayToController.cs | 2 +- Emby.Dlna/PlayTo/PlayToManager.cs | 2 +- Emby.Dlna/Ssdp/DeviceDiscovery.cs | 2 +- Emby.Notifications/NotificationEntryPoint.cs | 2 +- .../Activity/ActivityLogEntryPoint.cs | 2 +- .../Configuration/ServerConfigurationManager.cs | 2 +- .../Devices/DeviceManager.cs | 2 +- .../EntryPoints/ExternalPortForwarding.cs | 2 +- .../EntryPoints/LibraryChangedNotifier.cs | 2 +- .../EntryPoints/RecordingNotifier.cs | 9 ++++---- .../EntryPoints/ServerEventNotifier.cs | 2 +- .../HttpServer/HttpListenerHost.cs | 2 +- .../LiveTv/EmbyTV/EmbyTV.cs | 2 +- .../LiveTv/EmbyTV/TimerManager.cs | 2 +- .../LiveTv/LiveTvManager.cs | 2 +- .../ScheduledTasks/ScheduledTaskWorker.cs | 3 +-- .../ScheduledTasks/TaskManager.cs | 2 +- .../Session/SessionManager.cs | 2 +- .../Session/SessionWebSocketListener.cs | 2 +- .../ActivityLogWebSocketListener.cs | 2 +- .../ScheduledTasksWebSocketListener.cs | 2 +- Jellyfin.Data/Events/GenericEventArgs.cs | 26 ++++++++++++++++++++++ .../Activity/ActivityManager.cs | 2 +- .../Users/DeviceAccessEntryPoint.cs | 2 +- .../Users/UserManager.cs | 2 +- MediaBrowser.Controller/Devices/IDeviceManager.cs | 2 +- MediaBrowser.Controller/Library/IUserManager.cs | 2 +- MediaBrowser.Controller/LiveTv/ILiveTvManager.cs | 2 +- MediaBrowser.Controller/Net/IHttpServer.cs | 2 +- .../Providers/IProviderManager.cs | 2 +- MediaBrowser.Controller/Session/ISessionManager.cs | 2 +- MediaBrowser.Model/Activity/IActivityManager.cs | 2 +- MediaBrowser.Model/Dlna/IDeviceDiscovery.cs | 2 +- MediaBrowser.Model/Events/GenericEventArgs.cs | 26 ---------------------- MediaBrowser.Model/Tasks/IScheduledTaskWorker.cs | 2 +- MediaBrowser.Model/Tasks/ITaskManager.cs | 2 +- MediaBrowser.Providers/Manager/ProviderManager.cs | 2 +- 37 files changed, 65 insertions(+), 65 deletions(-) create mode 100644 Jellyfin.Data/Events/GenericEventArgs.cs delete mode 100644 MediaBrowser.Model/Events/GenericEventArgs.cs (limited to 'MediaBrowser.Controller') diff --git a/Emby.Dlna/PlayTo/PlayToController.cs b/Emby.Dlna/PlayTo/PlayToController.cs index 92a93d434..1f0da8d75 100644 --- a/Emby.Dlna/PlayTo/PlayToController.cs +++ b/Emby.Dlna/PlayTo/PlayToController.cs @@ -8,6 +8,7 @@ using System.Threading; using System.Threading.Tasks; using Emby.Dlna.Didl; using Jellyfin.Data.Entities; +using Jellyfin.Data.Events; using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Dlna; using MediaBrowser.Controller.Drawing; @@ -18,7 +19,6 @@ using MediaBrowser.Controller.Session; using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; -using MediaBrowser.Model.Events; using MediaBrowser.Model.Globalization; using MediaBrowser.Model.Session; using Microsoft.AspNetCore.WebUtilities; diff --git a/Emby.Dlna/PlayTo/PlayToManager.cs b/Emby.Dlna/PlayTo/PlayToManager.cs index 512589e4d..00edff1a6 100644 --- a/Emby.Dlna/PlayTo/PlayToManager.cs +++ b/Emby.Dlna/PlayTo/PlayToManager.cs @@ -6,6 +6,7 @@ using System.Linq; using System.Net; using System.Threading; using System.Threading.Tasks; +using Jellyfin.Data.Events; using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Net; using MediaBrowser.Controller; @@ -16,7 +17,6 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Controller.Session; using MediaBrowser.Model.Dlna; -using MediaBrowser.Model.Events; using MediaBrowser.Model.Globalization; using MediaBrowser.Model.Session; using Microsoft.Extensions.Logging; diff --git a/Emby.Dlna/Ssdp/DeviceDiscovery.cs b/Emby.Dlna/Ssdp/DeviceDiscovery.cs index 7daac96d1..18ee188fd 100644 --- a/Emby.Dlna/Ssdp/DeviceDiscovery.cs +++ b/Emby.Dlna/Ssdp/DeviceDiscovery.cs @@ -3,9 +3,9 @@ using System; using System.Collections.Generic; using System.Linq; +using Jellyfin.Data.Events; using MediaBrowser.Controller.Configuration; using MediaBrowser.Model.Dlna; -using MediaBrowser.Model.Events; using Rssdp; using Rssdp.Infrastructure; diff --git a/Emby.Notifications/NotificationEntryPoint.cs b/Emby.Notifications/NotificationEntryPoint.cs index b923fd26c..ded22d26c 100644 --- a/Emby.Notifications/NotificationEntryPoint.cs +++ b/Emby.Notifications/NotificationEntryPoint.cs @@ -4,6 +4,7 @@ using System.Globalization; using System.Linq; using System.Threading; using System.Threading.Tasks; +using Jellyfin.Data.Events; using MediaBrowser.Common.Configuration; using MediaBrowser.Controller; using MediaBrowser.Controller.Entities; @@ -13,7 +14,6 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Notifications; using MediaBrowser.Controller.Plugins; using MediaBrowser.Model.Activity; -using MediaBrowser.Model.Events; using MediaBrowser.Model.Globalization; using MediaBrowser.Model.Notifications; using Microsoft.Extensions.Logging; diff --git a/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs b/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs index 39b6361b7..75a791686 100644 --- a/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs +++ b/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs @@ -2,6 +2,7 @@ using System; using System.Globalization; using System.Threading.Tasks; using Jellyfin.Data.Entities; +using Jellyfin.Data.Events; using MediaBrowser.Common.Plugins; using MediaBrowser.Common.Updates; using MediaBrowser.Controller.Authentication; @@ -9,7 +10,6 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Plugins; using MediaBrowser.Controller.Session; using MediaBrowser.Model.Activity; -using MediaBrowser.Model.Events; using MediaBrowser.Model.Globalization; using MediaBrowser.Model.Notifications; using MediaBrowser.Model.Updates; diff --git a/Emby.Server.Implementations/Configuration/ServerConfigurationManager.cs b/Emby.Server.Implementations/Configuration/ServerConfigurationManager.cs index a15295fca..f05a30a89 100644 --- a/Emby.Server.Implementations/Configuration/ServerConfigurationManager.cs +++ b/Emby.Server.Implementations/Configuration/ServerConfigurationManager.cs @@ -2,11 +2,11 @@ using System; using System.Globalization; using System.IO; using Emby.Server.Implementations.AppBase; +using Jellyfin.Data.Events; using MediaBrowser.Common.Configuration; using MediaBrowser.Controller; using MediaBrowser.Controller.Configuration; using MediaBrowser.Model.Configuration; -using MediaBrowser.Model.Events; using MediaBrowser.Model.IO; using MediaBrowser.Model.Serialization; using Microsoft.Extensions.Logging; diff --git a/Emby.Server.Implementations/Devices/DeviceManager.cs b/Emby.Server.Implementations/Devices/DeviceManager.cs index cc4b407f5..f98c694c4 100644 --- a/Emby.Server.Implementations/Devices/DeviceManager.cs +++ b/Emby.Server.Implementations/Devices/DeviceManager.cs @@ -7,13 +7,13 @@ using System.IO; using System.Linq; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Data.Events; using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Devices; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Security; using MediaBrowser.Model.Devices; -using MediaBrowser.Model.Events; using MediaBrowser.Model.Querying; using MediaBrowser.Model.Serialization; using MediaBrowser.Model.Session; diff --git a/Emby.Server.Implementations/EntryPoints/ExternalPortForwarding.cs b/Emby.Server.Implementations/EntryPoints/ExternalPortForwarding.cs index 9fce49425..2e8cc76d2 100644 --- a/Emby.Server.Implementations/EntryPoints/ExternalPortForwarding.cs +++ b/Emby.Server.Implementations/EntryPoints/ExternalPortForwarding.cs @@ -7,11 +7,11 @@ using System.Net; using System.Text; using System.Threading; using System.Threading.Tasks; +using Jellyfin.Data.Events; using MediaBrowser.Controller; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Plugins; using MediaBrowser.Model.Dlna; -using MediaBrowser.Model.Events; using Microsoft.Extensions.Logging; using Mono.Nat; diff --git a/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs b/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs index 1deef7f72..c9d21d963 100644 --- a/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs +++ b/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs @@ -7,6 +7,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using Jellyfin.Data.Entities; +using Jellyfin.Data.Events; using MediaBrowser.Controller.Channels; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; @@ -15,7 +16,6 @@ using MediaBrowser.Controller.Plugins; using MediaBrowser.Controller.Providers; using MediaBrowser.Controller.Session; using MediaBrowser.Model.Entities; -using MediaBrowser.Model.Events; using Microsoft.Extensions.Logging; namespace Emby.Server.Implementations.EntryPoints diff --git a/Emby.Server.Implementations/EntryPoints/RecordingNotifier.cs b/Emby.Server.Implementations/EntryPoints/RecordingNotifier.cs index 632735910..44d2580d6 100644 --- a/Emby.Server.Implementations/EntryPoints/RecordingNotifier.cs +++ b/Emby.Server.Implementations/EntryPoints/RecordingNotifier.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using Jellyfin.Data.Enums; +using Jellyfin.Data.Events; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.LiveTv; using MediaBrowser.Controller.Plugins; @@ -43,22 +44,22 @@ namespace Emby.Server.Implementations.EntryPoints return Task.CompletedTask; } - private async void OnLiveTvManagerSeriesTimerCreated(object sender, MediaBrowser.Model.Events.GenericEventArgs<TimerEventInfo> e) + private async void OnLiveTvManagerSeriesTimerCreated(object sender, GenericEventArgs<TimerEventInfo> e) { await SendMessage("SeriesTimerCreated", e.Argument).ConfigureAwait(false); } - private async void OnLiveTvManagerTimerCreated(object sender, MediaBrowser.Model.Events.GenericEventArgs<TimerEventInfo> e) + private async void OnLiveTvManagerTimerCreated(object sender, GenericEventArgs<TimerEventInfo> e) { await SendMessage("TimerCreated", e.Argument).ConfigureAwait(false); } - private async void OnLiveTvManagerSeriesTimerCancelled(object sender, MediaBrowser.Model.Events.GenericEventArgs<TimerEventInfo> e) + private async void OnLiveTvManagerSeriesTimerCancelled(object sender, GenericEventArgs<TimerEventInfo> e) { await SendMessage("SeriesTimerCancelled", e.Argument).ConfigureAwait(false); } - private async void OnLiveTvManagerTimerCancelled(object sender, MediaBrowser.Model.Events.GenericEventArgs<TimerEventInfo> e) + private async void OnLiveTvManagerTimerCancelled(object sender, GenericEventArgs<TimerEventInfo> e) { await SendMessage("TimerCancelled", e.Argument).ConfigureAwait(false); } diff --git a/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs b/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs index 826d4d8dc..d023591e1 100644 --- a/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs +++ b/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs @@ -4,13 +4,13 @@ using System.Globalization; using System.Threading; using System.Threading.Tasks; using Jellyfin.Data.Entities; +using Jellyfin.Data.Events; using MediaBrowser.Common.Plugins; using MediaBrowser.Common.Updates; using MediaBrowser.Controller; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Plugins; using MediaBrowser.Controller.Session; -using MediaBrowser.Model.Events; using MediaBrowser.Model.Tasks; using MediaBrowser.Model.Updates; diff --git a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs index dafdd5b7b..fe39bb4b2 100644 --- a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs +++ b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs @@ -12,13 +12,13 @@ using System.Threading; using System.Threading.Tasks; using Emby.Server.Implementations.Services; using Emby.Server.Implementations.SocketSharp; +using Jellyfin.Data.Events; using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Net; using MediaBrowser.Controller; using MediaBrowser.Controller.Authentication; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Net; -using MediaBrowser.Model.Events; using MediaBrowser.Model.Globalization; using MediaBrowser.Model.Serialization; using MediaBrowser.Model.Services; diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index 80e09f0a3..09c52d95b 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -13,6 +13,7 @@ using System.Threading.Tasks; using System.Xml; using Emby.Server.Implementations.Library; using Jellyfin.Data.Enums; +using Jellyfin.Data.Events; using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Net; @@ -29,7 +30,6 @@ using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; -using MediaBrowser.Model.Events; using MediaBrowser.Model.IO; using MediaBrowser.Model.LiveTv; using MediaBrowser.Model.MediaInfo; diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs index 285a59a24..dd479b7d1 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs @@ -5,8 +5,8 @@ using System.Collections.Concurrent; using System.Globalization; using System.Linq; using System.Threading; +using Jellyfin.Data.Events; using MediaBrowser.Controller.LiveTv; -using MediaBrowser.Model.Events; using MediaBrowser.Model.LiveTv; using MediaBrowser.Model.Serialization; using Microsoft.Extensions.Logging; diff --git a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs index 1b075d86a..ef505c78e 100644 --- a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs @@ -10,6 +10,7 @@ using System.Threading.Tasks; using Emby.Server.Implementations.Library; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Data.Events; using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Progress; @@ -24,7 +25,6 @@ using MediaBrowser.Controller.Providers; using MediaBrowser.Controller.Sorting; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; -using MediaBrowser.Model.Events; using MediaBrowser.Model.Globalization; using MediaBrowser.Model.IO; using MediaBrowser.Model.LiveTv; diff --git a/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs b/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs index 8a900f42c..36faae65d 100644 --- a/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs +++ b/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs @@ -6,11 +6,10 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; +using Jellyfin.Data.Events; using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Progress; -using MediaBrowser.Model.Events; -using MediaBrowser.Model.IO; using MediaBrowser.Model.Serialization; using MediaBrowser.Model.Tasks; using Microsoft.Extensions.Logging; diff --git a/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs b/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs index 81096026b..fff52ff88 100644 --- a/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs +++ b/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs @@ -5,8 +5,8 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using Jellyfin.Data.Events; using MediaBrowser.Common.Configuration; -using MediaBrowser.Model.Events; using MediaBrowser.Model.Serialization; using MediaBrowser.Model.Tasks; using Microsoft.Extensions.Logging; diff --git a/Emby.Server.Implementations/Session/SessionManager.cs b/Emby.Server.Implementations/Session/SessionManager.cs index 862a7296c..6e4124463 100644 --- a/Emby.Server.Implementations/Session/SessionManager.cs +++ b/Emby.Server.Implementations/Session/SessionManager.cs @@ -9,6 +9,7 @@ using System.Threading; using System.Threading.Tasks; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Data.Events; using MediaBrowser.Common.Events; using MediaBrowser.Common.Extensions; using MediaBrowser.Controller; @@ -24,7 +25,6 @@ using MediaBrowser.Controller.Session; using MediaBrowser.Model.Devices; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; -using MediaBrowser.Model.Events; using MediaBrowser.Model.Library; using MediaBrowser.Model.Querying; using MediaBrowser.Model.Session; diff --git a/Emby.Server.Implementations/Session/SessionWebSocketListener.cs b/Emby.Server.Implementations/Session/SessionWebSocketListener.cs index 8bebd37dc..1da7a6473 100644 --- a/Emby.Server.Implementations/Session/SessionWebSocketListener.cs +++ b/Emby.Server.Implementations/Session/SessionWebSocketListener.cs @@ -4,9 +4,9 @@ using System.Linq; using System.Net.WebSockets; using System.Threading; using System.Threading.Tasks; +using Jellyfin.Data.Events; using MediaBrowser.Controller.Net; using MediaBrowser.Controller.Session; -using MediaBrowser.Model.Events; using MediaBrowser.Model.Net; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; diff --git a/Jellyfin.Api/WebSocketListeners/ActivityLogWebSocketListener.cs b/Jellyfin.Api/WebSocketListeners/ActivityLogWebSocketListener.cs index 6395b8d62..849b3b709 100644 --- a/Jellyfin.Api/WebSocketListeners/ActivityLogWebSocketListener.cs +++ b/Jellyfin.Api/WebSocketListeners/ActivityLogWebSocketListener.cs @@ -1,8 +1,8 @@ using System; using System.Threading.Tasks; +using Jellyfin.Data.Events; using MediaBrowser.Controller.Net; using MediaBrowser.Model.Activity; -using MediaBrowser.Model.Events; using Microsoft.Extensions.Logging; namespace Jellyfin.Api.WebSocketListeners diff --git a/Jellyfin.Api/WebSocketListeners/ScheduledTasksWebSocketListener.cs b/Jellyfin.Api/WebSocketListeners/ScheduledTasksWebSocketListener.cs index 12f815ff7..8a966c137 100644 --- a/Jellyfin.Api/WebSocketListeners/ScheduledTasksWebSocketListener.cs +++ b/Jellyfin.Api/WebSocketListeners/ScheduledTasksWebSocketListener.cs @@ -1,8 +1,8 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using Jellyfin.Data.Events; using MediaBrowser.Controller.Net; -using MediaBrowser.Model.Events; using MediaBrowser.Model.Tasks; using Microsoft.Extensions.Logging; diff --git a/Jellyfin.Data/Events/GenericEventArgs.cs b/Jellyfin.Data/Events/GenericEventArgs.cs new file mode 100644 index 000000000..7b9a5111e --- /dev/null +++ b/Jellyfin.Data/Events/GenericEventArgs.cs @@ -0,0 +1,26 @@ +using System; + +namespace Jellyfin.Data.Events +{ + /// <summary> + /// Provides a generic EventArgs subclass that can hold any kind of object. + /// </summary> + /// <typeparam name="T">The type of this event.</typeparam> + public class GenericEventArgs<T> : EventArgs + { + /// <summary> + /// Initializes a new instance of the <see cref="GenericEventArgs{T}"/> class. + /// </summary> + /// <param name="arg">The argument.</param> + public GenericEventArgs(T arg) + { + Argument = arg; + } + + /// <summary> + /// Gets the argument. + /// </summary> + /// <value>The argument.</value> + public T Argument { get; } + } +} diff --git a/Jellyfin.Server.Implementations/Activity/ActivityManager.cs b/Jellyfin.Server.Implementations/Activity/ActivityManager.cs index 2deefbe81..09f2611e4 100644 --- a/Jellyfin.Server.Implementations/Activity/ActivityManager.cs +++ b/Jellyfin.Server.Implementations/Activity/ActivityManager.cs @@ -2,8 +2,8 @@ using System; using System.Linq; using System.Threading.Tasks; using Jellyfin.Data.Entities; +using Jellyfin.Data.Events; using MediaBrowser.Model.Activity; -using MediaBrowser.Model.Events; using MediaBrowser.Model.Querying; namespace Jellyfin.Server.Implementations.Activity diff --git a/Jellyfin.Server.Implementations/Users/DeviceAccessEntryPoint.cs b/Jellyfin.Server.Implementations/Users/DeviceAccessEntryPoint.cs index 140853e52..1fb89c4a6 100644 --- a/Jellyfin.Server.Implementations/Users/DeviceAccessEntryPoint.cs +++ b/Jellyfin.Server.Implementations/Users/DeviceAccessEntryPoint.cs @@ -4,12 +4,12 @@ using System.Threading.Tasks; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Data.Events; using MediaBrowser.Controller.Devices; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Plugins; using MediaBrowser.Controller.Security; using MediaBrowser.Controller.Session; -using MediaBrowser.Model.Events; namespace Jellyfin.Server.Implementations.Users { diff --git a/Jellyfin.Server.Implementations/Users/UserManager.cs b/Jellyfin.Server.Implementations/Users/UserManager.cs index 11402ee05..267c1c103 100644 --- a/Jellyfin.Server.Implementations/Users/UserManager.cs +++ b/Jellyfin.Server.Implementations/Users/UserManager.cs @@ -10,6 +10,7 @@ using System.Text.RegularExpressions; using System.Threading.Tasks; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Data.Events; using MediaBrowser.Common; using MediaBrowser.Common.Cryptography; using MediaBrowser.Common.Extensions; @@ -21,7 +22,6 @@ using MediaBrowser.Controller.Net; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Cryptography; using MediaBrowser.Model.Dto; -using MediaBrowser.Model.Events; using MediaBrowser.Model.Users; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; diff --git a/MediaBrowser.Controller/Devices/IDeviceManager.cs b/MediaBrowser.Controller/Devices/IDeviceManager.cs index 7d279230b..a038d84d8 100644 --- a/MediaBrowser.Controller/Devices/IDeviceManager.cs +++ b/MediaBrowser.Controller/Devices/IDeviceManager.cs @@ -1,7 +1,7 @@ using System; using Jellyfin.Data.Entities; +using Jellyfin.Data.Events; using MediaBrowser.Model.Devices; -using MediaBrowser.Model.Events; using MediaBrowser.Model.Querying; using MediaBrowser.Model.Session; diff --git a/MediaBrowser.Controller/Library/IUserManager.cs b/MediaBrowser.Controller/Library/IUserManager.cs index 6685861a9..c8d8375b3 100644 --- a/MediaBrowser.Controller/Library/IUserManager.cs +++ b/MediaBrowser.Controller/Library/IUserManager.cs @@ -2,9 +2,9 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; using Jellyfin.Data.Entities; +using Jellyfin.Data.Events; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Dto; -using MediaBrowser.Model.Events; using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.Library diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs index f619b011b..d6f629a1b 100644 --- a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs +++ b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs @@ -3,11 +3,11 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using Jellyfin.Data.Entities; +using Jellyfin.Data.Events; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Model.Dto; -using MediaBrowser.Model.Events; using MediaBrowser.Model.LiveTv; using MediaBrowser.Model.Querying; diff --git a/MediaBrowser.Controller/Net/IHttpServer.cs b/MediaBrowser.Controller/Net/IHttpServer.cs index e6609fae3..b04ebda8c 100644 --- a/MediaBrowser.Controller/Net/IHttpServer.cs +++ b/MediaBrowser.Controller/Net/IHttpServer.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; -using MediaBrowser.Model.Events; +using Jellyfin.Data.Events; using MediaBrowser.Model.Services; using Microsoft.AspNetCore.Http; diff --git a/MediaBrowser.Controller/Providers/IProviderManager.cs b/MediaBrowser.Controller/Providers/IProviderManager.cs index 955db0278..ef744ee3c 100644 --- a/MediaBrowser.Controller/Providers/IProviderManager.cs +++ b/MediaBrowser.Controller/Providers/IProviderManager.cs @@ -4,12 +4,12 @@ using System.IO; using System.Threading; using System.Threading.Tasks; using Jellyfin.Data.Entities; +using Jellyfin.Data.Events; using MediaBrowser.Common.Net; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Entities; -using MediaBrowser.Model.Events; using MediaBrowser.Model.Providers; namespace MediaBrowser.Controller.Providers diff --git a/MediaBrowser.Controller/Session/ISessionManager.cs b/MediaBrowser.Controller/Session/ISessionManager.cs index e54f21050..d461a9281 100644 --- a/MediaBrowser.Controller/Session/ISessionManager.cs +++ b/MediaBrowser.Controller/Session/ISessionManager.cs @@ -2,11 +2,11 @@ using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; +using Jellyfin.Data.Events; using MediaBrowser.Controller.Authentication; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Security; using MediaBrowser.Model.Dto; -using MediaBrowser.Model.Events; using MediaBrowser.Model.Session; using MediaBrowser.Model.SyncPlay; diff --git a/MediaBrowser.Model/Activity/IActivityManager.cs b/MediaBrowser.Model/Activity/IActivityManager.cs index 9dab5e77b..2362f7e92 100644 --- a/MediaBrowser.Model/Activity/IActivityManager.cs +++ b/MediaBrowser.Model/Activity/IActivityManager.cs @@ -4,7 +4,7 @@ using System; using System.Linq; using System.Threading.Tasks; using Jellyfin.Data.Entities; -using MediaBrowser.Model.Events; +using Jellyfin.Data.Events; using MediaBrowser.Model.Querying; namespace MediaBrowser.Model.Activity diff --git a/MediaBrowser.Model/Dlna/IDeviceDiscovery.cs b/MediaBrowser.Model/Dlna/IDeviceDiscovery.cs index 76c9a4b04..05209e53d 100644 --- a/MediaBrowser.Model/Dlna/IDeviceDiscovery.cs +++ b/MediaBrowser.Model/Dlna/IDeviceDiscovery.cs @@ -1,7 +1,7 @@ #pragma warning disable CS1591 using System; -using MediaBrowser.Model.Events; +using Jellyfin.Data.Events; namespace MediaBrowser.Model.Dlna { diff --git a/MediaBrowser.Model/Events/GenericEventArgs.cs b/MediaBrowser.Model/Events/GenericEventArgs.cs deleted file mode 100644 index 347ea2281..000000000 --- a/MediaBrowser.Model/Events/GenericEventArgs.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System; - -namespace MediaBrowser.Model.Events -{ - /// <summary> - /// Provides a generic EventArgs subclass that can hold any kind of object. - /// </summary> - /// <typeparam name="T">The type of this event.</typeparam> - public class GenericEventArgs<T> : EventArgs - { - /// <summary> - /// Initializes a new instance of the <see cref="GenericEventArgs{T}"/> class. - /// </summary> - /// <param name="arg">The argument.</param> - public GenericEventArgs(T arg) - { - Argument = arg; - } - - /// <summary> - /// Gets the argument. - /// </summary> - /// <value>The argument.</value> - public T Argument { get; } - } -} diff --git a/MediaBrowser.Model/Tasks/IScheduledTaskWorker.cs b/MediaBrowser.Model/Tasks/IScheduledTaskWorker.cs index b08acba2c..2f05e08c5 100644 --- a/MediaBrowser.Model/Tasks/IScheduledTaskWorker.cs +++ b/MediaBrowser.Model/Tasks/IScheduledTaskWorker.cs @@ -1,6 +1,6 @@ #nullable disable using System; -using MediaBrowser.Model.Events; +using Jellyfin.Data.Events; namespace MediaBrowser.Model.Tasks { diff --git a/MediaBrowser.Model/Tasks/ITaskManager.cs b/MediaBrowser.Model/Tasks/ITaskManager.cs index 363773ff7..02b29074e 100644 --- a/MediaBrowser.Model/Tasks/ITaskManager.cs +++ b/MediaBrowser.Model/Tasks/ITaskManager.cs @@ -3,7 +3,7 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; -using MediaBrowser.Model.Events; +using Jellyfin.Data.Events; namespace MediaBrowser.Model.Tasks { diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs index bbd7166e6..9f63c6046 100644 --- a/MediaBrowser.Providers/Manager/ProviderManager.cs +++ b/MediaBrowser.Providers/Manager/ProviderManager.cs @@ -9,6 +9,7 @@ using System.Net.Mime; using System.Threading; using System.Threading.Tasks; using Jellyfin.Data.Entities; +using Jellyfin.Data.Events; using MediaBrowser.Common.Net; using MediaBrowser.Common.Progress; using MediaBrowser.Controller; @@ -22,7 +23,6 @@ using MediaBrowser.Controller.Providers; using MediaBrowser.Controller.Subtitles; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Entities; -using MediaBrowser.Model.Events; using MediaBrowser.Model.IO; using MediaBrowser.Model.Net; using MediaBrowser.Model.Providers; -- cgit v1.2.3 From b7f21971f43d6d9f956ff0aade31625d3995858a Mon Sep 17 00:00:00 2001 From: Patrick Barron <barronpm@gmail.com> Date: Fri, 14 Aug 2020 15:21:17 -0400 Subject: Migrate ActivityLogEntryPoint.OnPluginInstalled to IEventConsumer --- .../Activity/ActivityLogEntryPoint.cs | 19 -------- .../Consumers/Updates/PluginInstalledLogger.cs | 50 ++++++++++++++++++++++ .../Events/Updates/PluginInstalledEventArgs.cs | 19 ++++++++ 3 files changed, 69 insertions(+), 19 deletions(-) create mode 100644 Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginInstalledLogger.cs create mode 100644 MediaBrowser.Controller/Events/Updates/PluginInstalledEventArgs.cs (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs b/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs index 40fc7d890..600c1d3ea 100644 --- a/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs +++ b/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs @@ -45,7 +45,6 @@ namespace Emby.Server.Implementations.Activity /// <inheritdoc /> public Task RunAsync() { - _installationManager.PluginInstalled += OnPluginInstalled; _installationManager.PluginUninstalled += OnPluginUninstalled; _installationManager.PluginUpdated += OnPluginUpdated; _installationManager.PackageInstallationFailed += OnPackageInstallationFailed; @@ -136,23 +135,6 @@ namespace Emby.Server.Implementations.Activity .ConfigureAwait(false); } - private async void OnPluginInstalled(object sender, InstallationInfo e) - { - await CreateLogEntry(new ActivityLog( - string.Format( - CultureInfo.InvariantCulture, - _localization.GetLocalizedString("PluginInstalledWithName"), - e.Name), - NotificationType.PluginInstalled.ToString(), - Guid.Empty) - { - ShortOverview = string.Format( - CultureInfo.InvariantCulture, - _localization.GetLocalizedString("VersionNumber"), - e.Version) - }).ConfigureAwait(false); - } - private async void OnPackageInstallationFailed(object sender, InstallationFailedEventArgs e) { var installationInfo = e.InstallationInfo; @@ -179,7 +161,6 @@ namespace Emby.Server.Implementations.Activity /// <inheritdoc /> public void Dispose() { - _installationManager.PluginInstalled -= OnPluginInstalled; _installationManager.PluginUninstalled -= OnPluginUninstalled; _installationManager.PluginUpdated -= OnPluginUpdated; _installationManager.PackageInstallationFailed -= OnPackageInstallationFailed; diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginInstalledLogger.cs b/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginInstalledLogger.cs new file mode 100644 index 000000000..8837172db --- /dev/null +++ b/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginInstalledLogger.cs @@ -0,0 +1,50 @@ +using System; +using System.Globalization; +using System.Threading.Tasks; +using Jellyfin.Data.Entities; +using MediaBrowser.Controller.Events; +using MediaBrowser.Controller.Events.Updates; +using MediaBrowser.Model.Activity; +using MediaBrowser.Model.Globalization; +using MediaBrowser.Model.Notifications; + +namespace Jellyfin.Server.Implementations.Events.Consumers.Updates +{ + /// <summary> + /// Creates an entry in the activity log when a plugin is installed. + /// </summary> + public class PluginInstalledLogger : IEventConsumer<PluginInstalledEventArgs> + { + private readonly ILocalizationManager _localizationManager; + private readonly IActivityManager _activityManager; + + /// <summary> + /// Initializes a new instance of the <see cref="PluginInstalledLogger"/> class. + /// </summary> + /// <param name="localizationManager">The localization manager.</param> + /// <param name="activityManager">The activity manager.</param> + public PluginInstalledLogger(ILocalizationManager localizationManager, IActivityManager activityManager) + { + _localizationManager = localizationManager; + _activityManager = activityManager; + } + + /// <inheritdoc /> + public async Task OnEvent(PluginInstalledEventArgs eventArgs) + { + await _activityManager.CreateAsync(new ActivityLog( + string.Format( + CultureInfo.InvariantCulture, + _localizationManager.GetLocalizedString("PluginInstalledWithName"), + eventArgs.Argument.Name), + NotificationType.PluginInstalled.ToString(), + Guid.Empty) + { + ShortOverview = string.Format( + CultureInfo.InvariantCulture, + _localizationManager.GetLocalizedString("VersionNumber"), + eventArgs.Argument.Version) + }).ConfigureAwait(false); + } + } +} diff --git a/MediaBrowser.Controller/Events/Updates/PluginInstalledEventArgs.cs b/MediaBrowser.Controller/Events/Updates/PluginInstalledEventArgs.cs new file mode 100644 index 000000000..dfadc9f61 --- /dev/null +++ b/MediaBrowser.Controller/Events/Updates/PluginInstalledEventArgs.cs @@ -0,0 +1,19 @@ +using Jellyfin.Data.Events; +using MediaBrowser.Model.Updates; + +namespace MediaBrowser.Controller.Events.Updates +{ + /// <summary> + /// An event that occurs when a plugin is installed. + /// </summary> + public class PluginInstalledEventArgs : GenericEventArgs<InstallationInfo> + { + /// <summary> + /// Initializes a new instance of the <see cref="PluginInstalledEventArgs"/> class. + /// </summary> + /// <param name="arg">The installation info.</param> + public PluginInstalledEventArgs(InstallationInfo arg) : base(arg) + { + } + } +} -- cgit v1.2.3 From 0da7c0568d61e834b8b11693ed79eee2855d4ae6 Mon Sep 17 00:00:00 2001 From: Patrick Barron <barronpm@gmail.com> Date: Fri, 14 Aug 2020 15:22:12 -0400 Subject: Migrate ActivityLogEntryPoint.OnPluginUninstalled to IEventConsumer --- .../Activity/ActivityLogEntryPoint.cs | 15 -------- .../Consumers/Updates/PluginUninstalledLogger.cs | 45 ++++++++++++++++++++++ .../Events/Updates/PluginUninstalledEventArgs.cs | 19 +++++++++ 3 files changed, 64 insertions(+), 15 deletions(-) create mode 100644 Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginUninstalledLogger.cs create mode 100644 MediaBrowser.Controller/Events/Updates/PluginUninstalledEventArgs.cs (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs b/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs index 600c1d3ea..ba0bf9ea2 100644 --- a/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs +++ b/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs @@ -2,7 +2,6 @@ using System; using System.Globalization; using System.Threading.Tasks; using Jellyfin.Data.Entities; -using MediaBrowser.Common.Plugins; using MediaBrowser.Common.Updates; using MediaBrowser.Controller.Plugins; using MediaBrowser.Controller.Session; @@ -45,7 +44,6 @@ namespace Emby.Server.Implementations.Activity /// <inheritdoc /> public Task RunAsync() { - _installationManager.PluginUninstalled += OnPluginUninstalled; _installationManager.PluginUpdated += OnPluginUpdated; _installationManager.PackageInstallationFailed += OnPackageInstallationFailed; @@ -123,18 +121,6 @@ namespace Emby.Server.Implementations.Activity }).ConfigureAwait(false); } - private async void OnPluginUninstalled(object sender, IPlugin e) - { - await CreateLogEntry(new ActivityLog( - string.Format( - CultureInfo.InvariantCulture, - _localization.GetLocalizedString("PluginUninstalledWithName"), - e.Name), - NotificationType.PluginUninstalled.ToString(), - Guid.Empty)) - .ConfigureAwait(false); - } - private async void OnPackageInstallationFailed(object sender, InstallationFailedEventArgs e) { var installationInfo = e.InstallationInfo; @@ -161,7 +147,6 @@ namespace Emby.Server.Implementations.Activity /// <inheritdoc /> public void Dispose() { - _installationManager.PluginUninstalled -= OnPluginUninstalled; _installationManager.PluginUpdated -= OnPluginUpdated; _installationManager.PackageInstallationFailed -= OnPackageInstallationFailed; diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginUninstalledLogger.cs b/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginUninstalledLogger.cs new file mode 100644 index 000000000..91a30069e --- /dev/null +++ b/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginUninstalledLogger.cs @@ -0,0 +1,45 @@ +using System; +using System.Globalization; +using System.Threading.Tasks; +using Jellyfin.Data.Entities; +using MediaBrowser.Controller.Events; +using MediaBrowser.Controller.Events.Updates; +using MediaBrowser.Model.Activity; +using MediaBrowser.Model.Globalization; +using MediaBrowser.Model.Notifications; + +namespace Jellyfin.Server.Implementations.Events.Consumers.Updates +{ + /// <summary> + /// Creates an entry in the activity log when a plugin is uninstalled. + /// </summary> + public class PluginUninstalledLogger : IEventConsumer<PluginUninstalledEventArgs> + { + private readonly ILocalizationManager _localizationManager; + private readonly IActivityManager _activityManager; + + /// <summary> + /// Initializes a new instance of the <see cref="PluginUninstalledLogger"/> class. + /// </summary> + /// <param name="localizationManager">The localization manager.</param> + /// <param name="activityManager">The activity manager.</param> + public PluginUninstalledLogger(ILocalizationManager localizationManager, IActivityManager activityManager) + { + _localizationManager = localizationManager; + _activityManager = activityManager; + } + + /// <inheritdoc /> + public async Task OnEvent(PluginUninstalledEventArgs e) + { + await _activityManager.CreateAsync(new ActivityLog( + string.Format( + CultureInfo.InvariantCulture, + _localizationManager.GetLocalizedString("PluginUninstalledWithName"), + e.Argument.Name), + NotificationType.PluginUninstalled.ToString(), + Guid.Empty)) + .ConfigureAwait(false); + } + } +} diff --git a/MediaBrowser.Controller/Events/Updates/PluginUninstalledEventArgs.cs b/MediaBrowser.Controller/Events/Updates/PluginUninstalledEventArgs.cs new file mode 100644 index 000000000..7510b62b8 --- /dev/null +++ b/MediaBrowser.Controller/Events/Updates/PluginUninstalledEventArgs.cs @@ -0,0 +1,19 @@ +using Jellyfin.Data.Events; +using MediaBrowser.Common.Plugins; + +namespace MediaBrowser.Controller.Events.Updates +{ + /// <summary> + /// An event that occurs when a plugin is uninstalled. + /// </summary> + public class PluginUninstalledEventArgs : GenericEventArgs<IPlugin> + { + /// <summary> + /// Initializes a new instance of the <see cref="PluginUninstalledEventArgs"/> class. + /// </summary> + /// <param name="arg">The plugin.</param> + public PluginUninstalledEventArgs(IPlugin arg) : base(arg) + { + } + } +} -- cgit v1.2.3 From e9244448809cb4251b341832c8fdfecde5f169ab Mon Sep 17 00:00:00 2001 From: Patrick Barron <barronpm@gmail.com> Date: Fri, 14 Aug 2020 15:50:17 -0400 Subject: Migrate ActivityLogEntryPoint.OnPluginUpdated to IEventConsumer --- .../Activity/ActivityLogEntryPoint.cs | 21 --------- .../Consumers/Updates/PluginUpdatedLogger.cs | 51 ++++++++++++++++++++++ .../Events/Updates/PluginUpdatedEventArgs.cs | 19 ++++++++ 3 files changed, 70 insertions(+), 21 deletions(-) create mode 100644 Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginUpdatedLogger.cs create mode 100644 MediaBrowser.Controller/Events/Updates/PluginUpdatedEventArgs.cs (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs b/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs index ba0bf9ea2..ee058fd46 100644 --- a/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs +++ b/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs @@ -8,7 +8,6 @@ using MediaBrowser.Controller.Session; using MediaBrowser.Model.Activity; using MediaBrowser.Model.Globalization; using MediaBrowser.Model.Notifications; -using MediaBrowser.Model.Updates; namespace Emby.Server.Implementations.Activity { @@ -44,7 +43,6 @@ namespace Emby.Server.Implementations.Activity /// <inheritdoc /> public Task RunAsync() { - _installationManager.PluginUpdated += OnPluginUpdated; _installationManager.PackageInstallationFailed += OnPackageInstallationFailed; _sessionManager.SessionStarted += OnSessionStarted; @@ -103,24 +101,6 @@ namespace Emby.Server.Implementations.Activity }).ConfigureAwait(false); } - private async void OnPluginUpdated(object sender, InstallationInfo e) - { - await CreateLogEntry(new ActivityLog( - string.Format( - CultureInfo.InvariantCulture, - _localization.GetLocalizedString("PluginUpdatedWithName"), - e.Name), - NotificationType.PluginUpdateInstalled.ToString(), - Guid.Empty) - { - ShortOverview = string.Format( - CultureInfo.InvariantCulture, - _localization.GetLocalizedString("VersionNumber"), - e.Version), - Overview = e.Changelog - }).ConfigureAwait(false); - } - private async void OnPackageInstallationFailed(object sender, InstallationFailedEventArgs e) { var installationInfo = e.InstallationInfo; @@ -147,7 +127,6 @@ namespace Emby.Server.Implementations.Activity /// <inheritdoc /> public void Dispose() { - _installationManager.PluginUpdated -= OnPluginUpdated; _installationManager.PackageInstallationFailed -= OnPackageInstallationFailed; _sessionManager.SessionStarted -= OnSessionStarted; diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginUpdatedLogger.cs b/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginUpdatedLogger.cs new file mode 100644 index 000000000..9ce16f774 --- /dev/null +++ b/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginUpdatedLogger.cs @@ -0,0 +1,51 @@ +using System; +using System.Globalization; +using System.Threading.Tasks; +using Jellyfin.Data.Entities; +using MediaBrowser.Controller.Events; +using MediaBrowser.Controller.Events.Updates; +using MediaBrowser.Model.Activity; +using MediaBrowser.Model.Globalization; +using MediaBrowser.Model.Notifications; + +namespace Jellyfin.Server.Implementations.Events.Consumers.Updates +{ + /// <summary> + /// Creates an entry in the activity log when a plugin is updated. + /// </summary> + public class PluginUpdatedLogger : IEventConsumer<PluginUpdatedEventArgs> + { + private readonly ILocalizationManager _localizationManager; + private readonly IActivityManager _activityManager; + + /// <summary> + /// Initializes a new instance of the <see cref="PluginUpdatedLogger"/> class. + /// </summary> + /// <param name="localizationManager">The localization manager.</param> + /// <param name="activityManager">The activity manager.</param> + public PluginUpdatedLogger(ILocalizationManager localizationManager, IActivityManager activityManager) + { + _localizationManager = localizationManager; + _activityManager = activityManager; + } + + /// <inheritdoc /> + public async Task OnEvent(PluginUpdatedEventArgs eventArgs) + { + await _activityManager.CreateAsync(new ActivityLog( + string.Format( + CultureInfo.InvariantCulture, + _localizationManager.GetLocalizedString("PluginUpdatedWithName"), + eventArgs.Argument.Name), + NotificationType.PluginUpdateInstalled.ToString(), + Guid.Empty) + { + ShortOverview = string.Format( + CultureInfo.InvariantCulture, + _localizationManager.GetLocalizedString("VersionNumber"), + eventArgs.Argument.Version), + Overview = eventArgs.Argument.Changelog + }).ConfigureAwait(false); + } + } +} diff --git a/MediaBrowser.Controller/Events/Updates/PluginUpdatedEventArgs.cs b/MediaBrowser.Controller/Events/Updates/PluginUpdatedEventArgs.cs new file mode 100644 index 000000000..661ca066a --- /dev/null +++ b/MediaBrowser.Controller/Events/Updates/PluginUpdatedEventArgs.cs @@ -0,0 +1,19 @@ +using Jellyfin.Data.Events; +using MediaBrowser.Model.Updates; + +namespace MediaBrowser.Controller.Events.Updates +{ + /// <summary> + /// An event that occurs when a plugin is updated. + /// </summary> + public class PluginUpdatedEventArgs : GenericEventArgs<InstallationInfo> + { + /// <summary> + /// Initializes a new instance of the <see cref="PluginUpdatedEventArgs"/> class. + /// </summary> + /// <param name="arg">The installation info.</param> + public PluginUpdatedEventArgs(InstallationInfo arg) : base(arg) + { + } + } +} -- cgit v1.2.3 From ca3a8bdb98aeb5d112a4d2a456ebcc445dc5fd12 Mon Sep 17 00:00:00 2001 From: Patrick Barron <barronpm@gmail.com> Date: Sat, 15 Aug 2020 02:02:58 -0400 Subject: Migrate ActivityLogEntryPoint.OnSessionStarted to IEventConsumer --- .../Activity/ActivityLogEntryPoint.cs | 27 ----------- .../Consumers/Session/SessionStartedLogger.cs | 54 ++++++++++++++++++++++ .../Events/Session/SessionStartedEventArgs.cs | 19 ++++++++ 3 files changed, 73 insertions(+), 27 deletions(-) create mode 100644 Jellyfin.Server.Implementations/Events/Consumers/Session/SessionStartedLogger.cs create mode 100644 MediaBrowser.Controller/Events/Session/SessionStartedEventArgs.cs (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs b/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs index 00a14fb0b..d863acd0b 100644 --- a/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs +++ b/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs @@ -36,7 +36,6 @@ namespace Emby.Server.Implementations.Activity /// <inheritdoc /> public Task RunAsync() { - _sessionManager.SessionStarted += OnSessionStarted; _sessionManager.SessionEnded += OnSessionEnded; return Task.CompletedTask; @@ -67,38 +66,12 @@ namespace Emby.Server.Implementations.Activity }).ConfigureAwait(false); } - private async void OnSessionStarted(object sender, SessionEventArgs e) - { - var session = e.SessionInfo; - - if (string.IsNullOrEmpty(session.UserName)) - { - return; - } - - await CreateLogEntry(new ActivityLog( - string.Format( - CultureInfo.InvariantCulture, - _localization.GetLocalizedString("UserOnlineFromDevice"), - session.UserName, - session.DeviceName), - "SessionStarted", - session.UserId) - { - ShortOverview = string.Format( - CultureInfo.InvariantCulture, - _localization.GetLocalizedString("LabelIpAddressValue"), - session.RemoteEndPoint) - }).ConfigureAwait(false); - } - private async Task CreateLogEntry(ActivityLog entry) => await _activityManager.CreateAsync(entry).ConfigureAwait(false); /// <inheritdoc /> public void Dispose() { - _sessionManager.SessionStarted -= OnSessionStarted; _sessionManager.SessionEnded -= OnSessionEnded; } } diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Session/SessionStartedLogger.cs b/Jellyfin.Server.Implementations/Events/Consumers/Session/SessionStartedLogger.cs new file mode 100644 index 000000000..6a0f29b09 --- /dev/null +++ b/Jellyfin.Server.Implementations/Events/Consumers/Session/SessionStartedLogger.cs @@ -0,0 +1,54 @@ +using System.Globalization; +using System.Threading.Tasks; +using Jellyfin.Data.Entities; +using MediaBrowser.Controller.Events; +using MediaBrowser.Controller.Events.Session; +using MediaBrowser.Model.Activity; +using MediaBrowser.Model.Globalization; + +namespace Jellyfin.Server.Implementations.Events.Consumers.Session +{ + /// <summary> + /// Creates an entry in the activity log when a session is started. + /// </summary> + public class SessionStartedLogger : IEventConsumer<SessionStartedEventArgs> + { + private readonly ILocalizationManager _localizationManager; + private readonly IActivityManager _activityManager; + + /// <summary> + /// Initializes a new instance of the <see cref="SessionStartedLogger"/> class. + /// </summary> + /// <param name="localizationManager">The localization manager.</param> + /// <param name="activityManager">The activity manager.</param> + public SessionStartedLogger(ILocalizationManager localizationManager, IActivityManager activityManager) + { + _localizationManager = localizationManager; + _activityManager = activityManager; + } + + /// <inheritdoc /> + public async Task OnEvent(SessionStartedEventArgs eventArgs) + { + if (string.IsNullOrEmpty(eventArgs.Argument.UserName)) + { + return; + } + + await _activityManager.CreateAsync(new ActivityLog( + string.Format( + CultureInfo.InvariantCulture, + _localizationManager.GetLocalizedString("UserOnlineFromDevice"), + eventArgs.Argument.UserName, + eventArgs.Argument.DeviceName), + "SessionStarted", + eventArgs.Argument.UserId) + { + ShortOverview = string.Format( + CultureInfo.InvariantCulture, + _localizationManager.GetLocalizedString("LabelIpAddressValue"), + eventArgs.Argument.RemoteEndPoint) + }).ConfigureAwait(false); + } + } +} diff --git a/MediaBrowser.Controller/Events/Session/SessionStartedEventArgs.cs b/MediaBrowser.Controller/Events/Session/SessionStartedEventArgs.cs new file mode 100644 index 000000000..aab19cc46 --- /dev/null +++ b/MediaBrowser.Controller/Events/Session/SessionStartedEventArgs.cs @@ -0,0 +1,19 @@ +using Jellyfin.Data.Events; +using MediaBrowser.Controller.Session; + +namespace MediaBrowser.Controller.Events.Session +{ + /// <summary> + /// An event that fires when a session is started. + /// </summary> + public class SessionStartedEventArgs : GenericEventArgs<SessionInfo> + { + /// <summary> + /// Initializes a new instance of the <see cref="SessionStartedEventArgs"/> class. + /// </summary> + /// <param name="arg">The session info.</param> + public SessionStartedEventArgs(SessionInfo arg) : base(arg) + { + } + } +} -- cgit v1.2.3 From 8570cfdba652eb61e2746ea9de6cb9c8bb23eaf5 Mon Sep 17 00:00:00 2001 From: Patrick Barron <barronpm@gmail.com> Date: Sat, 15 Aug 2020 02:07:28 -0400 Subject: Migrate ActivityLogEntryPoint.OnSessionEnded to IEventConsumer --- .../Activity/ActivityLogEntryPoint.cs | 78 ---------------------- .../Consumers/Session/SessionManagerEndedLogger.cs | 54 +++++++++++++++ .../Events/Session/SessionEndedEventArgs.cs | 19 ++++++ 3 files changed, 73 insertions(+), 78 deletions(-) delete mode 100644 Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs create mode 100644 Jellyfin.Server.Implementations/Events/Consumers/Session/SessionManagerEndedLogger.cs create mode 100644 MediaBrowser.Controller/Events/Session/SessionEndedEventArgs.cs (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs b/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs deleted file mode 100644 index d863acd0b..000000000 --- a/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs +++ /dev/null @@ -1,78 +0,0 @@ -using System.Globalization; -using System.Threading.Tasks; -using Jellyfin.Data.Entities; -using MediaBrowser.Controller.Plugins; -using MediaBrowser.Controller.Session; -using MediaBrowser.Model.Activity; -using MediaBrowser.Model.Globalization; - -namespace Emby.Server.Implementations.Activity -{ - /// <summary> - /// Entry point for the activity logger. - /// </summary> - public sealed class ActivityLogEntryPoint : IServerEntryPoint - { - private readonly ISessionManager _sessionManager; - private readonly IActivityManager _activityManager; - private readonly ILocalizationManager _localization; - - /// <summary> - /// Initializes a new instance of the <see cref="ActivityLogEntryPoint"/> class. - /// </summary> - /// <param name="sessionManager">The session manager.</param> - /// <param name="activityManager">The activity manager.</param> - /// <param name="localization">The localization manager.</param> - public ActivityLogEntryPoint( - ISessionManager sessionManager, - IActivityManager activityManager, - ILocalizationManager localization) - { - _sessionManager = sessionManager; - _activityManager = activityManager; - _localization = localization; - } - - /// <inheritdoc /> - public Task RunAsync() - { - _sessionManager.SessionEnded += OnSessionEnded; - - return Task.CompletedTask; - } - - private async void OnSessionEnded(object sender, SessionEventArgs e) - { - var session = e.SessionInfo; - - if (string.IsNullOrEmpty(session.UserName)) - { - return; - } - - await CreateLogEntry(new ActivityLog( - string.Format( - CultureInfo.InvariantCulture, - _localization.GetLocalizedString("UserOfflineFromDevice"), - session.UserName, - session.DeviceName), - "SessionEnded", - session.UserId) - { - ShortOverview = string.Format( - CultureInfo.InvariantCulture, - _localization.GetLocalizedString("LabelIpAddressValue"), - session.RemoteEndPoint), - }).ConfigureAwait(false); - } - - private async Task CreateLogEntry(ActivityLog entry) - => await _activityManager.CreateAsync(entry).ConfigureAwait(false); - - /// <inheritdoc /> - public void Dispose() - { - _sessionManager.SessionEnded -= OnSessionEnded; - } - } -} diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Session/SessionManagerEndedLogger.cs b/Jellyfin.Server.Implementations/Events/Consumers/Session/SessionManagerEndedLogger.cs new file mode 100644 index 000000000..1162fe89b --- /dev/null +++ b/Jellyfin.Server.Implementations/Events/Consumers/Session/SessionManagerEndedLogger.cs @@ -0,0 +1,54 @@ +using System.Globalization; +using System.Threading.Tasks; +using Jellyfin.Data.Entities; +using MediaBrowser.Controller.Events; +using MediaBrowser.Controller.Events.Session; +using MediaBrowser.Model.Activity; +using MediaBrowser.Model.Globalization; + +namespace Jellyfin.Server.Implementations.Events.Consumers.Session +{ + /// <summary> + /// Creates an entry in the activity log whenever a session ends. + /// </summary> + public class SessionManagerEndedLogger : IEventConsumer<SessionEndedEventArgs> + { + private readonly ILocalizationManager _localizationManager; + private readonly IActivityManager _activityManager; + + /// <summary> + /// Initializes a new instance of the <see cref="SessionManagerEndedLogger"/> class. + /// </summary> + /// <param name="localizationManager">The localization manager.</param> + /// <param name="activityManager">The activity manager.</param> + public SessionManagerEndedLogger(ILocalizationManager localizationManager, IActivityManager activityManager) + { + _localizationManager = localizationManager; + _activityManager = activityManager; + } + + /// <inheritdoc /> + public async Task OnEvent(SessionEndedEventArgs eventArgs) + { + if (string.IsNullOrEmpty(eventArgs.Argument.UserName)) + { + return; + } + + await _activityManager.CreateAsync(new ActivityLog( + string.Format( + CultureInfo.InvariantCulture, + _localizationManager.GetLocalizedString("UserOfflineFromDevice"), + eventArgs.Argument.UserName, + eventArgs.Argument.DeviceName), + "SessionEnded", + eventArgs.Argument.UserId) + { + ShortOverview = string.Format( + CultureInfo.InvariantCulture, + _localizationManager.GetLocalizedString("LabelIpAddressValue"), + eventArgs.Argument.RemoteEndPoint), + }).ConfigureAwait(false); + } + } +} diff --git a/MediaBrowser.Controller/Events/Session/SessionEndedEventArgs.cs b/MediaBrowser.Controller/Events/Session/SessionEndedEventArgs.cs new file mode 100644 index 000000000..46d7e5a17 --- /dev/null +++ b/MediaBrowser.Controller/Events/Session/SessionEndedEventArgs.cs @@ -0,0 +1,19 @@ +using Jellyfin.Data.Events; +using MediaBrowser.Controller.Session; + +namespace MediaBrowser.Controller.Events.Session +{ + /// <summary> + /// An event that fires when a session is ended. + /// </summary> + public class SessionEndedEventArgs : GenericEventArgs<SessionInfo> + { + /// <summary> + /// Initializes a new instance of the <see cref="SessionEndedEventArgs"/> class. + /// </summary> + /// <param name="arg">The session info.</param> + public SessionEndedEventArgs(SessionInfo arg) : base(arg) + { + } + } +} -- cgit v1.2.3 From 396148599a2fa6d908580e7ff214d4036351f92d Mon Sep 17 00:00:00 2001 From: Orry Verducci <orry@orryverducci.co.uk> Date: Sat, 15 Aug 2020 12:55:58 +0100 Subject: Fix indentation in deinterlace if block Co-authored-by: Claus Vium <cvium@users.noreply.github.com> --- MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 84a6a461f..5067f6aab 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -2147,9 +2147,9 @@ namespace MediaBrowser.Controller.MediaEncoding // Add software deinterlace filter before scaling filter if ((state.DeInterlace("h264", true) - || state.DeInterlace("avc", true) - || state.DeInterlace("h265", true) - || state.DeInterlace("hevc", true)) + || state.DeInterlace("avc", true) + || state.DeInterlace("h265", true) + || state.DeInterlace("hevc", true)) && !isVaapiH264Encoder && !isQsvH264Encoder && !isNvdecH264Decoder) -- cgit v1.2.3 From 816c80525a64fcac441f44f1d508028070fdc21d Mon Sep 17 00:00:00 2001 From: Patrick Barron <barronpm@gmail.com> Date: Sat, 15 Aug 2020 15:55:15 -0400 Subject: Use IEventManager in UserManager --- .../Users/UserManager.cs | 29 +++++++++------------- MediaBrowser.Controller/Events/IEventManager.cs | 10 +++++++- MediaBrowser.Controller/Library/IUserManager.cs | 20 --------------- 3 files changed, 21 insertions(+), 38 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Jellyfin.Server.Implementations/Users/UserManager.cs b/Jellyfin.Server.Implementations/Users/UserManager.cs index 267c1c103..3e8edeb44 100644 --- a/Jellyfin.Server.Implementations/Users/UserManager.cs +++ b/Jellyfin.Server.Implementations/Users/UserManager.cs @@ -11,12 +11,14 @@ using System.Threading.Tasks; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; using Jellyfin.Data.Events; +using Jellyfin.Data.Events.Users; using MediaBrowser.Common; using MediaBrowser.Common.Cryptography; using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Net; using MediaBrowser.Controller.Authentication; using MediaBrowser.Controller.Drawing; +using MediaBrowser.Controller.Events; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Net; using MediaBrowser.Model.Configuration; @@ -34,6 +36,7 @@ namespace Jellyfin.Server.Implementations.Users public class UserManager : IUserManager { private readonly JellyfinDbProvider _dbProvider; + private readonly IEventManager _eventManager; private readonly ICryptoProvider _cryptoProvider; private readonly INetworkManager _networkManager; private readonly IApplicationHost _appHost; @@ -49,6 +52,7 @@ namespace Jellyfin.Server.Implementations.Users /// Initializes a new instance of the <see cref="UserManager"/> class. /// </summary> /// <param name="dbProvider">The database provider.</param> + /// <param name="eventManager">The event manager.</param> /// <param name="cryptoProvider">The cryptography provider.</param> /// <param name="networkManager">The network manager.</param> /// <param name="appHost">The application host.</param> @@ -56,6 +60,7 @@ namespace Jellyfin.Server.Implementations.Users /// <param name="logger">The logger.</param> public UserManager( JellyfinDbProvider dbProvider, + IEventManager eventManager, ICryptoProvider cryptoProvider, INetworkManager networkManager, IApplicationHost appHost, @@ -63,6 +68,7 @@ namespace Jellyfin.Server.Implementations.Users ILogger<UserManager> logger) { _dbProvider = dbProvider; + _eventManager = eventManager; _cryptoProvider = cryptoProvider; _networkManager = networkManager; _appHost = appHost; @@ -77,21 +83,9 @@ namespace Jellyfin.Server.Implementations.Users _defaultPasswordResetProvider = _passwordResetProviders.OfType<DefaultPasswordResetProvider>().First(); } - /// <inheritdoc/> - public event EventHandler<GenericEventArgs<User>>? OnUserPasswordChanged; - /// <inheritdoc/> public event EventHandler<GenericEventArgs<User>>? OnUserUpdated; - /// <inheritdoc/> - public event EventHandler<GenericEventArgs<User>>? OnUserCreated; - - /// <inheritdoc/> - public event EventHandler<GenericEventArgs<User>>? OnUserDeleted; - - /// <inheritdoc/> - public event EventHandler<GenericEventArgs<User>>? OnUserLockedOut; - /// <inheritdoc/> public IEnumerable<User> Users { @@ -234,7 +228,7 @@ namespace Jellyfin.Server.Implementations.Users dbContext.Users.Add(newUser); await dbContext.SaveChangesAsync().ConfigureAwait(false); - OnUserCreated?.Invoke(this, new GenericEventArgs<User>(newUser)); + await _eventManager.PublishAsync(new UserCreatedEventArgs(newUser)).ConfigureAwait(false); return newUser; } @@ -293,7 +287,8 @@ namespace Jellyfin.Server.Implementations.Users dbContext.RemoveRange(user.AccessSchedules); dbContext.Users.Remove(user); dbContext.SaveChanges(); - OnUserDeleted?.Invoke(this, new GenericEventArgs<User>(user)); + + _eventManager.Publish(new UserDeletedEventArgs(user)); } /// <inheritdoc/> @@ -319,7 +314,7 @@ namespace Jellyfin.Server.Implementations.Users await GetAuthenticationProvider(user).ChangePassword(user, newPassword).ConfigureAwait(false); await UpdateUserAsync(user).ConfigureAwait(false); - OnUserPasswordChanged?.Invoke(this, new GenericEventArgs<User>(user)); + await _eventManager.PublishAsync(new UserPasswordChangedEventArgs(user)).ConfigureAwait(false); } /// <inheritdoc/> @@ -338,7 +333,7 @@ namespace Jellyfin.Server.Implementations.Users user.EasyPassword = newPasswordSha1; UpdateUser(user); - OnUserPasswordChanged?.Invoke(this, new GenericEventArgs<User>(user)); + _eventManager.Publish(new UserPasswordChangedEventArgs(user)); } /// <inheritdoc/> @@ -901,7 +896,7 @@ namespace Jellyfin.Server.Implementations.Users if (maxInvalidLogins.HasValue && user.InvalidLoginAttemptCount >= maxInvalidLogins) { user.SetPermission(PermissionKind.IsDisabled, true); - OnUserLockedOut?.Invoke(this, new GenericEventArgs<User>(user)); + await _eventManager.PublishAsync(new UserLockedOutEventArgs(user)).ConfigureAwait(false); _logger.LogWarning( "Disabling user {Username} due to {Attempts} unsuccessful login attempts.", user.Username, diff --git a/MediaBrowser.Controller/Events/IEventManager.cs b/MediaBrowser.Controller/Events/IEventManager.cs index 794a8709e..a1f40b3a6 100644 --- a/MediaBrowser.Controller/Events/IEventManager.cs +++ b/MediaBrowser.Controller/Events/IEventManager.cs @@ -11,10 +11,18 @@ namespace MediaBrowser.Controller.Events /// <summary> /// Publishes an event. /// </summary> + /// <param name="eventArgs">the event arguments.</param> + /// <typeparam name="T">The type of event.</typeparam> + void Publish<T>(T eventArgs) + where T : EventArgs; + + /// <summary> + /// Publishes an event asynchronously. + /// </summary> /// <param name="eventArgs">The event arguments.</param> /// <typeparam name="T">The type of event.</typeparam> /// <returns>A task representing the publishing of the event.</returns> - Task Publish<T>(T eventArgs) + Task PublishAsync<T>(T eventArgs) where T : EventArgs; } } diff --git a/MediaBrowser.Controller/Library/IUserManager.cs b/MediaBrowser.Controller/Library/IUserManager.cs index c8d8375b3..96a41920a 100644 --- a/MediaBrowser.Controller/Library/IUserManager.cs +++ b/MediaBrowser.Controller/Library/IUserManager.cs @@ -19,26 +19,6 @@ namespace MediaBrowser.Controller.Library /// </summary> event EventHandler<GenericEventArgs<User>> OnUserUpdated; - /// <summary> - /// Occurs when a user is created. - /// </summary> - event EventHandler<GenericEventArgs<User>> OnUserCreated; - - /// <summary> - /// Occurs when a user is deleted. - /// </summary> - event EventHandler<GenericEventArgs<User>> OnUserDeleted; - - /// <summary> - /// Occurs when a user's password is changed. - /// </summary> - event EventHandler<GenericEventArgs<User>> OnUserPasswordChanged; - - /// <summary> - /// Occurs when a user is locked out. - /// </summary> - event EventHandler<GenericEventArgs<User>> OnUserLockedOut; - /// <summary> /// Gets the users. /// </summary> -- cgit v1.2.3 From b7ceb40d6efe083653734e6417b2f5e48b522872 Mon Sep 17 00:00:00 2001 From: Patrick Barron <barronpm@gmail.com> Date: Sat, 15 Aug 2020 18:57:46 -0400 Subject: Migrate ServerEventNotifier.OnPackageInstalling to IEventConsumer --- .../EntryPoints/ServerEventNotifier.cs | 7 ----- .../Consumers/Updates/PluginInstallingNotifier.cs | 31 ++++++++++++++++++++++ .../Events/Updates/PluginInstallingEventArgs.cs | 19 +++++++++++++ 3 files changed, 50 insertions(+), 7 deletions(-) create mode 100644 Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginInstallingNotifier.cs create mode 100644 MediaBrowser.Controller/Events/Updates/PluginInstallingEventArgs.cs (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs b/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs index 3d58b91e1..068872420 100644 --- a/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs +++ b/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs @@ -38,7 +38,6 @@ namespace Emby.Server.Implementations.EntryPoints public Task RunAsync() { _installationManager.PluginUninstalled += OnPluginUninstalled; - _installationManager.PackageInstalling += OnPackageInstalling; _installationManager.PackageInstallationCancelled += OnPackageInstallationCancelled; _installationManager.PackageInstallationCompleted += OnPackageInstallationCompleted; _installationManager.PackageInstallationFailed += OnPackageInstallationFailed; @@ -46,11 +45,6 @@ namespace Emby.Server.Implementations.EntryPoints return Task.CompletedTask; } - private async void OnPackageInstalling(object sender, InstallationInfo e) - { - await SendMessageToAdminSessions("PackageInstalling", e).ConfigureAwait(false); - } - private async void OnPackageInstallationCancelled(object sender, InstallationInfo e) { await SendMessageToAdminSessions("PackageInstallationCancelled", e).ConfigureAwait(false); @@ -103,7 +97,6 @@ namespace Emby.Server.Implementations.EntryPoints if (dispose) { _installationManager.PluginUninstalled -= OnPluginUninstalled; - _installationManager.PackageInstalling -= OnPackageInstalling; _installationManager.PackageInstallationCancelled -= OnPackageInstallationCancelled; _installationManager.PackageInstallationCompleted -= OnPackageInstallationCompleted; _installationManager.PackageInstallationFailed -= OnPackageInstallationFailed; diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginInstallingNotifier.cs b/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginInstallingNotifier.cs new file mode 100644 index 000000000..f691d11a7 --- /dev/null +++ b/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginInstallingNotifier.cs @@ -0,0 +1,31 @@ +using System.Threading; +using System.Threading.Tasks; +using MediaBrowser.Controller.Events; +using MediaBrowser.Controller.Events.Updates; +using MediaBrowser.Controller.Session; + +namespace Jellyfin.Server.Implementations.Events.Consumers.Updates +{ + /// <summary> + /// Notifies admin users when a plugin is being installed. + /// </summary> + public class PluginInstallingNotifier : IEventConsumer<PluginInstallingEventArgs> + { + private readonly ISessionManager _sessionManager; + + /// <summary> + /// Initializes a new instance of the <see cref="PluginInstallingNotifier"/> class. + /// </summary> + /// <param name="sessionManager">The session manager.</param> + public PluginInstallingNotifier(ISessionManager sessionManager) + { + _sessionManager = sessionManager; + } + + /// <inheritdoc /> + public async Task OnEvent(PluginInstallingEventArgs eventArgs) + { + await _sessionManager.SendMessageToAdminSessions("PackageInstalling", eventArgs.Argument, CancellationToken.None).ConfigureAwait(false); + } + } +} diff --git a/MediaBrowser.Controller/Events/Updates/PluginInstallingEventArgs.cs b/MediaBrowser.Controller/Events/Updates/PluginInstallingEventArgs.cs new file mode 100644 index 000000000..045a60027 --- /dev/null +++ b/MediaBrowser.Controller/Events/Updates/PluginInstallingEventArgs.cs @@ -0,0 +1,19 @@ +using Jellyfin.Data.Events; +using MediaBrowser.Model.Updates; + +namespace MediaBrowser.Controller.Events.Updates +{ + /// <summary> + /// An event that occurs when a plugin is installing. + /// </summary> + public class PluginInstallingEventArgs : GenericEventArgs<InstallationInfo> + { + /// <summary> + /// Initializes a new instance of the <see cref="PluginInstallingEventArgs"/> class. + /// </summary> + /// <param name="arg">The installation info.</param> + public PluginInstallingEventArgs(InstallationInfo arg) : base(arg) + { + } + } +} -- cgit v1.2.3 From a40064a146da17a49582f7ef1ad754a497725ccc Mon Sep 17 00:00:00 2001 From: Patrick Barron <barronpm@gmail.com> Date: Sat, 15 Aug 2020 23:20:41 -0400 Subject: Migrate ServerEventNotifier.OnPackageInstallationCancelled to IEventConsumer --- .../EntryPoints/ServerEventNotifier.cs | 79 ---------------------- .../Updates/PluginInstallationCancelledNotifier.cs | 31 +++++++++ .../PluginInstallationCancelledEventArgs.cs | 19 ++++++ 3 files changed, 50 insertions(+), 79 deletions(-) delete mode 100644 Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs create mode 100644 Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginInstallationCancelledNotifier.cs create mode 100644 MediaBrowser.Controller/Events/Updates/PluginInstallationCancelledEventArgs.cs (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs b/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs deleted file mode 100644 index 1fbb9f303..000000000 --- a/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs +++ /dev/null @@ -1,79 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; -using MediaBrowser.Common.Updates; -using MediaBrowser.Controller.Plugins; -using MediaBrowser.Controller.Session; -using MediaBrowser.Model.Updates; - -namespace Emby.Server.Implementations.EntryPoints -{ - /// <summary> - /// Class WebSocketEvents. - /// </summary> - public class ServerEventNotifier : IServerEntryPoint - { - /// <summary> - /// The installation manager. - /// </summary> - private readonly IInstallationManager _installationManager; - - private readonly ISessionManager _sessionManager; - - /// <summary> - /// Initializes a new instance of the <see cref="ServerEventNotifier"/> class. - /// </summary> - /// <param name="installationManager">The installation manager.</param> - /// <param name="sessionManager">The session manager.</param> - public ServerEventNotifier( - IInstallationManager installationManager, - ISessionManager sessionManager) - { - _installationManager = installationManager; - _sessionManager = sessionManager; - } - - /// <inheritdoc /> - public Task RunAsync() - { - _installationManager.PackageInstallationCancelled += OnPackageInstallationCancelled; - - return Task.CompletedTask; - } - - private async void OnPackageInstallationCancelled(object sender, InstallationInfo e) - { - await SendMessageToAdminSessions("PackageInstallationCancelled", e).ConfigureAwait(false); - } - - private async Task SendMessageToAdminSessions<T>(string name, T data) - { - try - { - await _sessionManager.SendMessageToAdminSessions(name, data, CancellationToken.None).ConfigureAwait(false); - } - catch (Exception) - { - } - } - - /// <inheritdoc /> - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - /// <summary> - /// Releases unmanaged and - optionally - managed resources. - /// </summary> - /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param> - protected virtual void Dispose(bool dispose) - { - if (dispose) - { - _installationManager.PackageInstallationCancelled -= OnPackageInstallationCancelled; - } - } - } -} diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginInstallationCancelledNotifier.cs b/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginInstallationCancelledNotifier.cs new file mode 100644 index 000000000..1c600683a --- /dev/null +++ b/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginInstallationCancelledNotifier.cs @@ -0,0 +1,31 @@ +using System.Threading; +using System.Threading.Tasks; +using MediaBrowser.Controller.Events; +using MediaBrowser.Controller.Events.Updates; +using MediaBrowser.Controller.Session; + +namespace Jellyfin.Server.Implementations.Events.Consumers.Updates +{ + /// <summary> + /// Notifies admin users when a plugin installation is cancelled. + /// </summary> + public class PluginInstallationCancelledNotifier : IEventConsumer<PluginInstallationCancelledEventArgs> + { + private readonly ISessionManager _sessionManager; + + /// <summary> + /// Initializes a new instance of the <see cref="PluginInstallationCancelledNotifier"/> class. + /// </summary> + /// <param name="sessionManager">The session manager.</param> + public PluginInstallationCancelledNotifier(ISessionManager sessionManager) + { + _sessionManager = sessionManager; + } + + /// <inheritdoc /> + public async Task OnEvent(PluginInstallationCancelledEventArgs eventArgs) + { + await _sessionManager.SendMessageToAdminSessions("PackageInstallationCancelled", eventArgs.Argument, CancellationToken.None).ConfigureAwait(false); + } + } +} diff --git a/MediaBrowser.Controller/Events/Updates/PluginInstallationCancelledEventArgs.cs b/MediaBrowser.Controller/Events/Updates/PluginInstallationCancelledEventArgs.cs new file mode 100644 index 000000000..b06046c05 --- /dev/null +++ b/MediaBrowser.Controller/Events/Updates/PluginInstallationCancelledEventArgs.cs @@ -0,0 +1,19 @@ +using Jellyfin.Data.Events; +using MediaBrowser.Model.Updates; + +namespace MediaBrowser.Controller.Events.Updates +{ + /// <summary> + /// An event that occurs when a plugin installation is cancelled. + /// </summary> + public class PluginInstallationCancelledEventArgs : GenericEventArgs<InstallationInfo> + { + /// <summary> + /// Initializes a new instance of the <see cref="PluginInstallationCancelledEventArgs"/> class. + /// </summary> + /// <param name="arg">The installation info.</param> + public PluginInstallationCancelledEventArgs(InstallationInfo arg) : base(arg) + { + } + } +} -- cgit v1.2.3 From 035d29fb357006c29ffb40e0a53c1e999237cdd1 Mon Sep 17 00:00:00 2001 From: Matt Montgomery <33811686+ConfusedPolarBear@users.noreply.github.com> Date: Thu, 13 Aug 2020 15:35:04 -0500 Subject: Migrate to new API standard --- .../QuickConnect/QuickConnectManager.cs | 5 +- Jellyfin.Api/Controllers/QuickConnectController.cs | 160 +++++++++++++++++++++ Jellyfin.Api/Controllers/UserController.cs | 41 ++++++ Jellyfin.Api/Models/UserDtos/QuickConnectDto.cs | 13 ++ .../QuickConnect/QuickConnectService.cs | 132 ----------------- .../QuickConnect/IQuickConnect.cs | 5 +- MediaBrowser.Controller/Session/ISessionManager.cs | 1 + 7 files changed, 219 insertions(+), 138 deletions(-) create mode 100644 Jellyfin.Api/Controllers/QuickConnectController.cs create mode 100644 Jellyfin.Api/Models/UserDtos/QuickConnectDto.cs delete mode 100644 MediaBrowser.Api/QuickConnect/QuickConnectService.cs (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/QuickConnect/QuickConnectManager.cs b/Emby.Server.Implementations/QuickConnect/QuickConnectManager.cs index 23e94afd7..949c3b505 100644 --- a/Emby.Server.Implementations/QuickConnect/QuickConnectManager.cs +++ b/Emby.Server.Implementations/QuickConnect/QuickConnectManager.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Concurrent; -using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Security.Cryptography; @@ -10,7 +9,7 @@ using MediaBrowser.Controller.Net; using MediaBrowser.Controller.QuickConnect; using MediaBrowser.Controller.Security; using MediaBrowser.Model.QuickConnect; -using MediaBrowser.Model.Services; +using Microsoft.AspNetCore.Http; using MediaBrowser.Common; using Microsoft.Extensions.Logging; using MediaBrowser.Common.Extensions; @@ -163,7 +162,7 @@ namespace Emby.Server.Implementations.QuickConnect } /// <inheritdoc/> - public bool AuthorizeRequest(IRequest request, string code) + public bool AuthorizeRequest(HttpRequest request, string code) { ExpireRequests(); AssertActive(); diff --git a/Jellyfin.Api/Controllers/QuickConnectController.cs b/Jellyfin.Api/Controllers/QuickConnectController.cs new file mode 100644 index 000000000..d45ea058d --- /dev/null +++ b/Jellyfin.Api/Controllers/QuickConnectController.cs @@ -0,0 +1,160 @@ +using System.ComponentModel.DataAnnotations; +using Jellyfin.Api.Constants; +using MediaBrowser.Common.Extensions; +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Net; +using MediaBrowser.Controller.QuickConnect; +using MediaBrowser.Model.QuickConnect; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; + +namespace Jellyfin.Api.Controllers +{ + /// <summary> + /// Quick connect controller. + /// </summary> + public class QuickConnectController : BaseJellyfinApiController + { + private readonly IQuickConnect _quickConnect; + private readonly IUserManager _userManager; + private readonly IAuthorizationContext _authContext; + + /// <summary> + /// Initializes a new instance of the <see cref="QuickConnectController"/> class. + /// </summary> + /// <param name="quickConnect">Instance of the <see cref="IQuickConnect"/> interface.</param> + /// <param name="userManager">Instance of the <see cref="IUserManager"/> interface.</param> + /// <param name="authContext">Instance of the <see cref="IAuthorizationContext"/> interface.</param> + public QuickConnectController( + IQuickConnect quickConnect, + IUserManager userManager, + IAuthorizationContext authContext) + { + _quickConnect = quickConnect; + _userManager = userManager; + _authContext = authContext; + } + + /// <summary> + /// Gets the current quick connect state. + /// </summary> + /// <response code="200">Quick connect state returned.</response> + /// <returns>The current <see cref="QuickConnectState"/>.</returns> + [HttpGet("Status")] + [ProducesResponseType(StatusCodes.Status200OK)] + public ActionResult<QuickConnectState> GetStatus() + { + _quickConnect.ExpireRequests(); + return Ok(_quickConnect.State); + } + + /// <summary> + /// Initiate a new quick connect request. + /// </summary> + /// <param name="friendlyName">Device friendly name.</param> + /// <response code="200">Quick connect request successfully created.</response> + /// <response code="401">Quick connect is not active on this server.</response> + /// <returns>A <see cref="QuickConnectResult"/> with a secret and code for future use or an error message.</returns> + [HttpGet("Initiate")] + [ProducesResponseType(StatusCodes.Status200OK)] + public ActionResult<QuickConnectResult> Initiate([FromQuery] string? friendlyName) + { + return Ok(_quickConnect.TryConnect(friendlyName)); + } + + /// <summary> + /// Attempts to retrieve authentication information. + /// </summary> + /// <param name="secret">Secret previously returned from the Initiate endpoint.</param> + /// <response code="200">Quick connect result returned.</response> + /// <response code="404">Unknown quick connect secret.</response> + /// <returns>An updated <see cref="QuickConnectResult"/>.</returns> + [HttpGet("Connect")] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public ActionResult<QuickConnectResult> Connect([FromQuery] string? secret) + { + try + { + var result = _quickConnect.CheckRequestStatus(secret); + return Ok(result); + } + catch (ResourceNotFoundException) + { + return NotFound("Unknown secret"); + } + } + + /// <summary> + /// Temporarily activates quick connect for five minutes. + /// </summary> + /// <response code="204">Quick connect has been temporarily activated.</response> + /// <response code="403">Quick connect is unavailable on this server.</response> + /// <returns>An <see cref="NoContentResult"/> on success.</returns> + [HttpPost("Activate")] + [Authorize(Policy = Policies.DefaultAuthorization)] + [ProducesResponseType(StatusCodes.Status204NoContent)] + [ProducesResponseType(StatusCodes.Status403Forbidden)] + public ActionResult Activate() + { + if (_quickConnect.State == QuickConnectState.Unavailable) + { + return Forbid("Quick connect is unavailable"); + } + + _quickConnect.Activate(); + return NoContent(); + } + + /// <summary> + /// Enables or disables quick connect. + /// </summary> + /// <param name="status">New <see cref="QuickConnectState"/>.</param> + /// <response code="204">Quick connect state set successfully.</response> + /// <returns>An <see cref="NoContentResult"/> on success.</returns> + [HttpPost("Available")] + [Authorize(Policy = Policies.RequiresElevation)] + [ProducesResponseType(StatusCodes.Status204NoContent)] + public ActionResult Available([FromQuery] QuickConnectState? status) + { + _quickConnect.SetState(status ?? QuickConnectState.Available); + return NoContent(); + } + + /// <summary> + /// Authorizes a pending quick connect request. + /// </summary> + /// <param name="code">Quick connect code to authorize.</param> + /// <response code="200">Quick connect result authorized successfully.</response> + /// <response code="400">Missing quick connect code.</response> + /// <returns>Boolean indicating if the authorization was successful.</returns> + [HttpPost("Authorize")] + [Authorize(Policy = Policies.DefaultAuthorization)] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + public ActionResult<bool> Authorize([FromQuery, Required] string? code) + { + if (code == null) + { + return BadRequest("Missing code"); + } + + return Ok(_quickConnect.AuthorizeRequest(Request, code)); + } + + /// <summary> + /// Deauthorize all quick connect devices for the current user. + /// </summary> + /// <response code="200">All quick connect devices were deleted.</response> + /// <returns>The number of devices that were deleted.</returns> + [HttpPost("Deauthorize")] + [Authorize(Policy = Policies.DefaultAuthorization)] + [ProducesResponseType(StatusCodes.Status200OK)] + public ActionResult<int> Deauthorize() + { + var userId = _authContext.GetAuthorizationInfo(Request).UserId; + return _quickConnect.DeleteAllDevices(userId); + } + } +} diff --git a/Jellyfin.Api/Controllers/UserController.cs b/Jellyfin.Api/Controllers/UserController.cs index 272312522..131fffb7a 100644 --- a/Jellyfin.Api/Controllers/UserController.cs +++ b/Jellyfin.Api/Controllers/UserController.cs @@ -216,6 +216,47 @@ namespace Jellyfin.Api.Controllers } } + /// <summary> + /// Authenticates a user with quick connect. + /// </summary> + /// <param name="request">The <see cref="QuickConnectDto"/> request.</param> + /// <response code="200">User authenticated.</response> + /// <response code="400">Missing token.</response> + /// <returns>A <see cref="Task"/> containing an <see cref="AuthenticationRequest"/> with information about the new session.</returns> + [HttpPost("AuthenticateWithQuickConnect")] + [ProducesResponseType(StatusCodes.Status200OK)] + public async Task<ActionResult<AuthenticationResult>> AuthenticateWithQuickConnect([FromBody, Required] QuickConnectDto request) + { + if (request.Token == null) + { + return BadRequest("Access token is required."); + } + + var auth = _authContext.GetAuthorizationInfo(Request); + + try + { + var authRequest = new AuthenticationRequest + { + App = auth.Client, + AppVersion = auth.Version, + DeviceId = auth.DeviceId, + DeviceName = auth.Device, + }; + + var result = await _sessionManager.AuthenticateQuickConnect( + authRequest, + request.Token).ConfigureAwait(false); + + return result; + } + catch (SecurityException e) + { + // rethrow adding IP address to message + throw new SecurityException($"[{HttpContext.Connection.RemoteIpAddress}] {e.Message}", e); + } + } + /// <summary> /// Updates a user's password. /// </summary> diff --git a/Jellyfin.Api/Models/UserDtos/QuickConnectDto.cs b/Jellyfin.Api/Models/UserDtos/QuickConnectDto.cs new file mode 100644 index 000000000..8f53d5f37 --- /dev/null +++ b/Jellyfin.Api/Models/UserDtos/QuickConnectDto.cs @@ -0,0 +1,13 @@ +namespace Jellyfin.Api.Models.UserDtos +{ + /// <summary> + /// The quick connect request body. + /// </summary> + public class QuickConnectDto + { + /// <summary> + /// Gets or sets the quick connect token. + /// </summary> + public string? Token { get; set; } + } +} diff --git a/MediaBrowser.Api/QuickConnect/QuickConnectService.cs b/MediaBrowser.Api/QuickConnect/QuickConnectService.cs deleted file mode 100644 index 7093be990..000000000 --- a/MediaBrowser.Api/QuickConnect/QuickConnectService.cs +++ /dev/null @@ -1,132 +0,0 @@ -using System; -using MediaBrowser.Controller.Configuration; -using MediaBrowser.Controller.Library; -using MediaBrowser.Controller.Net; -using MediaBrowser.Controller.QuickConnect; -using MediaBrowser.Model.QuickConnect; -using MediaBrowser.Model.Services; -using Microsoft.Extensions.Logging; - -namespace MediaBrowser.Api.QuickConnect -{ - [Route("/QuickConnect/Initiate", "GET", Summary = "Requests a new quick connect code")] - public class Initiate : IReturn<QuickConnectResult> - { - [ApiMember(Name = "FriendlyName", Description = "Device friendly name", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] - public string FriendlyName { get; set; } - } - - [Route("/QuickConnect/Connect", "GET", Summary = "Attempts to retrieve authentication information")] - public class Connect : IReturn<QuickConnectResult> - { - [ApiMember(Name = "Secret", Description = "Quick connect secret", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")] - public string Secret { get; set; } - } - - [Route("/QuickConnect/Authorize", "POST", Summary = "Authorizes a pending quick connect request")] - [Authenticated] - public class Authorize : IReturn<bool> - { - [ApiMember(Name = "Code", Description = "Quick connect identifying code", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")] - public string Code { get; set; } - } - - [Route("/QuickConnect/Deauthorize", "POST", Summary = "Deletes all quick connect authorization tokens for the current user")] - [Authenticated] - public class Deauthorize : IReturn<int> - { - [ApiMember(Name = "UserId", Description = "User Id", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] - public Guid UserId { get; set; } - } - - [Route("/QuickConnect/Status", "GET", Summary = "Gets the current quick connect state")] - public class QuickConnectStatus : IReturn<QuickConnectResult> - { - - } - - [Route("/QuickConnect/Available", "POST", Summary = "Enables or disables quick connect")] - [Authenticated(Roles = "Admin")] - public class Available : IReturn<QuickConnectState> - { - [ApiMember(Name = "Status", Description = "New quick connect status", IsRequired = false, DataType = "QuickConnectState", ParameterType = "query", Verb = "GET")] - public QuickConnectState Status { get; set; } - } - - [Route("/QuickConnect/Activate", "POST", Summary = "Temporarily activates quick connect for the time period defined in the server configuration")] - [Authenticated] - public class Activate : IReturn<bool> - { - - } - - public class QuickConnectService : BaseApiService - { - private IQuickConnect _quickConnect; - private IUserManager _userManager; - private IAuthorizationContext _authContext; - - public QuickConnectService( - ILogger<QuickConnectService> logger, - IServerConfigurationManager serverConfigurationManager, - IHttpResultFactory httpResultFactory, - IUserManager userManager, - IAuthorizationContext authContext, - IQuickConnect quickConnect) - : base(logger, serverConfigurationManager, httpResultFactory) - { - _userManager = userManager; - _quickConnect = quickConnect; - _authContext = authContext; - } - - public object Get(Initiate request) - { - return _quickConnect.TryConnect(request.FriendlyName); - } - - public object Get(Connect request) - { - return _quickConnect.CheckRequestStatus(request.Secret); - } - - public object Get(QuickConnectStatus request) - { - _quickConnect.ExpireRequests(); - return _quickConnect.State; - } - - public object Post(Deauthorize request) - { - AssertCanUpdateUser(_authContext, _userManager, request.UserId, true); - - return _quickConnect.DeleteAllDevices(request.UserId); - } - - public object Post(Authorize request) - { - return _quickConnect.AuthorizeRequest(Request, request.Code); - } - - public object Post(Activate request) - { - if (_quickConnect.State == QuickConnectState.Unavailable) - { - return false; - } - - string name = _authContext.GetAuthorizationInfo(Request).User.Username; - - Logger.LogInformation("{name} temporarily activated quick connect", name); - _quickConnect.Activate(); - - return true; - } - - public object Post(Available request) - { - _quickConnect.SetState(request.Status); - return _quickConnect.State; - } - } -} diff --git a/MediaBrowser.Controller/QuickConnect/IQuickConnect.cs b/MediaBrowser.Controller/QuickConnect/IQuickConnect.cs index 993637c8a..fd7e973f6 100644 --- a/MediaBrowser.Controller/QuickConnect/IQuickConnect.cs +++ b/MediaBrowser.Controller/QuickConnect/IQuickConnect.cs @@ -1,7 +1,6 @@ using System; -using System.Collections.Generic; using MediaBrowser.Model.QuickConnect; -using MediaBrowser.Model.Services; +using Microsoft.AspNetCore.Http; namespace MediaBrowser.Controller.QuickConnect { @@ -66,7 +65,7 @@ namespace MediaBrowser.Controller.QuickConnect /// <param name="request">HTTP request object.</param> /// <param name="code">Identifying code for the request.</param> /// <returns>A boolean indicating if the authorization completed successfully.</returns> - bool AuthorizeRequest(IRequest request, string code); + bool AuthorizeRequest(HttpRequest request, string code); /// <summary> /// Expire quick connect requests that are over the time limit. If <paramref name="expireAll"/> is true, all requests are unconditionally expired. diff --git a/MediaBrowser.Controller/Session/ISessionManager.cs b/MediaBrowser.Controller/Session/ISessionManager.cs index ffa19fb69..d44787b88 100644 --- a/MediaBrowser.Controller/Session/ISessionManager.cs +++ b/MediaBrowser.Controller/Session/ISessionManager.cs @@ -268,6 +268,7 @@ namespace MediaBrowser.Controller.Session /// Authenticates a new session with quick connect. /// </summary> /// <param name="request">The request.</param> + /// <param name="token">Quick connect access token.</param> /// <returns>Task{SessionInfo}.</returns> Task<AuthenticationResult> AuthenticateQuickConnect(AuthenticationRequest request, string token); -- cgit v1.2.3 From 2e0c2336ccb2746ed1851285429013862f835809 Mon Sep 17 00:00:00 2001 From: crobibero <cody@robibe.ro> Date: Mon, 17 Aug 2020 11:51:53 -0600 Subject: Remove IHttpClient from IRemoteImageProvider --- MediaBrowser.Controller/Providers/IRemoteImageProvider.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/Providers/IRemoteImageProvider.cs b/MediaBrowser.Controller/Providers/IRemoteImageProvider.cs index 68a968f90..ee8f5b860 100644 --- a/MediaBrowser.Controller/Providers/IRemoteImageProvider.cs +++ b/MediaBrowser.Controller/Providers/IRemoteImageProvider.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Net.Http; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Common.Net; @@ -34,6 +35,6 @@ namespace MediaBrowser.Controller.Providers /// <param name="url">The URL.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task{HttpResponseInfo}.</returns> - Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken); + Task<HttpResponseMessage> GetImageResponse(string url, CancellationToken cancellationToken); } } -- cgit v1.2.3 From 1325815182a9471b453da5abbfdaec68cac4feb2 Mon Sep 17 00:00:00 2001 From: crobibero <cody@robibe.ro> Date: Mon, 17 Aug 2020 13:10:02 -0600 Subject: Remove IHttpClient from Providers --- Jellyfin.Api/Controllers/ItemLookupController.cs | 6 +- .../Providers/IProviderManager.cs | 3 +- .../Providers/IRemoteSearchProvider.cs | 3 +- MediaBrowser.Providers/Manager/ProviderManager.cs | 2 +- .../MediaInfo/SubtitleResolver.cs | 1 - .../Plugins/AudioDb/AlbumProvider.cs | 25 +-- .../Plugins/AudioDb/ArtistProvider.cs | 31 +-- .../Plugins/MusicBrainz/AlbumProvider.cs | 213 +++++++++------------ .../Plugins/MusicBrainz/ArtistProvider.cs | 24 +-- .../Plugins/Omdb/OmdbEpisodeProvider.cs | 14 +- .../Plugins/Omdb/OmdbImageProvider.cs | 18 +- .../Plugins/Omdb/OmdbItemProvider.cs | 130 ++++++------- .../Plugins/Omdb/OmdbProvider.cs | 45 ++--- .../Plugins/TheTvdb/TvdbEpisodeImageProvider.cs | 16 +- .../Plugins/TheTvdb/TvdbEpisodeProvider.cs | 16 +- .../Plugins/TheTvdb/TvdbPersonImageProvider.cs | 16 +- .../Plugins/TheTvdb/TvdbSeasonImageProvider.cs | 16 +- .../Plugins/TheTvdb/TvdbSeriesImageProvider.cs | 16 +- .../Plugins/TheTvdb/TvdbSeriesProvider.cs | 17 +- .../Tmdb/BoxSets/TmdbBoxSetImageProvider.cs | 16 +- .../Plugins/Tmdb/BoxSets/TmdbBoxSetProvider.cs | 52 ++--- .../Plugins/Tmdb/Movies/TmdbImageProvider.cs | 16 +- .../Plugins/Tmdb/Movies/TmdbMovieProvider.cs | 103 +++------- .../Plugins/Tmdb/Movies/TmdbSearch.cs | 126 +++++------- .../Plugins/Tmdb/Music/TmdbMusicVideoProvider.cs | 4 +- .../Plugins/Tmdb/People/TmdbPersonImageProvider.cs | 16 +- .../Plugins/Tmdb/People/TmdbPersonProvider.cs | 61 ++---- .../Plugins/Tmdb/TV/TmdbEpisodeImageProvider.cs | 8 +- .../Plugins/Tmdb/TV/TmdbEpisodeProvider.cs | 8 +- .../Plugins/Tmdb/TV/TmdbEpisodeProviderBase.cs | 34 ++-- .../Plugins/Tmdb/TV/TmdbSeasonImageProvider.cs | 16 +- .../Plugins/Tmdb/TV/TmdbSeasonProvider.cs | 34 ++-- .../Plugins/Tmdb/TV/TmdbSeriesImageProvider.cs | 16 +- .../Plugins/Tmdb/TV/TmdbSeriesProvider.cs | 109 +++++------ .../Plugins/Tmdb/Trailers/TmdbTrailerProvider.cs | 16 +- .../Studios/StudiosImageProvider.cs | 1 - 36 files changed, 483 insertions(+), 765 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Jellyfin.Api/Controllers/ItemLookupController.cs b/Jellyfin.Api/Controllers/ItemLookupController.cs index c9ad15bab..a752af545 100644 --- a/Jellyfin.Api/Controllers/ItemLookupController.cs +++ b/Jellyfin.Api/Controllers/ItemLookupController.cs @@ -331,12 +331,12 @@ namespace Jellyfin.Api.Controllers /// <returns>Task.</returns> private async Task DownloadImage(string providerName, string url, Guid urlHash, string pointerCachePath) { - var result = await _providerManager.GetSearchImage(providerName, url, CancellationToken.None).ConfigureAwait(false); - var ext = result.ContentType.Split('/').Last(); + using var result = await _providerManager.GetSearchImage(providerName, url, CancellationToken.None).ConfigureAwait(false); + var ext = result.Content.Headers.ContentType.MediaType.Split('/').LastOrDefault(); var fullCachePath = GetFullCachePath(urlHash + "." + ext); Directory.CreateDirectory(Path.GetDirectoryName(fullCachePath)); - await using (var stream = result.Content) + using (var stream = result.Content) { await using var fileStream = new FileStream( fullCachePath, diff --git a/MediaBrowser.Controller/Providers/IProviderManager.cs b/MediaBrowser.Controller/Providers/IProviderManager.cs index 955db0278..8ba01d773 100644 --- a/MediaBrowser.Controller/Providers/IProviderManager.cs +++ b/MediaBrowser.Controller/Providers/IProviderManager.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Net.Http; using System.Threading; using System.Threading.Tasks; using Jellyfin.Data.Entities; @@ -157,7 +158,7 @@ namespace MediaBrowser.Controller.Providers /// <param name="url">The URL.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task{HttpResponseInfo}.</returns> - Task<HttpResponseInfo> GetSearchImage(string providerName, string url, CancellationToken cancellationToken); + Task<HttpResponseMessage> GetSearchImage(string providerName, string url, CancellationToken cancellationToken); Dictionary<Guid, Guid> GetRefreshQueue(); diff --git a/MediaBrowser.Controller/Providers/IRemoteSearchProvider.cs b/MediaBrowser.Controller/Providers/IRemoteSearchProvider.cs index fdb0c8eb5..17ad9e4a3 100644 --- a/MediaBrowser.Controller/Providers/IRemoteSearchProvider.cs +++ b/MediaBrowser.Controller/Providers/IRemoteSearchProvider.cs @@ -1,3 +1,4 @@ +using System.Net.Http; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Common.Net; @@ -12,6 +13,6 @@ namespace MediaBrowser.Controller.Providers /// <param name="url">The URL.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task{HttpResponseInfo}.</returns> - Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken); + Task<HttpResponseMessage> GetImageResponse(string url, CancellationToken cancellationToken); } } diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs index 8e46c73ee..34d3a8a0f 100644 --- a/MediaBrowser.Providers/Manager/ProviderManager.cs +++ b/MediaBrowser.Providers/Manager/ProviderManager.cs @@ -893,7 +893,7 @@ namespace MediaBrowser.Providers.Manager } /// <inheritdoc/> - public Task<HttpResponseInfo> GetSearchImage(string providerName, string url, CancellationToken cancellationToken) + public Task<HttpResponseMessage> GetSearchImage(string providerName, string url, CancellationToken cancellationToken) { var provider = _metadataProviders.OfType<IRemoteSearchProvider>().FirstOrDefault(i => string.Equals(i.Name, providerName, StringComparison.OrdinalIgnoreCase)); diff --git a/MediaBrowser.Providers/MediaInfo/SubtitleResolver.cs b/MediaBrowser.Providers/MediaInfo/SubtitleResolver.cs index 64a5e7c8e..43659b68c 100644 --- a/MediaBrowser.Providers/MediaInfo/SubtitleResolver.cs +++ b/MediaBrowser.Providers/MediaInfo/SubtitleResolver.cs @@ -8,7 +8,6 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Globalization; -using MediaBrowser.Model.IO; namespace MediaBrowser.Providers.MediaInfo { diff --git a/MediaBrowser.Providers/Plugins/AudioDb/AlbumProvider.cs b/MediaBrowser.Providers/Plugins/AudioDb/AlbumProvider.cs index 7e54fcbdd..321144edf 100644 --- a/MediaBrowser.Providers/Plugins/AudioDb/AlbumProvider.cs +++ b/MediaBrowser.Providers/Plugins/AudioDb/AlbumProvider.cs @@ -10,7 +10,6 @@ using System.Threading; using System.Threading.Tasks; using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Extensions; -using MediaBrowser.Common.Net; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Providers; @@ -26,16 +25,16 @@ namespace MediaBrowser.Providers.Plugins.AudioDb { private readonly IServerConfigurationManager _config; private readonly IFileSystem _fileSystem; - private readonly IHttpClient _httpClient; + private readonly IHttpClientFactory _httpClientFactory; private readonly IJsonSerializer _json; public static AudioDbAlbumProvider Current; - public AudioDbAlbumProvider(IServerConfigurationManager config, IFileSystem fileSystem, IHttpClient httpClient, IJsonSerializer json) + public AudioDbAlbumProvider(IServerConfigurationManager config, IFileSystem fileSystem, IHttpClientFactory httpClientFactory, IJsonSerializer json) { _config = config; _fileSystem = fileSystem; - _httpClient = httpClient; + _httpClientFactory = httpClientFactory; _json = json; Current = this; @@ -174,18 +173,10 @@ namespace MediaBrowser.Providers.Plugins.AudioDb Directory.CreateDirectory(Path.GetDirectoryName(path)); - using (var httpResponse = await _httpClient.SendAsync( - new HttpRequestOptions - { - Url = url, - CancellationToken = cancellationToken - }, - HttpMethod.Get).ConfigureAwait(false)) - using (var response = httpResponse.Content) - using (var xmlFileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read, IODefaults.FileStreamBufferSize, true)) - { - await response.CopyToAsync(xmlFileStream).ConfigureAwait(false); - } + using var response = await _httpClientFactory.CreateClient().GetAsync(url, cancellationToken); + await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); + await using var xmlFileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read, IODefaults.FileStreamBufferSize, true); + await stream.CopyToAsync(xmlFileStream, cancellationToken).ConfigureAwait(false); } private static string GetAlbumDataPath(IApplicationPaths appPaths, string musicBrainzReleaseGroupId) @@ -294,7 +285,7 @@ namespace MediaBrowser.Providers.Plugins.AudioDb } /// <inheritdoc /> - public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken) + public Task<HttpResponseMessage> GetImageResponse(string url, CancellationToken cancellationToken) { throw new NotImplementedException(); } diff --git a/MediaBrowser.Providers/Plugins/AudioDb/ArtistProvider.cs b/MediaBrowser.Providers/Plugins/AudioDb/ArtistProvider.cs index 892f73422..708426500 100644 --- a/MediaBrowser.Providers/Plugins/AudioDb/ArtistProvider.cs +++ b/MediaBrowser.Providers/Plugins/AudioDb/ArtistProvider.cs @@ -9,7 +9,6 @@ using System.Threading; using System.Threading.Tasks; using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Extensions; -using MediaBrowser.Common.Net; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Providers; @@ -25,7 +24,7 @@ namespace MediaBrowser.Providers.Plugins.AudioDb { private readonly IServerConfigurationManager _config; private readonly IFileSystem _fileSystem; - private readonly IHttpClient _httpClient; + private readonly IHttpClientFactory _httpClientFactory; private readonly IJsonSerializer _json; public static AudioDbArtistProvider Current; @@ -33,11 +32,11 @@ namespace MediaBrowser.Providers.Plugins.AudioDb private const string ApiKey = "195003"; public const string BaseUrl = "https://www.theaudiodb.com/api/v1/json/" + ApiKey; - public AudioDbArtistProvider(IServerConfigurationManager config, IFileSystem fileSystem, IHttpClient httpClient, IJsonSerializer json) + public AudioDbArtistProvider(IServerConfigurationManager config, IFileSystem fileSystem, IHttpClientFactory httpClientFactory, IJsonSerializer json) { _config = config; _fileSystem = fileSystem; - _httpClient = httpClient; + _httpClientFactory = httpClientFactory; _json = json; Current = this; } @@ -155,23 +154,13 @@ namespace MediaBrowser.Providers.Plugins.AudioDb var path = GetArtistInfoPath(_config.ApplicationPaths, musicBrainzId); - using (var httpResponse = await _httpClient.SendAsync( - new HttpRequestOptions - { - Url = url, - CancellationToken = cancellationToken, - BufferContent = true - }, - HttpMethod.Get).ConfigureAwait(false)) - using (var response = httpResponse.Content) - { - Directory.CreateDirectory(Path.GetDirectoryName(path)); + using var response = await _httpClientFactory.CreateClient().GetAsync(url, cancellationToken); + await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); - using (var xmlFileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read, IODefaults.FileStreamBufferSize, true)) - { - await response.CopyToAsync(xmlFileStream).ConfigureAwait(false); - } - } + Directory.CreateDirectory(Path.GetDirectoryName(path)); + + await using var xmlFileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read, IODefaults.FileStreamBufferSize, true); + await stream.CopyToAsync(xmlFileStream, cancellationToken).ConfigureAwait(false); } /// <summary> @@ -289,7 +278,7 @@ namespace MediaBrowser.Providers.Plugins.AudioDb } /// <inheritdoc /> - public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken) + public Task<HttpResponseMessage> GetImageResponse(string url, CancellationToken cancellationToken) { throw new NotImplementedException(); } diff --git a/MediaBrowser.Providers/Plugins/MusicBrainz/AlbumProvider.cs b/MediaBrowser.Providers/Plugins/MusicBrainz/AlbumProvider.cs index 9f36a03f9..23acb7fd6 100644 --- a/MediaBrowser.Providers/Plugins/MusicBrainz/AlbumProvider.cs +++ b/MediaBrowser.Providers/Plugins/MusicBrainz/AlbumProvider.cs @@ -8,12 +8,12 @@ using System.IO; using System.Linq; using System.Net; using System.Net.Http; +using System.Net.Http.Headers; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Xml; using MediaBrowser.Common; -using MediaBrowser.Common.Net; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; @@ -42,7 +42,7 @@ namespace MediaBrowser.Providers.Music internal static MusicBrainzAlbumProvider Current; - private readonly IHttpClient _httpClient; + private readonly IHttpClientFactory _httpClientFactory; private readonly IApplicationHost _appHost; private readonly ILogger<MusicBrainzAlbumProvider> _logger; @@ -51,11 +51,11 @@ namespace MediaBrowser.Providers.Music private Stopwatch _stopWatchMusicBrainz = new Stopwatch(); public MusicBrainzAlbumProvider( - IHttpClient httpClient, + IHttpClientFactory httpClientFactory, IApplicationHost appHost, ILogger<MusicBrainzAlbumProvider> logger) { - _httpClient = httpClient; + _httpClientFactory = httpClientFactory; _appHost = appHost; _logger = logger; @@ -123,11 +123,9 @@ namespace MediaBrowser.Providers.Music if (!string.IsNullOrWhiteSpace(url)) { - using (var response = await GetMusicBrainzResponse(url, cancellationToken).ConfigureAwait(false)) - using (var stream = response.Content) - { - return GetResultsFromResponse(stream); - } + using var response = await GetMusicBrainzResponse(url, cancellationToken).ConfigureAwait(false); + await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); + return GetResultsFromResponse(stream); } return Enumerable.Empty<RemoteSearchResult>(); @@ -282,23 +280,19 @@ namespace MediaBrowser.Providers.Music WebUtility.UrlEncode(albumName), artistId); - using (var response = await GetMusicBrainzResponse(url, cancellationToken).ConfigureAwait(false)) - using (var stream = response.Content) - using (var oReader = new StreamReader(stream, Encoding.UTF8)) + using var response = await GetMusicBrainzResponse(url, cancellationToken).ConfigureAwait(false); + await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); + using var oReader = new StreamReader(stream, Encoding.UTF8); + var settings = new XmlReaderSettings { - var settings = new XmlReaderSettings() - { - ValidationType = ValidationType.None, - CheckCharacters = false, - IgnoreProcessingInstructions = true, - IgnoreComments = true - }; + ValidationType = ValidationType.None, + CheckCharacters = false, + IgnoreProcessingInstructions = true, + IgnoreComments = true + }; - using (var reader = XmlReader.Create(oReader, settings)) - { - return ReleaseResult.Parse(reader).FirstOrDefault(); - } - } + using var reader = XmlReader.Create(oReader, settings); + return ReleaseResult.Parse(reader).FirstOrDefault(); } private async Task<ReleaseResult> GetReleaseResultByArtistName(string albumName, string artistName, CancellationToken cancellationToken) @@ -309,23 +303,19 @@ namespace MediaBrowser.Providers.Music WebUtility.UrlEncode(albumName), WebUtility.UrlEncode(artistName)); - using (var response = await GetMusicBrainzResponse(url, cancellationToken).ConfigureAwait(false)) - using (var stream = response.Content) - using (var oReader = new StreamReader(stream, Encoding.UTF8)) + using var response = await GetMusicBrainzResponse(url, cancellationToken).ConfigureAwait(false); + await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); + using var oReader = new StreamReader(stream, Encoding.UTF8); + var settings = new XmlReaderSettings() { - var settings = new XmlReaderSettings() - { - ValidationType = ValidationType.None, - CheckCharacters = false, - IgnoreProcessingInstructions = true, - IgnoreComments = true - }; + ValidationType = ValidationType.None, + CheckCharacters = false, + IgnoreProcessingInstructions = true, + IgnoreComments = true + }; - using (var reader = XmlReader.Create(oReader, settings)) - { - return ReleaseResult.Parse(reader).FirstOrDefault(); - } - } + using var reader = XmlReader.Create(oReader, settings); + return ReleaseResult.Parse(reader).FirstOrDefault(); } private class ReleaseResult @@ -624,30 +614,21 @@ namespace MediaBrowser.Providers.Music { var url = "/ws/2/release?release-group=" + releaseGroupId.ToString(CultureInfo.InvariantCulture); - using (var response = await GetMusicBrainzResponse(url, cancellationToken).ConfigureAwait(false)) - using (var stream = response.Content) - using (var oReader = new StreamReader(stream, Encoding.UTF8)) + using var response = await GetMusicBrainzResponse(url, cancellationToken).ConfigureAwait(false); + await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); + using var oReader = new StreamReader(stream, Encoding.UTF8); + var settings = new XmlReaderSettings { - var settings = new XmlReaderSettings() - { - ValidationType = ValidationType.None, - CheckCharacters = false, - IgnoreProcessingInstructions = true, - IgnoreComments = true - }; - - using (var reader = XmlReader.Create(oReader, settings)) - { - var result = ReleaseResult.Parse(reader).FirstOrDefault(); + ValidationType = ValidationType.None, + CheckCharacters = false, + IgnoreProcessingInstructions = true, + IgnoreComments = true + }; - if (result != null) - { - return result.ReleaseId; - } - } - } + using var reader = XmlReader.Create(oReader, settings); + var result = ReleaseResult.Parse(reader).FirstOrDefault(); - return null; + return result?.ReleaseId; } /// <summary> @@ -660,59 +641,57 @@ namespace MediaBrowser.Providers.Music { var url = "/ws/2/release-group/?query=reid:" + releaseEntryId.ToString(CultureInfo.InvariantCulture); - using (var response = await GetMusicBrainzResponse(url, cancellationToken).ConfigureAwait(false)) - using (var stream = response.Content) - using (var oReader = new StreamReader(stream, Encoding.UTF8)) + using var response = await GetMusicBrainzResponse(url, cancellationToken).ConfigureAwait(false); + await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); + using var oReader = new StreamReader(stream, Encoding.UTF8); + var settings = new XmlReaderSettings { - var settings = new XmlReaderSettings() - { - ValidationType = ValidationType.None, - CheckCharacters = false, - IgnoreProcessingInstructions = true, - IgnoreComments = true - }; + ValidationType = ValidationType.None, + CheckCharacters = false, + IgnoreProcessingInstructions = true, + IgnoreComments = true + }; - using (var reader = XmlReader.Create(oReader, settings)) - { - reader.MoveToContent(); - reader.Read(); + using (var reader = XmlReader.Create(oReader, settings)) + { + reader.MoveToContent(); + reader.Read(); - // Loop through each element - while (!reader.EOF && reader.ReadState == ReadState.Interactive) + // Loop through each element + while (!reader.EOF && reader.ReadState == ReadState.Interactive) + { + if (reader.NodeType == XmlNodeType.Element) { - if (reader.NodeType == XmlNodeType.Element) + switch (reader.Name) { - switch (reader.Name) + case "release-group-list": { - case "release-group-list": - { - if (reader.IsEmptyElement) - { - reader.Read(); - continue; - } + if (reader.IsEmptyElement) + { + reader.Read(); + continue; + } - using (var subReader = reader.ReadSubtree()) - { - return GetFirstReleaseGroupId(subReader); - } - } + using (var subReader = reader.ReadSubtree()) + { + return GetFirstReleaseGroupId(subReader); + } + } - default: - { - reader.Skip(); - break; - } + default: + { + reader.Skip(); + break; } } - else - { - reader.Read(); - } } - - return null; + else + { + reader.Read(); + } } + + return null; } } @@ -755,23 +734,19 @@ namespace MediaBrowser.Providers.Music /// A number of retries shall be made in order to try and satisfy the request before /// giving up and returning null. /// </summary> - internal async Task<HttpResponseInfo> GetMusicBrainzResponse(string url, CancellationToken cancellationToken) + internal async Task<HttpResponseMessage> GetMusicBrainzResponse(string url, CancellationToken cancellationToken) { - var options = new HttpRequestOptions - { - Url = _musicBrainzBaseUrl.TrimEnd('/') + url, - CancellationToken = cancellationToken, - // MusicBrainz request a contact email address is supplied, as comment, in user agent field: - // https://musicbrainz.org/doc/XML_Web_Service/Rate_Limiting#User-Agent - UserAgent = string.Format( - CultureInfo.InvariantCulture, - "{0} ( {1} )", - _appHost.ApplicationUserAgent, - _appHost.ApplicationUserAgentAddress), - BufferContent = false - }; + using var options = new HttpRequestMessage(HttpMethod.Get, _musicBrainzBaseUrl.TrimEnd('/') + url); + + // MusicBrainz request a contact email address is supplied, as comment, in user agent field: + // https://musicbrainz.org/doc/XML_Web_Service/Rate_Limiting#User-Agent + options.Headers.UserAgent.Add(new ProductInfoHeaderValue(string.Format( + CultureInfo.InvariantCulture, + "{0} ( {1} )", + _appHost.ApplicationUserAgent, + _appHost.ApplicationUserAgentAddress))); - HttpResponseInfo response; + HttpResponseMessage response; var attempts = 0u; do @@ -790,7 +765,7 @@ namespace MediaBrowser.Providers.Music _logger.LogDebug("GetMusicBrainzResponse: Time since previous request: {0} ms", _stopWatchMusicBrainz.ElapsedMilliseconds); _stopWatchMusicBrainz.Restart(); - response = await _httpClient.SendAsync(options, HttpMethod.Get).ConfigureAwait(false); + response = await _httpClientFactory.CreateClient().SendAsync(options).ConfigureAwait(false); // We retry a finite number of times, and only whilst MB is indicating 503 (throttling) } @@ -799,14 +774,14 @@ namespace MediaBrowser.Providers.Music // Log error if unable to query MB database due to throttling if (attempts == MusicBrainzQueryAttempts && response.StatusCode == HttpStatusCode.ServiceUnavailable) { - _logger.LogError("GetMusicBrainzResponse: 503 Service Unavailable (throttled) response received {0} times whilst requesting {1}", attempts, options.Url); + _logger.LogError("GetMusicBrainzResponse: 503 Service Unavailable (throttled) response received {0} times whilst requesting {1}", attempts, options.RequestUri); } return response; } /// <inheritdoc /> - public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken) + public Task<HttpResponseMessage> GetImageResponse(string url, CancellationToken cancellationToken) { throw new NotImplementedException(); } diff --git a/MediaBrowser.Providers/Plugins/MusicBrainz/ArtistProvider.cs b/MediaBrowser.Providers/Plugins/MusicBrainz/ArtistProvider.cs index 955766403..b829ed378 100644 --- a/MediaBrowser.Providers/Plugins/MusicBrainz/ArtistProvider.cs +++ b/MediaBrowser.Providers/Plugins/MusicBrainz/ArtistProvider.cs @@ -6,11 +6,11 @@ using System.Globalization; using System.IO; using System.Linq; using System.Net; +using System.Net.Http; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Xml; -using MediaBrowser.Common.Net; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Extensions; using MediaBrowser.Controller.Providers; @@ -37,11 +37,9 @@ namespace MediaBrowser.Providers.Music { var url = "/ws/2/artist/?query=arid:{0}" + musicBrainzId.ToString(CultureInfo.InvariantCulture); - using (var response = await MusicBrainzAlbumProvider.Current.GetMusicBrainzResponse(url, cancellationToken).ConfigureAwait(false)) - using (var stream = response.Content) - { - return GetResultsFromResponse(stream); - } + using var response = await MusicBrainzAlbumProvider.Current.GetMusicBrainzResponse(url, cancellationToken).ConfigureAwait(false); + await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); + return GetResultsFromResponse(stream); } else { @@ -51,7 +49,7 @@ namespace MediaBrowser.Providers.Music var url = string.Format("/ws/2/artist/?query=\"{0}\"&dismax=true", UrlEncode(nameToSearch)); using (var response = await MusicBrainzAlbumProvider.Current.GetMusicBrainzResponse(url, cancellationToken).ConfigureAwait(false)) - using (var stream = response.Content) + await using (var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false)) { var results = GetResultsFromResponse(stream).ToList(); @@ -66,13 +64,9 @@ namespace MediaBrowser.Providers.Music // Try again using the search with accent characters url url = string.Format("/ws/2/artist/?query=artistaccent:\"{0}\"", UrlEncode(nameToSearch)); - using (var response = await MusicBrainzAlbumProvider.Current.GetMusicBrainzResponse(url, cancellationToken).ConfigureAwait(false)) - { - using (var stream = response.Content) - { - return GetResultsFromResponse(stream); - } - } + using var response = await MusicBrainzAlbumProvider.Current.GetMusicBrainzResponse(url, cancellationToken).ConfigureAwait(false); + await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); + return GetResultsFromResponse(stream); } } @@ -298,7 +292,7 @@ namespace MediaBrowser.Providers.Music public string Name => "MusicBrainz"; - public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken) + public Task<HttpResponseMessage> GetImageResponse(string url, CancellationToken cancellationToken) { throw new NotImplementedException(); } diff --git a/MediaBrowser.Providers/Plugins/Omdb/OmdbEpisodeProvider.cs b/MediaBrowser.Providers/Plugins/Omdb/OmdbEpisodeProvider.cs index 50d6b78ae..bfc840ea5 100644 --- a/MediaBrowser.Providers/Plugins/Omdb/OmdbEpisodeProvider.cs +++ b/MediaBrowser.Providers/Plugins/Omdb/OmdbEpisodeProvider.cs @@ -1,10 +1,10 @@ #pragma warning disable CS1591 using System.Collections.Generic; +using System.Net.Http; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Common; -using MediaBrowser.Common.Net; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; @@ -19,7 +19,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb public class OmdbEpisodeProvider : IRemoteMetadataProvider<Episode, EpisodeInfo>, IHasOrder { private readonly IJsonSerializer _jsonSerializer; - private readonly IHttpClient _httpClient; + private readonly IHttpClientFactory _httpClientFactory; private readonly OmdbItemProvider _itemProvider; private readonly IFileSystem _fileSystem; private readonly IServerConfigurationManager _configurationManager; @@ -28,17 +28,17 @@ namespace MediaBrowser.Providers.Plugins.Omdb public OmdbEpisodeProvider( IJsonSerializer jsonSerializer, IApplicationHost appHost, - IHttpClient httpClient, + IHttpClientFactory httpClientFactory, ILibraryManager libraryManager, IFileSystem fileSystem, IServerConfigurationManager configurationManager) { _jsonSerializer = jsonSerializer; - _httpClient = httpClient; + _httpClientFactory = httpClientFactory; _fileSystem = fileSystem; _configurationManager = configurationManager; _appHost = appHost; - _itemProvider = new OmdbItemProvider(jsonSerializer, _appHost, httpClient, libraryManager, fileSystem, configurationManager); + _itemProvider = new OmdbItemProvider(jsonSerializer, _appHost, httpClientFactory, libraryManager, fileSystem, configurationManager); } // After TheTvDb @@ -69,7 +69,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb { if (info.IndexNumber.HasValue && info.ParentIndexNumber.HasValue) { - result.HasMetadata = await new OmdbProvider(_jsonSerializer, _httpClient, _fileSystem, _appHost, _configurationManager) + result.HasMetadata = await new OmdbProvider(_jsonSerializer, _httpClientFactory, _fileSystem, _appHost, _configurationManager) .FetchEpisodeData(result, info.IndexNumber.Value, info.ParentIndexNumber.Value, info.GetProviderId(MetadataProvider.Imdb), seriesImdbId, info.MetadataLanguage, info.MetadataCountryCode, cancellationToken).ConfigureAwait(false); } } @@ -77,7 +77,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb return result; } - public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken) + public Task<HttpResponseMessage> GetImageResponse(string url, CancellationToken cancellationToken) { return _itemProvider.GetImageResponse(url, cancellationToken); } diff --git a/MediaBrowser.Providers/Plugins/Omdb/OmdbImageProvider.cs b/MediaBrowser.Providers/Plugins/Omdb/OmdbImageProvider.cs index 2d09a66c3..41e664aac 100644 --- a/MediaBrowser.Providers/Plugins/Omdb/OmdbImageProvider.cs +++ b/MediaBrowser.Providers/Plugins/Omdb/OmdbImageProvider.cs @@ -1,10 +1,10 @@ #pragma warning disable CS1591 using System.Collections.Generic; +using System.Net.Http; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Common; -using MediaBrowser.Common.Net; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Movies; @@ -19,16 +19,16 @@ namespace MediaBrowser.Providers.Plugins.Omdb { public class OmdbImageProvider : IRemoteImageProvider, IHasOrder { - private readonly IHttpClient _httpClient; + private readonly IHttpClientFactory _httpClientFactory; private readonly IJsonSerializer _jsonSerializer; private readonly IFileSystem _fileSystem; private readonly IServerConfigurationManager _configurationManager; private readonly IApplicationHost _appHost; - public OmdbImageProvider(IJsonSerializer jsonSerializer, IApplicationHost appHost, IHttpClient httpClient, IFileSystem fileSystem, IServerConfigurationManager configurationManager) + public OmdbImageProvider(IJsonSerializer jsonSerializer, IApplicationHost appHost, IHttpClientFactory httpClientFactory, IFileSystem fileSystem, IServerConfigurationManager configurationManager) { _jsonSerializer = jsonSerializer; - _httpClient = httpClient; + _httpClientFactory = httpClientFactory; _fileSystem = fileSystem; _configurationManager = configurationManager; _appHost = appHost; @@ -48,7 +48,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb var list = new List<RemoteImageInfo>(); - var provider = new OmdbProvider(_jsonSerializer, _httpClient, _fileSystem, _appHost, _configurationManager); + var provider = new OmdbProvider(_jsonSerializer, _httpClientFactory, _fileSystem, _appHost, _configurationManager); if (!string.IsNullOrWhiteSpace(imdbId)) { @@ -79,13 +79,9 @@ namespace MediaBrowser.Providers.Plugins.Omdb return list; } - public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken) + public Task<HttpResponseMessage> GetImageResponse(string url, CancellationToken cancellationToken) { - return _httpClient.GetResponse(new HttpRequestOptions - { - CancellationToken = cancellationToken, - Url = url - }); + return _httpClientFactory.CreateClient().GetAsync(url, cancellationToken); } public string Name => "The Open Movie Database"; diff --git a/MediaBrowser.Providers/Plugins/Omdb/OmdbItemProvider.cs b/MediaBrowser.Providers/Plugins/Omdb/OmdbItemProvider.cs index 12aecba84..d2823a08c 100644 --- a/MediaBrowser.Providers/Plugins/Omdb/OmdbItemProvider.cs +++ b/MediaBrowser.Providers/Plugins/Omdb/OmdbItemProvider.cs @@ -5,10 +5,10 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Net; +using System.Net.Http; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Common; -using MediaBrowser.Common.Net; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Movies; @@ -26,7 +26,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb IRemoteMetadataProvider<Movie, MovieInfo>, IRemoteMetadataProvider<Trailer, TrailerInfo>, IHasOrder { private readonly IJsonSerializer _jsonSerializer; - private readonly IHttpClient _httpClient; + private readonly IHttpClientFactory _httpClientFactory; private readonly ILibraryManager _libraryManager; private readonly IFileSystem _fileSystem; private readonly IServerConfigurationManager _configurationManager; @@ -35,13 +35,13 @@ namespace MediaBrowser.Providers.Plugins.Omdb public OmdbItemProvider( IJsonSerializer jsonSerializer, IApplicationHost appHost, - IHttpClient httpClient, + IHttpClientFactory httpClientFactory, ILibraryManager libraryManager, IFileSystem fileSystem, IServerConfigurationManager configurationManager) { _jsonSerializer = jsonSerializer; - _httpClient = httpClient; + _httpClientFactory = httpClientFactory; _libraryManager = libraryManager; _fileSystem = fileSystem; _configurationManager = configurationManager; @@ -129,67 +129,63 @@ namespace MediaBrowser.Providers.Plugins.Omdb var url = OmdbProvider.GetOmdbUrl(urlQuery, _appHost, cancellationToken); - using (var response = await OmdbProvider.GetOmdbResponse(_httpClient, url, cancellationToken).ConfigureAwait(false)) + using var response = await OmdbProvider.GetOmdbResponse(_httpClientFactory.CreateClient(), url, cancellationToken).ConfigureAwait(false); + await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); + var resultList = new List<SearchResult>(); + + if (isSearch) { - using (var stream = response.Content) + var searchResultList = await _jsonSerializer.DeserializeFromStreamAsync<SearchResultList>(stream).ConfigureAwait(false); + if (searchResultList != null && searchResultList.Search != null) { - var resultList = new List<SearchResult>(); - - if (isSearch) - { - var searchResultList = await _jsonSerializer.DeserializeFromStreamAsync<SearchResultList>(stream).ConfigureAwait(false); - if (searchResultList != null && searchResultList.Search != null) - { - resultList.AddRange(searchResultList.Search); - } - } - else - { - var result = await _jsonSerializer.DeserializeFromStreamAsync<SearchResult>(stream).ConfigureAwait(false); - if (string.Equals(result.Response, "true", StringComparison.OrdinalIgnoreCase)) - { - resultList.Add(result); - } - } - - return resultList.Select(result => - { - var item = new RemoteSearchResult - { - IndexNumber = searchInfo.IndexNumber, - Name = result.Title, - ParentIndexNumber = searchInfo.ParentIndexNumber, - SearchProviderName = Name - }; - - if (episodeSearchInfo != null && episodeSearchInfo.IndexNumberEnd.HasValue) - { - item.IndexNumberEnd = episodeSearchInfo.IndexNumberEnd.Value; - } - - item.SetProviderId(MetadataProvider.Imdb, result.imdbID); - - if (result.Year.Length > 0 - && int.TryParse(result.Year.AsSpan().Slice(0, Math.Min(result.Year.Length, 4)), NumberStyles.Integer, CultureInfo.InvariantCulture, out var parsedYear)) - { - item.ProductionYear = parsedYear; - } - - if (!string.IsNullOrEmpty(result.Released) - && DateTime.TryParse(result.Released, CultureInfo.InvariantCulture, DateTimeStyles.AllowWhiteSpaces, out var released)) - { - item.PremiereDate = released; - } - - if (!string.IsNullOrWhiteSpace(result.Poster) && !string.Equals(result.Poster, "N/A", StringComparison.OrdinalIgnoreCase)) - { - item.ImageUrl = result.Poster; - } - - return item; - }); + resultList.AddRange(searchResultList.Search); } } + else + { + var result = await _jsonSerializer.DeserializeFromStreamAsync<SearchResult>(stream).ConfigureAwait(false); + if (string.Equals(result.Response, "true", StringComparison.OrdinalIgnoreCase)) + { + resultList.Add(result); + } + } + + return resultList.Select(result => + { + var item = new RemoteSearchResult + { + IndexNumber = searchInfo.IndexNumber, + Name = result.Title, + ParentIndexNumber = searchInfo.ParentIndexNumber, + SearchProviderName = Name + }; + + if (episodeSearchInfo != null && episodeSearchInfo.IndexNumberEnd.HasValue) + { + item.IndexNumberEnd = episodeSearchInfo.IndexNumberEnd.Value; + } + + item.SetProviderId(MetadataProvider.Imdb, result.imdbID); + + if (result.Year.Length > 0 + && int.TryParse(result.Year.AsSpan().Slice(0, Math.Min(result.Year.Length, 4)), NumberStyles.Integer, CultureInfo.InvariantCulture, out var parsedYear)) + { + item.ProductionYear = parsedYear; + } + + if (!string.IsNullOrEmpty(result.Released) + && DateTime.TryParse(result.Released, CultureInfo.InvariantCulture, DateTimeStyles.AllowWhiteSpaces, out var released)) + { + item.PremiereDate = released; + } + + if (!string.IsNullOrWhiteSpace(result.Poster) && !string.Equals(result.Poster, "N/A", StringComparison.OrdinalIgnoreCase)) + { + item.ImageUrl = result.Poster; + } + + return item; + }); } public Task<MetadataResult<Trailer>> GetMetadata(TrailerInfo info, CancellationToken cancellationToken) @@ -224,7 +220,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb result.Item.SetProviderId(MetadataProvider.Imdb, imdbId); result.HasMetadata = true; - await new OmdbProvider(_jsonSerializer, _httpClient, _fileSystem, _appHost, _configurationManager).Fetch(result, imdbId, info.MetadataLanguage, info.MetadataCountryCode, cancellationToken).ConfigureAwait(false); + await new OmdbProvider(_jsonSerializer, _httpClientFactory, _fileSystem, _appHost, _configurationManager).Fetch(result, imdbId, info.MetadataLanguage, info.MetadataCountryCode, cancellationToken).ConfigureAwait(false); } return result; @@ -256,7 +252,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb result.Item.SetProviderId(MetadataProvider.Imdb, imdbId); result.HasMetadata = true; - await new OmdbProvider(_jsonSerializer, _httpClient, _fileSystem, _appHost, _configurationManager).Fetch(result, imdbId, info.MetadataLanguage, info.MetadataCountryCode, cancellationToken).ConfigureAwait(false); + await new OmdbProvider(_jsonSerializer, _httpClientFactory, _fileSystem, _appHost, _configurationManager).Fetch(result, imdbId, info.MetadataLanguage, info.MetadataCountryCode, cancellationToken).ConfigureAwait(false); } return result; @@ -276,13 +272,9 @@ namespace MediaBrowser.Providers.Plugins.Omdb return first == null ? null : first.GetProviderId(MetadataProvider.Imdb); } - public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken) + public Task<HttpResponseMessage> GetImageResponse(string url, CancellationToken cancellationToken) { - return _httpClient.GetResponse(new HttpRequestOptions - { - CancellationToken = cancellationToken, - Url = url - }); + return _httpClientFactory.CreateClient().GetAsync(url, cancellationToken); } class SearchResult diff --git a/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs b/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs index 13098d140..6ad5298de 100644 --- a/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs +++ b/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs @@ -10,7 +10,6 @@ using System.Text; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Common; -using MediaBrowser.Common.Net; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Providers; @@ -25,14 +24,14 @@ namespace MediaBrowser.Providers.Plugins.Omdb private readonly IJsonSerializer _jsonSerializer; private readonly IFileSystem _fileSystem; private readonly IServerConfigurationManager _configurationManager; - private readonly IHttpClient _httpClient; + private readonly IHttpClientFactory _httpClientFactory; private readonly CultureInfo _usCulture = new CultureInfo("en-US"); private readonly IApplicationHost _appHost; - public OmdbProvider(IJsonSerializer jsonSerializer, IHttpClient httpClient, IFileSystem fileSystem, IApplicationHost appHost, IServerConfigurationManager configurationManager) + public OmdbProvider(IJsonSerializer jsonSerializer, IHttpClientFactory httpClientFactory, IFileSystem fileSystem, IApplicationHost appHost, IServerConfigurationManager configurationManager) { _jsonSerializer = jsonSerializer; - _httpClient = httpClient; + _httpClientFactory = httpClientFactory; _fileSystem = fileSystem; _configurationManager = configurationManager; _appHost = appHost; @@ -293,15 +292,11 @@ namespace MediaBrowser.Providers.Plugins.Omdb var url = GetOmdbUrl(string.Format("i={0}&plot=short&tomatoes=true&r=json", imdbParam), _appHost, cancellationToken); - using (var response = await GetOmdbResponse(_httpClient, url, cancellationToken).ConfigureAwait(false)) - { - using (var stream = response.Content) - { - var rootObject = await _jsonSerializer.DeserializeFromStreamAsync<RootObject>(stream).ConfigureAwait(false); - Directory.CreateDirectory(Path.GetDirectoryName(path)); - _jsonSerializer.SerializeToFile(rootObject, path); - } - } + using var response = await GetOmdbResponse(_httpClientFactory.CreateClient(), url, cancellationToken).ConfigureAwait(false); + await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); + var rootObject = await _jsonSerializer.DeserializeFromStreamAsync<RootObject>(stream).ConfigureAwait(false); + Directory.CreateDirectory(Path.GetDirectoryName(path)); + _jsonSerializer.SerializeToFile(rootObject, path); return path; } @@ -330,28 +325,18 @@ namespace MediaBrowser.Providers.Plugins.Omdb var url = GetOmdbUrl(string.Format("i={0}&season={1}&detail=full", imdbParam, seasonId), _appHost, cancellationToken); - using (var response = await GetOmdbResponse(_httpClient, url, cancellationToken).ConfigureAwait(false)) - { - using (var stream = response.Content) - { - var rootObject = await _jsonSerializer.DeserializeFromStreamAsync<SeasonRootObject>(stream).ConfigureAwait(false); - Directory.CreateDirectory(Path.GetDirectoryName(path)); - _jsonSerializer.SerializeToFile(rootObject, path); - } - } + using var response = await GetOmdbResponse(_httpClientFactory.CreateClient(), url, cancellationToken).ConfigureAwait(false); + await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); + var rootObject = await _jsonSerializer.DeserializeFromStreamAsync<SeasonRootObject>(stream).ConfigureAwait(false); + Directory.CreateDirectory(Path.GetDirectoryName(path)); + _jsonSerializer.SerializeToFile(rootObject, path); return path; } - public static Task<HttpResponseInfo> GetOmdbResponse(IHttpClient httpClient, string url, CancellationToken cancellationToken) + public static Task<HttpResponseMessage> GetOmdbResponse(HttpClient httpClient, string url, CancellationToken cancellationToken) { - return httpClient.SendAsync(new HttpRequestOptions - { - Url = url, - CancellationToken = cancellationToken, - BufferContent = true, - EnableDefaultUserAgent = true - }, HttpMethod.Get); + return httpClient.GetAsync(url, cancellationToken); } internal string GetDataFilePath(string imdbId) diff --git a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbEpisodeImageProvider.cs b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbEpisodeImageProvider.cs index 9b87e3617..4d38d38dc 100644 --- a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbEpisodeImageProvider.cs +++ b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbEpisodeImageProvider.cs @@ -2,9 +2,9 @@ using System; using System.Collections.Generic; +using System.Net.Http; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.Net; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Providers; @@ -18,13 +18,13 @@ namespace MediaBrowser.Providers.Plugins.TheTvdb { public class TvdbEpisodeImageProvider : IRemoteImageProvider { - private readonly IHttpClient _httpClient; + private readonly IHttpClientFactory _httpClientFactory; private readonly ILogger<TvdbEpisodeImageProvider> _logger; private readonly TvdbClientManager _tvdbClientManager; - public TvdbEpisodeImageProvider(IHttpClient httpClient, ILogger<TvdbEpisodeImageProvider> logger, TvdbClientManager tvdbClientManager) + public TvdbEpisodeImageProvider(IHttpClientFactory httpClientFactory, ILogger<TvdbEpisodeImageProvider> logger, TvdbClientManager tvdbClientManager) { - _httpClient = httpClient; + _httpClientFactory = httpClientFactory; _logger = logger; _tvdbClientManager = tvdbClientManager; } @@ -113,13 +113,9 @@ namespace MediaBrowser.Providers.Plugins.TheTvdb public int Order => 0; - public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken) + public Task<HttpResponseMessage> GetImageResponse(string url, CancellationToken cancellationToken) { - return _httpClient.GetResponse(new HttpRequestOptions - { - CancellationToken = cancellationToken, - Url = url - }); + return _httpClientFactory.CreateClient().GetAsync(url, cancellationToken); } } } diff --git a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbEpisodeProvider.cs b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbEpisodeProvider.cs index 52fc53872..90436c7c9 100644 --- a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbEpisodeProvider.cs +++ b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbEpisodeProvider.cs @@ -2,9 +2,9 @@ using System; using System.Collections.Generic; +using System.Net.Http; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.Net; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Providers; @@ -21,13 +21,13 @@ namespace MediaBrowser.Providers.Plugins.TheTvdb /// </summary> public class TvdbEpisodeProvider : IRemoteMetadataProvider<Episode, EpisodeInfo>, IHasOrder { - private readonly IHttpClient _httpClient; + private readonly IHttpClientFactory _httpClientFactory; private readonly ILogger<TvdbEpisodeProvider> _logger; private readonly TvdbClientManager _tvdbClientManager; - public TvdbEpisodeProvider(IHttpClient httpClient, ILogger<TvdbEpisodeProvider> logger, TvdbClientManager tvdbClientManager) + public TvdbEpisodeProvider(IHttpClientFactory httpClientFactory, ILogger<TvdbEpisodeProvider> logger, TvdbClientManager tvdbClientManager) { - _httpClient = httpClient; + _httpClientFactory = httpClientFactory; _logger = logger; _tvdbClientManager = tvdbClientManager; } @@ -242,13 +242,9 @@ namespace MediaBrowser.Providers.Plugins.TheTvdb return result; } - public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken) + public Task<HttpResponseMessage> GetImageResponse(string url, CancellationToken cancellationToken) { - return _httpClient.GetResponse(new HttpRequestOptions - { - CancellationToken = cancellationToken, - Url = url - }); + return _httpClientFactory.CreateClient().GetAsync(url, cancellationToken); } public int Order => 0; diff --git a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbPersonImageProvider.cs b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbPersonImageProvider.cs index 9db21f012..388a4e3e7 100644 --- a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbPersonImageProvider.cs +++ b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbPersonImageProvider.cs @@ -3,9 +3,9 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Net.Http; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.Net; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.TV; @@ -20,15 +20,15 @@ namespace MediaBrowser.Providers.Plugins.TheTvdb { public class TvdbPersonImageProvider : IRemoteImageProvider, IHasOrder { - private readonly IHttpClient _httpClient; + private readonly IHttpClientFactory _httpClientFactory; private readonly ILogger<TvdbPersonImageProvider> _logger; private readonly ILibraryManager _libraryManager; private readonly TvdbClientManager _tvdbClientManager; - public TvdbPersonImageProvider(ILibraryManager libraryManager, IHttpClient httpClient, ILogger<TvdbPersonImageProvider> logger, TvdbClientManager tvdbClientManager) + public TvdbPersonImageProvider(ILibraryManager libraryManager, IHttpClientFactory httpClientFactory, ILogger<TvdbPersonImageProvider> logger, TvdbClientManager tvdbClientManager) { _libraryManager = libraryManager; - _httpClient = httpClient; + _httpClientFactory = httpClientFactory; _logger = logger; _tvdbClientManager = tvdbClientManager; } @@ -104,13 +104,9 @@ namespace MediaBrowser.Providers.Plugins.TheTvdb } /// <inheritdoc /> - public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken) + public Task<HttpResponseMessage> GetImageResponse(string url, CancellationToken cancellationToken) { - return _httpClient.GetResponse(new HttpRequestOptions - { - CancellationToken = cancellationToken, - Url = url - }); + return _httpClientFactory.CreateClient().GetAsync(url, cancellationToken); } } } diff --git a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeasonImageProvider.cs b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeasonImageProvider.cs index e9ba20475..ff8c3455f 100644 --- a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeasonImageProvider.cs +++ b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeasonImageProvider.cs @@ -3,9 +3,9 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Net.Http; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.Net; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Providers; @@ -20,13 +20,13 @@ namespace MediaBrowser.Providers.Plugins.TheTvdb { public class TvdbSeasonImageProvider : IRemoteImageProvider, IHasOrder { - private readonly IHttpClient _httpClient; + private readonly IHttpClientFactory _httpClientFactory; private readonly ILogger<TvdbSeasonImageProvider> _logger; private readonly TvdbClientManager _tvdbClientManager; - public TvdbSeasonImageProvider(IHttpClient httpClient, ILogger<TvdbSeasonImageProvider> logger, TvdbClientManager tvdbClientManager) + public TvdbSeasonImageProvider(IHttpClientFactory httpClientFactory, ILogger<TvdbSeasonImageProvider> logger, TvdbClientManager tvdbClientManager) { - _httpClient = httpClient; + _httpClientFactory = httpClientFactory; _logger = logger; _tvdbClientManager = tvdbClientManager; } @@ -146,13 +146,9 @@ namespace MediaBrowser.Providers.Plugins.TheTvdb public int Order => 0; - public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken) + public Task<HttpResponseMessage> GetImageResponse(string url, CancellationToken cancellationToken) { - return _httpClient.GetResponse(new HttpRequestOptions - { - CancellationToken = cancellationToken, - Url = url - }); + return _httpClientFactory.CreateClient().GetAsync(url, cancellationToken); } } } diff --git a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeriesImageProvider.cs b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeriesImageProvider.cs index c33aefbc1..d287828eb 100644 --- a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeriesImageProvider.cs +++ b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeriesImageProvider.cs @@ -3,9 +3,9 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Net.Http; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.Net; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; @@ -20,13 +20,13 @@ namespace MediaBrowser.Providers.Plugins.TheTvdb { public class TvdbSeriesImageProvider : IRemoteImageProvider, IHasOrder { - private readonly IHttpClient _httpClient; + private readonly IHttpClientFactory _httpClientFactory; private readonly ILogger<TvdbSeriesImageProvider> _logger; private readonly TvdbClientManager _tvdbClientManager; - public TvdbSeriesImageProvider(IHttpClient httpClient, ILogger<TvdbSeriesImageProvider> logger, TvdbClientManager tvdbClientManager) + public TvdbSeriesImageProvider(IHttpClientFactory httpClientFactory, ILogger<TvdbSeriesImageProvider> logger, TvdbClientManager tvdbClientManager) { - _httpClient = httpClient; + _httpClientFactory = httpClientFactory; _logger = logger; _tvdbClientManager = tvdbClientManager; } @@ -144,13 +144,9 @@ namespace MediaBrowser.Providers.Plugins.TheTvdb public int Order => 0; - public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken) + public Task<HttpResponseMessage> GetImageResponse(string url, CancellationToken cancellationToken) { - return _httpClient.GetResponse(new HttpRequestOptions - { - CancellationToken = cancellationToken, - Url = url - }); + return _httpClientFactory.CreateClient().GetAsync(url, cancellationToken); } } } diff --git a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeriesProvider.cs b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeriesProvider.cs index df48629d0..c6dd8a5f3 100644 --- a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeriesProvider.cs +++ b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbSeriesProvider.cs @@ -3,11 +3,11 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Net.Http; using System.Text; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.Net; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Providers; @@ -25,15 +25,15 @@ namespace MediaBrowser.Providers.Plugins.TheTvdb { internal static TvdbSeriesProvider Current { get; private set; } - private readonly IHttpClient _httpClient; + private readonly IHttpClientFactory _httpClientFactory; private readonly ILogger<TvdbSeriesProvider> _logger; private readonly ILibraryManager _libraryManager; private readonly ILocalizationManager _localizationManager; private readonly TvdbClientManager _tvdbClientManager; - public TvdbSeriesProvider(IHttpClient httpClient, ILogger<TvdbSeriesProvider> logger, ILibraryManager libraryManager, ILocalizationManager localizationManager, TvdbClientManager tvdbClientManager) + public TvdbSeriesProvider(IHttpClientFactory httpClientFactory, ILogger<TvdbSeriesProvider> logger, ILibraryManager libraryManager, ILocalizationManager localizationManager, TvdbClientManager tvdbClientManager) { - _httpClient = httpClient; + _httpClientFactory = httpClientFactory; _logger = logger; _libraryManager = libraryManager; _localizationManager = localizationManager; @@ -408,14 +408,9 @@ namespace MediaBrowser.Providers.Plugins.TheTvdb public int Order => 0; - public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken) + public Task<HttpResponseMessage> GetImageResponse(string url, CancellationToken cancellationToken) { - return _httpClient.GetResponse(new HttpRequestOptions - { - CancellationToken = cancellationToken, - Url = url, - BufferContent = false - }); + return _httpClientFactory.CreateClient().GetAsync(url, cancellationToken); } } } diff --git a/MediaBrowser.Providers/Plugins/Tmdb/BoxSets/TmdbBoxSetImageProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/BoxSets/TmdbBoxSetImageProvider.cs index c41bd925e..f43444028 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/BoxSets/TmdbBoxSetImageProvider.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/BoxSets/TmdbBoxSetImageProvider.cs @@ -3,9 +3,9 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Net.Http; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.Net; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Providers; @@ -20,11 +20,11 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.BoxSets { public class TmdbBoxSetImageProvider : IRemoteImageProvider, IHasOrder { - private readonly IHttpClient _httpClient; + private readonly IHttpClientFactory _httpClientFactory; - public TmdbBoxSetImageProvider(IHttpClient httpClient) + public TmdbBoxSetImageProvider(IHttpClientFactory httpClientFactory) { - _httpClient = httpClient; + _httpClientFactory = httpClientFactory; } public string Name => ProviderName; @@ -153,13 +153,9 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.BoxSets public int Order => 0; - public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken) + public Task<HttpResponseMessage> GetImageResponse(string url, CancellationToken cancellationToken) { - return _httpClient.GetResponse(new HttpRequestOptions - { - CancellationToken = cancellationToken, - Url = url - }); + return _httpClientFactory.CreateClient().GetAsync(url, cancellationToken); } } } diff --git a/MediaBrowser.Providers/Plugins/Tmdb/BoxSets/TmdbBoxSetProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/BoxSets/TmdbBoxSetProvider.cs index 20b6cd505..a5f823f7c 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/BoxSets/TmdbBoxSetProvider.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/BoxSets/TmdbBoxSetProvider.cs @@ -5,10 +5,11 @@ using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; +using System.Net.Http; +using System.Net.Http.Headers; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Common.Configuration; -using MediaBrowser.Common.Net; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Library; @@ -36,7 +37,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.BoxSets private readonly IServerConfigurationManager _config; private readonly IFileSystem _fileSystem; private readonly ILocalizationManager _localization; - private readonly IHttpClient _httpClient; + private readonly IHttpClientFactory _httpClientFactory; private readonly ILibraryManager _libraryManager; public TmdbBoxSetProvider( @@ -45,7 +46,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.BoxSets IServerConfigurationManager config, IFileSystem fileSystem, ILocalizationManager localization, - IHttpClient httpClient, + IHttpClientFactory httpClientFactory, ILibraryManager libraryManager) { _logger = logger; @@ -53,7 +54,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.BoxSets _config = config; _fileSystem = fileSystem; _localization = localization; - _httpClient = httpClient; + _httpClientFactory = httpClientFactory; _libraryManager = libraryManager; Current = this; } @@ -187,20 +188,11 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.BoxSets cancellationToken.ThrowIfCancellationRequested(); - CollectionResult mainResult; - - using (var response = await TmdbMovieProvider.Current.GetMovieDbResponse(new HttpRequestOptions - { - Url = url, - CancellationToken = cancellationToken, - AcceptHeader = TmdbUtils.AcceptHeader - }).ConfigureAwait(false)) - { - using (var json = response.Content) - { - mainResult = await _json.DeserializeFromStreamAsync<CollectionResult>(json).ConfigureAwait(false); - } - } + using var requestMessage = new HttpRequestMessage(HttpMethod.Get, url); + requestMessage.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue(TmdbUtils.AcceptHeader)); + using var mainResponse = await TmdbMovieProvider.Current.GetMovieDbResponse(requestMessage); + await using var stream = await mainResponse.Content.ReadAsStreamAsync().ConfigureAwait(false); + var mainResult = await _json.DeserializeFromStreamAsync<CollectionResult>(stream).ConfigureAwait(false); cancellationToken.ThrowIfCancellationRequested(); @@ -216,18 +208,10 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.BoxSets url += "&include_image_language=" + TmdbMovieProvider.GetImageLanguagesParam(language); } - using (var response = await TmdbMovieProvider.Current.GetMovieDbResponse(new HttpRequestOptions - { - Url = url, - CancellationToken = cancellationToken, - AcceptHeader = TmdbUtils.AcceptHeader - }).ConfigureAwait(false)) - { - using (var json = response.Content) - { - mainResult = await _json.DeserializeFromStreamAsync<CollectionResult>(json).ConfigureAwait(false); - } - } + using var langRequestMessage = new HttpRequestMessage(HttpMethod.Get, url); + langRequestMessage.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue(TmdbUtils.AcceptHeader)); + await using var langStream = await mainResponse.Content.ReadAsStreamAsync().ConfigureAwait(false); + mainResult = await _json.DeserializeFromStreamAsync<CollectionResult>(langStream).ConfigureAwait(false); } } @@ -277,13 +261,9 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.BoxSets return dataPath; } - public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken) + public Task<HttpResponseMessage> GetImageResponse(string url, CancellationToken cancellationToken) { - return _httpClient.GetResponse(new HttpRequestOptions - { - CancellationToken = cancellationToken, - Url = url - }); + return _httpClientFactory.CreateClient().GetAsync(url, cancellationToken); } } } diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbImageProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbImageProvider.cs index 36a06fba7..60d7a599e 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbImageProvider.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbImageProvider.cs @@ -4,9 +4,9 @@ using System; using System.Collections.Generic; using System.Globalization; using System.Linq; +using System.Net.Http; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.Net; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Providers; @@ -23,13 +23,13 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Movies public class TmdbImageProvider : IRemoteImageProvider, IHasOrder { private readonly IJsonSerializer _jsonSerializer; - private readonly IHttpClient _httpClient; + private readonly IHttpClientFactory _httpClientFactory; private readonly IFileSystem _fileSystem; - public TmdbImageProvider(IJsonSerializer jsonSerializer, IHttpClient httpClient, IFileSystem fileSystem) + public TmdbImageProvider(IJsonSerializer jsonSerializer, IHttpClientFactory httpClientFactory, IFileSystem fileSystem) { _jsonSerializer = jsonSerializer; - _httpClient = httpClient; + _httpClientFactory = httpClientFactory; _fileSystem = fileSystem; } @@ -202,13 +202,9 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Movies public int Order => 0; - public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken) + public Task<HttpResponseMessage> GetImageResponse(string url, CancellationToken cancellationToken) { - return _httpClient.GetResponse(new HttpRequestOptions - { - CancellationToken = cancellationToken, - Url = url - }); + return _httpClientFactory.CreateClient().GetAsync(url, cancellationToken); } } } diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieProvider.cs index 27ab6756f..f078153f6 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieProvider.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieProvider.cs @@ -6,11 +6,11 @@ using System.Globalization; using System.IO; using System.Net; using System.Net.Http; +using System.Net.Http.Headers; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Common; using MediaBrowser.Common.Configuration; -using MediaBrowser.Common.Net; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Movies; @@ -18,7 +18,6 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; using MediaBrowser.Model.IO; -using MediaBrowser.Model.Net; using MediaBrowser.Model.Providers; using MediaBrowser.Model.Serialization; using MediaBrowser.Providers.Plugins.Tmdb.Models.Movies; @@ -34,7 +33,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Movies internal static TmdbMovieProvider Current { get; private set; } private readonly IJsonSerializer _jsonSerializer; - private readonly IHttpClient _httpClient; + private readonly IHttpClientFactory _httpClientFactory; private readonly IFileSystem _fileSystem; private readonly IServerConfigurationManager _configurationManager; private readonly ILogger<TmdbMovieProvider> _logger; @@ -45,7 +44,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Movies public TmdbMovieProvider( IJsonSerializer jsonSerializer, - IHttpClient httpClient, + IHttpClientFactory httpClientFactory, IFileSystem fileSystem, IServerConfigurationManager configurationManager, ILogger<TmdbMovieProvider> logger, @@ -53,7 +52,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Movies IApplicationHost appHost) { _jsonSerializer = jsonSerializer; - _httpClient = httpClient; + _httpClientFactory = httpClientFactory; _fileSystem = fileSystem; _configurationManager = configurationManager; _logger = logger; @@ -146,20 +145,12 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Movies return _tmdbSettings; } - using (HttpResponseInfo response = await GetMovieDbResponse(new HttpRequestOptions - { - Url = string.Format(CultureInfo.InvariantCulture, TmdbConfigUrl, TmdbUtils.ApiKey), - CancellationToken = cancellationToken, - AcceptHeader = TmdbUtils.AcceptHeader - }).ConfigureAwait(false)) - { - using (Stream json = response.Content) - { - _tmdbSettings = await _jsonSerializer.DeserializeFromStreamAsync<TmdbSettingsResult>(json).ConfigureAwait(false); - - return _tmdbSettings; - } - } + using var requestMessage = new HttpRequestMessage(HttpMethod.Get, string.Format(CultureInfo.InvariantCulture, TmdbConfigUrl, TmdbUtils.ApiKey)); + requestMessage.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue(TmdbUtils.AcceptHeader)); + using var response = await GetMovieDbResponse(requestMessage).ConfigureAwait(false); + await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); + _tmdbSettings = await _jsonSerializer.DeserializeFromStreamAsync<TmdbSettingsResult>(stream).ConfigureAwait(false); + return _tmdbSettings; } private const string TmdbConfigUrl = TmdbUtils.BaseTmdbApiUrl + "3/configuration?api_key={0}"; @@ -331,41 +322,18 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Movies url += "&include_image_language=" + GetImageLanguagesParam(language); } - MovieResult mainResult; - cancellationToken.ThrowIfCancellationRequested(); - // Cache if not using a tmdbId because we won't have the tmdb cache directory structure. So use the lower level cache. - var cacheMode = isTmdbId ? CacheMode.None : CacheMode.Unconditional; - var cacheLength = TimeSpan.FromDays(3); - - try + using var requestMessage = new HttpRequestMessage(HttpMethod.Get, url); + requestMessage.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue(TmdbUtils.AcceptHeader)); + using var mainResponse = await GetMovieDbResponse(requestMessage); + if (mainResponse.StatusCode == HttpStatusCode.NotFound) { - using (var response = await GetMovieDbResponse(new HttpRequestOptions - { - Url = url, - CancellationToken = cancellationToken, - AcceptHeader = TmdbUtils.AcceptHeader, - CacheMode = cacheMode, - CacheLength = cacheLength - }).ConfigureAwait(false)) - { - using (var json = response.Content) - { - mainResult = await _jsonSerializer.DeserializeFromStreamAsync<MovieResult>(json).ConfigureAwait(false); - } - } + return null; } - catch (HttpException ex) - { - // Return null so that callers know there is no metadata for this id - if (ex.StatusCode.HasValue && ex.StatusCode.Value == HttpStatusCode.NotFound) - { - return null; - } - throw; - } + await using var stream = await mainResponse.Content.ReadAsStreamAsync().ConfigureAwait(false); + var mainResult = await _jsonSerializer.DeserializeFromStreamAsync<MovieResult>(stream).ConfigureAwait(false); cancellationToken.ThrowIfCancellationRequested(); @@ -385,22 +353,13 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Movies url += "&include_image_language=" + GetImageLanguagesParam(language); } - using (var response = await GetMovieDbResponse(new HttpRequestOptions - { - Url = url, - CancellationToken = cancellationToken, - AcceptHeader = TmdbUtils.AcceptHeader, - CacheMode = cacheMode, - CacheLength = cacheLength - }).ConfigureAwait(false)) - { - using (var json = response.Content) - { - var englishResult = await _jsonSerializer.DeserializeFromStreamAsync<MovieResult>(json).ConfigureAwait(false); + using var langRequestMessage = new HttpRequestMessage(HttpMethod.Get, url); + langRequestMessage.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue(TmdbUtils.AcceptHeader)); + using var langResponse = await GetMovieDbResponse(langRequestMessage); - mainResult.Overview = englishResult.Overview; - } - } + await using var langStream = await langResponse.Content.ReadAsStreamAsync().ConfigureAwait(false); + var langResult = await _jsonSerializer.DeserializeFromStreamAsync<MovieResult>(stream).ConfigureAwait(false); + mainResult.Overview = langResult.Overview; } return mainResult; @@ -409,25 +368,19 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Movies /// <summary> /// Gets the movie db response. /// </summary> - internal async Task<HttpResponseInfo> GetMovieDbResponse(HttpRequestOptions options) + internal async Task<HttpResponseMessage> GetMovieDbResponse(HttpRequestMessage message) { - options.BufferContent = true; - options.UserAgent = _appHost.ApplicationUserAgent; - - return await _httpClient.SendAsync(options, HttpMethod.Get).ConfigureAwait(false); + message.Headers.UserAgent.Add(new ProductInfoHeaderValue(_appHost.ApplicationUserAgent)); + return await _httpClientFactory.CreateClient().SendAsync(message); } /// <inheritdoc /> public int Order => 1; /// <inheritdoc /> - public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken) + public Task<HttpResponseMessage> GetImageResponse(string url, CancellationToken cancellationToken) { - return _httpClient.GetResponse(new HttpRequestOptions - { - CancellationToken = cancellationToken, - Url = url - }); + return _httpClientFactory.CreateClient().GetAsync(url, cancellationToken); } } } diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbSearch.cs b/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbSearch.cs index 10935c655..d5dfca98a 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbSearch.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbSearch.cs @@ -5,10 +5,11 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Net; +using System.Net.Http; +using System.Net.Http.Headers; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.Net; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; @@ -168,47 +169,34 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Movies var url3 = string.Format(_searchURL, WebUtility.UrlEncode(name), TmdbUtils.ApiKey, language, type); - using (var response = await TmdbMovieProvider.Current.GetMovieDbResponse(new HttpRequestOptions - { - Url = url3, - CancellationToken = cancellationToken, - AcceptHeader = TmdbUtils.AcceptHeader + var requestMessage = new HttpRequestMessage(HttpMethod.Get, url3); + requestMessage.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue(TmdbUtils.AcceptHeader)); + using var response = await TmdbMovieProvider.Current.GetMovieDbResponse(requestMessage).ConfigureAwait(false); + await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); + var searchResults = await _json.DeserializeFromStreamAsync<TmdbSearchResult<MovieResult>>(stream).ConfigureAwait(false); - }).ConfigureAwait(false)) - { - using (var json = response.Content) - { - var searchResults = await _json.DeserializeFromStreamAsync<TmdbSearchResult<MovieResult>>(json).ConfigureAwait(false); + var results = searchResults.Results ?? new List<MovieResult>(); - var results = searchResults.Results ?? new List<MovieResult>(); + return results + .Select(i => + { + var remoteResult = new RemoteSearchResult {SearchProviderName = TmdbMovieProvider.Current.Name, Name = i.Title ?? i.Name ?? i.Original_Title, ImageUrl = string.IsNullOrWhiteSpace(i.Poster_Path) ? null : baseImageUrl + i.Poster_Path}; - return results - .Select(i => + if (!string.IsNullOrWhiteSpace(i.Release_Date)) + { + // These dates are always in this exact format + if (DateTime.TryParseExact(i.Release_Date, "yyyy-MM-dd", _usCulture, DateTimeStyles.None, out var r)) { - var remoteResult = new RemoteSearchResult - { - SearchProviderName = TmdbMovieProvider.Current.Name, - Name = i.Title ?? i.Name ?? i.Original_Title, - ImageUrl = string.IsNullOrWhiteSpace(i.Poster_Path) ? null : baseImageUrl + i.Poster_Path - }; - - if (!string.IsNullOrWhiteSpace(i.Release_Date)) - { - // These dates are always in this exact format - if (DateTime.TryParseExact(i.Release_Date, "yyyy-MM-dd", _usCulture, DateTimeStyles.None, out var r)) - { - remoteResult.PremiereDate = r.ToUniversalTime(); - remoteResult.ProductionYear = remoteResult.PremiereDate.Value.Year; - } - } - - remoteResult.SetProviderId(MetadataProvider.Tmdb, i.Id.ToString(_usCulture)); - - return remoteResult; - }) - .ToList(); - } - } + remoteResult.PremiereDate = r.ToUniversalTime(); + remoteResult.ProductionYear = remoteResult.PremiereDate.Value.Year; + } + } + + remoteResult.SetProviderId(MetadataProvider.Tmdb, i.Id.ToString(_usCulture)); + + return remoteResult; + }) + .ToList(); } private async Task<List<RemoteSearchResult>> GetSearchResultsTv(string name, int? year, string language, string baseImageUrl, CancellationToken cancellationToken) @@ -220,46 +208,34 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Movies var url3 = string.Format(_searchURL, WebUtility.UrlEncode(name), TmdbUtils.ApiKey, language, "tv"); - using (var response = await TmdbMovieProvider.Current.GetMovieDbResponse(new HttpRequestOptions - { - Url = url3, - CancellationToken = cancellationToken, - AcceptHeader = TmdbUtils.AcceptHeader - }).ConfigureAwait(false)) - { - using (var json = response.Content) - { - var searchResults = await _json.DeserializeFromStreamAsync<TmdbSearchResult<TvResult>>(json).ConfigureAwait(false); + var requestMessage = new HttpRequestMessage(HttpMethod.Get, url3); + requestMessage.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue(TmdbUtils.AcceptHeader)); + using var response = await TmdbMovieProvider.Current.GetMovieDbResponse(requestMessage).ConfigureAwait(false); + await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); + var searchResults = await _json.DeserializeFromStreamAsync<TmdbSearchResult<TvResult>>(stream).ConfigureAwait(false); - var results = searchResults.Results ?? new List<TvResult>(); + var results = searchResults.Results ?? new List<TvResult>(); - return results - .Select(i => + return results + .Select(i => + { + var remoteResult = new RemoteSearchResult {SearchProviderName = TmdbMovieProvider.Current.Name, Name = i.Name ?? i.Original_Name, ImageUrl = string.IsNullOrWhiteSpace(i.Poster_Path) ? null : baseImageUrl + i.Poster_Path}; + + if (!string.IsNullOrWhiteSpace(i.First_Air_Date)) + { + // These dates are always in this exact format + if (DateTime.TryParseExact(i.First_Air_Date, "yyyy-MM-dd", _usCulture, DateTimeStyles.None, out var r)) { - var remoteResult = new RemoteSearchResult - { - SearchProviderName = TmdbMovieProvider.Current.Name, - Name = i.Name ?? i.Original_Name, - ImageUrl = string.IsNullOrWhiteSpace(i.Poster_Path) ? null : baseImageUrl + i.Poster_Path - }; - - if (!string.IsNullOrWhiteSpace(i.First_Air_Date)) - { - // These dates are always in this exact format - if (DateTime.TryParseExact(i.First_Air_Date, "yyyy-MM-dd", _usCulture, DateTimeStyles.None, out var r)) - { - remoteResult.PremiereDate = r.ToUniversalTime(); - remoteResult.ProductionYear = remoteResult.PremiereDate.Value.Year; - } - } - - remoteResult.SetProviderId(MetadataProvider.Tmdb, i.Id.ToString(_usCulture)); - - return remoteResult; - }) - .ToList(); - } - } + remoteResult.PremiereDate = r.ToUniversalTime(); + remoteResult.ProductionYear = remoteResult.PremiereDate.Value.Year; + } + } + + remoteResult.SetProviderId(MetadataProvider.Tmdb, i.Id.ToString(_usCulture)); + + return remoteResult; + }) + .ToList(); } } } diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Music/TmdbMusicVideoProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/Music/TmdbMusicVideoProvider.cs index d4264dd4e..73e49ba5b 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/Music/TmdbMusicVideoProvider.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/Music/TmdbMusicVideoProvider.cs @@ -2,9 +2,9 @@ using System; using System.Collections.Generic; +using System.Net.Http; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.Net; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Providers; @@ -26,7 +26,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Music public string Name => TmdbMovieProvider.Current.Name; - public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken) + public Task<HttpResponseMessage> GetImageResponse(string url, CancellationToken cancellationToken) { throw new NotImplementedException(); } diff --git a/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonImageProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonImageProvider.cs index 2faa9f835..f31a7faea 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonImageProvider.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonImageProvider.cs @@ -3,9 +3,9 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Net.Http; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.Net; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Providers; @@ -22,13 +22,13 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.People { private readonly IServerConfigurationManager _config; private readonly IJsonSerializer _jsonSerializer; - private readonly IHttpClient _httpClient; + private readonly IHttpClientFactory _httpClientFactory; - public TmdbPersonImageProvider(IServerConfigurationManager config, IJsonSerializer jsonSerializer, IHttpClient httpClient) + public TmdbPersonImageProvider(IServerConfigurationManager config, IJsonSerializer jsonSerializer, IHttpClientFactory httpClientFactory) { _config = config; _jsonSerializer = jsonSerializer; - _httpClient = httpClient; + _httpClientFactory = httpClientFactory; } public string Name => ProviderName; @@ -127,13 +127,9 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.People public int Order => 0; - public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken) + public Task<HttpResponseMessage> GetImageResponse(string url, CancellationToken cancellationToken) { - return _httpClient.GetResponse(new HttpRequestOptions - { - CancellationToken = cancellationToken, - Url = url - }); + 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 58cbf9eef..97482f34a 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonProvider.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonProvider.cs @@ -6,11 +6,12 @@ using System.Globalization; using System.IO; using System.Linq; using System.Net; +using System.Net.Http; +using System.Net.Http.Headers; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Extensions; -using MediaBrowser.Common.Net; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Providers; @@ -36,20 +37,20 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.People private readonly IJsonSerializer _jsonSerializer; private readonly IFileSystem _fileSystem; private readonly IServerConfigurationManager _configurationManager; - private readonly IHttpClient _httpClient; + private readonly IHttpClientFactory _httpClientFactory; private readonly ILogger<TmdbPersonProvider> _logger; public TmdbPersonProvider( IFileSystem fileSystem, IServerConfigurationManager configurationManager, IJsonSerializer jsonSerializer, - IHttpClient httpClient, + IHttpClientFactory httpClientFactory, ILogger<TmdbPersonProvider> logger) { _fileSystem = fileSystem; _configurationManager = configurationManager; _jsonSerializer = jsonSerializer; - _httpClient = httpClient; + _httpClientFactory = httpClientFactory; _logger = logger; Current = this; } @@ -96,22 +97,15 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.People var url = string.Format(TmdbUtils.BaseTmdbApiUrl + @"3/search/person?api_key={1}&query={0}", WebUtility.UrlEncode(searchInfo.Name), TmdbUtils.ApiKey); - using (var response = await TmdbMovieProvider.Current.GetMovieDbResponse(new HttpRequestOptions - { - Url = url, - CancellationToken = cancellationToken, - AcceptHeader = TmdbUtils.AcceptHeader + using var requestMessage = new HttpRequestMessage(HttpMethod.Get, url); + requestMessage.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue(TmdbUtils.AcceptHeader)); + var response = await TmdbMovieProvider.Current.GetMovieDbResponse(requestMessage).ConfigureAwait(false); + await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); - }).ConfigureAwait(false)) - { - using (var json = response.Content) - { - var result = await _jsonSerializer.DeserializeFromStreamAsync<TmdbSearchResult<PersonSearchResult>>(json).ConfigureAwait(false) ?? - new TmdbSearchResult<PersonSearchResult>(); + var result2 = await _jsonSerializer.DeserializeFromStreamAsync<TmdbSearchResult<PersonSearchResult>>(stream).ConfigureAwait(false) + ?? new TmdbSearchResult<PersonSearchResult>(); - return result.Results.Select(i => GetSearchResult(i, tmdbImageUrl)); - } - } + return result2.Results.Select(i => GetSearchResult(i, tmdbImageUrl)); } private RemoteSearchResult GetSearchResult(PersonSearchResult i, string baseImageUrl) @@ -230,23 +224,12 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.People var url = string.Format(TmdbUtils.BaseTmdbApiUrl + @"3/person/{1}?api_key={0}&append_to_response=credits,images,external_ids", TmdbUtils.ApiKey, id); - using (var response = await TmdbMovieProvider.Current.GetMovieDbResponse(new HttpRequestOptions - { - Url = url, - CancellationToken = cancellationToken, - AcceptHeader = TmdbUtils.AcceptHeader - }).ConfigureAwait(false)) - { - using (var json = response.Content) - { - Directory.CreateDirectory(Path.GetDirectoryName(dataFilePath)); - - using (var fs = new FileStream(dataFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, IODefaults.FileStreamBufferSize, true)) - { - await json.CopyToAsync(fs).ConfigureAwait(false); - } - } - } + using var requestMessage = new HttpRequestMessage(HttpMethod.Get, url); + requestMessage.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue(TmdbUtils.AcceptHeader)); + using var response = await TmdbMovieProvider.Current.GetMovieDbResponse(requestMessage).ConfigureAwait(false); + Directory.CreateDirectory(Path.GetDirectoryName(dataFilePath)); + await using var fs = new FileStream(dataFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, IODefaults.FileStreamBufferSize, true); + await response.Content.CopyToAsync(fs).ConfigureAwait(false); } private static string GetPersonDataPath(IApplicationPaths appPaths, string tmdbId) @@ -266,13 +249,9 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.People return Path.Combine(appPaths.CachePath, "tmdb-people"); } - public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken) + public Task<HttpResponseMessage> GetImageResponse(string url, CancellationToken cancellationToken) { - return _httpClient.GetResponse(new HttpRequestOptions - { - CancellationToken = cancellationToken, - Url = url - }); + return _httpClientFactory.CreateClient().GetAsync(url, cancellationToken); } } } diff --git a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeImageProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeImageProvider.cs index 77e4b2c56..eebecdac6 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeImageProvider.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeImageProvider.cs @@ -3,9 +3,9 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Net.Http; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.Net; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Providers; @@ -26,8 +26,8 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV IRemoteImageProvider, IHasOrder { - public TmdbEpisodeImageProvider(IHttpClient httpClient, IServerConfigurationManager configurationManager, IJsonSerializer jsonSerializer, IFileSystem fileSystem, ILocalizationManager localization, ILoggerFactory loggerFactory) - : base(httpClient, configurationManager, jsonSerializer, fileSystem, localization, loggerFactory) + public TmdbEpisodeImageProvider(IHttpClientFactory httpClientFactory, IServerConfigurationManager configurationManager, IJsonSerializer jsonSerializer, IFileSystem fileSystem, ILocalizationManager localization, ILoggerFactory loggerFactory) + : base(httpClientFactory, configurationManager, jsonSerializer, fileSystem, localization, loggerFactory) { } public IEnumerable<ImageType> GetSupportedImages(BaseItem item) @@ -115,7 +115,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV return images.Stills ?? new List<Still>(); } - public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken) + public Task<HttpResponseMessage> GetImageResponse(string url, CancellationToken cancellationToken) { return GetResponse(url, cancellationToken); } diff --git a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeProvider.cs index a07ceb40e..b4aef4542 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeProvider.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeProvider.cs @@ -5,9 +5,9 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Net; +using System.Net.Http; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.Net; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.TV; @@ -27,8 +27,8 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV IRemoteMetadataProvider<Episode, EpisodeInfo>, IHasOrder { - public TmdbEpisodeProvider(IHttpClient httpClient, IServerConfigurationManager configurationManager, IJsonSerializer jsonSerializer, IFileSystem fileSystem, ILocalizationManager localization, ILoggerFactory loggerFactory) - : base(httpClient, configurationManager, jsonSerializer, fileSystem, localization, loggerFactory) + public TmdbEpisodeProvider(IHttpClientFactory httpClientFactory, IServerConfigurationManager configurationManager, IJsonSerializer jsonSerializer, IFileSystem fileSystem, ILocalizationManager localization, ILoggerFactory loggerFactory) + : base(httpClientFactory, configurationManager, jsonSerializer, fileSystem, localization, loggerFactory) { } public async Task<IEnumerable<RemoteSearchResult>> GetSearchResults(EpisodeInfo searchInfo, CancellationToken cancellationToken) @@ -201,7 +201,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV return result; } - public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken) + public Task<HttpResponseMessage> GetImageResponse(string url, CancellationToken cancellationToken) { return GetResponse(url, cancellationToken); } diff --git a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeProviderBase.cs b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeProviderBase.cs index 846e6095b..5ccccc04f 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeProviderBase.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeProviderBase.cs @@ -3,9 +3,10 @@ using System; using System.Globalization; using System.IO; +using System.Net.Http; +using System.Net.Http.Headers; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.Net; using MediaBrowser.Controller.Configuration; using MediaBrowser.Model.Globalization; using MediaBrowser.Model.IO; @@ -19,16 +20,16 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV public abstract class TmdbEpisodeProviderBase { private const string EpisodeUrlPattern = TmdbUtils.BaseTmdbApiUrl + @"3/tv/{0}/season/{1}/episode/{2}?api_key={3}&append_to_response=images,external_ids,credits,videos"; - private readonly IHttpClient _httpClient; + private readonly IHttpClientFactory _httpClientFactory; private readonly IServerConfigurationManager _configurationManager; private readonly IJsonSerializer _jsonSerializer; private readonly IFileSystem _fileSystem; private readonly ILocalizationManager _localization; private readonly ILogger<TmdbEpisodeProviderBase> _logger; - protected TmdbEpisodeProviderBase(IHttpClient httpClient, IServerConfigurationManager configurationManager, IJsonSerializer jsonSerializer, IFileSystem fileSystem, ILocalizationManager localization, ILoggerFactory loggerFactory) + protected TmdbEpisodeProviderBase(IHttpClientFactory httpClientFactory, IServerConfigurationManager configurationManager, IJsonSerializer jsonSerializer, IFileSystem fileSystem, ILocalizationManager localization, ILoggerFactory loggerFactory) { - _httpClient = httpClient; + _httpClientFactory = httpClientFactory; _configurationManager = configurationManager; _jsonSerializer = jsonSerializer; _fileSystem = fileSystem; @@ -124,27 +125,16 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV cancellationToken.ThrowIfCancellationRequested(); - using (var response = await TmdbMovieProvider.Current.GetMovieDbResponse(new HttpRequestOptions - { - Url = url, - CancellationToken = cancellationToken, - AcceptHeader = TmdbUtils.AcceptHeader - }).ConfigureAwait(false)) - { - using (var json = response.Content) - { - return await _jsonSerializer.DeserializeFromStreamAsync<EpisodeResult>(json).ConfigureAwait(false); - } - } + using var requestMessage = new HttpRequestMessage(HttpMethod.Get, url); + requestMessage.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue(TmdbUtils.AcceptHeader)); + using var response = await TmdbMovieProvider.Current.GetMovieDbResponse(requestMessage); + await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); + return await _jsonSerializer.DeserializeFromStreamAsync<EpisodeResult>(stream).ConfigureAwait(false); } - protected Task<HttpResponseInfo> GetResponse(string url, CancellationToken cancellationToken) + protected Task<HttpResponseMessage> GetResponse(string url, CancellationToken cancellationToken) { - return _httpClient.GetResponse(new HttpRequestOptions - { - CancellationToken = cancellationToken, - Url = url - }); + return _httpClientFactory.CreateClient().GetAsync(url, cancellationToken); } } } diff --git a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeasonImageProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeasonImageProvider.cs index 56b6e4483..787514d05 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeasonImageProvider.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeasonImageProvider.cs @@ -4,9 +4,9 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; +using System.Net.Http; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.Net; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Providers; @@ -22,12 +22,12 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV public class TmdbSeasonImageProvider : IRemoteImageProvider, IHasOrder { private readonly IJsonSerializer _jsonSerializer; - private readonly IHttpClient _httpClient; + private readonly IHttpClientFactory _httpClientFactory; - public TmdbSeasonImageProvider(IJsonSerializer jsonSerializer, IHttpClient httpClient) + public TmdbSeasonImageProvider(IJsonSerializer jsonSerializer, IHttpClientFactory httpClientFactory) { _jsonSerializer = jsonSerializer; - _httpClient = httpClient; + _httpClientFactory = httpClientFactory; } public int Order => 1; @@ -36,13 +36,9 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV public static string ProviderName => TmdbUtils.ProviderName; - public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken) + public Task<HttpResponseMessage> GetImageResponse(string url, CancellationToken cancellationToken) { - return _httpClient.GetResponse(new HttpRequestOptions - { - CancellationToken = cancellationToken, - Url = url - }); + return _httpClientFactory.CreateClient().GetAsync(url, cancellationToken); } public async Task<IEnumerable<RemoteImageInfo>> GetImages(BaseItem item, CancellationToken cancellationToken) diff --git a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeasonProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeasonProvider.cs index 822dc4317..247b794b1 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeasonProvider.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeasonProvider.cs @@ -5,9 +5,10 @@ using System.Collections.Generic; using System.Globalization; using System.IO; using System.Net; +using System.Net.Http; +using System.Net.Http.Headers; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.Net; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; @@ -26,7 +27,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV public class TmdbSeasonProvider : IRemoteMetadataProvider<Season, SeasonInfo> { private const string GetTvInfo3 = TmdbUtils.BaseTmdbApiUrl + @"3/tv/{0}/season/{1}?api_key={2}&append_to_response=images,keywords,external_ids,credits,videos"; - private readonly IHttpClient _httpClient; + private readonly IHttpClientFactory _httpClientFactory; private readonly IServerConfigurationManager _configurationManager; private readonly IJsonSerializer _jsonSerializer; private readonly IFileSystem _fileSystem; @@ -35,9 +36,9 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV internal static TmdbSeasonProvider Current { get; private set; } - public TmdbSeasonProvider(IHttpClient httpClient, IServerConfigurationManager configurationManager, IFileSystem fileSystem, ILocalizationManager localization, IJsonSerializer jsonSerializer, ILogger<TmdbSeasonProvider> logger) + public TmdbSeasonProvider(IHttpClientFactory httpClientFactory, IServerConfigurationManager configurationManager, IFileSystem fileSystem, ILocalizationManager localization, IJsonSerializer jsonSerializer, ILogger<TmdbSeasonProvider> logger) { - _httpClient = httpClient; + _httpClientFactory = httpClientFactory; _configurationManager = configurationManager; _fileSystem = fileSystem; _localization = localization; @@ -121,13 +122,9 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV return Task.FromResult<IEnumerable<RemoteSearchResult>>(new List<RemoteSearchResult>()); } - public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken) + public Task<HttpResponseMessage> GetImageResponse(string url, CancellationToken cancellationToken) { - return _httpClient.GetResponse(new HttpRequestOptions - { - CancellationToken = cancellationToken, - Url = url - }); + return _httpClientFactory.CreateClient().GetAsync(url, cancellationToken); } private async Task<SeasonResult> GetSeasonInfo(string seriesTmdbId, int season, string preferredMetadataLanguage, @@ -215,18 +212,11 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV cancellationToken.ThrowIfCancellationRequested(); - using (var response = await TmdbMovieProvider.Current.GetMovieDbResponse(new HttpRequestOptions - { - Url = url, - CancellationToken = cancellationToken, - AcceptHeader = TmdbUtils.AcceptHeader - }).ConfigureAwait(false)) - { - using (var json = response.Content) - { - return await _jsonSerializer.DeserializeFromStreamAsync<SeasonResult>(json).ConfigureAwait(false); - } - } + using var requestMessage = new HttpRequestMessage(HttpMethod.Get, url); + requestMessage.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue(TmdbUtils.AcceptHeader)); + using var response = await TmdbMovieProvider.Current.GetMovieDbResponse(requestMessage).ConfigureAwait(false); + await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); + return await _jsonSerializer.DeserializeFromStreamAsync<SeasonResult>(stream).ConfigureAwait(false); } } } diff --git a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesImageProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesImageProvider.cs index 95c451493..f11eeb15b 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesImageProvider.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesImageProvider.cs @@ -3,9 +3,9 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Net.Http; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.Net; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Providers; @@ -23,13 +23,13 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV public class TmdbSeriesImageProvider : IRemoteImageProvider, IHasOrder { private readonly IJsonSerializer _jsonSerializer; - private readonly IHttpClient _httpClient; + private readonly IHttpClientFactory _httpClientFactory; private readonly IFileSystem _fileSystem; - public TmdbSeriesImageProvider(IJsonSerializer jsonSerializer, IHttpClient httpClient, IFileSystem fileSystem) + public TmdbSeriesImageProvider(IJsonSerializer jsonSerializer, IHttpClientFactory httpClientFactory, IFileSystem fileSystem) { _jsonSerializer = jsonSerializer; - _httpClient = httpClient; + _httpClientFactory = httpClientFactory; _fileSystem = fileSystem; } @@ -180,13 +180,9 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV // After tvdb and fanart public int Order => 2; - public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken) + public Task<HttpResponseMessage> GetImageResponse(string url, CancellationToken cancellationToken) { - return _httpClient.GetResponse(new HttpRequestOptions - { - CancellationToken = cancellationToken, - Url = url - }); + return _httpClientFactory.CreateClient().GetAsync(url, cancellationToken); } } } diff --git a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesProvider.cs index 3480a15f6..6679f0684 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesProvider.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesProvider.cs @@ -5,10 +5,11 @@ using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; +using System.Net.Http; +using System.Net.Http.Headers; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Common.Configuration; -using MediaBrowser.Common.Net; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.TV; @@ -35,7 +36,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV private readonly IServerConfigurationManager _configurationManager; private readonly ILogger<TmdbSeriesProvider> _logger; private readonly ILocalizationManager _localization; - private readonly IHttpClient _httpClient; + private readonly IHttpClientFactory _httpClientFactory; private readonly ILibraryManager _libraryManager; private readonly CultureInfo _usCulture = new CultureInfo("en-US"); @@ -48,7 +49,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV IServerConfigurationManager configurationManager, ILogger<TmdbSeriesProvider> logger, ILocalizationManager localization, - IHttpClient httpClient, + IHttpClientFactory httpClientFactory, ILibraryManager libraryManager) { _jsonSerializer = jsonSerializer; @@ -56,7 +57,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV _configurationManager = configurationManager; _logger = logger; _localization = localization; - _httpClient = httpClient; + _httpClientFactory = httpClientFactory; _libraryManager = libraryManager; Current = this; } @@ -413,24 +414,15 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV cancellationToken.ThrowIfCancellationRequested(); - SeriesResult mainResult; + using var mainRequestMessage = new HttpRequestMessage(HttpMethod.Get, url); + mainRequestMessage.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue(TmdbUtils.AcceptHeader)); + using var mainResponse = await TmdbMovieProvider.Current.GetMovieDbResponse(mainRequestMessage); + await using var mainStream = await mainResponse.Content.ReadAsStreamAsync().ConfigureAwait(false); + var mainResult = await _jsonSerializer.DeserializeFromStreamAsync<SeriesResult>(mainStream).ConfigureAwait(false); - using (var response = await TmdbMovieProvider.Current.GetMovieDbResponse(new HttpRequestOptions - { - Url = url, - CancellationToken = cancellationToken, - AcceptHeader = TmdbUtils.AcceptHeader - }).ConfigureAwait(false)) + if (!string.IsNullOrEmpty(language)) { - using (var json = response.Content) - { - mainResult = await _jsonSerializer.DeserializeFromStreamAsync<SeriesResult>(json).ConfigureAwait(false); - - if (!string.IsNullOrEmpty(language)) - { - mainResult.ResultLanguage = language; - } - } + mainResult.ResultLanguage = language; } cancellationToken.ThrowIfCancellationRequested(); @@ -451,21 +443,14 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV url += "&include_image_language=" + TmdbMovieProvider.GetImageLanguagesParam(language); } - using (var response = await TmdbMovieProvider.Current.GetMovieDbResponse(new HttpRequestOptions - { - Url = url, - CancellationToken = cancellationToken, - AcceptHeader = TmdbUtils.AcceptHeader - }).ConfigureAwait(false)) - { - using (var json = response.Content) - { - var englishResult = await _jsonSerializer.DeserializeFromStreamAsync<SeriesResult>(json).ConfigureAwait(false); + using var requestMessage = new HttpRequestMessage(HttpMethod.Get, url); + requestMessage.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue(TmdbUtils.AcceptHeader)); + using var response = await TmdbMovieProvider.Current.GetMovieDbResponse(requestMessage); + await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); + var englishResult = await _jsonSerializer.DeserializeFromStreamAsync<SeriesResult>(stream).ConfigureAwait(false); - mainResult.Overview = englishResult.Overview; - mainResult.ResultLanguage = "en"; - } - } + mainResult.Overview = englishResult.Overview; + mainResult.ResultLanguage = "en"; } return mainResult; @@ -515,38 +500,34 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV TmdbUtils.ApiKey, externalSource); - using (var response = await TmdbMovieProvider.Current.GetMovieDbResponse(new HttpRequestOptions - { - Url = url, - CancellationToken = cancellationToken, - AcceptHeader = TmdbUtils.AcceptHeader - }).ConfigureAwait(false)) + using var requestMessage = new HttpRequestMessage(HttpMethod.Get, url); + requestMessage.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue(TmdbUtils.AcceptHeader)); + using var response = await TmdbMovieProvider.Current.GetMovieDbResponse(requestMessage); + await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); + + var result = await _jsonSerializer.DeserializeFromStreamAsync<ExternalIdLookupResult>(stream).ConfigureAwait(false); + + if (result != null && result.Tv_Results != null) { - using (var json = response.Content) + var tv = result.Tv_Results.FirstOrDefault(); + + if (tv != null) { - var result = await _jsonSerializer.DeserializeFromStreamAsync<ExternalIdLookupResult>(json).ConfigureAwait(false); + var tmdbSettings = await TmdbMovieProvider.Current.GetTmdbSettings(cancellationToken).ConfigureAwait(false); + var tmdbImageUrl = tmdbSettings.images.GetImageUrl("original"); - if (result != null && result.Tv_Results != null) + var remoteResult = new RemoteSearchResult { - var tv = result.Tv_Results.FirstOrDefault(); - - if (tv != null) - { - var tmdbSettings = await TmdbMovieProvider.Current.GetTmdbSettings(cancellationToken).ConfigureAwait(false); - var tmdbImageUrl = tmdbSettings.images.GetImageUrl("original"); - - var remoteResult = new RemoteSearchResult - { - Name = tv.Name, - SearchProviderName = Name, - ImageUrl = string.IsNullOrWhiteSpace(tv.Poster_Path) ? null : tmdbImageUrl + tv.Poster_Path - }; + Name = tv.Name, + SearchProviderName = Name, + ImageUrl = string.IsNullOrWhiteSpace(tv.Poster_Path) + ? null + : tmdbImageUrl + tv.Poster_Path + }; - remoteResult.SetProviderId(MetadataProvider.Tmdb, tv.Id.ToString(_usCulture)); + remoteResult.SetProviderId(MetadataProvider.Tmdb, tv.Id.ToString(_usCulture)); - return remoteResult; - } - } + return remoteResult; } } @@ -556,13 +537,9 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV // After TheTVDB public int Order => 1; - public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken) + public Task<HttpResponseMessage> GetImageResponse(string url, CancellationToken cancellationToken) { - return _httpClient.GetResponse(new HttpRequestOptions - { - CancellationToken = cancellationToken, - Url = url - }); + return _httpClientFactory.CreateClient().GetAsync(url, cancellationToken); } } } diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Trailers/TmdbTrailerProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/Trailers/TmdbTrailerProvider.cs index 7e2b06257..10374bde9 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/Trailers/TmdbTrailerProvider.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/Trailers/TmdbTrailerProvider.cs @@ -1,9 +1,9 @@ #pragma warning disable CS1591 using System.Collections.Generic; +using System.Net.Http; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.Net; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Providers; @@ -13,11 +13,11 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Trailers { public class TmdbTrailerProvider : IHasOrder, IRemoteMetadataProvider<Trailer, TrailerInfo> { - private readonly IHttpClient _httpClient; + private readonly IHttpClientFactory _httpClientFactory; - public TmdbTrailerProvider(IHttpClient httpClient) + public TmdbTrailerProvider(IHttpClientFactory httpClientFactory) { - _httpClient = httpClient; + _httpClientFactory = httpClientFactory; } public Task<IEnumerable<RemoteSearchResult>> GetSearchResults(TrailerInfo searchInfo, CancellationToken cancellationToken) @@ -34,13 +34,9 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Trailers public int Order => 0; - public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken) + public Task<HttpResponseMessage> GetImageResponse(string url, CancellationToken cancellationToken) { - return _httpClient.GetResponse(new HttpRequestOptions - { - CancellationToken = cancellationToken, - Url = url - }); + return _httpClientFactory.CreateClient().GetAsync(url, cancellationToken); } } } diff --git a/MediaBrowser.Providers/Studios/StudiosImageProvider.cs b/MediaBrowser.Providers/Studios/StudiosImageProvider.cs index 1c3de1f1a..dad155c81 100644 --- a/MediaBrowser.Providers/Studios/StudiosImageProvider.cs +++ b/MediaBrowser.Providers/Studios/StudiosImageProvider.cs @@ -7,7 +7,6 @@ using System.Linq; using System.Net.Http; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.Net; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Providers; -- cgit v1.2.3 From 5f1a86324170387f12602d77dad7249faf30548f Mon Sep 17 00:00:00 2001 From: Matt Montgomery <33811686+ConfusedPolarBear@users.noreply.github.com> Date: Mon, 17 Aug 2020 16:36:45 -0500 Subject: Apply suggestions from code review --- .../QuickConnect/QuickConnectManager.cs | 38 +++++++++------------- .../Session/SessionManager.cs | 2 +- Jellyfin.Api/Controllers/QuickConnectController.cs | 34 +++++++++---------- Jellyfin.Api/Controllers/UserController.cs | 4 +-- .../QuickConnect/IQuickConnect.cs | 12 +++---- .../QuickConnect/QuickConnectResult.cs | 5 --- 6 files changed, 40 insertions(+), 55 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/QuickConnect/QuickConnectManager.cs b/Emby.Server.Implementations/QuickConnect/QuickConnectManager.cs index 949c3b505..52e934229 100644 --- a/Emby.Server.Implementations/QuickConnect/QuickConnectManager.cs +++ b/Emby.Server.Implementations/QuickConnect/QuickConnectManager.cs @@ -3,17 +3,16 @@ using System.Collections.Concurrent; using System.Globalization; using System.Linq; using System.Security.Cryptography; +using MediaBrowser.Common; +using MediaBrowser.Common.Extensions; using MediaBrowser.Controller; +using MediaBrowser.Controller.Authentication; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Net; using MediaBrowser.Controller.QuickConnect; using MediaBrowser.Controller.Security; using MediaBrowser.Model.QuickConnect; -using Microsoft.AspNetCore.Http; -using MediaBrowser.Common; using Microsoft.Extensions.Logging; -using MediaBrowser.Common.Extensions; -using MediaBrowser.Controller.Authentication; namespace Emby.Server.Implementations.QuickConnect { @@ -60,7 +59,7 @@ namespace Emby.Server.Implementations.QuickConnect public int CodeLength { get; set; } = 6; /// <inheritdoc/> - public string TokenNamePrefix { get; set; } = "QuickConnect-"; + public string TokenName { get; set; } = "QuickConnect"; /// <inheritdoc/> public QuickConnectState State { get; private set; } = QuickConnectState.Unavailable; @@ -82,7 +81,7 @@ namespace Emby.Server.Implementations.QuickConnect /// <inheritdoc/> public void Activate() { - DateActivated = DateTime.Now; + DateActivated = DateTime.UtcNow; SetState(QuickConnectState.Active); } @@ -101,7 +100,7 @@ namespace Emby.Server.Implementations.QuickConnect } /// <inheritdoc/> - public QuickConnectResult TryConnect(string friendlyName) + public QuickConnectResult TryConnect() { ExpireRequests(); @@ -111,14 +110,11 @@ namespace Emby.Server.Implementations.QuickConnect throw new AuthenticationException("Quick connect is not active on this server"); } - _logger.LogDebug("Got new quick connect request from {friendlyName}", friendlyName); - var code = GenerateCode(); var result = new QuickConnectResult() { Secret = GenerateSecureRandom(), - FriendlyName = friendlyName, - DateAdded = DateTime.Now, + DateAdded = DateTime.UtcNow, Code = code }; @@ -162,13 +158,11 @@ namespace Emby.Server.Implementations.QuickConnect } /// <inheritdoc/> - public bool AuthorizeRequest(HttpRequest request, string code) + public bool AuthorizeRequest(Guid userId, string code) { ExpireRequests(); AssertActive(); - var auth = _authContext.GetAuthorizationInfo(request); - if (!_currentRequests.TryGetValue(code, out QuickConnectResult result)) { throw new ResourceNotFoundException("Unable to find request"); @@ -182,21 +176,21 @@ namespace Emby.Server.Implementations.QuickConnect result.Authentication = Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture); // Change the time on the request so it expires one minute into the future. It can't expire immediately as otherwise some clients wouldn't ever see that they have been authenticated. - var added = result.DateAdded ?? DateTime.Now.Subtract(new TimeSpan(0, Timeout, 0)); - result.DateAdded = added.Subtract(new TimeSpan(0, Timeout - 1, 0)); + var added = result.DateAdded ?? DateTime.UtcNow.Subtract(TimeSpan.FromMinutes(Timeout)); + result.DateAdded = added.Subtract(TimeSpan.FromMinutes(Timeout - 1)); _authenticationRepository.Create(new AuthenticationInfo { - AppName = TokenNamePrefix + result.FriendlyName, + AppName = TokenName, AccessToken = result.Authentication, DateCreated = DateTime.UtcNow, DeviceId = _appHost.SystemId, DeviceName = _appHost.FriendlyName, AppVersion = _appHost.ApplicationVersionString, - UserId = auth.UserId + UserId = userId }); - _logger.LogInformation("Allowing device {FriendlyName} to login as user {Username} with quick connect code {Code}", result.FriendlyName, auth.User.Username, result.Code); + _logger.LogDebug("Authorizing device with code {Code} to login as user {userId}", code, userId); return true; } @@ -210,7 +204,7 @@ namespace Emby.Server.Implementations.QuickConnect UserId = user }); - var tokens = raw.Items.Where(x => x.AppName.StartsWith(TokenNamePrefix, StringComparison.CurrentCulture)); + var tokens = raw.Items.Where(x => x.AppName.StartsWith(TokenName, StringComparison.CurrentCulture)); var removed = 0; foreach (var token in tokens) @@ -256,7 +250,7 @@ namespace Emby.Server.Implementations.QuickConnect public void ExpireRequests(bool expireAll = false) { // Check if quick connect should be deactivated - if (State == QuickConnectState.Active && DateTime.Now > DateActivated.AddMinutes(Timeout) && !expireAll) + if (State == QuickConnectState.Active && DateTime.UtcNow > DateActivated.AddMinutes(Timeout) && !expireAll) { _logger.LogDebug("Quick connect time expired, deactivating"); SetState(QuickConnectState.Available); @@ -270,7 +264,7 @@ namespace Emby.Server.Implementations.QuickConnect for (int i = 0; i < values.Count; i++) { var added = values[i].DateAdded ?? DateTime.UnixEpoch; - if (DateTime.Now > added.AddMinutes(Timeout) || expireAll) + if (DateTime.UtcNow > added.AddMinutes(Timeout) || expireAll) { code = values[i].Code; _logger.LogDebug("Removing expired request {code}", code); diff --git a/Emby.Server.Implementations/Session/SessionManager.cs b/Emby.Server.Implementations/Session/SessionManager.cs index 8a8223ee7..fbe8e065c 100644 --- a/Emby.Server.Implementations/Session/SessionManager.cs +++ b/Emby.Server.Implementations/Session/SessionManager.cs @@ -1433,7 +1433,7 @@ namespace Emby.Server.Implementations.Session Limit = 1 }); - if (result.TotalRecordCount < 1) + if (result.TotalRecordCount == 0) { throw new SecurityException("Unknown quick connect token"); } diff --git a/Jellyfin.Api/Controllers/QuickConnectController.cs b/Jellyfin.Api/Controllers/QuickConnectController.cs index 1625bcffe..b1ee2ff53 100644 --- a/Jellyfin.Api/Controllers/QuickConnectController.cs +++ b/Jellyfin.Api/Controllers/QuickConnectController.cs @@ -1,8 +1,8 @@ +using System; using System.ComponentModel.DataAnnotations; using Jellyfin.Api.Constants; using Jellyfin.Api.Helpers; using MediaBrowser.Common.Extensions; -using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Net; using MediaBrowser.Controller.QuickConnect; using MediaBrowser.Model.QuickConnect; @@ -18,22 +18,18 @@ namespace Jellyfin.Api.Controllers public class QuickConnectController : BaseJellyfinApiController { private readonly IQuickConnect _quickConnect; - private readonly IUserManager _userManager; private readonly IAuthorizationContext _authContext; /// <summary> /// Initializes a new instance of the <see cref="QuickConnectController"/> class. /// </summary> /// <param name="quickConnect">Instance of the <see cref="IQuickConnect"/> interface.</param> - /// <param name="userManager">Instance of the <see cref="IUserManager"/> interface.</param> /// <param name="authContext">Instance of the <see cref="IAuthorizationContext"/> interface.</param> public QuickConnectController( IQuickConnect quickConnect, - IUserManager userManager, IAuthorizationContext authContext) { _quickConnect = quickConnect; - _userManager = userManager; _authContext = authContext; } @@ -53,15 +49,14 @@ namespace Jellyfin.Api.Controllers /// <summary> /// Initiate a new quick connect request. /// </summary> - /// <param name="friendlyName">Device friendly name.</param> /// <response code="200">Quick connect request successfully created.</response> /// <response code="401">Quick connect is not active on this server.</response> /// <returns>A <see cref="QuickConnectResult"/> with a secret and code for future use or an error message.</returns> [HttpGet("Initiate")] [ProducesResponseType(StatusCodes.Status200OK)] - public ActionResult<QuickConnectResult> Initiate([FromQuery] string? friendlyName) + public ActionResult<QuickConnectResult> Initiate() { - return _quickConnect.TryConnect(friendlyName); + return _quickConnect.TryConnect(); } /// <summary> @@ -74,12 +69,11 @@ namespace Jellyfin.Api.Controllers [HttpGet("Connect")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] - public ActionResult<QuickConnectResult> Connect([FromQuery] string? secret) + public ActionResult<QuickConnectResult> Connect([FromQuery, Required] string secret) { try { - var result = _quickConnect.CheckRequestStatus(secret); - return result; + return _quickConnect.CheckRequestStatus(secret); } catch (ResourceNotFoundException) { @@ -117,9 +111,9 @@ namespace Jellyfin.Api.Controllers [HttpPost("Available")] [Authorize(Policy = Policies.RequiresElevation)] [ProducesResponseType(StatusCodes.Status204NoContent)] - public ActionResult Available([FromQuery] QuickConnectState? status) + public ActionResult Available([FromQuery] QuickConnectState status = QuickConnectState.Available) { - _quickConnect.SetState(status ?? QuickConnectState.Available); + _quickConnect.SetState(status); return NoContent(); } @@ -127,16 +121,22 @@ namespace Jellyfin.Api.Controllers /// Authorizes a pending quick connect request. /// </summary> /// <param name="code">Quick connect code to authorize.</param> + /// <param name="userId">User id.</param> /// <response code="200">Quick connect result authorized successfully.</response> - /// <response code="400">Missing quick connect code.</response> + /// <response code="403">User is not allowed to authorize quick connect requests.</response> /// <returns>Boolean indicating if the authorization was successful.</returns> [HttpPost("Authorize")] [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status200OK)] - [ProducesResponseType(StatusCodes.Status400BadRequest)] - public ActionResult<bool> Authorize([FromQuery, Required] string? code) + [ProducesResponseType(StatusCodes.Status403Forbidden)] + public ActionResult<bool> Authorize([FromQuery, Required] string code, [FromQuery, Required] Guid userId) { - return _quickConnect.AuthorizeRequest(Request, code); + if (!RequestHelpers.AssertCanUpdateUser(_authContext, HttpContext.Request, userId, true)) + { + return Forbid("User is not allowed to authorize quick connect requests."); + } + + return _quickConnect.AuthorizeRequest(userId, code); } /// <summary> diff --git a/Jellyfin.Api/Controllers/UserController.cs b/Jellyfin.Api/Controllers/UserController.cs index 355816bd3..d67f82219 100644 --- a/Jellyfin.Api/Controllers/UserController.cs +++ b/Jellyfin.Api/Controllers/UserController.cs @@ -239,11 +239,9 @@ namespace Jellyfin.Api.Controllers DeviceName = auth.Device, }; - var result = await _sessionManager.AuthenticateQuickConnect( + return await _sessionManager.AuthenticateQuickConnect( authRequest, request.Token).ConfigureAwait(false); - - return result; } catch (SecurityException e) { diff --git a/MediaBrowser.Controller/QuickConnect/IQuickConnect.cs b/MediaBrowser.Controller/QuickConnect/IQuickConnect.cs index fd7e973f6..959a2d771 100644 --- a/MediaBrowser.Controller/QuickConnect/IQuickConnect.cs +++ b/MediaBrowser.Controller/QuickConnect/IQuickConnect.cs @@ -1,6 +1,5 @@ using System; using MediaBrowser.Model.QuickConnect; -using Microsoft.AspNetCore.Http; namespace MediaBrowser.Controller.QuickConnect { @@ -15,9 +14,9 @@ namespace MediaBrowser.Controller.QuickConnect int CodeLength { get; set; } /// <summary> - /// Gets or sets the string to prefix internal access tokens with. + /// Gets or sets the name of internal access tokens. /// </summary> - string TokenNamePrefix { get; set; } + string TokenName { get; set; } /// <summary> /// Gets the current state of quick connect. @@ -48,9 +47,8 @@ namespace MediaBrowser.Controller.QuickConnect /// <summary> /// Initiates a new quick connect request. /// </summary> - /// <param name="friendlyName">Friendly device name to display in the request UI.</param> /// <returns>A quick connect result with tokens to proceed or throws an exception if not active.</returns> - QuickConnectResult TryConnect(string friendlyName); + QuickConnectResult TryConnect(); /// <summary> /// Checks the status of an individual request. @@ -62,10 +60,10 @@ namespace MediaBrowser.Controller.QuickConnect /// <summary> /// Authorizes a quick connect request to connect as the calling user. /// </summary> - /// <param name="request">HTTP request object.</param> + /// <param name="userId">User id.</param> /// <param name="code">Identifying code for the request.</param> /// <returns>A boolean indicating if the authorization completed successfully.</returns> - bool AuthorizeRequest(HttpRequest request, string code); + bool AuthorizeRequest(Guid userId, string code); /// <summary> /// Expire quick connect requests that are over the time limit. If <paramref name="expireAll"/> is true, all requests are unconditionally expired. diff --git a/MediaBrowser.Model/QuickConnect/QuickConnectResult.cs b/MediaBrowser.Model/QuickConnect/QuickConnectResult.cs index a10d60d57..0fa40b6a7 100644 --- a/MediaBrowser.Model/QuickConnect/QuickConnectResult.cs +++ b/MediaBrowser.Model/QuickConnect/QuickConnectResult.cs @@ -22,11 +22,6 @@ namespace MediaBrowser.Model.QuickConnect /// </summary> public string? Code { get; set; } - /// <summary> - /// Gets or sets the device friendly name. - /// </summary> - public string? FriendlyName { get; set; } - /// <summary> /// Gets or sets the private access token. /// </summary> -- cgit v1.2.3 From 2b400c99ef946ef1e52e3f01cb18bc008a369c59 Mon Sep 17 00:00:00 2001 From: Bond_009 <Bond.009@outlook.com> Date: Fri, 7 Aug 2020 19:26:28 +0200 Subject: Fix warnings --- Emby.Dlna/DlnaManager.cs | 12 +-- Emby.Dlna/PlayTo/Device.cs | 36 ++++--- Emby.Dlna/PlayTo/TransportCommands.cs | 17 ++-- .../Data/SqliteItemRepository.cs | 4 +- .../LiveTv/EmbyTV/EncodedRecorder.cs | 2 +- .../LiveTv/Listings/XmlTvListingsProvider.cs | 5 +- .../LiveTv/LiveTvManager.cs | 106 +++++++++++---------- .../LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs | 16 ++-- Jellyfin.Api/Controllers/ImageController.cs | 2 +- MediaBrowser.Controller/Entities/Movies/Movie.cs | 4 +- MediaBrowser.Controller/Entities/TV/Series.cs | 2 +- MediaBrowser.Controller/Entities/Trailer.cs | 3 +- MediaBrowser.Controller/Library/Profiler.cs | 17 +++- MediaBrowser.Controller/LiveTv/LiveTvChannel.cs | 2 +- MediaBrowser.Controller/LiveTv/LiveTvProgram.cs | 2 +- .../MediaEncoding/EncodingHelper.cs | 8 +- .../Providers/IProviderManager.cs | 2 +- .../Encoder/EncodingUtils.cs | 9 +- MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 14 +-- .../Subtitles/SubtitleEncoder.cs | 2 +- MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs | 2 +- MediaBrowser.Model/Dlna/DlnaMaps.cs | 8 +- .../Dlna/MediaFormatProfileResolver.cs | 21 ++-- MediaBrowser.Model/Dlna/StreamInfo.cs | 12 +-- MediaBrowser.Providers/Manager/ImageSaver.cs | 4 +- .../Manager/ItemImageProvider.cs | 57 +++++------ MediaBrowser.Providers/Manager/MetadataService.cs | 73 +++++++------- MediaBrowser.Providers/Manager/ProviderManager.cs | 37 +++++-- .../MediaInfo/FFProbeAudioInfo.cs | 15 +-- .../MediaInfo/FFProbeProvider.cs | 21 +--- MediaBrowser.Providers/Music/Extensions.cs | 4 +- .../Plugins/MusicBrainz/AlbumProvider.cs | 2 +- .../Plugins/MusicBrainz/ArtistProvider.cs | 4 +- .../Plugins/Omdb/OmdbImageProvider.cs | 3 +- .../Plugins/Omdb/OmdbItemProvider.cs | 2 +- .../Plugins/Omdb/OmdbProvider.cs | 25 +++-- .../Plugins/TheTvdb/TvdbClientManager.cs | 31 ++---- .../Plugins/TheTvdb/TvdbEpisodeImageProvider.cs | 7 +- .../Plugins/Tmdb/BoxSets/TmdbBoxSetProvider.cs | 4 +- .../Plugins/Tmdb/Movies/GenericTmdbMovieInfo.cs | 2 +- .../Plugins/Tmdb/Movies/TmdbSearch.cs | 54 +++++++++-- .../Plugins/Tmdb/TV/TmdbEpisodeProvider.cs | 2 +- .../Plugins/Tmdb/TV/TmdbEpisodeProviderBase.cs | 4 +- .../Plugins/Tmdb/TV/TmdbSeasonProvider.cs | 4 +- .../Plugins/Tmdb/TV/TmdbSeriesProvider.cs | 2 +- .../Studios/StudiosImageProvider.cs | 3 +- 46 files changed, 366 insertions(+), 302 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Dlna/DlnaManager.cs b/Emby.Dlna/DlnaManager.cs index 269f7ee43..ce4be7b51 100644 --- a/Emby.Dlna/DlnaManager.cs +++ b/Emby.Dlna/DlnaManager.cs @@ -54,11 +54,15 @@ namespace Emby.Dlna _appHost = appHost; } + private string UserProfilesPath => Path.Combine(_appPaths.ConfigurationDirectoryPath, "dlna", "user"); + + private string SystemProfilesPath => Path.Combine(_appPaths.ConfigurationDirectoryPath, "dlna", "system"); + public async Task InitProfilesAsync() { try { - await ExtractSystemProfilesAsync(); + await ExtractSystemProfilesAsync().ConfigureAwait(false); LoadProfiles(); } catch (Exception ex) @@ -240,7 +244,7 @@ namespace Emby.Dlna } else { - var headerString = string.Join(", ", headers.Select(i => string.Format("{0}={1}", i.Key, i.Value)).ToArray()); + var headerString = string.Join(", ", headers.Select(i => string.Format(CultureInfo.InvariantCulture, "{0}={1}", i.Key, i.Value))); _logger.LogDebug("No matching device profile found. {0}", headerString); } @@ -280,10 +284,6 @@ namespace Emby.Dlna return false; } - private string UserProfilesPath => Path.Combine(_appPaths.ConfigurationDirectoryPath, "dlna", "user"); - - private string SystemProfilesPath => Path.Combine(_appPaths.ConfigurationDirectoryPath, "dlna", "system"); - private IEnumerable<DeviceProfile> GetProfiles(string path, DeviceProfileType type) { try diff --git a/Emby.Dlna/PlayTo/Device.cs b/Emby.Dlna/PlayTo/Device.cs index 72834c69d..86dd52a1b 100644 --- a/Emby.Dlna/PlayTo/Device.cs +++ b/Emby.Dlna/PlayTo/Device.cs @@ -19,6 +19,8 @@ namespace Emby.Dlna.PlayTo { public class Device : IDisposable { + private static readonly CultureInfo UsCulture = new CultureInfo("en-US"); + private Timer _timer; public DeviceInfo Properties { get; set; } @@ -55,16 +57,13 @@ namespace Emby.Dlna.PlayTo private readonly ILogger _logger; - private readonly IServerConfigurationManager _config; - public Action OnDeviceUnavailable { get; set; } - public Device(DeviceInfo deviceProperties, IHttpClient httpClient, ILogger logger, IServerConfigurationManager config) + public Device(DeviceInfo deviceProperties, IHttpClient httpClient, ILogger logger) { Properties = deviceProperties; _httpClient = httpClient; _logger = logger; - _config = config; } public void Start() @@ -275,7 +274,7 @@ namespace Emby.Dlna.PlayTo throw new InvalidOperationException("Unable to find service"); } - await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, avCommands.BuildPost(command, service.ServiceType, string.Format("{0:hh}:{0:mm}:{0:ss}", value), "REL_TIME")) + await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, avCommands.BuildPost(command, service.ServiceType, string.Format(CultureInfo.InvariantCulture, "{0:hh}:{0:mm}:{0:ss}", value), "REL_TIME")) .ConfigureAwait(false); RestartTimer(true); @@ -285,7 +284,7 @@ namespace Emby.Dlna.PlayTo { var avCommands = await GetAVProtocolAsync(cancellationToken).ConfigureAwait(false); - url = url.Replace("&", "&"); + url = url.Replace("&", "&", StringComparison.Ordinal); _logger.LogDebug("{0} - SetAvTransport Uri: {1} DlnaHeaders: {2}", Properties.Name, url, header); @@ -297,8 +296,8 @@ namespace Emby.Dlna.PlayTo var dictionary = new Dictionary<string, string> { - {"CurrentURI", url}, - {"CurrentURIMetaData", CreateDidlMeta(metaData)} + { "CurrentURI", url }, + { "CurrentURIMetaData", CreateDidlMeta(metaData) } }; var service = GetAvTransportService(); @@ -732,10 +731,10 @@ namespace Emby.Dlna.PlayTo } var trackUriElem = result.Document.Descendants(uPnpNamespaces.AvTransport + "GetPositionInfoResponse").Select(i => i.Element("TrackURI")).FirstOrDefault(i => i != null); - var trackUri = trackUriElem == null ? null : trackUriElem.Value; + var trackUri = trackUriElem?.Value; var durationElem = result.Document.Descendants(uPnpNamespaces.AvTransport + "GetPositionInfoResponse").Select(i => i.Element("TrackDuration")).FirstOrDefault(i => i != null); - var duration = durationElem == null ? null : durationElem.Value; + var duration = durationElem?.Value; if (!string.IsNullOrWhiteSpace(duration) && !string.Equals(duration, "NOT_IMPLEMENTED", StringComparison.OrdinalIgnoreCase)) @@ -748,7 +747,7 @@ namespace Emby.Dlna.PlayTo } var positionElem = result.Document.Descendants(uPnpNamespaces.AvTransport + "GetPositionInfoResponse").Select(i => i.Element("RelTime")).FirstOrDefault(i => i != null); - var position = positionElem == null ? null : positionElem.Value; + var position = positionElem?.Value; if (!string.IsNullOrWhiteSpace(position) && !string.Equals(position, "NOT_IMPLEMENTED", StringComparison.OrdinalIgnoreCase)) { @@ -819,7 +818,7 @@ namespace Emby.Dlna.PlayTo // some devices send back invalid xml try { - return XElement.Parse(xml.Replace("&", "&")); + return XElement.Parse(xml.Replace("&", "&", StringComparison.Ordinal)); } catch (XmlException) { @@ -848,7 +847,7 @@ namespace Emby.Dlna.PlayTo ParentId = container.GetAttributeValue(uPnpNamespaces.ParentId), Title = container.GetValue(uPnpNamespaces.title), IconUrl = container.GetValue(uPnpNamespaces.Artwork), - SecondText = "", + SecondText = string.Empty, Url = url, ProtocolInfo = GetProtocolInfo(container), MetaData = container.ToString() @@ -941,12 +940,12 @@ namespace Emby.Dlna.PlayTo return url; } - if (!url.Contains("/")) + if (!url.Contains('/', StringComparison.Ordinal)) { url = "/dmr/" + url; } - if (!url.StartsWith("/")) + if (!url.StartsWith("/", StringComparison.Ordinal)) { url = "/" + url; } @@ -981,7 +980,7 @@ namespace Emby.Dlna.PlayTo var deviceProperties = new DeviceInfo() { Name = string.Join(" ", friendlyNames), - BaseUrl = string.Format("http://{0}:{1}", url.Host, url.Port) + BaseUrl = string.Format(CultureInfo.InvariantCulture, "http://{0}:{1}", url.Host, url.Port) }; var model = document.Descendants(uPnpNamespaces.ud.GetName("modelName")).FirstOrDefault(); @@ -1068,10 +1067,9 @@ namespace Emby.Dlna.PlayTo } } - return new Device(deviceProperties, httpClient, logger, config); + return new Device(deviceProperties, httpClient, logger); } - private static readonly CultureInfo UsCulture = new CultureInfo("en-US"); private static DeviceIcon CreateIcon(XElement element) { if (element == null) @@ -1222,7 +1220,7 @@ namespace Emby.Dlna.PlayTo public override string ToString() { - return string.Format("{0} - {1}", Properties.Name, Properties.BaseUrl); + return string.Format(CultureInfo.InvariantCulture, "{0} - {1}", Properties.Name, Properties.BaseUrl); } } } diff --git a/Emby.Dlna/PlayTo/TransportCommands.cs b/Emby.Dlna/PlayTo/TransportCommands.cs index c0ce3ab6e..dc797a691 100644 --- a/Emby.Dlna/PlayTo/TransportCommands.cs +++ b/Emby.Dlna/PlayTo/TransportCommands.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Xml.Linq; using Emby.Dlna.Common; @@ -11,14 +12,16 @@ namespace Emby.Dlna.PlayTo { public class TransportCommands { + private const string CommandBase = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n" + "<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" + "<SOAP-ENV:Body>" + "<m:{0} xmlns:m=\"{1}\">" + "{2}" + "</m:{0}>" + "</SOAP-ENV:Body></SOAP-ENV:Envelope>"; private List<StateVariable> _stateVariables = new List<StateVariable>(); + private List<ServiceAction> _serviceActions = new List<ServiceAction>(); + public List<StateVariable> StateVariables { get => _stateVariables; set => _stateVariables = value; } - private List<ServiceAction> _serviceActions = new List<ServiceAction>(); public List<ServiceAction> ServiceActions { get => _serviceActions; @@ -123,7 +126,7 @@ namespace Emby.Dlna.PlayTo } } - return string.Format(CommandBase, action.Name, xmlNamespace, stateString); + return string.Format(CultureInfo.InvariantCulture, CommandBase, action.Name, xmlNamespace, stateString); } public string BuildPost(ServiceAction action, string xmlNamesapce, object value, string commandParameter = "") @@ -147,7 +150,7 @@ namespace Emby.Dlna.PlayTo } } - return string.Format(CommandBase, action.Name, xmlNamesapce, stateString); + return string.Format(CultureInfo.InvariantCulture, CommandBase, action.Name, xmlNamesapce, stateString); } public string BuildPost(ServiceAction action, string xmlNamesapce, object value, Dictionary<string, string> dictionary) @@ -170,7 +173,7 @@ namespace Emby.Dlna.PlayTo } } - return string.Format(CommandBase, action.Name, xmlNamesapce, stateString); + return string.Format(CultureInfo.InvariantCulture, CommandBase, action.Name, xmlNamesapce, stateString); } private string BuildArgumentXml(Argument argument, string value, string commandParameter = "") @@ -183,12 +186,10 @@ namespace Emby.Dlna.PlayTo state.AllowedValues.FirstOrDefault() ?? value; - return string.Format("<{0} xmlns:dt=\"urn:schemas-microsoft-com:datatypes\" dt:dt=\"{1}\">{2}</{0}>", argument.Name, state.DataType ?? "string", sendValue); + return string.Format(CultureInfo.InvariantCulture, "<{0} xmlns:dt=\"urn:schemas-microsoft-com:datatypes\" dt:dt=\"{1}\">{2}</{0}>", argument.Name, state.DataType ?? "string", sendValue); } - return string.Format("<{0}>{1}</{0}>", argument.Name, value); + return string.Format(CultureInfo.InvariantCulture, "<{0}>{1}</{0}>", argument.Name, value); } - - private const string CommandBase = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n" + "<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" + "<SOAP-ENV:Body>" + "<m:{0} xmlns:m=\"{1}\">" + "{2}" + "</m:{0}>" + "</SOAP-ENV:Body></SOAP-ENV:Envelope>"; } } diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index d11e5e62e..331ffc134 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -4560,13 +4560,13 @@ namespace Emby.Server.Implementations.Data if (query.AncestorIds.Length > 1) { var inClause = string.Join(",", query.AncestorIds.Select(i => "'" + i.ToString("N", CultureInfo.InvariantCulture) + "'")); - whereClauses.Add(string.Format("Guid in (select itemId from AncestorIds where AncestorIdText in ({0}))", inClause)); + whereClauses.Add(string.Format(CultureInfo.InvariantCulture, "Guid in (select itemId from AncestorIds where AncestorIdText in ({0}))", inClause)); } if (!string.IsNullOrWhiteSpace(query.AncestorWithPresentationUniqueKey)) { var inClause = "select guid from TypedBaseItems where PresentationUniqueKey=@AncestorWithPresentationUniqueKey"; - whereClauses.Add(string.Format("Guid in (select itemId from AncestorIds where AncestorId in ({0}))", inClause)); + whereClauses.Add(string.Format(CultureInfo.InvariantCulture, "Guid in (select itemId from AncestorIds where AncestorId in ({0}))", inClause)); if (statement != null) { statement.TryBind("@AncestorWithPresentationUniqueKey", query.AncestorWithPresentationUniqueKey); diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs index d8ec107ec..612dc5238 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs @@ -230,7 +230,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV if (filters.Count > 0) { - output += string.Format(" -vf \"{0}\"", string.Join(",", filters.ToArray())); + output += string.Format(CultureInfo.InvariantCulture, " -vf \"{0}\"", string.Join(",", filters.ToArray())); } return output; diff --git a/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs b/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs index 0a93c4674..f33d07174 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs @@ -237,7 +237,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings && !programInfo.IsRepeat && (programInfo.EpisodeNumber ?? 0) == 0) { - programInfo.ShowId = programInfo.ShowId + programInfo.StartDate.Ticks.ToString(CultureInfo.InvariantCulture); + programInfo.ShowId += programInfo.StartDate.Ticks.ToString(CultureInfo.InvariantCulture); } } else @@ -246,7 +246,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings } // Construct an id from the channel and start date - programInfo.Id = string.Format("{0}_{1:O}", program.ChannelId, program.StartDate); + programInfo.Id = string.Format(CultureInfo.InvariantCulture, "{0}_{1:O}", program.ChannelId, program.StartDate); if (programInfo.IsMovie) { @@ -296,7 +296,6 @@ namespace Emby.Server.Implementations.LiveTv.Listings Name = c.DisplayName, ImageUrl = c.Icon != null && !string.IsNullOrEmpty(c.Icon.Source) ? c.Icon.Source : null, Number = string.IsNullOrWhiteSpace(c.Number) ? c.Id : c.Number - }).ToList(); } } diff --git a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs index 1b075d86a..90cbd85a5 100644 --- a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs @@ -41,6 +41,7 @@ namespace Emby.Server.Implementations.LiveTv /// </summary> public class LiveTvManager : ILiveTvManager, IDisposable { + private const int MaxGuideDays = 14; private const string ExternalServiceTag = "ExternalServiceId"; private const string EtagKey = "ProgramEtag"; @@ -560,7 +561,7 @@ namespace Emby.Server.Implementations.LiveTv item.Audio = info.Audio; item.ChannelId = channel.Id; - item.CommunityRating = item.CommunityRating ?? info.CommunityRating; + item.CommunityRating ??= info.CommunityRating; if ((item.CommunityRating ?? 0).Equals(0)) { item.CommunityRating = null; @@ -645,8 +646,8 @@ namespace Emby.Server.Implementations.LiveTv item.IsSeries = isSeries; item.Name = info.Name; - item.OfficialRating = item.OfficialRating ?? info.OfficialRating; - item.Overview = item.Overview ?? info.Overview; + item.OfficialRating ??= info.OfficialRating; + item.Overview ??= info.Overview; item.RunTimeTicks = (info.EndDate - info.StartDate).Ticks; item.ProviderIds = info.ProviderIds; @@ -683,19 +684,23 @@ namespace Emby.Server.Implementations.LiveTv { if (!string.IsNullOrWhiteSpace(info.ImagePath)) { - item.SetImage(new ItemImageInfo - { - Path = info.ImagePath, - Type = ImageType.Primary - }, 0); + item.SetImage( + new ItemImageInfo + { + Path = info.ImagePath, + Type = ImageType.Primary + }, + 0); } else if (!string.IsNullOrWhiteSpace(info.ImageUrl)) { - item.SetImage(new ItemImageInfo - { - Path = info.ImageUrl, - Type = ImageType.Primary - }, 0); + item.SetImage( + new ItemImageInfo + { + Path = info.ImageUrl, + Type = ImageType.Primary + }, + 0); } } @@ -703,11 +708,13 @@ namespace Emby.Server.Implementations.LiveTv { if (!string.IsNullOrWhiteSpace(info.ThumbImageUrl)) { - item.SetImage(new ItemImageInfo - { - Path = info.ThumbImageUrl, - Type = ImageType.Thumb - }, 0); + item.SetImage( + new ItemImageInfo + { + Path = info.ThumbImageUrl, + Type = ImageType.Thumb + }, + 0); } } @@ -715,11 +722,13 @@ namespace Emby.Server.Implementations.LiveTv { if (!string.IsNullOrWhiteSpace(info.LogoImageUrl)) { - item.SetImage(new ItemImageInfo - { - Path = info.LogoImageUrl, - Type = ImageType.Logo - }, 0); + item.SetImage( + new ItemImageInfo + { + Path = info.LogoImageUrl, + Type = ImageType.Logo + }, + 0); } } @@ -727,11 +736,13 @@ namespace Emby.Server.Implementations.LiveTv { if (!string.IsNullOrWhiteSpace(info.BackdropImageUrl)) { - item.SetImage(new ItemImageInfo - { - Path = info.BackdropImageUrl, - Type = ImageType.Backdrop - }, 0); + item.SetImage( + new ItemImageInfo + { + Path = info.BackdropImageUrl, + Type = ImageType.Backdrop + }, + 0); } } @@ -786,7 +797,6 @@ namespace Emby.Server.Implementations.LiveTv if (query.OrderBy.Count == 0) { - // Unless something else was specified, order by start date to take advantage of a specialized index query.OrderBy = new[] { @@ -824,7 +834,7 @@ namespace Emby.Server.Implementations.LiveTv if (!string.IsNullOrWhiteSpace(query.SeriesTimerId)) { - var seriesTimers = await GetSeriesTimersInternal(new SeriesTimerQuery { }, cancellationToken).ConfigureAwait(false); + var seriesTimers = await GetSeriesTimersInternal(new SeriesTimerQuery(), cancellationToken).ConfigureAwait(false); var seriesTimer = seriesTimers.Items.FirstOrDefault(i => string.Equals(_tvDtoService.GetInternalSeriesTimerId(i.Id).ToString("N", CultureInfo.InvariantCulture), query.SeriesTimerId, StringComparison.OrdinalIgnoreCase)); if (seriesTimer != null) { @@ -847,13 +857,11 @@ namespace Emby.Server.Implementations.LiveTv var returnArray = _dtoService.GetBaseItemDtos(queryResult.Items, options, user); - var result = new QueryResult<BaseItemDto> + return new QueryResult<BaseItemDto> { Items = returnArray, TotalRecordCount = queryResult.TotalRecordCount }; - - return result; } public QueryResult<BaseItem> GetRecommendedProgramsInternal(InternalItemsQuery query, DtoOptions options, CancellationToken cancellationToken) @@ -1173,7 +1181,6 @@ namespace Emby.Server.Implementations.LiveTv var existingPrograms = _libraryManager.GetItemList(new InternalItemsQuery { - IncludeItemTypes = new string[] { typeof(LiveTvProgram).Name }, ChannelIds = new Guid[] { currentChannel.Id }, DtoOptions = new DtoOptions(true) @@ -1298,8 +1305,6 @@ namespace Emby.Server.Implementations.LiveTv } } - private const int MaxGuideDays = 14; - private double GetGuideDays() { var config = GetConfiguration(); @@ -1712,7 +1717,7 @@ namespace Emby.Server.Implementations.LiveTv if (timer == null) { - throw new ResourceNotFoundException(string.Format("Timer with Id {0} not found", id)); + throw new ResourceNotFoundException(string.Format(CultureInfo.InvariantCulture, "Timer with Id {0} not found", id)); } var service = GetService(timer.ServiceName); @@ -1731,7 +1736,7 @@ namespace Emby.Server.Implementations.LiveTv if (timer == null) { - throw new ResourceNotFoundException(string.Format("SeriesTimer with Id {0} not found", id)); + throw new ResourceNotFoundException(string.Format(CultureInfo.InvariantCulture, "SeriesTimer with Id {0} not found", id)); } var service = GetService(timer.ServiceName); @@ -1743,10 +1748,12 @@ namespace Emby.Server.Implementations.LiveTv public async Task<TimerInfoDto> GetTimer(string id, CancellationToken cancellationToken) { - var results = await GetTimers(new TimerQuery - { - Id = id - }, cancellationToken).ConfigureAwait(false); + var results = await GetTimers( + new TimerQuery + { + Id = id + }, + cancellationToken).ConfigureAwait(false); return results.Items.FirstOrDefault(i => string.Equals(i.Id, id, StringComparison.OrdinalIgnoreCase)); } @@ -1794,10 +1801,7 @@ namespace Emby.Server.Implementations.LiveTv } var returnArray = timers - .Select(i => - { - return i.Item1; - }) + .Select(i => i.Item1) .ToArray(); return new QueryResult<SeriesTimerInfo> @@ -1968,7 +1972,7 @@ namespace Emby.Server.Implementations.LiveTv if (service == null) { - service = _services.First(); + service = _services[0]; } var info = await service.GetNewTimerDefaultsAsync(cancellationToken, programInfo).ConfigureAwait(false); @@ -1994,9 +1998,7 @@ namespace Emby.Server.Implementations.LiveTv { var info = await GetNewTimerDefaultsInternal(cancellationToken).ConfigureAwait(false); - var obj = _tvDtoService.GetSeriesTimerInfoDto(info.Item1, info.Item2, null); - - return obj; + return _tvDtoService.GetSeriesTimerInfoDto(info.Item1, info.Item2, null); } public async Task<SeriesTimerInfoDto> GetNewTimerDefaults(string programId, CancellationToken cancellationToken) @@ -2125,6 +2127,7 @@ namespace Emby.Server.Implementations.LiveTv public void Dispose() { Dispose(true); + GC.SuppressFinalize(this); } private bool _disposed = false; @@ -2447,8 +2450,7 @@ namespace Emby.Server.Implementations.LiveTv .SelectMany(i => i.Locations) .Distinct(StringComparer.OrdinalIgnoreCase) .Select(i => _libraryManager.FindByPath(i, true)) - .Where(i => i != null) - .Where(i => i.IsVisibleStandalone(user)) + .Where(i => i != null && i.IsVisibleStandalone(user)) .SelectMany(i => _libraryManager.GetCollectionFolders(i)) .GroupBy(x => x.Id) .Select(x => x.First()) diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs index c61189c0a..f1e120a64 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs @@ -182,12 +182,14 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun { var model = await GetModelInfo(info, false, cancellationToken).ConfigureAwait(false); - using (var response = await _httpClient.SendAsync(new HttpRequestOptions() - { - Url = string.Format("{0}/tuners.html", GetApiUrl(info)), - CancellationToken = cancellationToken, - BufferContent = false - }, HttpMethod.Get).ConfigureAwait(false)) + using (var response = await _httpClient.SendAsync( + new HttpRequestOptions() + { + Url = string.Format(CultureInfo.InvariantCulture, "{0}/tuners.html", GetApiUrl(info)), + CancellationToken = cancellationToken, + BufferContent = false + }, + HttpMethod.Get).ConfigureAwait(false)) using (var stream = response.Content) using (var sr = new StreamReader(stream, System.Text.Encoding.UTF8)) { @@ -730,7 +732,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun // Need a way to set the Receive timeout on the socket otherwise this might never timeout? try { - await udpClient.SendToAsync(discBytes, 0, discBytes.Length, new IPEndPoint(IPAddress.Parse("255.255.255.255"), 65001), cancellationToken); + await udpClient.SendToAsync(discBytes, 0, discBytes.Length, new IPEndPoint(IPAddress.Parse("255.255.255.255"), 65001), cancellationToken).ConfigureAwait(false); var receiveBuffer = new byte[8192]; while (!cancellationToken.IsCancellationRequested) diff --git a/Jellyfin.Api/Controllers/ImageController.cs b/Jellyfin.Api/Controllers/ImageController.cs index 8f5c6beb3..75734f0af 100644 --- a/Jellyfin.Api/Controllers/ImageController.cs +++ b/Jellyfin.Api/Controllers/ImageController.cs @@ -113,7 +113,7 @@ namespace Jellyfin.Api.Controllers user.ProfileImage = new Data.Entities.ImageInfo(Path.Combine(userDataPath, "profile" + MimeTypes.ToExtension(mimeType))); await _providerManager - .SaveImage(user, memoryStream, mimeType, user.ProfileImage.Path) + .SaveImage(memoryStream, mimeType, user.ProfileImage.Path) .ConfigureAwait(false); await _userManager.UpdateUserAsync(user).ConfigureAwait(false); diff --git a/MediaBrowser.Controller/Entities/Movies/Movie.cs b/MediaBrowser.Controller/Entities/Movies/Movie.cs index 53badac4d..5ae396e68 100644 --- a/MediaBrowser.Controller/Entities/Movies/Movie.cs +++ b/MediaBrowser.Controller/Entities/Movies/Movie.cs @@ -1,5 +1,7 @@ + using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Text.Json.Serialization; using System.Threading; @@ -179,7 +181,7 @@ namespace MediaBrowser.Controller.Entities.Movies list.Add(new ExternalUrl { Name = "Trakt", - Url = string.Format("https://trakt.tv/movies/{0}", imdbId) + Url = string.Format(CultureInfo.InvariantCulture, "https://trakt.tv/movies/{0}", imdbId) }); } diff --git a/MediaBrowser.Controller/Entities/TV/Series.cs b/MediaBrowser.Controller/Entities/TV/Series.cs index 45daa8a53..23d960092 100644 --- a/MediaBrowser.Controller/Entities/TV/Series.cs +++ b/MediaBrowser.Controller/Entities/TV/Series.cs @@ -496,7 +496,7 @@ namespace MediaBrowser.Controller.Entities.TV list.Add(new ExternalUrl { Name = "Trakt", - Url = string.Format("https://trakt.tv/shows/{0}", imdbId) + Url = string.Format(CultureInfo.InvariantCulture, "https://trakt.tv/shows/{0}", imdbId) }); } diff --git a/MediaBrowser.Controller/Entities/Trailer.cs b/MediaBrowser.Controller/Entities/Trailer.cs index 6b544afc6..83e9ce1e7 100644 --- a/MediaBrowser.Controller/Entities/Trailer.cs +++ b/MediaBrowser.Controller/Entities/Trailer.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Text.Json.Serialization; using Jellyfin.Data.Enums; using MediaBrowser.Controller.Providers; @@ -86,7 +87,7 @@ namespace MediaBrowser.Controller.Entities list.Add(new ExternalUrl { Name = "Trakt", - Url = string.Format("https://trakt.tv/movies/{0}", imdbId) + Url = string.Format(CultureInfo.InvariantCulture, "https://trakt.tv/movies/{0}", imdbId) }); } diff --git a/MediaBrowser.Controller/Library/Profiler.cs b/MediaBrowser.Controller/Library/Profiler.cs index 399378a09..5efdc6a48 100644 --- a/MediaBrowser.Controller/Library/Profiler.cs +++ b/MediaBrowser.Controller/Library/Profiler.cs @@ -1,5 +1,6 @@ using System; using System.Diagnostics; +using System.Globalization; using Microsoft.Extensions.Logging; namespace MediaBrowser.Controller.Library @@ -13,6 +14,7 @@ namespace MediaBrowser.Controller.Library /// The name. /// </summary> readonly string _name; + /// <summary> /// The stopwatch. /// </summary> @@ -44,6 +46,7 @@ namespace MediaBrowser.Controller.Library public void Dispose() { Dispose(true); + GC.SuppressFinalize(this); } /// <summary> @@ -58,13 +61,19 @@ namespace MediaBrowser.Controller.Library string message; if (_stopwatch.ElapsedMilliseconds > 300000) { - message = string.Format("{0} took {1} minutes.", - _name, ((float)_stopwatch.ElapsedMilliseconds / 60000).ToString("F")); + message = string.Format( + CultureInfo.InvariantCulture, + "{0} took {1} minutes.", + _name, + ((float)_stopwatch.ElapsedMilliseconds / 60000).ToString("F", CultureInfo.InvariantCulture)); } else { - message = string.Format("{0} took {1} seconds.", - _name, ((float)_stopwatch.ElapsedMilliseconds / 1000).ToString("#0.000")); + message = string.Format( + CultureInfo.InvariantCulture, + "{0} took {1} seconds.", + _name, + ((float)_stopwatch.ElapsedMilliseconds / 1000).ToString("#0.000", CultureInfo.InvariantCulture)); } _logger.LogInformation(message); diff --git a/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs b/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs index 10af98121..aa7c12dd1 100644 --- a/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs +++ b/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs @@ -63,7 +63,7 @@ namespace MediaBrowser.Controller.LiveTv if (double.TryParse(Number, NumberStyles.Any, CultureInfo.InvariantCulture, out number)) { - return string.Format("{0:00000.0}", number) + "-" + (Name ?? string.Empty); + return string.Format(CultureInfo.InvariantCulture, "{0:00000.0}", number) + "-" + (Name ?? string.Empty); } } diff --git a/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs b/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs index 472b061e6..e1de01ff0 100644 --- a/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs +++ b/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs @@ -261,7 +261,7 @@ namespace MediaBrowser.Controller.LiveTv list.Add(new ExternalUrl { Name = "Trakt", - Url = string.Format("https://trakt.tv/movies/{0}", imdbId) + Url = string.Format(CultureInfo.InvariantCulture, "https://trakt.tv/movies/{0}", imdbId) }); } } diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 2dd21be3c..7b09f489e 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -675,7 +675,7 @@ namespace MediaBrowser.Controller.MediaEncoding // } // } - // fallbackFontParam = string.Format(":force_style='FontName=Droid Sans Fallback':fontsdir='{0}'", _mediaEncoder.EscapeSubtitleFilterPath(_fileSystem.GetDirectoryName(fallbackFontPath))); + // fallbackFontParam = string.Format(CultureInfo.InvariantCulture, ":force_style='FontName=Droid Sans Fallback':fontsdir='{0}'", _mediaEncoder.EscapeSubtitleFilterPath(_fileSystem.GetDirectoryName(fallbackFontPath))); if (state.SubtitleStream.IsExternal) { @@ -880,7 +880,7 @@ namespace MediaBrowser.Controller.MediaEncoding profileScore = Math.Min(profileScore, 2); // http://www.webmproject.org/docs/encoder-parameters/ - param += string.Format("-speed 16 -quality good -profile:v {0} -slices 8 -crf {1} -qmin {2} -qmax {3}", + param += string.Format(CultureInfo.InvariantCulture, "-speed 16 -quality good -profile:v {0} -slices 8 -crf {1} -qmin {2} -qmax {3}", profileScore.ToString(_usCulture), crf, qmin, @@ -904,7 +904,7 @@ namespace MediaBrowser.Controller.MediaEncoding var framerate = GetFramerateParam(state); if (framerate.HasValue) { - param += string.Format(" -r {0}", framerate.Value.ToString(_usCulture)); + param += string.Format(CultureInfo.InvariantCulture, " -r {0}", framerate.Value.ToString(_usCulture)); } var targetVideoCodec = state.ActualOutputVideoCodec; @@ -1484,7 +1484,7 @@ namespace MediaBrowser.Controller.MediaEncoding if (time > 0) { - return string.Format("-ss {0}", _mediaEncoder.GetTimeParameter(time)); + return string.Format(CultureInfo.InvariantCulture, "-ss {0}", _mediaEncoder.GetTimeParameter(time)); } return string.Empty; diff --git a/MediaBrowser.Controller/Providers/IProviderManager.cs b/MediaBrowser.Controller/Providers/IProviderManager.cs index 8ba01d773..c77349d01 100644 --- a/MediaBrowser.Controller/Providers/IProviderManager.cs +++ b/MediaBrowser.Controller/Providers/IProviderManager.cs @@ -72,7 +72,7 @@ namespace MediaBrowser.Controller.Providers /// <returns>Task.</returns> Task SaveImage(BaseItem item, string source, string mimeType, ImageType type, int? imageIndex, bool? saveLocallyWithMedia, CancellationToken cancellationToken); - Task SaveImage(User user, Stream source, string mimeType, string path); + Task SaveImage(Stream source, string mimeType, string path); /// <summary> /// Adds the metadata providers. diff --git a/MediaBrowser.MediaEncoding/Encoder/EncodingUtils.cs b/MediaBrowser.MediaEncoding/Encoder/EncodingUtils.cs index 7c2d9f1fd..082ae2888 100644 --- a/MediaBrowser.MediaEncoding/Encoder/EncodingUtils.cs +++ b/MediaBrowser.MediaEncoding/Encoder/EncodingUtils.cs @@ -1,6 +1,7 @@ #pragma warning disable CS1591 using System.Collections.Generic; +using System.Globalization; using System.Linq; using MediaBrowser.Model.MediaInfo; @@ -14,7 +15,7 @@ namespace MediaBrowser.MediaEncoding.Encoder { var url = inputFiles[0]; - return string.Format("\"{0}\"", url); + return string.Format(CultureInfo.InvariantCulture, "\"{0}\"", url); } return GetConcatInputArgument(inputFiles); @@ -33,7 +34,7 @@ namespace MediaBrowser.MediaEncoding.Encoder { var files = string.Join("|", inputFiles.Select(NormalizePath)); - return string.Format("concat:\"{0}\"", files); + return string.Format(CultureInfo.InvariantCulture, "concat:\"{0}\"", files); } // Determine the input path for video files @@ -49,13 +50,13 @@ namespace MediaBrowser.MediaEncoding.Encoder { if (path.IndexOf("://") != -1) { - return string.Format("\"{0}\"", path); + return string.Format(CultureInfo.InvariantCulture, "\"{0}\"", path); } // Quotes are valid path characters in linux and they need to be escaped here with a leading \ path = NormalizePath(path); - return string.Format("file:\"{0}\"", path); + return string.Format(CultureInfo.InvariantCulture, "file:\"{0}\"", path); } /// <summary> diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index 778c0b18c..b9a6432ad 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -552,8 +552,8 @@ namespace MediaBrowser.MediaEncoding.Encoder // Use ffmpeg to sample 100 (we can drop this if required using thumbnail=50 for 50 frames) frames and pick the best thumbnail. Have a fall back just in case. var thumbnail = enableThumbnail ? ",thumbnail=24" : string.Empty; - var args = useIFrame ? string.Format("-i {0}{3} -threads 0 -v quiet -vframes 1 -vf \"{2}{4}\" -f image2 \"{1}\"", inputPath, tempExtractPath, vf, mapArg, thumbnail) : - string.Format("-i {0}{3} -threads 0 -v quiet -vframes 1 -vf \"{2}\" -f image2 \"{1}\"", inputPath, tempExtractPath, vf, mapArg); + var args = useIFrame ? string.Format(CultureInfo.InvariantCulture, "-i {0}{3} -threads 0 -v quiet -vframes 1 -vf \"{2}{4}\" -f image2 \"{1}\"", inputPath, tempExtractPath, vf, mapArg, thumbnail) : + string.Format(CultureInfo.InvariantCulture, "-i {0}{3} -threads 0 -v quiet -vframes 1 -vf \"{2}\" -f image2 \"{1}\"", inputPath, tempExtractPath, vf, mapArg); var probeSizeArgument = EncodingHelper.GetProbeSizeArgument(1); var analyzeDurationArgument = EncodingHelper.GetAnalyzeDurationArgument(1); @@ -570,7 +570,7 @@ namespace MediaBrowser.MediaEncoding.Encoder if (offset.HasValue) { - args = string.Format("-ss {0} ", GetTimeParameter(offset.Value)) + args; + args = string.Format(CultureInfo.InvariantCulture, "-ss {0} ", GetTimeParameter(offset.Value)) + args; } if (videoStream != null) @@ -641,7 +641,7 @@ namespace MediaBrowser.MediaEncoding.Encoder if (exitCode == -1 || !file.Exists || file.Length == 0) { - var msg = string.Format("ffmpeg image extraction failed for {0}", inputPath); + var msg = string.Format(CultureInfo.InvariantCulture, "ffmpeg image extraction failed for {0}", inputPath); _logger.LogError(msg); @@ -684,13 +684,13 @@ namespace MediaBrowser.MediaEncoding.Encoder { var maxWidthParam = maxWidth.Value.ToString(_usCulture); - vf += string.Format(",scale=min(iw\\,{0}):trunc(ow/dar/2)*2", maxWidthParam); + vf += string.Format(CultureInfo.InvariantCulture, ",scale=min(iw\\,{0}):trunc(ow/dar/2)*2", maxWidthParam); } Directory.CreateDirectory(targetDirectory); var outputPath = Path.Combine(targetDirectory, filenamePrefix + "%05d.jpg"); - var args = string.Format("-i {0} -threads 0 -v quiet -vf \"{2}\" -f image2 \"{1}\"", inputArgument, outputPath, vf); + var args = string.Format(CultureInfo.InvariantCulture, "-i {0} -threads 0 -v quiet -vf \"{2}\" -f image2 \"{1}\"", inputArgument, outputPath, vf); var probeSizeArgument = EncodingHelper.GetProbeSizeArgument(1); var analyzeDurationArgument = EncodingHelper.GetAnalyzeDurationArgument(1); @@ -790,7 +790,7 @@ namespace MediaBrowser.MediaEncoding.Encoder if (exitCode == -1) { - var msg = string.Format("ffmpeg image extraction failed for {0}", inputArgument); + var msg = string.Format(CultureInfo.InvariantCulture, "ffmpeg image extraction failed for {0}", inputArgument); _logger.LogError(msg); diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs index 374e35b96..fbe8bd69f 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs @@ -435,7 +435,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles CreateNoWindow = true, UseShellExecute = false, FileName = _mediaEncoder.EncoderPath, - Arguments = string.Format("{0} -i \"{1}\" -c:s srt \"{2}\"", encodingParam, inputPath, outputPath), + Arguments = string.Format(CultureInfo.InvariantCulture, "{0} -i \"{1}\" -c:s srt \"{2}\"", encodingParam, inputPath, outputPath), WindowStyle = ProcessWindowStyle.Hidden, ErrorDialog = false }, diff --git a/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs b/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs index a579f8464..93e60753a 100644 --- a/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs +++ b/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs @@ -157,7 +157,7 @@ namespace MediaBrowser.Model.Dlna // flagValue = flagValue | DlnaFlags.TimeBasedSeek; //} - string dlnaflags = string.Format(";DLNA.ORG_FLAGS={0}", + string dlnaflags = string.Format(CultureInfo.InvariantCulture, ";DLNA.ORG_FLAGS={0}", DlnaMaps.FlagsToString(flagValue)); ResponseProfile mediaProfile = _profile.GetVideoMediaProfile(container, diff --git a/MediaBrowser.Model/Dlna/DlnaMaps.cs b/MediaBrowser.Model/Dlna/DlnaMaps.cs index 052b4b78b..95cd0ac27 100644 --- a/MediaBrowser.Model/Dlna/DlnaMaps.cs +++ b/MediaBrowser.Model/Dlna/DlnaMaps.cs @@ -1,18 +1,20 @@ #pragma warning disable CS1591 +using System.Globalization; + namespace MediaBrowser.Model.Dlna { public static class DlnaMaps { private static readonly string DefaultStreaming = - FlagsToString(DlnaFlags.StreamingTransferMode | + FlagsToString(DlnaFlags.StreamingTransferMode | DlnaFlags.BackgroundTransferMode | DlnaFlags.ConnectionStall | DlnaFlags.ByteBasedSeek | DlnaFlags.DlnaV15); private static readonly string DefaultInteractive = - FlagsToString(DlnaFlags.InteractiveTransferMode | + FlagsToString(DlnaFlags.InteractiveTransferMode | DlnaFlags.BackgroundTransferMode | DlnaFlags.ConnectionStall | DlnaFlags.ByteBasedSeek | @@ -20,7 +22,7 @@ namespace MediaBrowser.Model.Dlna public static string FlagsToString(DlnaFlags flags) { - return string.Format("{0:X8}{1:D24}", (ulong)flags, 0); + return string.Format(CultureInfo.InvariantCulture, "{0:X8}{1:D24}", (ulong)flags, 0); } public static string GetOrgOpValue(bool hasKnownRuntime, bool isDirectStream, TranscodeSeekInfo profileTranscodeSeekInfo) diff --git a/MediaBrowser.Model/Dlna/MediaFormatProfileResolver.cs b/MediaBrowser.Model/Dlna/MediaFormatProfileResolver.cs index bdc5f8bb7..3c955989a 100644 --- a/MediaBrowser.Model/Dlna/MediaFormatProfileResolver.cs +++ b/MediaBrowser.Model/Dlna/MediaFormatProfileResolver.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using MediaBrowser.Model.MediaInfo; @@ -142,26 +143,26 @@ namespace MediaBrowser.Model.Dlna { if (timestampType == TransportStreamTimestamp.None) { - return new MediaFormatProfile[] { ValueOf(string.Format("AVC_TS_HP_{0}D_MPEG1_L2_ISO", resolution)) }; + return new MediaFormatProfile[] { ValueOf(string.Format(CultureInfo.InvariantCulture, "AVC_TS_HP_{0}D_MPEG1_L2_ISO", resolution)) }; } - return new MediaFormatProfile[] { ValueOf(string.Format("AVC_TS_HP_{0}D_MPEG1_L2_T", resolution)) }; + return new MediaFormatProfile[] { ValueOf(string.Format(CultureInfo.InvariantCulture, "AVC_TS_HP_{0}D_MPEG1_L2_T", resolution)) }; } if (string.Equals(audioCodec, "aac", StringComparison.OrdinalIgnoreCase)) { - return new MediaFormatProfile[] { ValueOf(string.Format("AVC_TS_MP_{0}D_AAC_MULT5{1}", resolution, suffix)) }; + return new MediaFormatProfile[] { ValueOf(string.Format(CultureInfo.InvariantCulture, "AVC_TS_MP_{0}D_AAC_MULT5{1}", resolution, suffix)) }; } if (string.Equals(audioCodec, "mp3", StringComparison.OrdinalIgnoreCase)) { - return new MediaFormatProfile[] { ValueOf(string.Format("AVC_TS_MP_{0}D_MPEG1_L3{1}", resolution, suffix)) }; + return new MediaFormatProfile[] { ValueOf(string.Format(CultureInfo.InvariantCulture, "AVC_TS_MP_{0}D_MPEG1_L3{1}", resolution, suffix)) }; } if (string.IsNullOrEmpty(audioCodec) || string.Equals(audioCodec, "ac3", StringComparison.OrdinalIgnoreCase)) { - return new MediaFormatProfile[] { ValueOf(string.Format("AVC_TS_MP_{0}D_AC3{1}", resolution, suffix)) }; + return new MediaFormatProfile[] { ValueOf(string.Format(CultureInfo.InvariantCulture, "AVC_TS_MP_{0}D_AC3{1}", resolution, suffix)) }; } } else if (string.Equals(videoCodec, "vc1", StringComparison.OrdinalIgnoreCase)) @@ -180,29 +181,29 @@ namespace MediaBrowser.Model.Dlna { suffix = string.Equals(suffix, "_ISO", StringComparison.OrdinalIgnoreCase) ? suffix : "_T"; - return new MediaFormatProfile[] { ValueOf(string.Format("VC1_TS_HD_DTS{0}", suffix)) }; + return new MediaFormatProfile[] { ValueOf(string.Format(CultureInfo.InvariantCulture, "VC1_TS_HD_DTS{0}", suffix)) }; } } else if (string.Equals(videoCodec, "mpeg4", StringComparison.OrdinalIgnoreCase) || string.Equals(videoCodec, "msmpeg4", StringComparison.OrdinalIgnoreCase)) { if (string.Equals(audioCodec, "aac", StringComparison.OrdinalIgnoreCase)) { - return new MediaFormatProfile[] { ValueOf(string.Format("MPEG4_P2_TS_ASP_AAC{0}", suffix)) }; + return new MediaFormatProfile[] { ValueOf(string.Format(CultureInfo.InvariantCulture, "MPEG4_P2_TS_ASP_AAC{0}", suffix)) }; } if (string.Equals(audioCodec, "mp3", StringComparison.OrdinalIgnoreCase)) { - return new MediaFormatProfile[] { ValueOf(string.Format("MPEG4_P2_TS_ASP_MPEG1_L3{0}", suffix)) }; + return new MediaFormatProfile[] { ValueOf(string.Format(CultureInfo.InvariantCulture, "MPEG4_P2_TS_ASP_MPEG1_L3{0}", suffix)) }; } if (string.Equals(audioCodec, "mp2", StringComparison.OrdinalIgnoreCase)) { - return new MediaFormatProfile[] { ValueOf(string.Format("MPEG4_P2_TS_ASP_MPEG2_L2{0}", suffix)) }; + return new MediaFormatProfile[] { ValueOf(string.Format(CultureInfo.InvariantCulture, "MPEG4_P2_TS_ASP_MPEG2_L2{0}", suffix)) }; } if (string.Equals(audioCodec, "ac3", StringComparison.OrdinalIgnoreCase)) { - return new MediaFormatProfile[] { ValueOf(string.Format("MPEG4_P2_TS_ASP_AC3{0}", suffix)) }; + return new MediaFormatProfile[] { ValueOf(string.Format(CultureInfo.InvariantCulture, "MPEG4_P2_TS_ASP_AC3{0}", suffix)) }; } } diff --git a/MediaBrowser.Model/Dlna/StreamInfo.cs b/MediaBrowser.Model/Dlna/StreamInfo.cs index 204340c46..94d53ab70 100644 --- a/MediaBrowser.Model/Dlna/StreamInfo.cs +++ b/MediaBrowser.Model/Dlna/StreamInfo.cs @@ -191,7 +191,7 @@ namespace MediaBrowser.Model.Dlna var encodedValue = pair.Value.Replace(" ", "%20"); - list.Add(string.Format("{0}={1}", pair.Name, encodedValue)); + list.Add(string.Format(CultureInfo.InvariantCulture, "{0}={1}", pair.Name, encodedValue)); } string queryString = string.Join("&", list.ToArray()); @@ -214,18 +214,18 @@ namespace MediaBrowser.Model.Dlna { if (string.Equals(SubProtocol, "hls", StringComparison.OrdinalIgnoreCase)) { - return string.Format("{0}/audio/{1}/master.m3u8?{2}", baseUrl, ItemId, queryString); + return string.Format(CultureInfo.InvariantCulture, "{0}/audio/{1}/master.m3u8?{2}", baseUrl, ItemId, queryString); } - return string.Format("{0}/audio/{1}/stream{2}?{3}", baseUrl, ItemId, extension, queryString); + return string.Format(CultureInfo.InvariantCulture, "{0}/audio/{1}/stream{2}?{3}", baseUrl, ItemId, extension, queryString); } if (string.Equals(SubProtocol, "hls", StringComparison.OrdinalIgnoreCase)) { - return string.Format("{0}/videos/{1}/master.m3u8?{2}", baseUrl, ItemId, queryString); + return string.Format(CultureInfo.InvariantCulture, "{0}/videos/{1}/master.m3u8?{2}", baseUrl, ItemId, queryString); } - return string.Format("{0}/videos/{1}/stream{2}?{3}", baseUrl, ItemId, extension, queryString); + return string.Format(CultureInfo.InvariantCulture, "{0}/videos/{1}/stream{2}?{3}", baseUrl, ItemId, extension, queryString); } private static List<NameValuePair> BuildParams(StreamInfo item, string accessToken) @@ -457,7 +457,7 @@ namespace MediaBrowser.Model.Dlna { if (MediaSource.Protocol == MediaProtocol.File || !string.Equals(stream.Codec, subtitleProfile.Format, StringComparison.OrdinalIgnoreCase) || !stream.IsExternal) { - info.Url = string.Format("{0}/Videos/{1}/{2}/Subtitles/{3}/{4}/Stream.{5}", + info.Url = string.Format(CultureInfo.InvariantCulture, "{0}/Videos/{1}/{2}/Subtitles/{3}/{4}/Stream.{5}", baseUrl, ItemId, MediaSourceId, diff --git a/MediaBrowser.Providers/Manager/ImageSaver.cs b/MediaBrowser.Providers/Manager/ImageSaver.cs index 26b50784b..413d297cb 100644 --- a/MediaBrowser.Providers/Manager/ImageSaver.cs +++ b/MediaBrowser.Providers/Manager/ImageSaver.cs @@ -187,7 +187,7 @@ namespace MediaBrowser.Providers.Manager } } - public async Task SaveImage(User user, Stream source, string path) + public async Task SaveImage(Stream source, string path) { await SaveImageToLocation(source, path, path, CancellationToken.None).ConfigureAwait(false); } @@ -355,7 +355,7 @@ namespace MediaBrowser.Providers.Manager if (string.IsNullOrWhiteSpace(extension)) { - throw new ArgumentException(string.Format("Unable to determine image file extension from mime type {0}", mimeType)); + throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, "Unable to determine image file extension from mime type {0}", mimeType)); } if (type == ImageType.Thumb && saveLocally) diff --git a/MediaBrowser.Providers/Manager/ItemImageProvider.cs b/MediaBrowser.Providers/Manager/ItemImageProvider.cs index a5eb095c4..9227b6d93 100644 --- a/MediaBrowser.Providers/Manager/ItemImageProvider.cs +++ b/MediaBrowser.Providers/Manager/ItemImageProvider.cs @@ -54,7 +54,12 @@ namespace MediaBrowser.Providers.Manager return hasChanges; } - public async Task<RefreshResult> RefreshImages(BaseItem item, LibraryOptions libraryOptions, List<IImageProvider> providers, ImageRefreshOptions refreshOptions, MetadataOptions savedOptions, CancellationToken cancellationToken) + public async Task<RefreshResult> RefreshImages( + BaseItem item, + LibraryOptions libraryOptions, + List<IImageProvider> providers, + ImageRefreshOptions refreshOptions, + CancellationToken cancellationToken) { if (refreshOptions.IsReplacingImage(ImageType.Backdrop)) { @@ -78,19 +83,15 @@ namespace MediaBrowser.Providers.Manager foreach (var provider in providers) { - var remoteProvider = provider as IRemoteImageProvider; - - if (remoteProvider != null) + if (provider is IRemoteImageProvider remoteProvider) { await RefreshFromProvider(item, libraryOptions, remoteProvider, refreshOptions, typeOptions, backdropLimit, screenshotLimit, downloadedImages, result, cancellationToken).ConfigureAwait(false); continue; } - var dynamicImageProvider = provider as IDynamicImageProvider; - - if (dynamicImageProvider != null) + if (provider is IDynamicImageProvider dynamicImageProvider) { - await RefreshFromProvider(item, dynamicImageProvider, refreshOptions, typeOptions, libraryOptions, downloadedImages, result, cancellationToken).ConfigureAwait(false); + await RefreshFromProvider(item, dynamicImageProvider, refreshOptions, typeOptions, downloadedImages, result, cancellationToken).ConfigureAwait(false); } } @@ -100,11 +101,11 @@ namespace MediaBrowser.Providers.Manager /// <summary> /// Refreshes from provider. /// </summary> - private async Task RefreshFromProvider(BaseItem item, + private async Task RefreshFromProvider( + BaseItem item, IDynamicImageProvider provider, ImageRefreshOptions refreshOptions, TypeOptions savedOptions, - LibraryOptions libraryOptions, ICollection<ImageType> downloadedImages, RefreshResult result, CancellationToken cancellationToken) @@ -115,7 +116,7 @@ namespace MediaBrowser.Providers.Manager foreach (var imageType in images) { - if (!IsEnabled(savedOptions, imageType, item)) + if (!IsEnabled(savedOptions, imageType)) { continue; } @@ -133,12 +134,13 @@ namespace MediaBrowser.Providers.Manager if (response.Protocol == MediaProtocol.Http) { _logger.LogDebug("Setting image url into item {0}", item.Id); - item.SetImage(new ItemImageInfo - { - Path = response.Path, - Type = imageType - - }, 0); + item.SetImage( + new ItemImageInfo + { + Path = response.Path, + Type = imageType + }, + 0); } else { @@ -157,7 +159,7 @@ namespace MediaBrowser.Providers.Manager } downloadedImages.Add(imageType); - result.UpdateType = result.UpdateType | ItemUpdateType.ImageUpdate; + result.UpdateType |= ItemUpdateType.ImageUpdate; } } } @@ -279,7 +281,7 @@ namespace MediaBrowser.Providers.Manager foreach (var imageType in _singularImages) { - if (!IsEnabled(savedOptions, imageType, item)) + if (!IsEnabled(savedOptions, imageType)) { continue; } @@ -299,8 +301,7 @@ namespace MediaBrowser.Providers.Manager minWidth = savedOptions.GetMinWidth(ImageType.Backdrop); await DownloadBackdrops(item, libraryOptions, ImageType.Backdrop, backdropLimit, provider, result, list, minWidth, cancellationToken).ConfigureAwait(false); - var hasScreenshots = item as IHasScreenshots; - if (hasScreenshots != null) + if (item is IHasScreenshots hasScreenshots) { minWidth = savedOptions.GetMinWidth(ImageType.Screenshot); await DownloadBackdrops(item, libraryOptions, ImageType.Screenshot, screenshotLimit, provider, result, list, minWidth, cancellationToken).ConfigureAwait(false); @@ -317,7 +318,7 @@ namespace MediaBrowser.Providers.Manager } } - private bool IsEnabled(TypeOptions options, ImageType type, BaseItem item) + private bool IsEnabled(TypeOptions options, ImageType type) { return options.IsEnabled(type); } @@ -452,10 +453,10 @@ namespace MediaBrowser.Providers.Manager .Where(i => i.Type == type && !(i.Width.HasValue && i.Width.Value < minWidth)) .ToList(); - if (EnableImageStub(item, type, libraryOptions) && eligibleImages.Count > 0) + if (EnableImageStub(item, libraryOptions) && eligibleImages.Count > 0) { SaveImageStub(item, type, eligibleImages.Select(i => i.Url)); - result.UpdateType = result.UpdateType | ItemUpdateType.ImageUpdate; + result.UpdateType |= ItemUpdateType.ImageUpdate; return true; } @@ -476,7 +477,7 @@ namespace MediaBrowser.Providers.Manager null, cancellationToken).ConfigureAwait(false); - result.UpdateType = result.UpdateType | ItemUpdateType.ImageUpdate; + result.UpdateType |= ItemUpdateType.ImageUpdate; return true; } catch (HttpException ex) @@ -495,7 +496,7 @@ namespace MediaBrowser.Providers.Manager return false; } - private bool EnableImageStub(BaseItem item, ImageType type, LibraryOptions libraryOptions) + private bool EnableImageStub(BaseItem item, LibraryOptions libraryOptions) { if (item is LiveTvProgram) { @@ -563,10 +564,10 @@ namespace MediaBrowser.Providers.Manager var url = image.Url; - if (EnableImageStub(item, imageType, libraryOptions)) + if (EnableImageStub(item, libraryOptions)) { SaveImageStub(item, imageType, new[] { url }); - result.UpdateType = result.UpdateType | ItemUpdateType.ImageUpdate; + result.UpdateType |= ItemUpdateType.ImageUpdate; continue; } diff --git a/MediaBrowser.Providers/Manager/MetadataService.cs b/MediaBrowser.Providers/Manager/MetadataService.cs index 3b0c7b56c..dcae300fc 100644 --- a/MediaBrowser.Providers/Manager/MetadataService.cs +++ b/MediaBrowser.Providers/Manager/MetadataService.cs @@ -52,7 +52,6 @@ namespace MediaBrowser.Providers.Manager public async Task<ItemUpdateType> RefreshMetadata(BaseItem item, MetadataRefreshOptions refreshOptions, CancellationToken cancellationToken) { var itemOfType = (TItemType)item; - var config = ProviderManager.GetMetadataOptions(item); var updateType = ItemUpdateType.None; var requiresRefresh = false; @@ -86,7 +85,7 @@ namespace MediaBrowser.Providers.Manager // Always validate images and check for new locally stored ones. if (itemImageProvider.ValidateImages(item, allImageProviders.OfType<ILocalImageProvider>(), refreshOptions.DirectoryService)) { - updateType = updateType | ItemUpdateType.ImageUpdate; + updateType |= ItemUpdateType.ImageUpdate; } } catch (Exception ex) @@ -102,7 +101,7 @@ namespace MediaBrowser.Providers.Manager bool hasRefreshedMetadata = true; bool hasRefreshedImages = true; - var isFirstRefresh = item.DateLastRefreshed == default(DateTime); + var isFirstRefresh = item.DateLastRefreshed == default; // Next run metadata providers if (refreshOptions.MetadataRefreshMode != MetadataRefreshMode.None) @@ -114,7 +113,7 @@ namespace MediaBrowser.Providers.Manager { if (item.BeforeMetadataRefresh(refreshOptions.ReplaceAllMetadata)) { - updateType = updateType | ItemUpdateType.MetadataImport; + updateType |= ItemUpdateType.MetadataImport; } } @@ -132,7 +131,7 @@ namespace MediaBrowser.Providers.Manager var result = await RefreshWithProviders(metadataResult, id, refreshOptions, providers, itemImageProvider, cancellationToken).ConfigureAwait(false); - updateType = updateType | result.UpdateType; + updateType |= result.UpdateType; if (result.Failures > 0) { hasRefreshedMetadata = false; @@ -147,9 +146,9 @@ namespace MediaBrowser.Providers.Manager if (providers.Count > 0) { - var result = await itemImageProvider.RefreshImages(itemOfType, libraryOptions, providers, refreshOptions, config, cancellationToken).ConfigureAwait(false); + var result = await itemImageProvider.RefreshImages(itemOfType, libraryOptions, providers, refreshOptions, cancellationToken).ConfigureAwait(false); - updateType = updateType | result.UpdateType; + updateType |= result.UpdateType; if (result.Failures > 0) { hasRefreshedImages = false; @@ -158,7 +157,7 @@ namespace MediaBrowser.Providers.Manager } var beforeSaveResult = BeforeSave(itemOfType, isFirstRefresh || refreshOptions.ReplaceAllMetadata || refreshOptions.MetadataRefreshMode == MetadataRefreshMode.FullRefresh || requiresRefresh || refreshOptions.ForceSave, updateType); - updateType = updateType | beforeSaveResult; + updateType |= beforeSaveResult; // Save if changes were made, or it's never been saved before if (refreshOptions.ForceSave || updateType > ItemUpdateType.None || isFirstRefresh || refreshOptions.ReplaceAllMetadata || requiresRefresh) @@ -175,7 +174,7 @@ namespace MediaBrowser.Providers.Manager // If any of these properties are set then make sure the updateType is not None, just to force everything to save if (refreshOptions.ForceSave || refreshOptions.ReplaceAllMetadata) { - updateType = updateType | ItemUpdateType.MetadataDownload; + updateType |= ItemUpdateType.MetadataDownload; } if (hasRefreshedMetadata && hasRefreshedImages) @@ -184,11 +183,11 @@ namespace MediaBrowser.Providers.Manager } else { - item.DateLastRefreshed = default(DateTime); + item.DateLastRefreshed = default; } // Save to database - SaveItem(metadataResult, libraryOptions, updateType, cancellationToken); + await SaveItemAsync(metadataResult, libraryOptions, updateType, cancellationToken).ConfigureAwait(false); } await AfterMetadataRefresh(itemOfType, refreshOptions, cancellationToken).ConfigureAwait(false); @@ -203,26 +202,26 @@ namespace MediaBrowser.Providers.Manager lookupInfo.Year = result.ProductionYear; } - protected void SaveItem(MetadataResult<TItemType> result, LibraryOptions libraryOptions, ItemUpdateType reason, CancellationToken cancellationToken) + protected async Task SaveItemAsync(MetadataResult<TItemType> result, LibraryOptions libraryOptions, ItemUpdateType reason, CancellationToken cancellationToken) { if (result.Item.SupportsPeople && result.People != null) { var baseItem = result.Item; LibraryManager.UpdatePeople(baseItem, result.People); - SavePeopleMetadata(result.People, libraryOptions, cancellationToken); + await SavePeopleMetadataAsync(result.People, libraryOptions, cancellationToken).ConfigureAwait(false); } result.Item.UpdateToRepository(reason, cancellationToken); } - private void SavePeopleMetadata(List<PersonInfo> people, LibraryOptions libraryOptions, CancellationToken cancellationToken) + private async Task SavePeopleMetadataAsync(List<PersonInfo> people, LibraryOptions libraryOptions, CancellationToken cancellationToken) { foreach (var person in people) { cancellationToken.ThrowIfCancellationRequested(); - if (person.ProviderIds.Any() || !string.IsNullOrWhiteSpace(person.ImageUrl)) + if (person.ProviderIds.Count > 0 || !string.IsNullOrWhiteSpace(person.ImageUrl)) { var updateType = ItemUpdateType.MetadataDownload; @@ -239,10 +238,10 @@ namespace MediaBrowser.Providers.Manager if (!string.IsNullOrWhiteSpace(person.ImageUrl) && !personEntity.HasImage(ImageType.Primary)) { - AddPersonImage(personEntity, libraryOptions, person.ImageUrl, cancellationToken); + await AddPersonImageAsync(personEntity, libraryOptions, person.ImageUrl, cancellationToken).ConfigureAwait(false); saveEntity = true; - updateType = updateType | ItemUpdateType.ImageUpdate; + updateType |= ItemUpdateType.ImageUpdate; } if (saveEntity) @@ -253,26 +252,28 @@ namespace MediaBrowser.Providers.Manager } } - private void AddPersonImage(Person personEntity, LibraryOptions libraryOptions, string imageUrl, CancellationToken cancellationToken) + private async Task AddPersonImageAsync(Person personEntity, LibraryOptions libraryOptions, string imageUrl, CancellationToken cancellationToken) { - // if (libraryOptions.DownloadImagesInAdvance) - //{ - // try - // { - // await ProviderManager.SaveImage(personEntity, imageUrl, ImageType.Primary, null, cancellationToken).ConfigureAwait(false); - // return; - // } - // catch (Exception ex) - // { - // Logger.LogError(ex, "Error in AddPersonImage"); - // } - //} - - personEntity.SetImage(new ItemImageInfo - { - Path = imageUrl, - Type = ImageType.Primary - }, 0); + if (libraryOptions.DownloadImagesInAdvance) + { + try + { + await ProviderManager.SaveImage(personEntity, imageUrl, ImageType.Primary, null, cancellationToken).ConfigureAwait(false); + return; + } + catch (Exception ex) + { + Logger.LogError(ex, "Error in AddPersonImage"); + } + } + + personEntity.SetImage( + new ItemImageInfo + { + Path = imageUrl, + Type = ImageType.Primary + }, + 0); } protected virtual Task AfterMetadataRefresh(TItemType item, MetadataRefreshOptions refreshOptions, CancellationToken cancellationToken) diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs index e67d1b8c3..d9a84be5c 100644 --- a/MediaBrowser.Providers/Manager/ProviderManager.cs +++ b/MediaBrowser.Providers/Manager/ProviderManager.cs @@ -210,10 +210,10 @@ namespace MediaBrowser.Providers.Manager } /// <inheritdoc/> - public Task SaveImage(User user, Stream source, string mimeType, string path) + public Task SaveImage(Stream source, string mimeType, string path) { return new ImageSaver(_configurationManager, _libraryMonitor, _fileSystem, _logger) - .SaveImage(user, source, path); + .SaveImage(source, path); } /// <inheritdoc/> @@ -563,7 +563,7 @@ namespace MediaBrowser.Providers.Manager var pluginList = summary.Plugins.ToList(); AddMetadataPlugins(pluginList, dummy, libraryOptions, options); - AddImagePlugins(pluginList, dummy, imageProviders); + AddImagePlugins(pluginList, imageProviders); var subtitleProviders = _subtitleManager.GetSupportedProviders(dummy); @@ -594,14 +594,14 @@ namespace MediaBrowser.Providers.Manager var providers = GetMetadataProvidersInternal<T>(item, libraryOptions, options, true, true).ToList(); // Locals - list.AddRange(providers.Where(i => (i is ILocalMetadataProvider)).Select(i => new MetadataPlugin + list.AddRange(providers.Where(i => i is ILocalMetadataProvider).Select(i => new MetadataPlugin { Name = i.Name, Type = MetadataPluginType.LocalMetadataProvider })); // Fetchers - list.AddRange(providers.Where(i => (i is IRemoteMetadataProvider)).Select(i => new MetadataPlugin + list.AddRange(providers.Where(i => i is IRemoteMetadataProvider).Select(i => new MetadataPlugin { Name = i.Name, Type = MetadataPluginType.MetadataFetcher @@ -615,11 +615,10 @@ namespace MediaBrowser.Providers.Manager })); } - private void AddImagePlugins<T>(List<MetadataPlugin> list, T item, List<IImageProvider> imageProviders) - where T : BaseItem + private void AddImagePlugins(List<MetadataPlugin> list, List<IImageProvider> imageProviders) { // Locals - list.AddRange(imageProviders.Where(i => (i is ILocalImageProvider)).Select(i => new MetadataPlugin + list.AddRange(imageProviders.Where(i => i is ILocalImageProvider).Select(i => new MetadataPlugin { Name = i.Name, Type = MetadataPluginType.LocalImageProvider @@ -1166,12 +1165,32 @@ namespace MediaBrowser.Providers.Manager /// <inheritdoc/> public void Dispose() { - _disposed = true; + Dispose(true); + GC.SuppressFinalize(this); + } + + /// <summary> + /// Releases unmanaged and optionally managed resources. + /// </summary> + /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param> + protected virtual void Dispose(bool disposing) + { + if (_disposed) + { + return; + } if (!_disposeCancellationTokenSource.IsCancellationRequested) { _disposeCancellationTokenSource.Cancel(); } + + if (disposing) + { + _disposeCancellationTokenSource.Dispose(); + } + + _disposed = true; } } } diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs b/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs index 69c6fd722..77f03580a 100644 --- a/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs +++ b/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs @@ -2,11 +2,9 @@ using System; using System.Collections.Generic; -using System.Globalization; using System.Linq; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Library; @@ -17,7 +15,6 @@ using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; using MediaBrowser.Model.MediaInfo; -using MediaBrowser.Model.Serialization; namespace MediaBrowser.Providers.MediaInfo { @@ -25,19 +22,17 @@ namespace MediaBrowser.Providers.MediaInfo { private readonly IMediaEncoder _mediaEncoder; private readonly IItemRepository _itemRepo; - private readonly IApplicationPaths _appPaths; - private readonly IJsonSerializer _json; private readonly ILibraryManager _libraryManager; private readonly IMediaSourceManager _mediaSourceManager; - private readonly CultureInfo _usCulture = new CultureInfo("en-US"); - - public FFProbeAudioInfo(IMediaSourceManager mediaSourceManager, IMediaEncoder mediaEncoder, IItemRepository itemRepo, IApplicationPaths appPaths, IJsonSerializer json, ILibraryManager libraryManager) + public FFProbeAudioInfo( + IMediaSourceManager mediaSourceManager, + IMediaEncoder mediaEncoder, + IItemRepository itemRepo, + ILibraryManager libraryManager) { _mediaEncoder = mediaEncoder; _itemRepo = itemRepo; - _appPaths = appPaths; - _json = json; _libraryManager = libraryManager; _mediaSourceManager = mediaSourceManager; } diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs b/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs index 4fabe709b..9926275ae 100644 --- a/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs +++ b/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs @@ -40,19 +40,15 @@ namespace MediaBrowser.Providers.MediaInfo IHasItemChangeMonitor { private readonly ILogger<FFProbeProvider> _logger; - private readonly IIsoManager _isoManager; private readonly IMediaEncoder _mediaEncoder; private readonly IItemRepository _itemRepo; private readonly IBlurayExaminer _blurayExaminer; private readonly ILocalizationManager _localization; - private readonly IApplicationPaths _appPaths; - private readonly IJsonSerializer _json; private readonly IEncodingManager _encodingManager; private readonly IServerConfigurationManager _config; private readonly ISubtitleManager _subtitleManager; private readonly IChapterManager _chapterManager; private readonly ILibraryManager _libraryManager; - private readonly IChannelManager _channelManager; private readonly IMediaSourceManager _mediaSourceManager; public string Name => "ffprobe"; @@ -126,14 +122,10 @@ namespace MediaBrowser.Providers.MediaInfo public FFProbeProvider( ILogger<FFProbeProvider> logger, IMediaSourceManager mediaSourceManager, - IChannelManager channelManager, - IIsoManager isoManager, IMediaEncoder mediaEncoder, IItemRepository itemRepo, IBlurayExaminer blurayExaminer, ILocalizationManager localization, - IApplicationPaths appPaths, - IJsonSerializer json, IEncodingManager encodingManager, IServerConfigurationManager config, ISubtitleManager subtitleManager, @@ -141,19 +133,15 @@ namespace MediaBrowser.Providers.MediaInfo ILibraryManager libraryManager) { _logger = logger; - _isoManager = isoManager; _mediaEncoder = mediaEncoder; _itemRepo = itemRepo; _blurayExaminer = blurayExaminer; _localization = localization; - _appPaths = appPaths; - _json = json; _encodingManager = encodingManager; _config = config; _subtitleManager = subtitleManager; _chapterManager = chapterManager; _libraryManager = libraryManager; - _channelManager = channelManager; _mediaSourceManager = mediaSourceManager; _subtitleResolver = new SubtitleResolver(BaseItem.LocalizationManager); @@ -211,9 +199,9 @@ namespace MediaBrowser.Providers.MediaInfo private string NormalizeStrmLine(string line) { - return line.Replace("\t", string.Empty) - .Replace("\r", string.Empty) - .Replace("\n", string.Empty) + return line.Replace("\t", string.Empty, StringComparison.Ordinal) + .Replace("\r", string.Empty, StringComparison.Ordinal) + .Replace("\n", string.Empty, StringComparison.Ordinal) .Trim(); } @@ -242,10 +230,11 @@ namespace MediaBrowser.Providers.MediaInfo FetchShortcutInfo(item); } - var prober = new FFProbeAudioInfo(_mediaSourceManager, _mediaEncoder, _itemRepo, _appPaths, _json, _libraryManager); + var prober = new FFProbeAudioInfo(_mediaSourceManager, _mediaEncoder, _itemRepo, _libraryManager); return prober.Probe(item, options, cancellationToken); } + // Run last public int Order => 100; } diff --git a/MediaBrowser.Providers/Music/Extensions.cs b/MediaBrowser.Providers/Music/Extensions.cs index b57d35256..dddfd02e4 100644 --- a/MediaBrowser.Providers/Music/Extensions.cs +++ b/MediaBrowser.Providers/Music/Extensions.cs @@ -6,7 +6,7 @@ using MediaBrowser.Model.Entities; namespace MediaBrowser.Providers.Music { - public static class Extensions + public static class AlbumInfoExtensions { public static string GetAlbumArtist(this AlbumInfo info) { @@ -18,7 +18,7 @@ namespace MediaBrowser.Providers.Music return id; } - return info.AlbumArtists.FirstOrDefault(); + return info.AlbumArtists.Count > 0 ? info.AlbumArtists[0] : default; } public static string GetReleaseGroupId(this AlbumInfo info) diff --git a/MediaBrowser.Providers/Plugins/MusicBrainz/AlbumProvider.cs b/MediaBrowser.Providers/Plugins/MusicBrainz/AlbumProvider.cs index 23acb7fd6..3550614dd 100644 --- a/MediaBrowser.Providers/Plugins/MusicBrainz/AlbumProvider.cs +++ b/MediaBrowser.Providers/Plugins/MusicBrainz/AlbumProvider.cs @@ -276,7 +276,7 @@ namespace MediaBrowser.Providers.Music private async Task<ReleaseResult> GetReleaseResult(string albumName, string artistId, CancellationToken cancellationToken) { - var url = string.Format("/ws/2/release/?query=\"{0}\" AND arid:{1}", + var url = string.Format(CultureInfo.InvariantCulture, "/ws/2/release/?query=\"{0}\" AND arid:{1}", WebUtility.UrlEncode(albumName), artistId); diff --git a/MediaBrowser.Providers/Plugins/MusicBrainz/ArtistProvider.cs b/MediaBrowser.Providers/Plugins/MusicBrainz/ArtistProvider.cs index b829ed378..781b71640 100644 --- a/MediaBrowser.Providers/Plugins/MusicBrainz/ArtistProvider.cs +++ b/MediaBrowser.Providers/Plugins/MusicBrainz/ArtistProvider.cs @@ -46,7 +46,7 @@ namespace MediaBrowser.Providers.Music // They seem to throw bad request failures on any term with a slash var nameToSearch = searchInfo.Name.Replace('/', ' '); - var url = string.Format("/ws/2/artist/?query=\"{0}\"&dismax=true", UrlEncode(nameToSearch)); + var url = string.Format(CultureInfo.InvariantCulture, "/ws/2/artist/?query=\"{0}\"&dismax=true", UrlEncode(nameToSearch)); using (var response = await MusicBrainzAlbumProvider.Current.GetMusicBrainzResponse(url, cancellationToken).ConfigureAwait(false)) await using (var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false)) @@ -62,7 +62,7 @@ namespace MediaBrowser.Providers.Music if (HasDiacritics(searchInfo.Name)) { // Try again using the search with accent characters url - url = string.Format("/ws/2/artist/?query=artistaccent:\"{0}\"", UrlEncode(nameToSearch)); + url = string.Format(CultureInfo.InvariantCulture, "/ws/2/artist/?query=artistaccent:\"{0}\"", UrlEncode(nameToSearch)); using var response = await MusicBrainzAlbumProvider.Current.GetMusicBrainzResponse(url, cancellationToken).ConfigureAwait(false); await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); diff --git a/MediaBrowser.Providers/Plugins/Omdb/OmdbImageProvider.cs b/MediaBrowser.Providers/Plugins/Omdb/OmdbImageProvider.cs index 41e664aac..c18725e0a 100644 --- a/MediaBrowser.Providers/Plugins/Omdb/OmdbImageProvider.cs +++ b/MediaBrowser.Providers/Plugins/Omdb/OmdbImageProvider.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Net.Http; +using System.Globalization; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Common; @@ -70,7 +71,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb list.Add(new RemoteImageInfo { ProviderName = Name, - Url = string.Format("https://img.omdbapi.com/?i={0}&apikey=2c9d9507", imdbId) + Url = string.Format(CultureInfo.InvariantCulture, "https://img.omdbapi.com/?i={0}&apikey=2c9d9507", imdbId) }); } } diff --git a/MediaBrowser.Providers/Plugins/Omdb/OmdbItemProvider.cs b/MediaBrowser.Providers/Plugins/Omdb/OmdbItemProvider.cs index d2823a08c..102ad82e1 100644 --- a/MediaBrowser.Providers/Plugins/Omdb/OmdbItemProvider.cs +++ b/MediaBrowser.Providers/Plugins/Omdb/OmdbItemProvider.cs @@ -127,7 +127,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb } } - var url = OmdbProvider.GetOmdbUrl(urlQuery, _appHost, cancellationToken); + var url = OmdbProvider.GetOmdbUrl(urlQuery); using var response = await OmdbProvider.GetOmdbResponse(_httpClientFactory.CreateClient(), url, cancellationToken).ConfigureAwait(false); await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); diff --git a/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs b/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs index 6ad5298de..c45149c3a 100644 --- a/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs +++ b/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs @@ -256,16 +256,16 @@ namespace MediaBrowser.Providers.Plugins.Omdb return false; } - public static string GetOmdbUrl(string query, IApplicationHost appHost, CancellationToken cancellationToken) + public static string GetOmdbUrl(string query) { - const string url = "https://www.omdbapi.com?apikey=2c9d9507"; + const string Url = "https://www.omdbapi.com?apikey=2c9d9507"; if (string.IsNullOrWhiteSpace(query)) { - return url; + return Url; } - return url + "&" + query; + return Url + "&" + query; } private async Task<string> EnsureItemInfo(string imdbId, CancellationToken cancellationToken) @@ -290,7 +290,11 @@ namespace MediaBrowser.Providers.Plugins.Omdb } } - var url = GetOmdbUrl(string.Format("i={0}&plot=short&tomatoes=true&r=json", imdbParam), _appHost, cancellationToken); + var url = GetOmdbUrl( + string.Format( + CultureInfo.InvariantCulture, + "i={0}&plot=short&tomatoes=true&r=json", + imdbParam)); using var response = await GetOmdbResponse(_httpClientFactory.CreateClient(), url, cancellationToken).ConfigureAwait(false); await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); @@ -323,7 +327,12 @@ namespace MediaBrowser.Providers.Plugins.Omdb } } - var url = GetOmdbUrl(string.Format("i={0}&season={1}&detail=full", imdbParam, seasonId), _appHost, cancellationToken); + var url = GetOmdbUrl( + string.Format( + CultureInfo.InvariantCulture, + "i={0}&season={1}&detail=full", + imdbParam, + seasonId)); using var response = await GetOmdbResponse(_httpClientFactory.CreateClient(), url, cancellationToken).ConfigureAwait(false); await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); @@ -348,7 +357,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb var dataPath = Path.Combine(_configurationManager.ApplicationPaths.CachePath, "omdb"); - var filename = string.Format("{0}.json", imdbId); + var filename = string.Format(CultureInfo.InvariantCulture, "{0}.json", imdbId); return Path.Combine(dataPath, filename); } @@ -362,7 +371,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb var dataPath = Path.Combine(_configurationManager.ApplicationPaths.CachePath, "omdb"); - var filename = string.Format("{0}_season_{1}.json", imdbId, seasonId); + var filename = string.Format(CultureInfo.InvariantCulture, "{0}_season_{1}.json", imdbId, seasonId); return Path.Combine(dataPath, filename); } diff --git a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbClientManager.cs b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbClientManager.cs index cd2f96f14..f22d484ab 100644 --- a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbClientManager.cs +++ b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbClientManager.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; @@ -19,7 +20,6 @@ namespace MediaBrowser.Providers.Plugins.TheTvdb { private const string DefaultLanguage = "en"; - private readonly SemaphoreSlim _cacheWriteLock = new SemaphoreSlim(1, 1); private readonly IMemoryCache _cache; private readonly TvDbClient _tvDbClient; private DateTime _tokenCreatedAt; @@ -176,7 +176,7 @@ namespace MediaBrowser.Providers.Plugins.TheTvdb string language, CancellationToken cancellationToken) { - searchInfo.SeriesProviderIds.TryGetValue(MetadataProvider.Tvdb.ToString(), + searchInfo.SeriesProviderIds.TryGetValue(nameof(MetadataProvider.Tvdb), out var seriesTvdbId); var episodeQuery = new EpisodeQuery(); @@ -203,10 +203,10 @@ namespace MediaBrowser.Providers.Plugins.TheTvdb else if (searchInfo.PremiereDate.HasValue) { // tvdb expects yyyy-mm-dd format - episodeQuery.FirstAired = searchInfo.PremiereDate.Value.ToString("yyyy-MM-dd"); + episodeQuery.FirstAired = searchInfo.PremiereDate.Value.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture); } - return GetEpisodeTvdbId(Convert.ToInt32(seriesTvdbId), episodeQuery, language, cancellationToken); + return GetEpisodeTvdbId(Convert.ToInt32(seriesTvdbId, CultureInfo.InvariantCulture), episodeQuery, language, cancellationToken); } public async Task<string> GetEpisodeTvdbId( @@ -218,7 +218,7 @@ namespace MediaBrowser.Providers.Plugins.TheTvdb var episodePage = await GetEpisodesPageAsync(Convert.ToInt32(seriesTvdbId), episodeQuery, language, cancellationToken) .ConfigureAwait(false); - return episodePage.Data.FirstOrDefault()?.Id.ToString(); + return episodePage.Data.FirstOrDefault()?.Id.ToString(CultureInfo.InvariantCulture); } public Task<TvDbResponse<EpisodeRecord[]>> GetEpisodesPageAsync( @@ -276,23 +276,10 @@ namespace MediaBrowser.Providers.Plugins.TheTvdb return cachedValue; } - await _cacheWriteLock.WaitAsync().ConfigureAwait(false); - try - { - if (_cache.TryGetValue(key, out cachedValue)) - { - return cachedValue; - } - - _tvDbClient.AcceptedLanguage = TvdbUtils.NormalizeLanguage(language) ?? DefaultLanguage; - var result = await resultFactory.Invoke().ConfigureAwait(false); - _cache.Set(key, result, TimeSpan.FromHours(1)); - return result; - } - finally - { - _cacheWriteLock.Release(); - } + _tvDbClient.AcceptedLanguage = TvdbUtils.NormalizeLanguage(language) ?? DefaultLanguage; + var result = await resultFactory.Invoke().ConfigureAwait(false); + _cache.Set(key, result, TimeSpan.FromHours(1)); + return result; } private static string GenerateKey(params object[] objects) diff --git a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbEpisodeImageProvider.cs b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbEpisodeImageProvider.cs index 4d38d38dc..4e7c0e5a6 100644 --- a/MediaBrowser.Providers/Plugins/TheTvdb/TvdbEpisodeImageProvider.cs +++ b/MediaBrowser.Providers/Plugins/TheTvdb/TvdbEpisodeImageProvider.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using System.Net.Http; +using System.Globalization; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Controller.Entities; @@ -76,7 +77,7 @@ namespace MediaBrowser.Providers.Plugins.TheTvdb var episodeResult = await _tvdbClientManager - .GetEpisodesAsync(Convert.ToInt32(episodeTvdbId), language, cancellationToken) + .GetEpisodesAsync(Convert.ToInt32(episodeTvdbId, CultureInfo.InvariantCulture), language, cancellationToken) .ConfigureAwait(false); var image = GetImageInfo(episodeResult.Data); @@ -103,8 +104,8 @@ namespace MediaBrowser.Providers.Plugins.TheTvdb return new RemoteImageInfo { - Width = Convert.ToInt32(episode.ThumbWidth), - Height = Convert.ToInt32(episode.ThumbHeight), + Width = Convert.ToInt32(episode.ThumbWidth, CultureInfo.InvariantCulture), + Height = Convert.ToInt32(episode.ThumbHeight, CultureInfo.InvariantCulture), ProviderName = Name, Url = TvdbUtils.BannerUrl + episode.Filename, Type = ImageType.Primary diff --git a/MediaBrowser.Providers/Plugins/Tmdb/BoxSets/TmdbBoxSetProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/BoxSets/TmdbBoxSetProvider.cs index 4f86a0293..4da2c042f 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/BoxSets/TmdbBoxSetProvider.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/BoxSets/TmdbBoxSetProvider.cs @@ -180,7 +180,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.BoxSets if (!string.IsNullOrEmpty(language)) { - url += string.Format("&language={0}", TmdbMovieProvider.NormalizeLanguage(language)); + url += string.Format(CultureInfo.InvariantCulture, "&language={0}", TmdbMovieProvider.NormalizeLanguage(language)); // Get images in english and with no language url += "&include_image_language=" + TmdbMovieProvider.GetImageLanguagesParam(language); @@ -250,7 +250,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.BoxSets { var path = GetDataPath(appPaths, tmdbId); - var filename = string.Format("all-{0}.json", preferredLanguage ?? string.Empty); + var filename = string.Format(CultureInfo.InvariantCulture, "all-{0}.json", preferredLanguage ?? string.Empty); return Path.Combine(path, filename); } diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Movies/GenericTmdbMovieInfo.cs b/MediaBrowser.Providers/Plugins/Tmdb/Movies/GenericTmdbMovieInfo.cs index 27ca3759e..01a887eed 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/Movies/GenericTmdbMovieInfo.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/Movies/GenericTmdbMovieInfo.cs @@ -300,7 +300,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Movies { movie.RemoteTrailers = movieData.Trailers.Youtube.Select(i => new MediaUrl { - Url = string.Format("https://www.youtube.com/watch?v={0}", i.Source), + Url = string.Format(CultureInfo.InvariantCulture, "https://www.youtube.com/watch?v={0}", i.Source), Name = i.Name }).ToArray(); diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbSearch.cs b/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbSearch.cs index 48f2a68a6..b7c4a5643 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbSearch.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbSearch.cs @@ -37,7 +37,8 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Movies ).* # Match rest of string", RegexOptions.Compiled | RegexOptions.IgnorePatternWhitespace | RegexOptions.IgnoreCase); - private const string _searchURL = TmdbUtils.BaseTmdbApiUrl + @"3/search/{3}?api_key={1}&query={0}&language={2}"; + private const string SearchUrl = TmdbUtils.BaseTmdbApiUrl + @"3/search/{3}?api_key={1}&query={0}&language={2}"; + private const string SearchUrlWithYear = TmdbUtils.BaseTmdbApiUrl + @"3/search/{3}?api_key={1}&query={0}&language={2}&first_air_date_year={4}"; private readonly ILogger _logger; private readonly IJsonSerializer _json; @@ -124,7 +125,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Movies name2 = name2.Trim(); // Search again if the new name is different - if (!string.Equals(name2, name) && !string.IsNullOrWhiteSpace(name2)) + if (!string.Equals(name2, name, StringComparison.Ordinal) && !string.IsNullOrWhiteSpace(name2)) { _logger.LogInformation("TmdbSearch: Finding id for item: {0} ({1})", name2, year); results = await GetSearchResults(name2, searchType, year, language, tmdbImageUrl, cancellationToken).ConfigureAwait(false); @@ -164,10 +165,30 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Movies { if (string.IsNullOrWhiteSpace(name)) { - throw new ArgumentException("name"); + throw new ArgumentException("String can't be null or empty.", nameof(name)); } - var url3 = string.Format(_searchURL, WebUtility.UrlEncode(name), TmdbUtils.ApiKey, language, type); + string url3; + if (year != null && string.Equals(type, "movie", StringComparison.OrdinalIgnoreCase)) + { + url3 = string.Format( + CultureInfo.InvariantCulture, + SearchUrl, + WebUtility.UrlEncode(name), + TmdbUtils.ApiKey, + language, + type) + "&primary_release_year=" + year; + } + else + { + url3 = string.Format( + CultureInfo.InvariantCulture, + SearchUrl, + WebUtility.UrlEncode(name), + TmdbUtils.ApiKey, + language, + type); + } var requestMessage = new HttpRequestMessage(HttpMethod.Get, url3); foreach (var header in TmdbUtils.AcceptHeaders) @@ -207,10 +228,31 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Movies { if (string.IsNullOrWhiteSpace(name)) { - throw new ArgumentException("name"); + throw new ArgumentException("String can't be null or empty.", nameof(name)); } - var url3 = string.Format(_searchURL, WebUtility.UrlEncode(name), TmdbUtils.ApiKey, language, "tv"); + string url3; + if (year == null) + { + url3 = string.Format( + CultureInfo.InvariantCulture, + SearchUrl, + WebUtility.UrlEncode(name), + TmdbUtils.ApiKey, + language, + "tv"); + } + else + { + url3 = string.Format( + CultureInfo.InvariantCulture, + SearchUrlWithYear, + WebUtility.UrlEncode(name), + TmdbUtils.ApiKey, + language, + "tv", + year); + } var requestMessage = new HttpRequestMessage(HttpMethod.Get, url3); foreach (var header in TmdbUtils.AcceptHeaders) diff --git a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeProvider.cs index b4aef4542..90e3cea93 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeProvider.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeProvider.cs @@ -131,7 +131,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV { if (video.Site.Equals("youtube", System.StringComparison.OrdinalIgnoreCase)) { - var videoUrl = string.Format("http://www.youtube.com/watch?v={0}", video.Key); + var videoUrl = string.Format(CultureInfo.InvariantCulture, "http://www.youtube.com/watch?v={0}", video.Key); item.AddTrailerUrl(videoUrl); } } diff --git a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeProviderBase.cs b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeProviderBase.cs index 154664321..5705885b4 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeProviderBase.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeProviderBase.cs @@ -92,7 +92,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV var path = TmdbSeriesProvider.GetSeriesDataPath(_configurationManager.ApplicationPaths, tmdbId); - var filename = string.Format("season-{0}-episode-{1}-{2}.json", + var filename = string.Format(CultureInfo.InvariantCulture, "season-{0}-episode-{1}-{2}.json", seasonNumber.ToString(CultureInfo.InvariantCulture), episodeNumber.ToString(CultureInfo.InvariantCulture), preferredLanguage); @@ -116,7 +116,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV if (!string.IsNullOrEmpty(language)) { - url += string.Format("&language={0}", language); + url += string.Format(CultureInfo.InvariantCulture, "&language={0}", language); } var includeImageLanguageParam = TmdbMovieProvider.GetImageLanguagesParam(language); diff --git a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeasonProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeasonProvider.cs index 2b9077f55..e59504cc6 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeasonProvider.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeasonProvider.cs @@ -180,7 +180,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV var path = TmdbSeriesProvider.GetSeriesDataPath(_configurationManager.ApplicationPaths, tmdbId); - var filename = string.Format("season-{0}-{1}.json", + var filename = string.Format(CultureInfo.InvariantCulture, "season-{0}-{1}.json", seasonNumber.ToString(CultureInfo.InvariantCulture), preferredLanguage); @@ -203,7 +203,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV if (!string.IsNullOrEmpty(language)) { - url += string.Format("&language={0}", TmdbMovieProvider.NormalizeLanguage(language)); + url += string.Format(CultureInfo.InvariantCulture, "&language={0}", TmdbMovieProvider.NormalizeLanguage(language)); } var includeImageLanguageParam = TmdbMovieProvider.GetImageLanguagesParam(language); diff --git a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesProvider.cs index ac577b125..0eded3233 100644 --- a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesProvider.cs +++ b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesProvider.cs @@ -496,7 +496,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV var path = GetSeriesDataPath(_configurationManager.ApplicationPaths, tmdbId); - var filename = string.Format("series-{0}.json", preferredLanguage ?? string.Empty); + var filename = string.Format(CultureInfo.InvariantCulture, "series-{0}.json", preferredLanguage ?? string.Empty); return Path.Combine(path, filename); } diff --git a/MediaBrowser.Providers/Studios/StudiosImageProvider.cs b/MediaBrowser.Providers/Studios/StudiosImageProvider.cs index dad155c81..321153c6b 100644 --- a/MediaBrowser.Providers/Studios/StudiosImageProvider.cs +++ b/MediaBrowser.Providers/Studios/StudiosImageProvider.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.IO; using System.Linq; using System.Net.Http; @@ -100,7 +101,7 @@ namespace MediaBrowser.Providers.Studios private string GetUrl(string image, string filename) { - return string.Format("https://raw.github.com/MediaBrowser/MediaBrowser.Resources/master/images/imagesbyname/studios/{0}/{1}.jpg", image, filename); + return string.Format(CultureInfo.InvariantCulture, "https://raw.github.com/MediaBrowser/MediaBrowser.Resources/master/images/imagesbyname/studios/{0}/{1}.jpg", image, filename); } private Task<string> EnsureThumbsList(string file, CancellationToken cancellationToken) -- cgit v1.2.3 From 68edccd9f4e9137b13ad4006c19bb6582341aec6 Mon Sep 17 00:00:00 2001 From: Bond_009 <bond.009@outlook.com> Date: Wed, 19 Aug 2020 18:02:34 +0200 Subject: More warn --- .../LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs | 3 ++- MediaBrowser.Controller/Entities/IHasSpecialFeatures.cs | 5 ++++- MediaBrowser.Controller/Entities/Movies/Movie.cs | 15 ++++++++++----- MediaBrowser.Controller/Entities/UserViewBuilder.cs | 14 ++++++-------- 4 files changed, 22 insertions(+), 15 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs index 04b208fdd..2b5f69d41 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs @@ -37,6 +37,8 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun private readonly INetworkManager _networkManager; private readonly IStreamHelper _streamHelper; + private readonly Dictionary<string, DiscoverResponse> _modelCache = new Dictionary<string, DiscoverResponse>(); + public HdHomerunHost( IServerConfigurationManager config, ILogger<HdHomerunHost> logger, @@ -114,7 +116,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun }).Cast<ChannelInfo>().ToList(); } - private readonly Dictionary<string, DiscoverResponse> _modelCache = new Dictionary<string, DiscoverResponse>(); private async Task<DiscoverResponse> GetModelInfo(TunerHostInfo info, bool throwAllExceptions, CancellationToken cancellationToken) { var cacheKey = info.Id; diff --git a/MediaBrowser.Controller/Entities/IHasSpecialFeatures.cs b/MediaBrowser.Controller/Entities/IHasSpecialFeatures.cs index 688439e6c..6a350212b 100644 --- a/MediaBrowser.Controller/Entities/IHasSpecialFeatures.cs +++ b/MediaBrowser.Controller/Entities/IHasSpecialFeatures.cs @@ -1,4 +1,7 @@ +#pragma warning disable CS1591 + using System; +using System.Collections.Generic; namespace MediaBrowser.Controller.Entities { @@ -8,6 +11,6 @@ namespace MediaBrowser.Controller.Entities /// Gets or sets the special feature ids. /// </summary> /// <value>The special feature ids.</value> - Guid[] SpecialFeatureIds { get; set; } + IReadOnlyList<Guid> SpecialFeatureIds { get; set; } } } diff --git a/MediaBrowser.Controller/Entities/Movies/Movie.cs b/MediaBrowser.Controller/Entities/Movies/Movie.cs index 5ae396e68..8b67aaccc 100644 --- a/MediaBrowser.Controller/Entities/Movies/Movie.cs +++ b/MediaBrowser.Controller/Entities/Movies/Movie.cs @@ -1,3 +1,4 @@ +#pragma warning disable CS1591 using System; using System.Collections.Generic; @@ -19,8 +20,6 @@ namespace MediaBrowser.Controller.Entities.Movies /// </summary> public class Movie : Video, IHasSpecialFeatures, IHasTrailers, IHasLookupInfo<MovieInfo>, ISupportsBoxSetGrouping { - public Guid[] SpecialFeatureIds { get; set; } - public Movie() { SpecialFeatureIds = Array.Empty<Guid>(); @@ -29,6 +28,9 @@ namespace MediaBrowser.Controller.Entities.Movies RemoteTrailerIds = Array.Empty<Guid>(); } + /// <inheritdoc /> + public IReadOnlyList<Guid> SpecialFeatureIds { get; set; } + /// <inheritdoc /> public IReadOnlyList<Guid> LocalTrailerIds { get; set; } @@ -48,6 +50,9 @@ namespace MediaBrowser.Controller.Entities.Movies set => TmdbCollectionName = value; } + [JsonIgnore] + public override bool StopRefreshIfLocalMetadataFound => false; + public override double GetDefaultPrimaryImageAspectRatio() { // hack for tv plugins @@ -107,6 +112,7 @@ namespace MediaBrowser.Controller.Entities.Movies return itemsChanged; } + /// <inheritdoc /> public override UnratedItem GetBlockUnratedType() { return UnratedItem.Movie; @@ -135,6 +141,7 @@ namespace MediaBrowser.Controller.Entities.Movies return info; } + /// <inheritdoc /> public override bool BeforeMetadataRefresh(bool replaceAllMetdata) { var hasChanges = base.BeforeMetadataRefresh(replaceAllMetdata); @@ -171,6 +178,7 @@ namespace MediaBrowser.Controller.Entities.Movies return hasChanges; } + /// <inheritdoc /> public override List<ExternalUrl> GetRelatedUrls() { var list = base.GetRelatedUrls(); @@ -187,8 +195,5 @@ namespace MediaBrowser.Controller.Entities.Movies return list; } - - [JsonIgnore] - public override bool StopRefreshIfLocalMetadataFound => false; } } diff --git a/MediaBrowser.Controller/Entities/UserViewBuilder.cs b/MediaBrowser.Controller/Entities/UserViewBuilder.cs index 22bb7fd55..e3f4025bb 100644 --- a/MediaBrowser.Controller/Entities/UserViewBuilder.cs +++ b/MediaBrowser.Controller/Entities/UserViewBuilder.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using System.Globalization; @@ -672,9 +674,7 @@ namespace MediaBrowser.Controller.Entities var isPlaceHolder = false; - var hasPlaceHolder = item as ISupportsPlaceHolders; - - if (hasPlaceHolder != null) + if (item is ISupportsPlaceHolders hasPlaceHolder) { isPlaceHolder = hasPlaceHolder.IsPlaceHolder; } @@ -689,13 +689,11 @@ namespace MediaBrowser.Controller.Entities { var filterValue = query.HasSpecialFeature.Value; - var movie = item as IHasSpecialFeatures; - - if (movie != null) + if (item is IHasSpecialFeatures movie) { var ok = filterValue - ? movie.SpecialFeatureIds.Length > 0 - : movie.SpecialFeatureIds.Length == 0; + ? movie.SpecialFeatureIds.Count > 0 + : movie.SpecialFeatureIds.Count == 0; if (!ok) { -- cgit v1.2.3 From ab2147751f9079bc104da068909a485fc9402a64 Mon Sep 17 00:00:00 2001 From: Bond_009 <bond.009@outlook.com> Date: Thu, 20 Aug 2020 12:16:24 +0200 Subject: Make MediaBrowser.MediaEncoding warnings free --- Emby.Dlna/Main/DlnaEntryPoint.cs | 4 +- Emby.Dlna/PlayTo/uBaseObject.cs | 2 +- Emby.Dlna/PlayTo/uPnpNamespaces.cs | 2 +- .../Data/SqliteItemRepository.cs | 7 +- Emby.Server.Implementations/IO/LibraryMonitor.cs | 27 +--- .../IO/LibraryMonitorStartup.cs | 35 +++++ .../Library/LibraryManager.cs | 2 +- .../LiveTv/EmbyTV/EntryPoint.cs | 2 +- .../LiveTv/Listings/SchedulesDirect.cs | 2 +- .../ScheduledTasks/ScheduledTaskWorker.cs | 148 +++++++++++---------- .../ScheduledTasks/TaskManager.cs | 1 + .../ScheduledTasks/Tasks/DeleteLogFileTask.cs | 64 ++++----- .../Services/ServicePath.cs | 8 +- .../Entities/UserViewBuilder.cs | 1 - .../Attachments/AttachmentExtractor.cs | 4 +- .../Encoder/EncodingUtils.cs | 5 +- MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 4 +- .../MediaBrowser.MediaEncoding.csproj | 2 +- .../Probing/ProbeResultNormalizer.cs | 9 +- MediaBrowser.MediaEncoding/Subtitles/AssParser.cs | 8 +- MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs | 95 ++++++------- .../Subtitles/SubtitleEncoder.cs | 17 +-- 22 files changed, 236 insertions(+), 213 deletions(-) create mode 100644 Emby.Server.Implementations/IO/LibraryMonitorStartup.cs (limited to 'MediaBrowser.Controller') diff --git a/Emby.Dlna/Main/DlnaEntryPoint.cs b/Emby.Dlna/Main/DlnaEntryPoint.cs index a21d4cc11..191763de4 100644 --- a/Emby.Dlna/Main/DlnaEntryPoint.cs +++ b/Emby.Dlna/Main/DlnaEntryPoint.cs @@ -30,7 +30,7 @@ using OperatingSystem = MediaBrowser.Common.System.OperatingSystem; namespace Emby.Dlna.Main { - public class DlnaEntryPoint : IServerEntryPoint, IRunBeforeStartup + public sealed class DlnaEntryPoint : IServerEntryPoint, IRunBeforeStartup { private readonly IServerConfigurationManager _config; private readonly ILogger<DlnaEntryPoint> _logger; @@ -60,7 +60,7 @@ namespace Emby.Dlna.Main public IMediaReceiverRegistrar MediaReceiverRegistrar { get; private set; } - public static DlnaEntryPoint Current; + public static DlnaEntryPoint Current { get; private set; }; public DlnaEntryPoint( IServerConfigurationManager config, diff --git a/Emby.Dlna/PlayTo/uBaseObject.cs b/Emby.Dlna/PlayTo/uBaseObject.cs index 05c19299f..f2dc31f6d 100644 --- a/Emby.Dlna/PlayTo/uBaseObject.cs +++ b/Emby.Dlna/PlayTo/uBaseObject.cs @@ -31,7 +31,7 @@ namespace Emby.Dlna.PlayTo throw new ArgumentNullException(nameof(obj)); } - return string.Equals(Id, obj.Id); + return string.Equals(Id, obj.Id, StringComparison.Ordinal); } public string MediaType diff --git a/Emby.Dlna/PlayTo/uPnpNamespaces.cs b/Emby.Dlna/PlayTo/uPnpNamespaces.cs index dc65cdf43..6ea7dc9cf 100644 --- a/Emby.Dlna/PlayTo/uPnpNamespaces.cs +++ b/Emby.Dlna/PlayTo/uPnpNamespaces.cs @@ -4,7 +4,7 @@ using System.Xml.Linq; namespace Emby.Dlna.PlayTo { - public class uPnpNamespaces + public static class uPnpNamespaces { public static XNamespace dc = "http://purl.org/dc/elements/1.1/"; public static XNamespace ns = "urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/"; diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index 331ffc134..5bf740cfc 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -4308,7 +4308,7 @@ namespace Emby.Server.Implementations.Data whereClauses.Add("ProductionYear=@Years"); if (statement != null) { - statement.TryBind("@Years", query.Years[0].ToString()); + statement.TryBind("@Years", query.Years[0].ToString(CultureInfo.InvariantCulture)); } } else if (query.Years.Length > 1) @@ -5170,7 +5170,10 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type insertText.Append(','); } - insertText.AppendFormat("(@ItemId, @AncestorId{0}, @AncestorIdText{0})", i.ToString(CultureInfo.InvariantCulture)); + insertText.AppendFormat( + CultureInfo.InvariantCulture, + "(@ItemId, @AncestorId{0}, @AncestorIdText{0})", + i.ToString(CultureInfo.InvariantCulture)); } using (var statement = PrepareStatement(db, insertText.ToString())) diff --git a/Emby.Server.Implementations/IO/LibraryMonitor.cs b/Emby.Server.Implementations/IO/LibraryMonitor.cs index a32b03aaa..9290dfcd0 100644 --- a/Emby.Server.Implementations/IO/LibraryMonitor.cs +++ b/Emby.Server.Implementations/IO/LibraryMonitor.cs @@ -6,12 +6,11 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; +using Emby.Server.Implementations.Library; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; -using MediaBrowser.Controller.Plugins; using MediaBrowser.Model.IO; -using Emby.Server.Implementations.Library; using Microsoft.Extensions.Logging; namespace Emby.Server.Implementations.IO @@ -38,6 +37,8 @@ namespace Emby.Server.Implementations.IO /// </summary> private readonly ConcurrentDictionary<string, string> _tempIgnoredPaths = new ConcurrentDictionary<string, string>(StringComparer.OrdinalIgnoreCase); + private bool _disposed = false; + /// <summary> /// Add the path to our temporary ignore list. Use when writing to a path within our listening scope. /// </summary> @@ -492,8 +493,6 @@ namespace Emby.Server.Implementations.IO } } - private bool _disposed = false; - /// <summary> /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// </summary> @@ -522,24 +521,4 @@ namespace Emby.Server.Implementations.IO _disposed = true; } } - - public class LibraryMonitorStartup : IServerEntryPoint - { - private readonly ILibraryMonitor _monitor; - - public LibraryMonitorStartup(ILibraryMonitor monitor) - { - _monitor = monitor; - } - - public Task RunAsync() - { - _monitor.Start(); - return Task.CompletedTask; - } - - public void Dispose() - { - } - } } diff --git a/Emby.Server.Implementations/IO/LibraryMonitorStartup.cs b/Emby.Server.Implementations/IO/LibraryMonitorStartup.cs new file mode 100644 index 000000000..c51cf0545 --- /dev/null +++ b/Emby.Server.Implementations/IO/LibraryMonitorStartup.cs @@ -0,0 +1,35 @@ +using System.Threading.Tasks; +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Plugins; + +namespace Emby.Server.Implementations.IO +{ + /// <summary> + /// <see cref="IServerEntryPoint" /> which is responsible for starting the library monitor. + /// </summary> + public sealed class LibraryMonitorStartup : IServerEntryPoint + { + private readonly ILibraryMonitor _monitor; + + /// <summary> + /// Initializes a new instance of the <see cref="LibraryMonitorStartup"/> class. + /// </summary> + /// <param name="monitor">The library monitor.</param> + public LibraryMonitorStartup(ILibraryMonitor monitor) + { + _monitor = monitor; + } + + /// <inheritdoc /> + public Task RunAsync() + { + _monitor.Start(); + return Task.CompletedTask; + } + + /// <inheritdoc /> + public void Dispose() + { + } + } +} diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index 7b770d940..7ed8f0bbf 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -729,7 +729,7 @@ namespace Emby.Server.Implementations.Library Directory.CreateDirectory(rootFolderPath); var rootFolder = GetItemById(GetNewItemId(rootFolderPath, typeof(AggregateFolder))) as AggregateFolder ?? - ((Folder) ResolvePath(_fileSystem.GetDirectoryInfo(rootFolderPath))) + ((Folder)ResolvePath(_fileSystem.GetDirectoryInfo(rootFolderPath))) .DeepCopy<Folder, AggregateFolder>(); // In case program data folder was moved diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EntryPoint.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EntryPoint.cs index 69a9cb78a..a2ec2df37 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/EntryPoint.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EntryPoint.cs @@ -5,7 +5,7 @@ using MediaBrowser.Controller.Plugins; namespace Emby.Server.Implementations.LiveTv.EmbyTV { - public class EntryPoint : IServerEntryPoint + public sealed class EntryPoint : IServerEntryPoint { /// <inheritdoc /> public Task RunAsync() diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs index 77a7069eb..c4d5cc58a 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs @@ -929,7 +929,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings private static string NormalizeName(string value) { - return value.Replace(" ", string.Empty).Replace("-", string.Empty); + return value.Replace(" ", string.Empty, StringComparison.Ordinal).Replace("-", string.Empty, StringComparison.Ordinal); } public class ScheduleDirect diff --git a/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs b/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs index 8a900f42c..1ef083d04 100644 --- a/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs +++ b/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs @@ -10,7 +10,6 @@ using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Progress; using MediaBrowser.Model.Events; -using MediaBrowser.Model.IO; using MediaBrowser.Model.Serialization; using MediaBrowser.Model.Tasks; using Microsoft.Extensions.Logging; @@ -22,37 +21,53 @@ namespace Emby.Server.Implementations.ScheduledTasks /// </summary> public class ScheduledTaskWorker : IScheduledTaskWorker { - public event EventHandler<GenericEventArgs<double>> TaskProgress; - - /// <summary> - /// Gets the scheduled task. - /// </summary> - /// <value>The scheduled task.</value> - public IScheduledTask ScheduledTask { get; private set; } - /// <summary> /// Gets or sets the json serializer. /// </summary> /// <value>The json serializer.</value> - private IJsonSerializer JsonSerializer { get; set; } + private readonly IJsonSerializer _jsonSerializer; /// <summary> /// Gets or sets the application paths. /// </summary> /// <value>The application paths.</value> - private IApplicationPaths ApplicationPaths { get; set; } + private readonly IApplicationPaths _applicationPaths; /// <summary> - /// Gets the logger. + /// Gets or sets the logger. /// </summary> /// <value>The logger.</value> - private ILogger Logger { get; set; } + private readonly ILogger _logger; /// <summary> - /// Gets the task manager. + /// Gets or sets the task manager. /// </summary> /// <value>The task manager.</value> - private ITaskManager TaskManager { get; set; } + private readonly ITaskManager _taskManager; + + /// <summary> + /// The _last execution result sync lock. + /// </summary> + private readonly object _lastExecutionResultSyncLock = new object(); + + private bool _readFromFile = false; + + /// <summary> + /// The _last execution result. + /// </summary> + private TaskResult _lastExecutionResult; + + private Task _currentTask; + + /// <summary> + /// The _triggers. + /// </summary> + private Tuple<TaskTriggerInfo, ITaskTrigger>[] _triggers; + + /// <summary> + /// The _id. + /// </summary> + private string _id; /// <summary> /// Initializes a new instance of the <see cref="ScheduledTaskWorker" /> class. @@ -71,7 +86,7 @@ namespace Emby.Server.Implementations.ScheduledTasks /// or /// jsonSerializer /// or - /// logger + /// logger. /// </exception> public ScheduledTaskWorker(IScheduledTask scheduledTask, IApplicationPaths applicationPaths, ITaskManager taskManager, IJsonSerializer jsonSerializer, ILogger logger) { @@ -101,23 +116,22 @@ namespace Emby.Server.Implementations.ScheduledTasks } ScheduledTask = scheduledTask; - ApplicationPaths = applicationPaths; - TaskManager = taskManager; - JsonSerializer = jsonSerializer; - Logger = logger; + _applicationPaths = applicationPaths; + _taskManager = taskManager; + _jsonSerializer = jsonSerializer; + _logger = logger; InitTriggerEvents(); } - private bool _readFromFile = false; - /// <summary> - /// The _last execution result. - /// </summary> - private TaskResult _lastExecutionResult; + public event EventHandler<GenericEventArgs<double>> TaskProgress; + /// <summary> - /// The _last execution result sync lock. + /// Gets the scheduled task. /// </summary> - private readonly object _lastExecutionResultSyncLock = new object(); + /// <value>The scheduled task.</value> + public IScheduledTask ScheduledTask { get; private set; } + /// <summary> /// Gets the last execution result. /// </summary> @@ -136,11 +150,11 @@ namespace Emby.Server.Implementations.ScheduledTasks { try { - _lastExecutionResult = JsonSerializer.DeserializeFromFile<TaskResult>(path); + _lastExecutionResult = _jsonSerializer.DeserializeFromFile<TaskResult>(path); } catch (Exception ex) { - Logger.LogError(ex, "Error deserializing {File}", path); + _logger.LogError(ex, "Error deserializing {File}", path); } } @@ -160,7 +174,7 @@ namespace Emby.Server.Implementations.ScheduledTasks lock (_lastExecutionResultSyncLock) { - JsonSerializer.SerializeToFile(value, path); + _jsonSerializer.SerializeToFile(value, path); } } } @@ -184,7 +198,7 @@ namespace Emby.Server.Implementations.ScheduledTasks public string Category => ScheduledTask.Category; /// <summary> - /// Gets the current cancellation token. + /// Gets or sets the current cancellation token. /// </summary> /// <value>The current cancellation token source.</value> private CancellationTokenSource CurrentCancellationTokenSource { get; set; } @@ -221,12 +235,7 @@ namespace Emby.Server.Implementations.ScheduledTasks public double? CurrentProgress { get; private set; } /// <summary> - /// The _triggers. - /// </summary> - private Tuple<TaskTriggerInfo, ITaskTrigger>[] _triggers; - - /// <summary> - /// Gets the triggers that define when the task will run. + /// Gets or sets the triggers that define when the task will run. /// </summary> /// <value>The triggers.</value> private Tuple<TaskTriggerInfo, ITaskTrigger>[] InternalTriggers @@ -255,7 +264,7 @@ namespace Emby.Server.Implementations.ScheduledTasks /// Gets the triggers that define when the task will run. /// </summary> /// <value>The triggers.</value> - /// <exception cref="ArgumentNullException">value</exception> + /// <exception cref="ArgumentNullException"><c>value</c> is <c>null</c>.</exception> public TaskTriggerInfo[] Triggers { get @@ -280,11 +289,6 @@ namespace Emby.Server.Implementations.ScheduledTasks } } - /// <summary> - /// The _id. - /// </summary> - private string _id; - /// <summary> /// Gets the unique id. /// </summary> @@ -325,9 +329,9 @@ namespace Emby.Server.Implementations.ScheduledTasks trigger.Stop(); - trigger.Triggered -= trigger_Triggered; - trigger.Triggered += trigger_Triggered; - trigger.Start(LastExecutionResult, Logger, Name, isApplicationStartup); + trigger.Triggered -= OnTriggerTriggered; + trigger.Triggered += OnTriggerTriggered; + trigger.Start(LastExecutionResult, _logger, Name, isApplicationStartup); } } @@ -336,7 +340,7 @@ namespace Emby.Server.Implementations.ScheduledTasks /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param> - async void trigger_Triggered(object sender, EventArgs e) + private async void OnTriggerTriggered(object sender, EventArgs e) { var trigger = (ITaskTrigger)sender; @@ -347,19 +351,17 @@ namespace Emby.Server.Implementations.ScheduledTasks return; } - Logger.LogInformation("{0} fired for task: {1}", trigger.GetType().Name, Name); + _logger.LogInformation("{0} fired for task: {1}", trigger.GetType().Name, Name); trigger.Stop(); - TaskManager.QueueScheduledTask(ScheduledTask, trigger.TaskOptions); + _taskManager.QueueScheduledTask(ScheduledTask, trigger.TaskOptions); await Task.Delay(1000).ConfigureAwait(false); - trigger.Start(LastExecutionResult, Logger, Name, false); + trigger.Start(LastExecutionResult, _logger, Name, false); } - private Task _currentTask; - /// <summary> /// Executes the task. /// </summary> @@ -395,9 +397,9 @@ namespace Emby.Server.Implementations.ScheduledTasks CurrentCancellationTokenSource = new CancellationTokenSource(); - Logger.LogInformation("Executing {0}", Name); + _logger.LogInformation("Executing {0}", Name); - ((TaskManager)TaskManager).OnTaskExecuting(this); + ((TaskManager)_taskManager).OnTaskExecuting(this); progress.ProgressChanged += OnProgressChanged; @@ -423,7 +425,7 @@ namespace Emby.Server.Implementations.ScheduledTasks } catch (Exception ex) { - Logger.LogError(ex, "Error"); + _logger.LogError(ex, "Error"); failureException = ex; @@ -476,7 +478,7 @@ namespace Emby.Server.Implementations.ScheduledTasks { if (State == TaskState.Running) { - Logger.LogInformation("Attempting to cancel Scheduled Task {0}", Name); + _logger.LogInformation("Attempting to cancel Scheduled Task {0}", Name); CurrentCancellationTokenSource.Cancel(); } } @@ -487,7 +489,7 @@ namespace Emby.Server.Implementations.ScheduledTasks /// <returns>System.String.</returns> private string GetScheduledTasksConfigurationDirectory() { - return Path.Combine(ApplicationPaths.ConfigurationDirectoryPath, "ScheduledTasks"); + return Path.Combine(_applicationPaths.ConfigurationDirectoryPath, "ScheduledTasks"); } /// <summary> @@ -496,7 +498,7 @@ namespace Emby.Server.Implementations.ScheduledTasks /// <returns>System.String.</returns> private string GetScheduledTasksDataDirectory() { - return Path.Combine(ApplicationPaths.DataPath, "ScheduledTasks"); + return Path.Combine(_applicationPaths.DataPath, "ScheduledTasks"); } /// <summary> @@ -535,7 +537,7 @@ namespace Emby.Server.Implementations.ScheduledTasks TaskTriggerInfo[] list = null; if (File.Exists(path)) { - list = JsonSerializer.DeserializeFromFile<TaskTriggerInfo[]>(path); + list = _jsonSerializer.DeserializeFromFile<TaskTriggerInfo[]>(path); } // Return defaults if file doesn't exist. @@ -571,7 +573,7 @@ namespace Emby.Server.Implementations.ScheduledTasks Directory.CreateDirectory(Path.GetDirectoryName(path)); - JsonSerializer.SerializeToFile(triggers, path); + _jsonSerializer.SerializeToFile(triggers, path); } /// <summary> @@ -585,7 +587,7 @@ namespace Emby.Server.Implementations.ScheduledTasks { var elapsedTime = endTime - startTime; - Logger.LogInformation("{0} {1} after {2} minute(s) and {3} seconds", Name, status, Math.Truncate(elapsedTime.TotalMinutes), elapsedTime.Seconds); + _logger.LogInformation("{0} {1} after {2} minute(s) and {3} seconds", Name, status, Math.Truncate(elapsedTime.TotalMinutes), elapsedTime.Seconds); var result = new TaskResult { @@ -606,7 +608,7 @@ namespace Emby.Server.Implementations.ScheduledTasks LastExecutionResult = result; - ((TaskManager)TaskManager).OnTaskCompleted(this, result); + ((TaskManager)_taskManager).OnTaskCompleted(this, result); } /// <summary> @@ -615,6 +617,7 @@ namespace Emby.Server.Implementations.ScheduledTasks public void Dispose() { Dispose(true); + GC.SuppressFinalize(this); } /// <summary> @@ -635,12 +638,12 @@ namespace Emby.Server.Implementations.ScheduledTasks { try { - Logger.LogInformation(Name + ": Cancelling"); + _logger.LogInformation(Name + ": Cancelling"); token.Cancel(); } catch (Exception ex) { - Logger.LogError(ex, "Error calling CancellationToken.Cancel();"); + _logger.LogError(ex, "Error calling CancellationToken.Cancel();"); } } @@ -649,21 +652,21 @@ namespace Emby.Server.Implementations.ScheduledTasks { try { - Logger.LogInformation(Name + ": Waiting on Task"); + _logger.LogInformation(Name + ": Waiting on Task"); var exited = Task.WaitAll(new[] { task }, 2000); if (exited) { - Logger.LogInformation(Name + ": Task exited"); + _logger.LogInformation(Name + ": Task exited"); } else { - Logger.LogInformation(Name + ": Timed out waiting for task to stop"); + _logger.LogInformation(Name + ": Timed out waiting for task to stop"); } } catch (Exception ex) { - Logger.LogError(ex, "Error calling Task.WaitAll();"); + _logger.LogError(ex, "Error calling Task.WaitAll();"); } } @@ -671,12 +674,12 @@ namespace Emby.Server.Implementations.ScheduledTasks { try { - Logger.LogDebug(Name + ": Disposing CancellationToken"); + _logger.LogDebug(Name + ": Disposing CancellationToken"); token.Dispose(); } catch (Exception ex) { - Logger.LogError(ex, "Error calling CancellationToken.Dispose();"); + _logger.LogError(ex, "Error calling CancellationToken.Dispose();"); } } @@ -692,8 +695,7 @@ namespace Emby.Server.Implementations.ScheduledTasks /// </summary> /// <param name="info">The info.</param> /// <returns>BaseTaskTrigger.</returns> - /// <exception cref="ArgumentNullException"></exception> - /// <exception cref="ArgumentException">Invalid trigger type: + info.Type</exception> + /// <exception cref="ArgumentException">Invalid trigger type: + info.Type.</exception> private ITaskTrigger GetTrigger(TaskTriggerInfo info) { var options = new TaskOptions @@ -765,7 +767,7 @@ namespace Emby.Server.Implementations.ScheduledTasks foreach (var triggerInfo in InternalTriggers) { var trigger = triggerInfo.Item2; - trigger.Triggered -= trigger_Triggered; + trigger.Triggered -= OnTriggerTriggered; trigger.Stop(); } } diff --git a/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs b/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs index 81096026b..6d2b4ffc8 100644 --- a/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs +++ b/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs @@ -207,6 +207,7 @@ namespace Emby.Server.Implementations.ScheduledTasks public void Dispose() { Dispose(true); + GC.SuppressFinalize(this); } /// <summary> diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs index 402b39a26..54e18eaea 100644 --- a/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs +++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs @@ -1,12 +1,13 @@ using System; using System.Collections.Generic; +using System.Globalization; 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 MediaBrowser.Model.Globalization; namespace Emby.Server.Implementations.ScheduledTasks.Tasks { @@ -15,12 +16,7 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks /// </summary> public class DeleteLogFileTask : IScheduledTask, IConfigurableScheduledTask { - /// <summary> - /// Gets or sets the configuration manager. - /// </summary> - /// <value>The configuration manager.</value> - private IConfigurationManager ConfigurationManager { get; set; } - + private readonly IConfigurationManager _configurationManager; private readonly IFileSystem _fileSystem; private readonly ILocalizationManager _localization; @@ -32,18 +28,43 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks /// <param name="localization">The localization manager.</param> public DeleteLogFileTask(IConfigurationManager configurationManager, IFileSystem fileSystem, ILocalizationManager localization) { - ConfigurationManager = configurationManager; + _configurationManager = configurationManager; _fileSystem = fileSystem; _localization = localization; } + /// <inheritdoc /> + public string Name => _localization.GetLocalizedString("TaskCleanLogs"); + + /// <inheritdoc /> + public string Description => string.Format( + CultureInfo.InvariantCulture, + _localization.GetLocalizedString("TaskCleanLogsDescription"), + _configurationManager.CommonConfiguration.LogFileRetentionDays); + + /// <inheritdoc /> + public string Category => _localization.GetLocalizedString("TasksMaintenanceCategory"); + + /// <inheritdoc /> + public string Key => "CleanLogFiles"; + + /// <inheritdoc /> + public bool IsHidden => false; + + /// <inheritdoc /> + public bool IsEnabled => true; + + /// <inheritdoc /> + public bool IsLogged => true; + /// <summary> /// Creates the triggers that define when the task will run. /// </summary> /// <returns>IEnumerable{BaseTaskTrigger}.</returns> public IEnumerable<TaskTriggerInfo> GetDefaultTriggers() { - return new[] { + return new[] + { new TaskTriggerInfo { Type = TaskTriggerInfo.TriggerInterval, IntervalTicks = TimeSpan.FromHours(24).Ticks} }; } @@ -57,10 +78,10 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks public Task Execute(CancellationToken cancellationToken, IProgress<double> progress) { // Delete log files more than n days old - var minDateModified = DateTime.UtcNow.AddDays(-ConfigurationManager.CommonConfiguration.LogFileRetentionDays); + var minDateModified = DateTime.UtcNow.AddDays(-_configurationManager.CommonConfiguration.LogFileRetentionDays); // Only delete the .txt log files, the *.log files created by serilog get managed by itself - var filesToDelete = _fileSystem.GetFiles(ConfigurationManager.CommonApplicationPaths.LogDirectoryPath, new[] { ".txt" }, true, true) + var filesToDelete = _fileSystem.GetFiles(_configurationManager.CommonApplicationPaths.LogDirectoryPath, new[] { ".txt" }, true, true) .Where(f => _fileSystem.GetLastWriteTimeUtc(f) < minDateModified) .ToList(); @@ -83,26 +104,5 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks return Task.CompletedTask; } - - /// <inheritdoc /> - public string Name => _localization.GetLocalizedString("TaskCleanLogs"); - - /// <inheritdoc /> - public string Description => string.Format(_localization.GetLocalizedString("TaskCleanLogsDescription"), ConfigurationManager.CommonConfiguration.LogFileRetentionDays); - - /// <inheritdoc /> - public string Category => _localization.GetLocalizedString("TasksMaintenanceCategory"); - - /// <inheritdoc /> - public string Key => "CleanLogFiles"; - - /// <inheritdoc /> - public bool IsHidden => false; - - /// <inheritdoc /> - public bool IsEnabled => true; - - /// <inheritdoc /> - public bool IsLogged => true; } } diff --git a/Emby.Server.Implementations/Services/ServicePath.cs b/Emby.Server.Implementations/Services/ServicePath.cs index 442b2ab1c..0d4728b43 100644 --- a/Emby.Server.Implementations/Services/ServicePath.cs +++ b/Emby.Server.Implementations/Services/ServicePath.cs @@ -80,8 +80,8 @@ namespace Emby.Server.Implementations.Services public static List<string> GetFirstMatchWildCardHashKeys(string[] pathPartsForMatching) { - const string hashPrefix = WildCard + PathSeperator; - return GetPotentialMatchesWithPrefix(hashPrefix, pathPartsForMatching); + const string HashPrefix = WildCard + PathSeperator; + return GetPotentialMatchesWithPrefix(HashPrefix, pathPartsForMatching); } private static List<string> GetPotentialMatchesWithPrefix(string hashPrefix, string[] pathPartsForMatching) @@ -92,7 +92,7 @@ namespace Emby.Server.Implementations.Services { list.Add(hashPrefix + part); - if (part.IndexOf(ComponentSeperator) == -1) + if (part.IndexOf(ComponentSeperator, StringComparison.Ordinal) == -1) { continue; } @@ -130,7 +130,7 @@ namespace Emby.Server.Implementations.Services } if (component.IndexOf(VariablePrefix, StringComparison.OrdinalIgnoreCase) != -1 - && component.IndexOf(ComponentSeperator) != -1) + && component.IndexOf(ComponentSeperator, StringComparison.Ordinal) != -1) { hasSeparators.Add(true); componentsList.AddRange(component.Split(ComponentSeperator)); diff --git a/MediaBrowser.Controller/Entities/UserViewBuilder.cs b/MediaBrowser.Controller/Entities/UserViewBuilder.cs index e3f4025bb..b384b27d1 100644 --- a/MediaBrowser.Controller/Entities/UserViewBuilder.cs +++ b/MediaBrowser.Controller/Entities/UserViewBuilder.cs @@ -10,7 +10,6 @@ using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.TV; -using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Querying; using Microsoft.Extensions.Logging; diff --git a/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs b/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs index a8ebe6bc5..21b5d0c5b 100644 --- a/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs +++ b/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs @@ -240,11 +240,11 @@ namespace MediaBrowser.MediaEncoding.Attachments if (protocol == MediaProtocol.File) { var date = _fileSystem.GetLastWriteTimeUtc(mediaPath); - filename = (mediaPath + attachmentStreamIndex.ToString(CultureInfo.InvariantCulture) + "_" + date.Ticks.ToString(CultureInfo.InvariantCulture)).GetMD5().ToString("D"); + filename = (mediaPath + attachmentStreamIndex.ToString(CultureInfo.InvariantCulture) + "_" + date.Ticks.ToString(CultureInfo.InvariantCulture)).GetMD5().ToString("D", CultureInfo.InvariantCulture); } else { - filename = (mediaPath + attachmentStreamIndex.ToString(CultureInfo.InvariantCulture)).GetMD5().ToString("D"); + filename = (mediaPath + attachmentStreamIndex.ToString(CultureInfo.InvariantCulture)).GetMD5().ToString("D", CultureInfo.InvariantCulture); } var prefix = filename.Substring(0, 1); diff --git a/MediaBrowser.MediaEncoding/Encoder/EncodingUtils.cs b/MediaBrowser.MediaEncoding/Encoder/EncodingUtils.cs index 082ae2888..63310fdf6 100644 --- a/MediaBrowser.MediaEncoding/Encoder/EncodingUtils.cs +++ b/MediaBrowser.MediaEncoding/Encoder/EncodingUtils.cs @@ -1,5 +1,6 @@ #pragma warning disable CS1591 +using System; using System.Collections.Generic; using System.Globalization; using System.Linq; @@ -48,7 +49,7 @@ namespace MediaBrowser.MediaEncoding.Encoder /// <returns>System.String.</returns> private static string GetFileInputArgument(string path) { - if (path.IndexOf("://") != -1) + if (path.IndexOf("://", StringComparison.Ordinal) != -1) { return string.Format(CultureInfo.InvariantCulture, "\"{0}\"", path); } @@ -67,7 +68,7 @@ namespace MediaBrowser.MediaEncoding.Encoder private static string NormalizePath(string path) { // Quotes are valid path characters in linux and they need to be escaped here with a leading \ - return path.Replace("\"", "\\\""); + return path.Replace("\"", "\\\"", StringComparison.Ordinal); } } } diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index b9a6432ad..7449e4a62 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -377,7 +377,7 @@ namespace MediaBrowser.MediaEncoding.Encoder var args = extractChapters ? "{0} -i {1} -threads 0 -v warning -print_format json -show_streams -show_chapters -show_format" : "{0} -i {1} -threads 0 -v warning -print_format json -show_streams -show_format"; - args = string.Format(args, probeSizeArgument, inputPath).Trim(); + args = string.Format(CultureInfo.InvariantCulture, args, probeSizeArgument, inputPath).Trim(); var process = new Process { @@ -856,7 +856,7 @@ namespace MediaBrowser.MediaEncoding.Encoder // https://ffmpeg.org/ffmpeg-filters.html#Notes-on-filtergraph-escaping // We need to double escape - return path.Replace('\\', '/').Replace(":", "\\:").Replace("'", "'\\\\\\''"); + return path.Replace('\\', '/').Replace(":", "\\:", StringComparison.Ordinal).Replace("'", "'\\\\\\''", StringComparison.Ordinal); } /// <inheritdoc /> diff --git a/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj b/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj index 017f917e2..814edd732 100644 --- a/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj +++ b/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj @@ -34,7 +34,7 @@ <!-- Code Analyzers--> <ItemGroup Condition=" '$(Configuration)' == 'Debug' "> - <!-- <PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.8" PrivateAssets="All" /> --> + <PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.8" PrivateAssets="All" /> <PackageReference Include="SerilogAnalyzer" Version="0.15.0" PrivateAssets="All" /> <PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="All" /> <PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" PrivateAssets="All" /> diff --git a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs index 19e3bd8e6..40a3b43e1 100644 --- a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs +++ b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs @@ -42,7 +42,8 @@ namespace MediaBrowser.MediaEncoding.Probing var info = new MediaInfo { Path = path, - Protocol = protocol + Protocol = protocol, + VideoType = videoType }; FFProbeHelpers.NormalizeFFProbeResult(data); @@ -1133,7 +1134,7 @@ namespace MediaBrowser.MediaEncoding.Probing { // Only use the comma as a delimeter if there are no slashes or pipes. // We want to be careful not to split names that have commas in them - var delimeter = !allowCommaDelimiter || _nameDelimiters.Any(i => val.IndexOf(i) != -1) ? + var delimeter = !allowCommaDelimiter || _nameDelimiters.Any(i => val.IndexOf(i, StringComparison.Ordinal) != -1) ? _nameDelimiters : new[] { ',' }; @@ -1377,8 +1378,8 @@ namespace MediaBrowser.MediaEncoding.Probing if (subtitle.Contains('/', StringComparison.Ordinal)) // It contains a episode number and season number { string[] numbers = subtitle.Split(' '); - video.IndexNumber = int.Parse(numbers[0].Replace(".", string.Empty, StringComparison.Ordinal).Split('/')[0]); - int totalEpisodesInSeason = int.Parse(numbers[0].Replace(".", string.Empty, StringComparison.Ordinal).Split('/')[1]); + video.IndexNumber = int.Parse(numbers[0].Replace(".", string.Empty, StringComparison.Ordinal).Split('/')[0], CultureInfo.InvariantCulture); + int totalEpisodesInSeason = int.Parse(numbers[0].Replace(".", string.Empty, StringComparison.Ordinal).Split('/')[1], CultureInfo.InvariantCulture); description = string.Join(" ", numbers, 1, numbers.Length - 1).Trim(); // Skip the first, concatenate the rest, clean up spaces and save it } diff --git a/MediaBrowser.MediaEncoding/Subtitles/AssParser.cs b/MediaBrowser.MediaEncoding/Subtitles/AssParser.cs index 308b62886..86b87fddd 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/AssParser.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/AssParser.cs @@ -86,9 +86,9 @@ namespace MediaBrowser.MediaEncoding.Subtitles private void RemoteNativeFormatting(SubtitleTrackEvent p) { - int indexOfBegin = p.Text.IndexOf('{'); + int indexOfBegin = p.Text.IndexOf('{', StringComparison.Ordinal); string pre = string.Empty; - while (indexOfBegin >= 0 && p.Text.IndexOf('}') > indexOfBegin) + while (indexOfBegin >= 0 && p.Text.IndexOf('}', StringComparison.Ordinal) > indexOfBegin) { string s = p.Text.Substring(indexOfBegin); if (s.StartsWith("{\\an1}", StringComparison.Ordinal) || @@ -116,10 +116,10 @@ namespace MediaBrowser.MediaEncoding.Subtitles pre = s.Substring(0, 5) + "}"; } - int indexOfEnd = p.Text.IndexOf('}'); + int indexOfEnd = p.Text.IndexOf('}', StringComparison.Ordinal); p.Text = p.Text.Remove(indexOfBegin, (indexOfEnd - indexOfBegin) + 1); - indexOfBegin = p.Text.IndexOf('{'); + indexOfBegin = p.Text.IndexOf('{', StringComparison.Ordinal); } p.Text = pre + p.Text; diff --git a/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs b/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs index 6b7a81e6e..a5d641747 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.IO; using System.Text; using System.Threading; @@ -50,14 +51,14 @@ namespace MediaBrowser.MediaEncoding.Subtitles { eventsStarted = true; } - else if (!string.IsNullOrEmpty(line) && line.Trim().StartsWith(";")) + else if (!string.IsNullOrEmpty(line) && line.Trim().StartsWith(";", StringComparison.Ordinal)) { // skip comment lines } else if (eventsStarted && line.Trim().Length > 0) { string s = line.Trim().ToLowerInvariant(); - if (s.StartsWith("format:")) + if (s.StartsWith("format:", StringComparison.Ordinal)) { if (line.Length > 10) { @@ -103,7 +104,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles string[] splittedLine; - if (s.StartsWith("dialogue:")) + if (s.StartsWith("dialogue:", StringComparison.Ordinal)) { splittedLine = line.Substring(10).Split(','); } @@ -181,10 +182,10 @@ namespace MediaBrowser.MediaEncoding.Subtitles string[] timeCode = time.Split(':', '.'); return new TimeSpan( 0, - int.Parse(timeCode[0]), - int.Parse(timeCode[1]), - int.Parse(timeCode[2]), - int.Parse(timeCode[3]) * 10).Ticks; + int.Parse(timeCode[0], CultureInfo.InvariantCulture), + int.Parse(timeCode[1], CultureInfo.InvariantCulture), + int.Parse(timeCode[2], CultureInfo.InvariantCulture), + int.Parse(timeCode[3], CultureInfo.InvariantCulture) * 10).Ticks; } private static string GetFormattedText(string text) @@ -193,11 +194,11 @@ namespace MediaBrowser.MediaEncoding.Subtitles for (int i = 0; i < 10; i++) // just look ten times... { - if (text.Contains(@"{\fn")) + if (text.Contains(@"{\fn", StringComparison.Ordinal)) { - int start = text.IndexOf(@"{\fn"); + int start = text.IndexOf(@"{\fn", StringComparison.Ordinal); int end = text.IndexOf('}', start); - if (end > 0 && !text.Substring(start).StartsWith("{\\fn}")) + if (end > 0 && !text.Substring(start).StartsWith("{\\fn}", StringComparison.Ordinal)) { string fontName = text.Substring(start + 4, end - (start + 4)); string extraTags = string.Empty; @@ -212,7 +213,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles text = text.Insert(start, "<font face=\"" + fontName + "\"" + extraTags + ">"); } - int indexOfEndTag = text.IndexOf("{\\fn}", start); + int indexOfEndTag = text.IndexOf("{\\fn}", start, StringComparison.Ordinal); if (indexOfEndTag > 0) { text = text.Remove(indexOfEndTag, "{\\fn}".Length).Insert(indexOfEndTag, "</font>"); @@ -224,11 +225,11 @@ namespace MediaBrowser.MediaEncoding.Subtitles } } - if (text.Contains(@"{\fs")) + if (text.Contains(@"{\fs", StringComparison.Ordinal)) { - int start = text.IndexOf(@"{\fs"); + int start = text.IndexOf(@"{\fs", StringComparison.Ordinal); int end = text.IndexOf('}', start); - if (end > 0 && !text.Substring(start).StartsWith("{\\fs}")) + if (end > 0 && !text.Substring(start).StartsWith("{\\fs}", StringComparison.Ordinal)) { string fontSize = text.Substring(start + 4, end - (start + 4)); string extraTags = string.Empty; @@ -245,7 +246,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles text = text.Insert(start, "<font size=\"" + fontSize + "\"" + extraTags + ">"); } - int indexOfEndTag = text.IndexOf("{\\fs}", start); + int indexOfEndTag = text.IndexOf("{\\fs}", start, StringComparison.Ordinal); if (indexOfEndTag > 0) { text = text.Remove(indexOfEndTag, "{\\fs}".Length).Insert(indexOfEndTag, "</font>"); @@ -258,17 +259,17 @@ namespace MediaBrowser.MediaEncoding.Subtitles } } - if (text.Contains(@"{\c")) + if (text.Contains(@"{\c", StringComparison.Ordinal)) { - int start = text.IndexOf(@"{\c"); + int start = text.IndexOf(@"{\c", StringComparison.Ordinal); int end = text.IndexOf('}', start); - if (end > 0 && !text.Substring(start).StartsWith("{\\c}")) + if (end > 0 && !text.Substring(start).StartsWith("{\\c}", StringComparison.Ordinal)) { string color = text.Substring(start + 4, end - (start + 4)); string extraTags = string.Empty; CheckAndAddSubTags(ref color, ref extraTags, out bool italic); - color = color.Replace("&", string.Empty).TrimStart('H'); + color = color.Replace("&", string.Empty, StringComparison.Ordinal).TrimStart('H'); color = color.PadLeft(6, '0'); // switch to rrggbb from bbggrr @@ -285,7 +286,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles text = text.Insert(start, "<font color=\"" + color + "\"" + extraTags + ">"); } - int indexOfEndTag = text.IndexOf("{\\c}", start); + int indexOfEndTag = text.IndexOf("{\\c}", start, StringComparison.Ordinal); if (indexOfEndTag > 0) { text = text.Remove(indexOfEndTag, "{\\c}".Length).Insert(indexOfEndTag, "</font>"); @@ -297,17 +298,17 @@ namespace MediaBrowser.MediaEncoding.Subtitles } } - if (text.Contains(@"{\1c")) // "1" specifices primary color + if (text.Contains(@"{\1c", StringComparison.Ordinal)) // "1" specifices primary color { - int start = text.IndexOf(@"{\1c"); + int start = text.IndexOf(@"{\1c", StringComparison.Ordinal); int end = text.IndexOf('}', start); - if (end > 0 && !text.Substring(start).StartsWith("{\\1c}")) + if (end > 0 && !text.Substring(start).StartsWith("{\\1c}", StringComparison.Ordinal)) { string color = text.Substring(start + 5, end - (start + 5)); string extraTags = string.Empty; CheckAndAddSubTags(ref color, ref extraTags, out bool italic); - color = color.Replace("&", string.Empty).TrimStart('H'); + color = color.Replace("&", string.Empty, StringComparison.Ordinal).TrimStart('H'); color = color.PadLeft(6, '0'); // switch to rrggbb from bbggrr @@ -329,25 +330,25 @@ namespace MediaBrowser.MediaEncoding.Subtitles } } - text = text.Replace(@"{\i1}", "<i>"); - text = text.Replace(@"{\i0}", "</i>"); - text = text.Replace(@"{\i}", "</i>"); + text = text.Replace(@"{\i1}", "<i>", StringComparison.Ordinal); + text = text.Replace(@"{\i0}", "</i>", StringComparison.Ordinal); + text = text.Replace(@"{\i}", "</i>", StringComparison.Ordinal); if (CountTagInText(text, "<i>") > CountTagInText(text, "</i>")) { text += "</i>"; } - text = text.Replace(@"{\u1}", "<u>"); - text = text.Replace(@"{\u0}", "</u>"); - text = text.Replace(@"{\u}", "</u>"); + text = text.Replace(@"{\u1}", "<u>", StringComparison.Ordinal); + text = text.Replace(@"{\u0}", "</u>", StringComparison.Ordinal); + text = text.Replace(@"{\u}", "</u>", StringComparison.Ordinal); if (CountTagInText(text, "<u>") > CountTagInText(text, "</u>")) { text += "</u>"; } - text = text.Replace(@"{\b1}", "<b>"); - text = text.Replace(@"{\b0}", "</b>"); - text = text.Replace(@"{\b}", "</b>"); + text = text.Replace(@"{\b1}", "<b>", StringComparison.Ordinal); + text = text.Replace(@"{\b0}", "</b>", StringComparison.Ordinal); + text = text.Replace(@"{\b}", "</b>", StringComparison.Ordinal); if (CountTagInText(text, "<b>") > CountTagInText(text, "</b>")) { text += "</b>"; @@ -362,7 +363,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles private static int CountTagInText(string text, string tag) { int count = 0; - int index = text.IndexOf(tag); + int index = text.IndexOf(tag, StringComparison.Ordinal); while (index >= 0) { count++; @@ -371,7 +372,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles return count; } - index = text.IndexOf(tag, index + 1); + index = text.IndexOf(tag, index + 1, StringComparison.Ordinal); } return count; @@ -380,7 +381,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles private static void CheckAndAddSubTags(ref string tagName, ref string extraTags, out bool italic) { italic = false; - int indexOfSPlit = tagName.IndexOf(@"\"); + int indexOfSPlit = tagName.IndexOf('\\', StringComparison.Ordinal); if (indexOfSPlit > 0) { string rest = tagName.Substring(indexOfSPlit).TrimStart('\\'); @@ -388,9 +389,9 @@ namespace MediaBrowser.MediaEncoding.Subtitles for (int i = 0; i < 10; i++) { - if (rest.StartsWith("fs") && rest.Length > 2) + if (rest.StartsWith("fs", StringComparison.Ordinal) && rest.Length > 2) { - indexOfSPlit = rest.IndexOf(@"\"); + indexOfSPlit = rest.IndexOf('\\', StringComparison.Ordinal); string fontSize = rest; if (indexOfSPlit > 0) { @@ -404,9 +405,9 @@ namespace MediaBrowser.MediaEncoding.Subtitles extraTags += " size=\"" + fontSize.Substring(2) + "\""; } - else if (rest.StartsWith("fn") && rest.Length > 2) + else if (rest.StartsWith("fn", StringComparison.Ordinal) && rest.Length > 2) { - indexOfSPlit = rest.IndexOf(@"\"); + indexOfSPlit = rest.IndexOf('\\', StringComparison.Ordinal); string fontName = rest; if (indexOfSPlit > 0) { @@ -420,9 +421,9 @@ namespace MediaBrowser.MediaEncoding.Subtitles extraTags += " face=\"" + fontName.Substring(2) + "\""; } - else if (rest.StartsWith("c") && rest.Length > 2) + else if (rest.StartsWith("c", StringComparison.Ordinal) && rest.Length > 2) { - indexOfSPlit = rest.IndexOf(@"\"); + indexOfSPlit = rest.IndexOf('\\', StringComparison.Ordinal); string fontColor = rest; if (indexOfSPlit > 0) { @@ -435,7 +436,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles } string color = fontColor.Substring(2); - color = color.Replace("&", string.Empty).TrimStart('H'); + color = color.Replace("&", string.Empty, StringComparison.Ordinal).TrimStart('H'); color = color.PadLeft(6, '0'); // switch to rrggbb from bbggrr color = "#" + color.Remove(color.Length - 6) + color.Substring(color.Length - 2, 2) + color.Substring(color.Length - 4, 2) + color.Substring(color.Length - 6, 2); @@ -443,9 +444,9 @@ namespace MediaBrowser.MediaEncoding.Subtitles extraTags += " color=\"" + color + "\""; } - else if (rest.StartsWith("i1") && rest.Length > 1) + else if (rest.StartsWith("i1", StringComparison.Ordinal) && rest.Length > 1) { - indexOfSPlit = rest.IndexOf(@"\"); + indexOfSPlit = rest.IndexOf('\\', StringComparison.Ordinal); italic = true; if (indexOfSPlit > 0) { @@ -456,9 +457,9 @@ namespace MediaBrowser.MediaEncoding.Subtitles rest = string.Empty; } } - else if (rest.Length > 0 && rest.Contains("\\")) + else if (rest.Length > 0 && rest.Contains('\\', StringComparison.Ordinal)) { - indexOfSPlit = rest.IndexOf(@"\"); + indexOfSPlit = rest.IndexOf('\\', StringComparison.Ordinal); rest = rest.Substring(indexOfSPlit).TrimStart('\\'); } } diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs index fbe8bd69f..6ac5ac2ff 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs @@ -415,7 +415,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles // FFmpeg automatically convert character encoding when it is UTF-16 // If we specify character encoding, it rejects with "do not specify a character encoding" and "Unable to recode subtitle event" - if ((inputPath.EndsWith(".smi") || inputPath.EndsWith(".sami")) && + if ((inputPath.EndsWith(".smi", StringComparison.Ordinal) || inputPath.EndsWith(".sami", StringComparison.Ordinal)) && (encodingParam.Equals("UTF-16BE", StringComparison.OrdinalIgnoreCase) || encodingParam.Equals("UTF-16LE", StringComparison.OrdinalIgnoreCase))) { @@ -506,7 +506,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles string.Format(CultureInfo.InvariantCulture, "ffmpeg subtitle conversion failed for {0}", inputPath)); } - await SetAssFont(outputPath).ConfigureAwait(false); + await SetAssFont(outputPath, cancellationToken).ConfigureAwait(false); _logger.LogInformation("ffmpeg subtitle conversion succeeded for {Path}", inputPath); } @@ -668,7 +668,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles if (string.Equals(outputCodec, "ass", StringComparison.OrdinalIgnoreCase)) { - await SetAssFont(outputPath).ConfigureAwait(false); + await SetAssFont(outputPath, cancellationToken).ConfigureAwait(false); } } @@ -676,8 +676,9 @@ namespace MediaBrowser.MediaEncoding.Subtitles /// Sets the ass font. /// </summary> /// <param name="file">The file.</param> + /// <param name="cancellationToken">The token to monitor for cancellation requests. The default value is <c>System.Threading.CancellationToken.None</c>.</param> /// <returns>Task.</returns> - private async Task SetAssFont(string file) + private async Task SetAssFont(string file, CancellationToken cancellationToken = default) { _logger.LogInformation("Setting ass font within {File}", file); @@ -692,14 +693,14 @@ namespace MediaBrowser.MediaEncoding.Subtitles text = await reader.ReadToEndAsync().ConfigureAwait(false); } - var newText = text.Replace(",Arial,", ",Arial Unicode MS,"); + var newText = text.Replace(",Arial,", ",Arial Unicode MS,", StringComparison.Ordinal); - if (!string.Equals(text, newText)) + if (!string.Equals(text, newText, StringComparison.Ordinal)) { using (var fileStream = new FileStream(file, FileMode.Create, FileAccess.Write, FileShare.Read)) using (var writer = new StreamWriter(fileStream, encoding)) { - writer.Write(newText); + await writer.WriteAsync(newText.AsMemory(), cancellationToken).ConfigureAwait(false); } } } @@ -736,7 +737,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles var charset = CharsetDetector.DetectFromStream(stream).Detected?.EncodingName; // UTF16 is automatically converted to UTF8 by FFmpeg, do not specify a character encoding - if ((path.EndsWith(".ass") || path.EndsWith(".ssa") || path.EndsWith(".srt")) + if ((path.EndsWith(".ass", StringComparison.Ordinal) || path.EndsWith(".ssa", StringComparison.Ordinal) || path.EndsWith(".srt", StringComparison.Ordinal)) && (string.Equals(charset, "utf-16le", StringComparison.OrdinalIgnoreCase) || string.Equals(charset, "utf-16be", StringComparison.OrdinalIgnoreCase))) { -- cgit v1.2.3 From 54349fc94597824714f623b8c31583fc044274aa Mon Sep 17 00:00:00 2001 From: nyanmisaka <nst799610810@gmail.com> Date: Thu, 20 Aug 2020 19:08:36 +0800 Subject: fix outputSize --- .../MediaEncoding/EncodingHelper.cs | 64 +++++++++++++--------- 1 file changed, 37 insertions(+), 27 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 9433d33b4..7ceb25bad 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -1639,35 +1639,45 @@ namespace MediaBrowser.Controller.MediaEncoding var outputSizeParam = ReadOnlySpan<char>.Empty; var request = state.BaseRequest; - // Add resolution params, if specified - if (request.Width.HasValue - || request.Height.HasValue - || request.MaxHeight.HasValue - || request.MaxWidth.HasValue) - { - outputSizeParam = GetOutputSizeParam(state, options, outputVideoCodec).TrimEnd('"'); - - // All possible beginning of video filters - // Don't break the order - string[] beginOfParam = new[] - { - "hwupload,tonemap_opencl", - "hwupload=extra_hw_frames", - "vpp", - "hwdownload", - "format", - "yadif", - "scale" - }; + outputSizeParam = GetOutputSizeParam(state, options, outputVideoCodec).TrimEnd('"'); + + // All possible beginning of video filters + // Don't break the order + string[] beginOfOutputSizeParam = new[] + { + // for tonemap_opencl + "hwupload,tonemap_opencl", + + // hwupload=extra_hw_frames=64,vpp_qsv (for overlay_qsv on linux) + "hwupload=extra_hw_frames", + + // vpp_qsv + "vpp", + + // hwdownload,format=p010le (hardware decode + software encode for vaapi) + "hwdownload", + + // format=nv12|vaapi,hwupload,scale_vaapi + "format", + + // bwdif,scale=expr + "bwdif", - for (int i = 0, index = -1; i < beginOfParam.Length; i++) + // yadif,scale=expr + "yadif", + + // scale=expr + "scale" + }; + + var index = -1; + foreach (var param in beginOfOutputSizeParam) + { + index = outputSizeParam.IndexOf(param, StringComparison.OrdinalIgnoreCase); + if (index != -1) { - index = outputSizeParam.IndexOf(beginOfParam[i], StringComparison.OrdinalIgnoreCase); - if (index != -1) - { - outputSizeParam = outputSizeParam.Slice(index); - break; - } + outputSizeParam = outputSizeParam.Slice(index); + break; } } -- cgit v1.2.3 From 119f64f5e7b09aeb4ff8f59237093906c1e08f5f Mon Sep 17 00:00:00 2001 From: Bond_009 <bond.009@outlook.com> Date: Fri, 21 Aug 2020 22:01:19 +0200 Subject: Make some methods async --- .../Channels/ChannelManager.cs | 21 ++++++--- .../Collections/CollectionManager.cs | 51 +++++++++------------- .../Library/LibraryManager.cs | 39 +++++++---------- .../LiveTv/LiveTvManager.cs | 16 ++++--- .../Playlists/PlaylistManager.cs | 16 +++---- Jellyfin.Api/Controllers/CollectionController.cs | 15 ++++--- Jellyfin.Api/Controllers/ImageController.cs | 14 +++--- Jellyfin.Api/Controllers/ItemUpdateController.cs | 7 +-- Jellyfin.Api/Controllers/PlaylistsController.cs | 12 ++--- Jellyfin.Api/Controllers/RemoteImageController.cs | 2 +- Jellyfin.Api/Controllers/VideosController.cs | 14 +++--- .../Collections/ICollectionManager.cs | 12 ++--- MediaBrowser.Controller/Entities/BaseItem.cs | 20 ++++----- MediaBrowser.Controller/Entities/Folder.cs | 4 +- MediaBrowser.Controller/Entities/Video.cs | 7 +-- MediaBrowser.Controller/Library/ILibraryManager.cs | 41 +++++++++++++---- .../Playlists/IPlaylistManager.cs | 6 +-- .../Encoder/EncoderValidator.cs | 5 ++- MediaBrowser.Providers/Manager/MetadataService.cs | 4 +- MediaBrowser.Providers/TV/DummySeasonProvider.cs | 4 +- 20 files changed, 165 insertions(+), 145 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/Channels/ChannelManager.cs b/Emby.Server.Implementations/Channels/ChannelManager.cs index d8ab1f1a1..26fc1bee4 100644 --- a/Emby.Server.Implementations/Channels/ChannelManager.cs +++ b/Emby.Server.Implementations/Channels/ChannelManager.cs @@ -746,12 +746,21 @@ namespace Emby.Server.Implementations.Channels // null if came from cache if (itemsResult != null) { - var internalItems = itemsResult.Items - .Select(i => GetChannelItemEntity(i, channelProvider, channel.Id, parentItem, cancellationToken)) - .ToArray(); + var items = itemsResult.Items; + var itemsLen = items.Count; + var internalItems = new Guid[itemsLen]; + for (int i = 0; i < itemsLen; i++) + { + internalItems[i] = (await GetChannelItemEntityAsync( + items[i], + channelProvider, + channel.Id, + parentItem, + cancellationToken).ConfigureAwait(false)).Id; + } var existingIds = _libraryManager.GetItemIds(query); - var deadIds = existingIds.Except(internalItems.Select(i => i.Id)) + var deadIds = existingIds.Except(internalItems) .ToArray(); foreach (var deadId in deadIds) @@ -963,7 +972,7 @@ namespace Emby.Server.Implementations.Channels return item; } - private BaseItem GetChannelItemEntity(ChannelItemInfo info, IChannel channelProvider, Guid internalChannelId, BaseItem parentFolder, CancellationToken cancellationToken) + private async Task<BaseItem> GetChannelItemEntityAsync(ChannelItemInfo info, IChannel channelProvider, Guid internalChannelId, BaseItem parentFolder, CancellationToken cancellationToken) { var parentFolderId = parentFolder.Id; @@ -1165,7 +1174,7 @@ namespace Emby.Server.Implementations.Channels } else if (forceUpdate) { - item.UpdateToRepository(ItemUpdateType.None, cancellationToken); + await item.UpdateToRepositoryAsync(ItemUpdateType.None, cancellationToken).ConfigureAwait(false); } if ((isNew || forceUpdate) && info.Type == ChannelItemType.Media) diff --git a/Emby.Server.Implementations/Collections/CollectionManager.cs b/Emby.Server.Implementations/Collections/CollectionManager.cs index ac2edc1e2..3011a37e3 100644 --- a/Emby.Server.Implementations/Collections/CollectionManager.cs +++ b/Emby.Server.Implementations/Collections/CollectionManager.cs @@ -132,7 +132,7 @@ namespace Emby.Server.Implementations.Collections } /// <inheritdoc /> - public BoxSet CreateCollection(CollectionCreationOptions options) + public async Task<BoxSet> CreateCollectionAsync(CollectionCreationOptions options) { var name = options.Name; @@ -141,7 +141,7 @@ namespace Emby.Server.Implementations.Collections // This could cause it to get re-resolved as a plain folder var folderName = _fileSystem.GetValidFilename(name) + " [boxset]"; - var parentFolder = GetCollectionsFolder(true).GetAwaiter().GetResult(); + var parentFolder = await GetCollectionsFolder(true).ConfigureAwait(false); if (parentFolder == null) { @@ -169,12 +169,16 @@ namespace Emby.Server.Implementations.Collections if (options.ItemIdList.Length > 0) { - AddToCollection(collection.Id, options.ItemIdList, false, new MetadataRefreshOptions(new DirectoryService(_fileSystem)) - { - // The initial adding of items is going to create a local metadata file - // This will cause internet metadata to be skipped as a result - MetadataRefreshMode = MetadataRefreshMode.FullRefresh - }); + await AddToCollectionAsync( + collection.Id, + options.ItemIdList.Select(x => new Guid(x)), + false, + new MetadataRefreshOptions(new DirectoryService(_fileSystem)) + { + // The initial adding of items is going to create a local metadata file + // This will cause internet metadata to be skipped as a result + MetadataRefreshMode = MetadataRefreshMode.FullRefresh + }).ConfigureAwait(false); } else { @@ -197,18 +201,10 @@ namespace Emby.Server.Implementations.Collections } /// <inheritdoc /> - public void AddToCollection(Guid collectionId, IEnumerable<string> ids) - { - AddToCollection(collectionId, ids, true, new MetadataRefreshOptions(new DirectoryService(_fileSystem))); - } + public Task AddToCollectionAsync(Guid collectionId, IEnumerable<Guid> ids) + => AddToCollectionAsync(collectionId, ids, true, new MetadataRefreshOptions(new DirectoryService(_fileSystem))); - /// <inheritdoc /> - public void AddToCollection(Guid collectionId, IEnumerable<Guid> ids) - { - AddToCollection(collectionId, ids.Select(i => i.ToString("N", CultureInfo.InvariantCulture)), true, new MetadataRefreshOptions(new DirectoryService(_fileSystem))); - } - - private void AddToCollection(Guid collectionId, IEnumerable<string> ids, bool fireEvent, MetadataRefreshOptions refreshOptions) + private async Task AddToCollectionAsync(Guid collectionId, IEnumerable<Guid> ids, bool fireEvent, MetadataRefreshOptions refreshOptions) { var collection = _libraryManager.GetItemById(collectionId) as BoxSet; if (collection == null) @@ -224,15 +220,14 @@ namespace Emby.Server.Implementations.Collections foreach (var id in ids) { - var guidId = new Guid(id); - var item = _libraryManager.GetItemById(guidId); + var item = _libraryManager.GetItemById(id); if (item == null) { throw new ArgumentException("No item exists with the supplied Id"); } - if (!currentLinkedChildrenIds.Contains(guidId)) + if (!currentLinkedChildrenIds.Contains(id)) { itemList.Add(item); @@ -249,7 +244,7 @@ namespace Emby.Server.Implementations.Collections collection.UpdateRatingToItems(linkedChildrenList); - collection.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None); + await collection.UpdateToRepositoryAsync(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false); refreshOptions.ForceSave = true; _providerManager.QueueRefresh(collection.Id, refreshOptions, RefreshPriority.High); @@ -266,13 +261,7 @@ namespace Emby.Server.Implementations.Collections } /// <inheritdoc /> - public void RemoveFromCollection(Guid collectionId, IEnumerable<string> itemIds) - { - RemoveFromCollection(collectionId, itemIds.Select(i => new Guid(i))); - } - - /// <inheritdoc /> - public void RemoveFromCollection(Guid collectionId, IEnumerable<Guid> itemIds) + public async Task RemoveFromCollectionAsync(Guid collectionId, IEnumerable<Guid> itemIds) { var collection = _libraryManager.GetItemById(collectionId) as BoxSet; @@ -309,7 +298,7 @@ namespace Emby.Server.Implementations.Collections collection.LinkedChildren = collection.LinkedChildren.Except(list).ToArray(); } - collection.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None); + await collection.UpdateToRepositoryAsync(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false); _providerManager.QueueRefresh( collection.Id, new MetadataRefreshOptions(new DirectoryService(_fileSystem)) diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index 7ed8f0bbf..375f09f5b 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -771,7 +771,7 @@ namespace Emby.Server.Implementations.Library if (folder.ParentId != rootFolder.Id) { folder.ParentId = rootFolder.Id; - folder.UpdateToRepository(ItemUpdateType.MetadataImport, CancellationToken.None); + folder.UpdateToRepositoryAsync(ItemUpdateType.MetadataImport, CancellationToken.None).GetAwaiter().GetResult(); } rootFolder.AddVirtualChild(folder); @@ -1868,7 +1868,8 @@ namespace Emby.Server.Implementations.Library return image.Path != null && !image.IsLocalFile; } - public void UpdateImages(BaseItem item, bool forceUpdate = false) + /// <inheritdoc /> + public async Task UpdateImagesAsync(BaseItem item, bool forceUpdate = false) { if (item == null) { @@ -1891,7 +1892,7 @@ namespace Emby.Server.Implementations.Library try { var index = item.GetImageIndex(img); - image = ConvertImageToLocal(item, img, index).ConfigureAwait(false).GetAwaiter().GetResult(); + image = await ConvertImageToLocal(item, img, index).ConfigureAwait(false); } catch (ArgumentException) { @@ -1913,7 +1914,7 @@ namespace Emby.Server.Implementations.Library } catch (Exception ex) { - _logger.LogError(ex, "Cannnot get image dimensions for {0}", image.Path); + _logger.LogError(ex, "Cannot get image dimensions for {0}", image.Path); image.Width = 0; image.Height = 0; continue; @@ -1943,10 +1944,8 @@ namespace Emby.Server.Implementations.Library RegisterItem(item); } - /// <summary> - /// Updates the item. - /// </summary> - public void UpdateItems(IReadOnlyList<BaseItem> items, BaseItem parent, ItemUpdateType updateReason, CancellationToken cancellationToken) + /// <inheritdoc /> + public async Task UpdateItemsAsync(IReadOnlyList<BaseItem> items, BaseItem parent, ItemUpdateType updateReason, CancellationToken cancellationToken) { foreach (var item in items) { @@ -1957,7 +1956,7 @@ namespace Emby.Server.Implementations.Library item.DateLastSaved = DateTime.UtcNow; - UpdateImages(item, updateReason >= ItemUpdateType.ImageUpdate); + await UpdateImagesAsync(item, updateReason >= ItemUpdateType.ImageUpdate).ConfigureAwait(false); } _itemRepository.SaveItems(items, cancellationToken); @@ -1991,17 +1990,9 @@ namespace Emby.Server.Implementations.Library } } - /// <summary> - /// Updates the item. - /// </summary> - /// <param name="item">The item.</param> - /// <param name="parent">The parent item.</param> - /// <param name="updateReason">The update reason.</param> - /// <param name="cancellationToken">The cancellation token.</param> - public void UpdateItem(BaseItem item, BaseItem parent, ItemUpdateType updateReason, CancellationToken cancellationToken) - { - UpdateItems(new[] { item }, parent, updateReason, cancellationToken); - } + /// <inheritdoc /> + public Task UpdateItemAsync(BaseItem item, BaseItem parent, ItemUpdateType updateReason, CancellationToken cancellationToken) + => UpdateItemsAsync(new[] { item }, parent, updateReason, cancellationToken); /// <summary> /// Reports the item removed. @@ -2233,7 +2224,7 @@ namespace Emby.Server.Implementations.Library if (refresh) { - item.UpdateToRepository(ItemUpdateType.MetadataImport, CancellationToken.None); + item.UpdateToRepositoryAsync(ItemUpdateType.MetadataImport, CancellationToken.None).GetAwaiter().GetResult(); ProviderManager.QueueRefresh(item.Id, new MetadataRefreshOptions(new DirectoryService(_fileSystem)), RefreshPriority.Normal); } @@ -2420,7 +2411,7 @@ namespace Emby.Server.Implementations.Library if (!string.Equals(viewType, item.ViewType, StringComparison.OrdinalIgnoreCase)) { item.ViewType = viewType; - item.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None); + item.UpdateToRepositoryAsync(ItemUpdateType.MetadataEdit, CancellationToken.None).GetAwaiter().GetResult(); } var refresh = isNew || DateTime.UtcNow - item.DateLastRefreshed >= _viewRefreshInterval; @@ -2902,7 +2893,7 @@ namespace Emby.Server.Implementations.Library await ProviderManager.SaveImage(item, url, image.Type, imageIndex, CancellationToken.None).ConfigureAwait(false); - item.UpdateToRepository(ItemUpdateType.ImageUpdate, CancellationToken.None); + await item.UpdateToRepositoryAsync(ItemUpdateType.ImageUpdate, CancellationToken.None).ConfigureAwait(false); return item.GetImageInfo(image.Type, imageIndex); } @@ -2920,7 +2911,7 @@ namespace Emby.Server.Implementations.Library // Remove this image to prevent it from retrying over and over item.RemoveImage(image); - item.UpdateToRepository(ItemUpdateType.ImageUpdate, CancellationToken.None); + await item.UpdateToRepositoryAsync(ItemUpdateType.ImageUpdate, CancellationToken.None).ConfigureAwait(false); throw new InvalidOperationException(); } diff --git a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs index 90cbd85a5..5ed6baeb9 100644 --- a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs @@ -422,7 +422,7 @@ namespace Emby.Server.Implementations.LiveTv } } - private LiveTvChannel GetChannel(ChannelInfo channelInfo, string serviceName, BaseItem parentFolder, CancellationToken cancellationToken) + private async Task<LiveTvChannel> GetChannelAsync(ChannelInfo channelInfo, string serviceName, BaseItem parentFolder, CancellationToken cancellationToken) { var parentFolderId = parentFolder.Id; var isNew = false; @@ -512,7 +512,7 @@ namespace Emby.Server.Implementations.LiveTv } else if (forceUpdate) { - _libraryManager.UpdateItem(item, parentFolder, ItemUpdateType.MetadataImport, cancellationToken); + await _libraryManager.UpdateItemAsync(item, parentFolder, ItemUpdateType.MetadataImport, cancellationToken).ConfigureAwait(false); } return item; @@ -1129,7 +1129,7 @@ namespace Emby.Server.Implementations.LiveTv try { - var item = GetChannel(channelInfo.Item2, channelInfo.Item1, parentFolder, cancellationToken); + var item = await GetChannelAsync(channelInfo.Item2, channelInfo.Item1, parentFolder, cancellationToken).ConfigureAwait(false); list.Add(item); } @@ -1146,7 +1146,7 @@ namespace Emby.Server.Implementations.LiveTv double percent = numComplete; percent /= allChannelsList.Count; - progress.Report(5 * percent + 10); + progress.Report((5 * percent) + 10); } progress.Report(15); @@ -1221,7 +1221,11 @@ namespace Emby.Server.Implementations.LiveTv if (updatedPrograms.Count > 0) { - _libraryManager.UpdateItems(updatedPrograms, currentChannel, ItemUpdateType.MetadataImport, cancellationToken); + await _libraryManager.UpdateItemsAsync( + updatedPrograms, + currentChannel, + ItemUpdateType.MetadataImport, + cancellationToken).ConfigureAwait(false); } currentChannel.IsMovie = isMovie; @@ -1234,7 +1238,7 @@ namespace Emby.Server.Implementations.LiveTv currentChannel.AddTag("Kids"); } - currentChannel.UpdateToRepository(ItemUpdateType.MetadataImport, cancellationToken); + await currentChannel.UpdateToRepositoryAsync(ItemUpdateType.MetadataImport, cancellationToken).ConfigureAwait(false); await currentChannel.RefreshMetadata( new MetadataRefreshOptions(new DirectoryService(_fileSystem)) { diff --git a/Emby.Server.Implementations/Playlists/PlaylistManager.cs b/Emby.Server.Implementations/Playlists/PlaylistManager.cs index 38ceadedb..d35223b0a 100644 --- a/Emby.Server.Implementations/Playlists/PlaylistManager.cs +++ b/Emby.Server.Implementations/Playlists/PlaylistManager.cs @@ -184,17 +184,17 @@ namespace Emby.Server.Implementations.Playlists return Playlist.GetPlaylistItems(playlistMediaType, items, user, options); } - public void AddToPlaylist(string playlistId, ICollection<Guid> itemIds, Guid userId) + public Task AddToPlaylistAsync(string playlistId, ICollection<Guid> itemIds, Guid userId) { var user = userId.Equals(Guid.Empty) ? null : _userManager.GetUserById(userId); - AddToPlaylistInternal(playlistId, itemIds, user, new DtoOptions(false) + return AddToPlaylistInternal(playlistId, itemIds, user, new DtoOptions(false) { EnableImages = true }); } - private void AddToPlaylistInternal(string playlistId, ICollection<Guid> newItemIds, User user, DtoOptions options) + private async Task AddToPlaylistInternal(string playlistId, ICollection<Guid> newItemIds, User user, DtoOptions options) { // Retrieve the existing playlist var playlist = _libraryManager.GetItemById(playlistId) as Playlist @@ -238,7 +238,7 @@ namespace Emby.Server.Implementations.Playlists // Update the playlist in the repository playlist.LinkedChildren = newLinkedChildren; - playlist.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None); + await playlist.UpdateToRepositoryAsync(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false); // Update the playlist on disk if (playlist.IsFile) @@ -256,7 +256,7 @@ namespace Emby.Server.Implementations.Playlists RefreshPriority.High); } - public void RemoveFromPlaylist(string playlistId, IEnumerable<string> entryIds) + public async Task RemoveFromPlaylistAsync(string playlistId, IEnumerable<string> entryIds) { if (!(_libraryManager.GetItemById(playlistId) is Playlist playlist)) { @@ -273,7 +273,7 @@ namespace Emby.Server.Implementations.Playlists .Select(i => i.Item1) .ToArray(); - playlist.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None); + await playlist.UpdateToRepositoryAsync(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false); if (playlist.IsFile) { @@ -289,7 +289,7 @@ namespace Emby.Server.Implementations.Playlists RefreshPriority.High); } - public void MoveItem(string playlistId, string entryId, int newIndex) + public async Task MoveItemAsync(string playlistId, string entryId, int newIndex) { if (!(_libraryManager.GetItemById(playlistId) is Playlist playlist)) { @@ -322,7 +322,7 @@ namespace Emby.Server.Implementations.Playlists playlist.LinkedChildren = newList.ToArray(); - playlist.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None); + await playlist.UpdateToRepositoryAsync(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false); if (playlist.IsFile) { diff --git a/Jellyfin.Api/Controllers/CollectionController.cs b/Jellyfin.Api/Controllers/CollectionController.cs index 53821a188..c5910d6e8 100644 --- a/Jellyfin.Api/Controllers/CollectionController.cs +++ b/Jellyfin.Api/Controllers/CollectionController.cs @@ -1,5 +1,6 @@ using System; using System.ComponentModel.DataAnnotations; +using System.Threading.Tasks; using Jellyfin.Api.Constants; using Jellyfin.Api.Extensions; using Jellyfin.Api.Helpers; @@ -51,7 +52,7 @@ namespace Jellyfin.Api.Controllers /// <returns>A <see cref="CollectionCreationOptions"/> with information about the new collection.</returns> [HttpPost] [ProducesResponseType(StatusCodes.Status200OK)] - public ActionResult<CollectionCreationResult> CreateCollection( + public async Task<ActionResult<CollectionCreationResult>> CreateCollection( [FromQuery] string? name, [FromQuery] string? ids, [FromQuery] Guid? parentId, @@ -59,14 +60,14 @@ namespace Jellyfin.Api.Controllers { var userId = _authContext.GetAuthorizationInfo(Request).UserId; - var item = _collectionManager.CreateCollection(new CollectionCreationOptions + var item = await _collectionManager.CreateCollectionAsync(new CollectionCreationOptions { IsLocked = isLocked, Name = name, ParentId = parentId, ItemIdList = RequestHelpers.Split(ids, ',', true), UserIds = new[] { userId } - }); + }).ConfigureAwait(false); var dtoOptions = new DtoOptions().AddClientFields(Request); @@ -87,9 +88,9 @@ namespace Jellyfin.Api.Controllers /// <returns>A <see cref="NoContentResult"/> indicating success.</returns> [HttpPost("{collectionId}/Items")] [ProducesResponseType(StatusCodes.Status204NoContent)] - public ActionResult AddToCollection([FromRoute] Guid collectionId, [FromQuery, Required] string? itemIds) + public async Task<ActionResult> AddToCollection([FromRoute] Guid collectionId, [FromQuery, Required] string? itemIds) { - _collectionManager.AddToCollection(collectionId, RequestHelpers.Split(itemIds, ',', true)); + await _collectionManager.AddToCollectionAsync(collectionId, RequestHelpers.GetGuids(itemIds)).ConfigureAwait(true); return NoContent(); } @@ -102,9 +103,9 @@ namespace Jellyfin.Api.Controllers /// <returns>A <see cref="NoContentResult"/> indicating success.</returns> [HttpDelete("{collectionId}/Items")] [ProducesResponseType(StatusCodes.Status204NoContent)] - public ActionResult RemoveFromCollection([FromRoute] Guid collectionId, [FromQuery, Required] string? itemIds) + public async Task<ActionResult> RemoveFromCollection([FromRoute] Guid collectionId, [FromQuery, Required] string? itemIds) { - _collectionManager.RemoveFromCollection(collectionId, RequestHelpers.Split(itemIds, ',', true)); + await _collectionManager.RemoveFromCollectionAsync(collectionId, RequestHelpers.GetGuids(itemIds)).ConfigureAwait(false); return NoContent(); } } diff --git a/Jellyfin.Api/Controllers/ImageController.cs b/Jellyfin.Api/Controllers/ImageController.cs index 75734f0af..ca9c2fa46 100644 --- a/Jellyfin.Api/Controllers/ImageController.cs +++ b/Jellyfin.Api/Controllers/ImageController.cs @@ -174,7 +174,7 @@ namespace Jellyfin.Api.Controllers [Authorize(Policy = Policies.RequiresElevation)] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status404NotFound)] - public ActionResult DeleteItemImage( + public async Task<ActionResult> DeleteItemImage( [FromRoute] Guid itemId, [FromRoute] ImageType imageType, [FromRoute] int? imageIndex = null) @@ -185,7 +185,7 @@ namespace Jellyfin.Api.Controllers return NotFound(); } - item.DeleteImage(imageType, imageIndex ?? 0); + await item.DeleteImageAsync(imageType, imageIndex ?? 0).ConfigureAwait(false); return NoContent(); } @@ -218,7 +218,7 @@ namespace Jellyfin.Api.Controllers // Handle image/png; charset=utf-8 var mimeType = Request.ContentType.Split(';').FirstOrDefault(); await _providerManager.SaveImage(item, Request.Body, mimeType, imageType, null, CancellationToken.None).ConfigureAwait(false); - item.UpdateToRepository(ItemUpdateType.ImageUpdate, CancellationToken.None); + await item.UpdateToRepositoryAsync(ItemUpdateType.ImageUpdate, CancellationToken.None).ConfigureAwait(false); return NoContent(); } @@ -237,7 +237,7 @@ namespace Jellyfin.Api.Controllers [Authorize(Policy = Policies.RequiresElevation)] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status404NotFound)] - public ActionResult UpdateItemImageIndex( + public async Task<ActionResult> UpdateItemImageIndex( [FromRoute] Guid itemId, [FromRoute] ImageType imageType, [FromRoute] int imageIndex, @@ -249,7 +249,7 @@ namespace Jellyfin.Api.Controllers return NotFound(); } - item.SwapImages(imageType, imageIndex, newIndex); + await item.SwapImagesAsync(imageType, imageIndex, newIndex).ConfigureAwait(false); return NoContent(); } @@ -264,7 +264,7 @@ namespace Jellyfin.Api.Controllers [Authorize(Policy = Policies.DefaultAuthorization)] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] - public ActionResult<IEnumerable<ImageInfo>> GetItemImageInfos([FromRoute] Guid itemId) + public async Task<ActionResult<IEnumerable<ImageInfo>>> GetItemImageInfos([FromRoute] Guid itemId) { var item = _libraryManager.GetItemById(itemId); if (item == null) @@ -281,7 +281,7 @@ namespace Jellyfin.Api.Controllers return list; } - _libraryManager.UpdateImages(item); // this makes sure dimensions and hashes are correct + await _libraryManager.UpdateImagesAsync(item).ConfigureAwait(false); // this makes sure dimensions and hashes are correct foreach (var image in itemImages) { diff --git a/Jellyfin.Api/Controllers/ItemUpdateController.cs b/Jellyfin.Api/Controllers/ItemUpdateController.cs index 4b40c6ada..ec52f4996 100644 --- a/Jellyfin.Api/Controllers/ItemUpdateController.cs +++ b/Jellyfin.Api/Controllers/ItemUpdateController.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; using System.Threading; +using System.Threading.Tasks; using Jellyfin.Api.Constants; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; @@ -67,7 +68,7 @@ namespace Jellyfin.Api.Controllers [HttpPost("Items/{itemId}")] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status404NotFound)] - public ActionResult UpdateItem([FromRoute] Guid itemId, [FromBody, Required] BaseItemDto request) + public async Task<ActionResult> UpdateItem([FromRoute] Guid itemId, [FromBody, Required] BaseItemDto request) { var item = _libraryManager.GetItemById(itemId); if (item == null) @@ -101,7 +102,7 @@ namespace Jellyfin.Api.Controllers item.OnMetadataChanged(); - item.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None); + await item.UpdateToRepositoryAsync(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false); if (isLockedChanged && item.IsFolder) { @@ -110,7 +111,7 @@ namespace Jellyfin.Api.Controllers foreach (var child in folder.GetRecursiveChildren()) { child.IsLocked = newLockData; - child.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None); + await child.UpdateToRepositoryAsync(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false); } } diff --git a/Jellyfin.Api/Controllers/PlaylistsController.cs b/Jellyfin.Api/Controllers/PlaylistsController.cs index 12c87d7c3..d69228c33 100644 --- a/Jellyfin.Api/Controllers/PlaylistsController.cs +++ b/Jellyfin.Api/Controllers/PlaylistsController.cs @@ -83,12 +83,12 @@ namespace Jellyfin.Api.Controllers /// <returns>An <see cref="NoContentResult"/> on success.</returns> [HttpPost("{playlistId}/Items")] [ProducesResponseType(StatusCodes.Status204NoContent)] - public ActionResult AddToPlaylist( + public async Task<ActionResult> AddToPlaylist( [FromRoute] string? playlistId, [FromQuery] string? ids, [FromQuery] Guid? userId) { - _playlistManager.AddToPlaylist(playlistId, RequestHelpers.GetGuids(ids), userId ?? Guid.Empty); + await _playlistManager.AddToPlaylistAsync(playlistId, RequestHelpers.GetGuids(ids), userId ?? Guid.Empty).ConfigureAwait(false); return NoContent(); } @@ -102,12 +102,12 @@ namespace Jellyfin.Api.Controllers /// <returns>An <see cref="NoContentResult"/> on success.</returns> [HttpPost("{playlistId}/Items/{itemId}/Move/{newIndex}")] [ProducesResponseType(StatusCodes.Status204NoContent)] - public ActionResult MoveItem( + public async Task<ActionResult> MoveItem( [FromRoute] string? playlistId, [FromRoute] string? itemId, [FromRoute] int newIndex) { - _playlistManager.MoveItem(playlistId, itemId, newIndex); + await _playlistManager.MoveItemAsync(playlistId, itemId, newIndex).ConfigureAwait(false); return NoContent(); } @@ -120,9 +120,9 @@ namespace Jellyfin.Api.Controllers /// <returns>An <see cref="NoContentResult"/> on success.</returns> [HttpDelete("{playlistId}/Items")] [ProducesResponseType(StatusCodes.Status204NoContent)] - public ActionResult RemoveFromPlaylist([FromRoute] string? playlistId, [FromQuery] string? entryIds) + public async Task<ActionResult> RemoveFromPlaylist([FromRoute] string? playlistId, [FromQuery] string? entryIds) { - _playlistManager.RemoveFromPlaylist(playlistId, RequestHelpers.Split(entryIds, ',', true)); + await _playlistManager.RemoveFromPlaylistAsync(playlistId, RequestHelpers.Split(entryIds, ',', true)).ConfigureAwait(false); return NoContent(); } diff --git a/Jellyfin.Api/Controllers/RemoteImageController.cs b/Jellyfin.Api/Controllers/RemoteImageController.cs index a203c50b9..30a4f73fc 100644 --- a/Jellyfin.Api/Controllers/RemoteImageController.cs +++ b/Jellyfin.Api/Controllers/RemoteImageController.cs @@ -221,7 +221,7 @@ namespace Jellyfin.Api.Controllers await _providerManager.SaveImage(item, imageUrl, type, null, CancellationToken.None) .ConfigureAwait(false); - item.UpdateToRepository(ItemUpdateType.ImageUpdate, CancellationToken.None); + await item.UpdateToRepositoryAsync(ItemUpdateType.ImageUpdate, CancellationToken.None).ConfigureAwait(false); return NoContent(); } diff --git a/Jellyfin.Api/Controllers/VideosController.cs b/Jellyfin.Api/Controllers/VideosController.cs index 14d3f2460..f42810c94 100644 --- a/Jellyfin.Api/Controllers/VideosController.cs +++ b/Jellyfin.Api/Controllers/VideosController.cs @@ -161,7 +161,7 @@ namespace Jellyfin.Api.Controllers [Authorize(Policy = Policies.RequiresElevation)] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] - public ActionResult DeleteAlternateSources([FromRoute] Guid itemId) + public async Task<ActionResult> DeleteAlternateSources([FromRoute] Guid itemId) { var video = (Video)_libraryManager.GetItemById(itemId); @@ -180,12 +180,12 @@ namespace Jellyfin.Api.Controllers link.SetPrimaryVersionId(null); link.LinkedAlternateVersions = Array.Empty<LinkedChild>(); - link.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None); + await link.UpdateToRepositoryAsync(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false); } video.LinkedAlternateVersions = Array.Empty<LinkedChild>(); video.SetPrimaryVersionId(null); - video.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None); + await video.UpdateToRepositoryAsync(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false); return NoContent(); } @@ -201,7 +201,7 @@ namespace Jellyfin.Api.Controllers [Authorize(Policy = Policies.RequiresElevation)] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status400BadRequest)] - public ActionResult MergeVersions([FromQuery, Required] string? itemIds) + public async Task<ActionResult> MergeVersions([FromQuery, Required] string? itemIds) { var items = RequestHelpers.Split(itemIds, ',', true) .Select(i => _libraryManager.GetItemById(i)) @@ -239,7 +239,7 @@ namespace Jellyfin.Api.Controllers { item.SetPrimaryVersionId(primaryVersion.Id.ToString("N", CultureInfo.InvariantCulture)); - item.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None); + await item.UpdateToRepositoryAsync(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false); list.Add(new LinkedChild { @@ -258,12 +258,12 @@ namespace Jellyfin.Api.Controllers if (item.LinkedAlternateVersions.Length > 0) { item.LinkedAlternateVersions = Array.Empty<LinkedChild>(); - item.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None); + await item.UpdateToRepositoryAsync(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false); } } primaryVersion.LinkedAlternateVersions = list.ToArray(); - primaryVersion.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None); + await primaryVersion.UpdateToRepositoryAsync(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false); return NoContent(); } diff --git a/MediaBrowser.Controller/Collections/ICollectionManager.cs b/MediaBrowser.Controller/Collections/ICollectionManager.cs index 701423c0f..3861ae634 100644 --- a/MediaBrowser.Controller/Collections/ICollectionManager.cs +++ b/MediaBrowser.Controller/Collections/ICollectionManager.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Threading.Tasks; using Jellyfin.Data.Entities; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Movies; @@ -27,24 +28,23 @@ namespace MediaBrowser.Controller.Collections /// Creates the collection. /// </summary> /// <param name="options">The options.</param> - BoxSet CreateCollection(CollectionCreationOptions options); + Task<BoxSet> CreateCollectionAsync(CollectionCreationOptions options); /// <summary> /// Adds to collection. /// </summary> /// <param name="collectionId">The collection identifier.</param> /// <param name="itemIds">The item ids.</param> - void AddToCollection(Guid collectionId, IEnumerable<string> itemIds); + /// <returns><see cref="Task"/> representing the asynchronous operation.</returns> + Task AddToCollectionAsync(Guid collectionId, IEnumerable<Guid> itemIds); /// <summary> /// Removes from collection. /// </summary> /// <param name="collectionId">The collection identifier.</param> /// <param name="itemIds">The item ids.</param> - void RemoveFromCollection(Guid collectionId, IEnumerable<string> itemIds); - - void AddToCollection(Guid collectionId, IEnumerable<Guid> itemIds); - void RemoveFromCollection(Guid collectionId, IEnumerable<Guid> itemIds); + /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns> + Task RemoveFromCollectionAsync(Guid collectionId, IEnumerable<Guid> itemIds); /// <summary> /// Collapses the items within box sets. diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index f34309c40..9e595ddc3 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -1390,7 +1390,7 @@ namespace MediaBrowser.Controller.Entities new List<FileSystemMetadata>(); var ownedItemsChanged = await RefreshedOwnedItems(options, files, cancellationToken).ConfigureAwait(false); - LibraryManager.UpdateImages(this); // ensure all image properties in DB are fresh + await LibraryManager.UpdateImagesAsync(this).ConfigureAwait(false); // ensure all image properties in DB are fresh if (ownedItemsChanged) { @@ -2279,7 +2279,7 @@ namespace MediaBrowser.Controller.Entities /// </summary> /// <param name="type">The type.</param> /// <param name="index">The index.</param> - public void DeleteImage(ImageType type, int index) + public async Task DeleteImageAsync(ImageType type, int index) { var info = GetImageInfo(type, index); @@ -2297,7 +2297,7 @@ namespace MediaBrowser.Controller.Entities FileSystem.DeleteFile(info.Path); } - UpdateToRepository(ItemUpdateType.ImageUpdate, CancellationToken.None); + await UpdateToRepositoryAsync(ItemUpdateType.ImageUpdate, CancellationToken.None).ConfigureAwait(false); } public void RemoveImage(ItemImageInfo image) @@ -2310,10 +2310,8 @@ namespace MediaBrowser.Controller.Entities ImageInfos = ImageInfos.Except(deletedImages).ToArray(); } - public virtual void UpdateToRepository(ItemUpdateType updateReason, CancellationToken cancellationToken) - { - LibraryManager.UpdateItem(this, GetParent(), updateReason, cancellationToken); - } + public virtual Task UpdateToRepositoryAsync(ItemUpdateType updateReason, CancellationToken cancellationToken) + => LibraryManager.UpdateItemAsync(this, GetParent(), updateReason, cancellationToken); /// <summary> /// Validates that images within the item are still on the filesystem. @@ -2558,7 +2556,7 @@ namespace MediaBrowser.Controller.Entities return type == ImageType.Backdrop || type == ImageType.Screenshot || type == ImageType.Chapter; } - public void SwapImages(ImageType type, int index1, int index2) + public Task SwapImagesAsync(ImageType type, int index1, int index2) { if (!AllowsMultipleImages(type)) { @@ -2571,13 +2569,13 @@ namespace MediaBrowser.Controller.Entities if (info1 == null || info2 == null) { // Nothing to do - return; + return Task.CompletedTask; } if (!info1.IsLocalFile || !info2.IsLocalFile) { // TODO: Not supported yet - return; + return Task.CompletedTask; } var path1 = info1.Path; @@ -2594,7 +2592,7 @@ namespace MediaBrowser.Controller.Entities info2.Width = 0; info2.Height = 0; - UpdateToRepository(ItemUpdateType.ImageUpdate, CancellationToken.None); + return UpdateToRepositoryAsync(ItemUpdateType.ImageUpdate, CancellationToken.None); } public virtual bool IsPlayed(User user) diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index 6441340f9..11542c1ca 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -350,12 +350,12 @@ namespace MediaBrowser.Controller.Entities if (currentChild.UpdateFromResolvedItem(child) > ItemUpdateType.None) { - currentChild.UpdateToRepository(ItemUpdateType.MetadataImport, cancellationToken); + await currentChild.UpdateToRepositoryAsync(ItemUpdateType.MetadataImport, cancellationToken).ConfigureAwait(false); } else { // metadata is up-to-date; make sure DB has correct images dimensions and hash - LibraryManager.UpdateImages(currentChild); + await LibraryManager.UpdateImagesAsync(currentChild).ConfigureAwait(false); } continue; diff --git a/MediaBrowser.Controller/Entities/Video.cs b/MediaBrowser.Controller/Entities/Video.cs index b7d7e8e1a..eeff78e10 100644 --- a/MediaBrowser.Controller/Entities/Video.cs +++ b/MediaBrowser.Controller/Entities/Video.cs @@ -495,9 +495,10 @@ namespace MediaBrowser.Controller.Entities } } - public override void UpdateToRepository(ItemUpdateType updateReason, CancellationToken cancellationToken) + /// <inheritdoc /> + public override async Task UpdateToRepositoryAsync(ItemUpdateType updateReason, CancellationToken cancellationToken) { - base.UpdateToRepository(updateReason, cancellationToken); + await base.UpdateToRepositoryAsync(updateReason, cancellationToken).ConfigureAwait(false); var localAlternates = GetLocalAlternateVersionIds() .Select(i => LibraryManager.GetItemById(i)) @@ -514,7 +515,7 @@ namespace MediaBrowser.Controller.Entities item.Genres = Genres; item.ProviderIds = ProviderIds; - item.UpdateToRepository(ItemUpdateType.MetadataDownload, cancellationToken); + await item.UpdateToRepositoryAsync(ItemUpdateType.MetadataDownload, cancellationToken).ConfigureAwait(false); } } diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs index 9abcf2b62..d53b1fc8d 100644 --- a/MediaBrowser.Controller/Library/ILibraryManager.cs +++ b/MediaBrowser.Controller/Library/ILibraryManager.cs @@ -72,6 +72,7 @@ namespace MediaBrowser.Controller.Library /// <param name="name">The name.</param> /// <returns>Task{Artist}.</returns> MusicArtist GetArtist(string name); + MusicArtist GetArtist(string name, DtoOptions options); /// <summary> /// Gets a Studio. @@ -124,7 +125,7 @@ namespace MediaBrowser.Controller.Library /// </summary> void QueueLibraryScan(); - void UpdateImages(BaseItem item, bool forceUpdate = false); + Task UpdateImagesAsync(BaseItem item, bool forceUpdate = false); /// <summary> /// Gets the default view. @@ -179,6 +180,7 @@ namespace MediaBrowser.Controller.Library /// <param name="sortOrder">The sort order.</param> /// <returns>IEnumerable{BaseItem}.</returns> IEnumerable<BaseItem> Sort(IEnumerable<BaseItem> items, User user, IEnumerable<string> sortBy, SortOrder sortOrder); + IEnumerable<BaseItem> Sort(IEnumerable<BaseItem> items, User user, IEnumerable<ValueTuple<string, SortOrder>> orderBy); /// <summary> @@ -200,9 +202,16 @@ namespace MediaBrowser.Controller.Library /// <summary> /// Updates the item. /// </summary> - void UpdateItems(IReadOnlyList<BaseItem> items, BaseItem parent, ItemUpdateType updateReason, CancellationToken cancellationToken); + Task UpdateItemsAsync(IReadOnlyList<BaseItem> items, BaseItem parent, ItemUpdateType updateReason, CancellationToken cancellationToken); - void UpdateItem(BaseItem item, BaseItem parent, ItemUpdateType updateReason, CancellationToken cancellationToken); + /// <summary> + /// Updates the item. + /// </summary> + /// <param name="item">The item.</param> + /// <param name="parent">The parent item.</param> + /// <param name="updateReason">The update reason.</param> + /// <param name="cancellationToken">The cancellation token.</param> + Task UpdateItemAsync(BaseItem item, BaseItem parent, ItemUpdateType updateReason, CancellationToken cancellationToken); /// <summary> /// Retrieves the item. @@ -317,7 +326,8 @@ namespace MediaBrowser.Controller.Library /// <param name="name">The name.</param> /// <param name="viewType">Type of the view.</param> /// <param name="sortName">Name of the sort.</param> - UserView GetNamedView(string name, + UserView GetNamedView( + string name, string viewType, string sortName); @@ -329,7 +339,8 @@ namespace MediaBrowser.Controller.Library /// <param name="viewType">Type of the view.</param> /// <param name="sortName">Name of the sort.</param> /// <param name="uniqueId">The unique identifier.</param> - UserView GetNamedView(string name, + UserView GetNamedView( + string name, Guid parentId, string viewType, string sortName, @@ -341,7 +352,8 @@ namespace MediaBrowser.Controller.Library /// <param name="parent">The parent.</param> /// <param name="viewType">Type of the view.</param> /// <param name="sortName">Name of the sort.</param> - UserView GetShadowView(BaseItem parent, + UserView GetShadowView( + BaseItem parent, string viewType, string sortName); @@ -393,7 +405,9 @@ namespace MediaBrowser.Controller.Library /// <param name="fileSystemChildren">The file system children.</param> /// <param name="directoryService">The directory service.</param> /// <returns>IEnumerable<Trailer>.</returns> - IEnumerable<Video> FindTrailers(BaseItem owner, List<FileSystemMetadata> fileSystemChildren, + IEnumerable<Video> FindTrailers( + BaseItem owner, + List<FileSystemMetadata> fileSystemChildren, IDirectoryService directoryService); /// <summary> @@ -403,7 +417,9 @@ namespace MediaBrowser.Controller.Library /// <param name="fileSystemChildren">The file system children.</param> /// <param name="directoryService">The directory service.</param> /// <returns>IEnumerable<Video>.</returns> - IEnumerable<Video> FindExtras(BaseItem owner, List<FileSystemMetadata> fileSystemChildren, + IEnumerable<Video> FindExtras( + BaseItem owner, + List<FileSystemMetadata> fileSystemChildren, IDirectoryService directoryService); /// <summary> @@ -522,16 +538,25 @@ namespace MediaBrowser.Controller.Library Guid GetMusicGenreId(string name); Task AddVirtualFolder(string name, string collectionType, LibraryOptions options, bool refreshLibrary); + Task RemoveVirtualFolder(string name, bool refreshLibrary); + void AddMediaPath(string virtualFolderName, MediaPathInfo path); + void UpdateMediaPath(string virtualFolderName, MediaPathInfo path); + void RemoveMediaPath(string virtualFolderName, string path); QueryResult<(BaseItem, ItemCounts)> GetGenres(InternalItemsQuery query); + QueryResult<(BaseItem, ItemCounts)> GetMusicGenres(InternalItemsQuery query); + QueryResult<(BaseItem, ItemCounts)> GetStudios(InternalItemsQuery query); + QueryResult<(BaseItem, ItemCounts)> GetArtists(InternalItemsQuery query); + QueryResult<(BaseItem, ItemCounts)> GetAlbumArtists(InternalItemsQuery query); + QueryResult<(BaseItem, ItemCounts)> GetAllArtists(InternalItemsQuery query); int GetCount(InternalItemsQuery query); diff --git a/MediaBrowser.Controller/Playlists/IPlaylistManager.cs b/MediaBrowser.Controller/Playlists/IPlaylistManager.cs index 544cd2643..e92abccd1 100644 --- a/MediaBrowser.Controller/Playlists/IPlaylistManager.cs +++ b/MediaBrowser.Controller/Playlists/IPlaylistManager.cs @@ -29,7 +29,7 @@ namespace MediaBrowser.Controller.Playlists /// <param name="itemIds">The item ids.</param> /// <param name="userId">The user identifier.</param> /// <returns>Task.</returns> - void AddToPlaylist(string playlistId, ICollection<Guid> itemIds, Guid userId); + Task AddToPlaylistAsync(string playlistId, ICollection<Guid> itemIds, Guid userId); /// <summary> /// Removes from playlist. @@ -37,7 +37,7 @@ namespace MediaBrowser.Controller.Playlists /// <param name="playlistId">The playlist identifier.</param> /// <param name="entryIds">The entry ids.</param> /// <returns>Task.</returns> - void RemoveFromPlaylist(string playlistId, IEnumerable<string> entryIds); + Task RemoveFromPlaylistAsync(string playlistId, IEnumerable<string> entryIds); /// <summary> /// Gets the playlists folder. @@ -53,6 +53,6 @@ namespace MediaBrowser.Controller.Playlists /// <param name="entryId">The entry identifier.</param> /// <param name="newIndex">The new index.</param> /// <returns>Task.</returns> - void MoveItem(string playlistId, string entryId, int newIndex); + Task MoveItemAsync(string playlistId, string entryId, int newIndex); } } diff --git a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs index 3c19109a7..c8bf5557b 100644 --- a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs +++ b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Globalization; using System.Linq; using System.Text.RegularExpressions; using Microsoft.Extensions.Logging; @@ -258,8 +259,8 @@ namespace MediaBrowser.MediaEncoding.Encoder RegexOptions.Multiline)) { var version = new Version( - int.Parse(match.Groups["major"].Value), - int.Parse(match.Groups["minor"].Value)); + int.Parse(match.Groups["major"].Value, CultureInfo.InvariantCulture), + int.Parse(match.Groups["minor"].Value, CultureInfo.InvariantCulture)); map.Add(match.Groups["name"].Value, version); } diff --git a/MediaBrowser.Providers/Manager/MetadataService.cs b/MediaBrowser.Providers/Manager/MetadataService.cs index dcae300fc..d0de58427 100644 --- a/MediaBrowser.Providers/Manager/MetadataService.cs +++ b/MediaBrowser.Providers/Manager/MetadataService.cs @@ -212,7 +212,7 @@ namespace MediaBrowser.Providers.Manager await SavePeopleMetadataAsync(result.People, libraryOptions, cancellationToken).ConfigureAwait(false); } - result.Item.UpdateToRepository(reason, cancellationToken); + await result.Item.UpdateToRepositoryAsync(reason, cancellationToken).ConfigureAwait(false); } private async Task SavePeopleMetadataAsync(List<PersonInfo> people, LibraryOptions libraryOptions, CancellationToken cancellationToken) @@ -246,7 +246,7 @@ namespace MediaBrowser.Providers.Manager if (saveEntity) { - personEntity.UpdateToRepository(updateType, cancellationToken); + await personEntity.UpdateToRepositoryAsync(updateType, cancellationToken).ConfigureAwait(false); } } } diff --git a/MediaBrowser.Providers/TV/DummySeasonProvider.cs b/MediaBrowser.Providers/TV/DummySeasonProvider.cs index df09d13dd..0c09cdef6 100644 --- a/MediaBrowser.Providers/TV/DummySeasonProvider.cs +++ b/MediaBrowser.Providers/TV/DummySeasonProvider.cs @@ -87,7 +87,7 @@ namespace MediaBrowser.Providers.TV else if (existingSeason.IsVirtualItem) { existingSeason.IsVirtualItem = false; - existingSeason.UpdateToRepository(ItemUpdateType.MetadataEdit, cancellationToken); + await existingSeason.UpdateToRepositoryAsync(ItemUpdateType.MetadataEdit, cancellationToken).ConfigureAwait(false); seasons = null; } } @@ -113,7 +113,7 @@ namespace MediaBrowser.Providers.TV else if (existingSeason.IsVirtualItem) { existingSeason.IsVirtualItem = false; - existingSeason.UpdateToRepository(ItemUpdateType.MetadataEdit, cancellationToken); + await existingSeason.UpdateToRepositoryAsync(ItemUpdateType.MetadataEdit, cancellationToken).ConfigureAwait(false); seasons = null; } } -- cgit v1.2.3 From 2b832de2898d465ba2a3c154c7fa3ead814b5021 Mon Sep 17 00:00:00 2001 From: Bond_009 <bond.009@outlook.com> Date: Fri, 21 Aug 2020 22:19:16 +0200 Subject: Fix build --- Emby.Server.Implementations/Playlists/PlaylistManager.cs | 8 ++++---- Jellyfin.Api/Controllers/PlaylistsController.cs | 4 ++-- MediaBrowser.Controller/Playlists/IPlaylistManager.cs | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/Playlists/PlaylistManager.cs b/Emby.Server.Implementations/Playlists/PlaylistManager.cs index d35223b0a..d3b64fb31 100644 --- a/Emby.Server.Implementations/Playlists/PlaylistManager.cs +++ b/Emby.Server.Implementations/Playlists/PlaylistManager.cs @@ -152,10 +152,10 @@ namespace Emby.Server.Implementations.Playlists if (options.ItemIdList.Length > 0) { - AddToPlaylistInternal(playlist.Id.ToString("N", CultureInfo.InvariantCulture), options.ItemIdList, user, new DtoOptions(false) + await AddToPlaylistInternal(playlist.Id, options.ItemIdList, user, new DtoOptions(false) { EnableImages = true - }); + }).ConfigureAwait(false); } return new PlaylistCreationResult(playlist.Id.ToString("N", CultureInfo.InvariantCulture)); @@ -184,7 +184,7 @@ namespace Emby.Server.Implementations.Playlists return Playlist.GetPlaylistItems(playlistMediaType, items, user, options); } - public Task AddToPlaylistAsync(string playlistId, ICollection<Guid> itemIds, Guid userId) + public Task AddToPlaylistAsync(Guid playlistId, ICollection<Guid> itemIds, Guid userId) { var user = userId.Equals(Guid.Empty) ? null : _userManager.GetUserById(userId); @@ -194,7 +194,7 @@ namespace Emby.Server.Implementations.Playlists }); } - private async Task AddToPlaylistInternal(string playlistId, ICollection<Guid> newItemIds, User user, DtoOptions options) + private async Task AddToPlaylistInternal(Guid playlistId, ICollection<Guid> newItemIds, User user, DtoOptions options) { // Retrieve the existing playlist var playlist = _libraryManager.GetItemById(playlistId) as Playlist diff --git a/Jellyfin.Api/Controllers/PlaylistsController.cs b/Jellyfin.Api/Controllers/PlaylistsController.cs index d69228c33..31c4f228d 100644 --- a/Jellyfin.Api/Controllers/PlaylistsController.cs +++ b/Jellyfin.Api/Controllers/PlaylistsController.cs @@ -84,11 +84,11 @@ namespace Jellyfin.Api.Controllers [HttpPost("{playlistId}/Items")] [ProducesResponseType(StatusCodes.Status204NoContent)] public async Task<ActionResult> AddToPlaylist( - [FromRoute] string? playlistId, + [FromRoute] Guid? playlistId, [FromQuery] string? ids, [FromQuery] Guid? userId) { - await _playlistManager.AddToPlaylistAsync(playlistId, RequestHelpers.GetGuids(ids), userId ?? Guid.Empty).ConfigureAwait(false); + await _playlistManager.AddToPlaylistAsync(playlistId ?? Guid.Empty, RequestHelpers.GetGuids(ids), userId ?? Guid.Empty).ConfigureAwait(false); return NoContent(); } diff --git a/MediaBrowser.Controller/Playlists/IPlaylistManager.cs b/MediaBrowser.Controller/Playlists/IPlaylistManager.cs index e92abccd1..a3e7d4a67 100644 --- a/MediaBrowser.Controller/Playlists/IPlaylistManager.cs +++ b/MediaBrowser.Controller/Playlists/IPlaylistManager.cs @@ -29,7 +29,7 @@ namespace MediaBrowser.Controller.Playlists /// <param name="itemIds">The item ids.</param> /// <param name="userId">The user identifier.</param> /// <returns>Task.</returns> - Task AddToPlaylistAsync(string playlistId, ICollection<Guid> itemIds, Guid userId); + Task AddToPlaylistAsync(Guid playlistId, ICollection<Guid> itemIds, Guid userId); /// <summary> /// Removes from playlist. -- cgit v1.2.3 From 404bb4f83521760b3e9eeb748ab21d9056c4c023 Mon Sep 17 00:00:00 2001 From: Bond_009 <bond.009@outlook.com> Date: Sat, 22 Aug 2020 21:56:24 +0200 Subject: Enable TreatWarningsAsErrors for MediaBrowser.Controller in Release --- .../Authentication/AuthenticationResult.cs | 1 + .../Authentication/IAuthenticationProvider.cs | 4 ++++ .../Authentication/IPasswordResetProvider.cs | 3 +++ MediaBrowser.Controller/Channels/Channel.cs | 2 ++ MediaBrowser.Controller/Channels/ChannelItemInfo.cs | 2 ++ MediaBrowser.Controller/Channels/ChannelItemResult.cs | 2 ++ MediaBrowser.Controller/Channels/ChannelItemType.cs | 2 ++ .../Channels/ChannelParentalRating.cs | 2 ++ MediaBrowser.Controller/Channels/ChannelSearchInfo.cs | 2 ++ MediaBrowser.Controller/Channels/IChannel.cs | 2 ++ MediaBrowser.Controller/Channels/IChannelManager.cs | 3 +++ MediaBrowser.Controller/Channels/IHasCacheKey.cs | 2 ++ .../Channels/IRequiresMediaInfoCallback.cs | 2 ++ MediaBrowser.Controller/Channels/ISearchableChannel.cs | 3 +++ .../Channels/InternalChannelFeatures.cs | 18 ++++++++++-------- .../Channels/InternalChannelItemQuery.cs | 3 ++- .../Collections/CollectionCreationOptions.cs | 16 +++++++++------- .../Collections/CollectionEvents.cs | 2 ++ .../Collections/ICollectionManager.cs | 2 ++ MediaBrowser.Controller/Devices/IDeviceManager.cs | 6 +++++- MediaBrowser.Controller/Dlna/IDlnaManager.cs | 2 ++ MediaBrowser.Controller/Drawing/IImageEncoder.cs | 2 ++ MediaBrowser.Controller/Drawing/IImageProcessor.cs | 2 ++ MediaBrowser.Controller/Drawing/ImageCollageOptions.cs | 5 +++++ MediaBrowser.Controller/Drawing/ImageHelper.cs | 2 ++ .../Drawing/ImageProcessingOptions.cs | 2 ++ .../Drawing/ImageProcessorExtensions.cs | 2 ++ MediaBrowser.Controller/Drawing/ImageStream.cs | 3 +++ MediaBrowser.Controller/Dto/DtoOptions.cs | 2 ++ MediaBrowser.Controller/Entities/AggregateFolder.cs | 3 +++ MediaBrowser.Controller/Entities/Audio/Audio.cs | 2 ++ .../Entities/Audio/IHasAlbumArtist.cs | 2 ++ .../Entities/Audio/IHasMusicGenres.cs | 2 ++ MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs | 2 ++ MediaBrowser.Controller/Entities/Audio/MusicArtist.cs | 2 ++ MediaBrowser.Controller/Entities/Audio/MusicGenre.cs | 2 ++ MediaBrowser.Controller/Entities/AudioBook.cs | 4 ++++ MediaBrowser.Controller/Entities/BaseItem.cs | 2 ++ MediaBrowser.Controller/Entities/BaseItemExtensions.cs | 2 ++ MediaBrowser.Controller/Entities/BasePluginFolder.cs | 10 ++-------- MediaBrowser.Controller/Entities/Book.cs | 4 ++++ MediaBrowser.Controller/Entities/CollectionFolder.cs | 2 ++ MediaBrowser.Controller/Entities/Folder.cs | 2 ++ MediaBrowser.Controller/Entities/Genre.cs | 2 ++ MediaBrowser.Controller/Entities/ICollectionFolder.cs | 2 ++ MediaBrowser.Controller/Entities/IHasMediaSources.cs | 12 +++++++++--- .../Entities/IHasProgramAttributes.cs | 2 ++ MediaBrowser.Controller/Entities/IHasSeries.cs | 9 +++++++-- MediaBrowser.Controller/Entities/IHasStartDate.cs | 2 ++ MediaBrowser.Controller/Entities/IHasTrailers.cs | 2 ++ MediaBrowser.Controller/Entities/IItemByName.cs | 2 ++ MediaBrowser.Controller/Entities/IMetadataContainer.cs | 2 ++ .../Entities/ISupportsPlaceHolders.cs | 2 ++ MediaBrowser.Controller/Entities/InternalItemsQuery.cs | 2 ++ .../Entities/InternalPeopleQuery.cs | 2 ++ MediaBrowser.Controller/Entities/ItemImageInfo.cs | 2 ++ MediaBrowser.Controller/Entities/LinkedChild.cs | 2 ++ MediaBrowser.Controller/Entities/Movies/BoxSet.cs | 2 ++ MediaBrowser.Controller/Entities/MusicVideo.cs | 2 ++ MediaBrowser.Controller/Entities/PeopleHelper.cs | 2 ++ MediaBrowser.Controller/Entities/Person.cs | 2 ++ MediaBrowser.Controller/Entities/PersonInfo.cs | 2 ++ MediaBrowser.Controller/Entities/Photo.cs | 2 ++ MediaBrowser.Controller/Entities/PhotoAlbum.cs | 2 ++ MediaBrowser.Controller/Entities/Share.cs | 2 ++ MediaBrowser.Controller/Entities/SourceType.cs | 2 ++ MediaBrowser.Controller/Entities/Studio.cs | 2 ++ MediaBrowser.Controller/Entities/TV/Episode.cs | 2 ++ MediaBrowser.Controller/Entities/TV/Season.cs | 2 ++ MediaBrowser.Controller/Entities/TV/Series.cs | 2 ++ MediaBrowser.Controller/Entities/TagExtensions.cs | 2 ++ MediaBrowser.Controller/Entities/Trailer.cs | 2 ++ MediaBrowser.Controller/Entities/UserItemData.cs | 5 +++++ MediaBrowser.Controller/Entities/UserRootFolder.cs | 2 ++ MediaBrowser.Controller/Entities/UserView.cs | 3 ++- MediaBrowser.Controller/Entities/Video.cs | 2 ++ MediaBrowser.Controller/Entities/Year.cs | 2 ++ MediaBrowser.Controller/Extensions/StringExtensions.cs | 2 ++ MediaBrowser.Controller/IDisplayPreferencesManager.cs | 2 +- MediaBrowser.Controller/IO/FileData.cs | 15 ++------------- MediaBrowser.Controller/IResourceFileManager.cs | 2 ++ MediaBrowser.Controller/IServerApplicationHost.cs | 2 ++ MediaBrowser.Controller/IServerApplicationPaths.cs | 6 ++++++ MediaBrowser.Controller/Library/DeleteOptions.cs | 2 ++ MediaBrowser.Controller/Library/ILibraryManager.cs | 3 +++ MediaBrowser.Controller/Library/ILibraryMonitor.cs | 2 ++ MediaBrowser.Controller/Library/ILiveStream.cs | 8 ++++++-- MediaBrowser.Controller/Library/IMediaSourceManager.cs | 2 ++ MediaBrowser.Controller/Library/IMetadataFileSaver.cs | 2 ++ MediaBrowser.Controller/Library/IMusicManager.cs | 2 ++ MediaBrowser.Controller/Library/IUserDataManager.cs | 3 +++ MediaBrowser.Controller/Library/IUserManager.cs | 2 ++ MediaBrowser.Controller/Library/IUserViewManager.cs | 3 +++ MediaBrowser.Controller/Library/IntroInfo.cs | 2 ++ MediaBrowser.Controller/Library/ItemChangeEventArgs.cs | 2 ++ MediaBrowser.Controller/Library/ItemResolveArgs.cs | 2 ++ MediaBrowser.Controller/Library/ItemUpdateType.cs | 2 ++ .../Library/LibraryManagerExtensions.cs | 2 ++ .../Library/MetadataConfigurationStore.cs | 2 ++ MediaBrowser.Controller/Library/NameExtensions.cs | 2 ++ .../Library/PlaybackProgressEventArgs.cs | 12 +++++++----- .../Library/PlaybackStopEventArgs.cs | 2 ++ .../Library/UserDataSaveEventArgs.cs | 2 ++ MediaBrowser.Controller/LiveTv/ChannelInfo.cs | 2 ++ MediaBrowser.Controller/LiveTv/IListingsProvider.cs | 2 ++ MediaBrowser.Controller/LiveTv/ILiveTvManager.cs | 3 +++ MediaBrowser.Controller/LiveTv/ILiveTvService.cs | 2 ++ MediaBrowser.Controller/LiveTv/ITunerHost.cs | 16 ++++++++++++---- MediaBrowser.Controller/LiveTv/LiveTvChannel.cs | 2 ++ .../LiveTv/LiveTvConflictException.cs | 2 ++ MediaBrowser.Controller/LiveTv/LiveTvProgram.cs | 2 ++ .../LiveTv/LiveTvServiceStatusInfo.cs | 14 ++++++++------ MediaBrowser.Controller/LiveTv/LiveTvTunerInfo.cs | 12 +++++++----- MediaBrowser.Controller/LiveTv/ProgramInfo.cs | 2 ++ MediaBrowser.Controller/LiveTv/RecordingInfo.cs | 2 ++ .../LiveTv/RecordingStatusChangedEventArgs.cs | 2 ++ MediaBrowser.Controller/LiveTv/SeriesTimerInfo.cs | 2 ++ MediaBrowser.Controller/LiveTv/TimerInfo.cs | 2 ++ MediaBrowser.Controller/LiveTv/TunerChannelMapping.cs | 2 ++ MediaBrowser.Controller/MediaBrowser.Controller.csproj | 1 + .../MediaEncoding/EncodingHelper.cs | 2 ++ .../MediaEncoding/EncodingJobInfo.cs | 2 ++ .../MediaEncoding/EncodingJobOptions.cs | 2 ++ .../MediaEncoding/IAttachmentExtractor.cs | 2 ++ MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs | 2 ++ .../MediaEncoding/ISubtitleEncoder.cs | 6 +++++- .../MediaEncoding/ImageEncodingOptions.cs | 2 ++ MediaBrowser.Controller/MediaEncoding/JobLogger.cs | 2 ++ .../MediaEncoding/MediaEncoderHelpers.cs | 2 ++ .../MediaEncoding/MediaInfoRequest.cs | 2 ++ MediaBrowser.Controller/Net/AuthenticatedAttribute.cs | 6 ++++-- MediaBrowser.Controller/Net/AuthorizationInfo.cs | 2 ++ .../Net/BasePeriodicWebSocketListener.cs | 2 ++ MediaBrowser.Controller/Net/IHttpResultFactory.cs | 4 ++++ MediaBrowser.Controller/Net/ISessionContext.cs | 4 ++++ MediaBrowser.Controller/Net/IWebSocketConnection.cs | 2 ++ MediaBrowser.Controller/Net/SecurityException.cs | 2 ++ MediaBrowser.Controller/Net/StaticResultOptions.cs | 2 ++ .../Notifications/INotificationManager.cs | 2 ++ .../Notifications/INotificationService.cs | 2 ++ .../Notifications/INotificationTypeFactory.cs | 2 ++ .../Notifications/UserNotification.cs | 2 ++ MediaBrowser.Controller/Persistence/IItemRepository.cs | 10 ++++++++++ .../Persistence/IUserDataRepository.cs | 8 +++++++- .../Persistence/MediaAttachmentQuery.cs | 2 ++ .../Persistence/MediaStreamQuery.cs | 2 ++ MediaBrowser.Controller/Playlists/IPlaylistManager.cs | 2 ++ MediaBrowser.Controller/Playlists/Playlist.cs | 2 ++ MediaBrowser.Controller/Plugins/ILocalizablePlugin.cs | 2 ++ .../Plugins/IPluginConfigurationPage.cs | 1 + MediaBrowser.Controller/Providers/AlbumInfo.cs | 2 ++ MediaBrowser.Controller/Providers/ArtistInfo.cs | 2 ++ MediaBrowser.Controller/Providers/BookInfo.cs | 2 ++ MediaBrowser.Controller/Providers/BoxSetInfo.cs | 2 ++ MediaBrowser.Controller/Providers/DirectoryService.cs | 2 ++ .../Providers/DynamicImageResponse.cs | 2 ++ MediaBrowser.Controller/Providers/EpisodeInfo.cs | 2 ++ .../Providers/ICustomMetadataProvider.cs | 2 ++ MediaBrowser.Controller/Providers/IDirectoryService.cs | 2 ++ .../Providers/IDynamicImageProvider.cs | 2 ++ .../Providers/IHasItemChangeMonitor.cs | 2 ++ MediaBrowser.Controller/Providers/IHasLookupInfo.cs | 2 ++ MediaBrowser.Controller/Providers/IHasOrder.cs | 2 ++ .../Providers/ILocalImageProvider.cs | 2 ++ .../Providers/ILocalMetadataProvider.cs | 2 ++ MediaBrowser.Controller/Providers/IMetadataProvider.cs | 2 ++ MediaBrowser.Controller/Providers/IMetadataService.cs | 2 ++ .../Providers/IPreRefreshProvider.cs | 2 ++ MediaBrowser.Controller/Providers/IProviderManager.cs | 2 ++ .../Providers/IRemoteMetadataProvider.cs | 2 ++ .../Providers/IRemoteSearchProvider.cs | 2 ++ .../Providers/ImageRefreshOptions.cs | 2 ++ MediaBrowser.Controller/Providers/ItemInfo.cs | 2 ++ MediaBrowser.Controller/Providers/ItemLookupInfo.cs | 2 ++ MediaBrowser.Controller/Providers/LocalImageInfo.cs | 2 ++ .../Providers/MetadataRefreshMode.cs | 2 ++ .../Providers/MetadataRefreshOptions.cs | 2 ++ MediaBrowser.Controller/Providers/MetadataResult.cs | 2 ++ MediaBrowser.Controller/Providers/MovieInfo.cs | 2 ++ MediaBrowser.Controller/Providers/MusicVideoInfo.cs | 2 ++ MediaBrowser.Controller/Providers/PersonLookupInfo.cs | 2 ++ MediaBrowser.Controller/Providers/RemoteSearchQuery.cs | 2 ++ MediaBrowser.Controller/Providers/SeasonInfo.cs | 2 ++ MediaBrowser.Controller/Providers/SeriesInfo.cs | 2 ++ MediaBrowser.Controller/Providers/SongInfo.cs | 2 ++ MediaBrowser.Controller/Providers/TrailerInfo.cs | 2 ++ MediaBrowser.Controller/Resolvers/IItemResolver.cs | 2 ++ MediaBrowser.Controller/Resolvers/ResolverPriority.cs | 7 +++++++ MediaBrowser.Controller/Security/AuthenticationInfo.cs | 2 ++ .../Security/AuthenticationInfoQuery.cs | 2 ++ .../Security/IAuthenticationRepository.cs | 3 +++ .../Session/AuthenticationRequest.cs | 2 ++ MediaBrowser.Controller/Session/ISessionController.cs | 2 ++ MediaBrowser.Controller/Session/ISessionManager.cs | 2 ++ MediaBrowser.Controller/Session/SessionEventArgs.cs | 2 ++ MediaBrowser.Controller/Session/SessionInfo.cs | 2 ++ MediaBrowser.Controller/Sorting/AlphanumComparator.cs | 4 +++- MediaBrowser.Controller/Sorting/SortExtensions.cs | 3 +++ MediaBrowser.Controller/Subtitles/ISubtitleManager.cs | 2 ++ MediaBrowser.Controller/Subtitles/ISubtitleProvider.cs | 2 ++ .../Subtitles/SubtitleDownloadEventArgs.cs | 2 ++ MediaBrowser.Controller/Subtitles/SubtitleResponse.cs | 2 ++ .../Subtitles/SubtitleSearchRequest.cs | 2 ++ MediaBrowser.Controller/Sync/IHasDynamicAccess.cs | 2 ++ MediaBrowser.Controller/Sync/IServerSyncProvider.cs | 2 ++ MediaBrowser.Controller/Sync/ISyncProvider.cs | 2 ++ MediaBrowser.Controller/Sync/SyncedFileInfo.cs | 15 ++++++++++----- .../SyncPlay/ISyncPlayController.cs | 2 +- MediaBrowser.Controller/TV/ITVSeriesManager.cs | 2 ++ 209 files changed, 536 insertions(+), 78 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/Authentication/AuthenticationResult.cs b/MediaBrowser.Controller/Authentication/AuthenticationResult.cs index 4249a9a66..bdebd76ab 100644 --- a/MediaBrowser.Controller/Authentication/AuthenticationResult.cs +++ b/MediaBrowser.Controller/Authentication/AuthenticationResult.cs @@ -1,5 +1,6 @@ #pragma warning disable CS1591 + using MediaBrowser.Controller.Session; using MediaBrowser.Model.Dto; diff --git a/MediaBrowser.Controller/Authentication/IAuthenticationProvider.cs b/MediaBrowser.Controller/Authentication/IAuthenticationProvider.cs index 15c902777..ecdffa2eb 100644 --- a/MediaBrowser.Controller/Authentication/IAuthenticationProvider.cs +++ b/MediaBrowser.Controller/Authentication/IAuthenticationProvider.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System.Threading.Tasks; using Jellyfin.Data.Entities; using MediaBrowser.Model.Users; @@ -11,7 +13,9 @@ namespace MediaBrowser.Controller.Authentication bool IsEnabled { get; } Task<ProviderAuthenticationResult> Authenticate(string username, string password); + bool HasPassword(User user); + Task ChangePassword(User user, string newPassword); } diff --git a/MediaBrowser.Controller/Authentication/IPasswordResetProvider.cs b/MediaBrowser.Controller/Authentication/IPasswordResetProvider.cs index 693df80ac..6729b9115 100644 --- a/MediaBrowser.Controller/Authentication/IPasswordResetProvider.cs +++ b/MediaBrowser.Controller/Authentication/IPasswordResetProvider.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Threading.Tasks; using Jellyfin.Data.Entities; @@ -12,6 +14,7 @@ namespace MediaBrowser.Controller.Authentication bool IsEnabled { get; } Task<ForgotPasswordResult> StartForgotPasswordProcess(User user, bool isInNetwork); + Task<PinRedeemResult> RedeemPasswordResetPin(string pin); } diff --git a/MediaBrowser.Controller/Channels/Channel.cs b/MediaBrowser.Controller/Channels/Channel.cs index dbb047804..129cdb519 100644 --- a/MediaBrowser.Controller/Channels/Channel.cs +++ b/MediaBrowser.Controller/Channels/Channel.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Globalization; using System.Linq; diff --git a/MediaBrowser.Controller/Channels/ChannelItemInfo.cs b/MediaBrowser.Controller/Channels/ChannelItemInfo.cs index 00d4d9cb3..476992cbd 100644 --- a/MediaBrowser.Controller/Channels/ChannelItemInfo.cs +++ b/MediaBrowser.Controller/Channels/ChannelItemInfo.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using MediaBrowser.Controller.Entities; diff --git a/MediaBrowser.Controller/Channels/ChannelItemResult.cs b/MediaBrowser.Controller/Channels/ChannelItemResult.cs index c194c8e48..cee7b2003 100644 --- a/MediaBrowser.Controller/Channels/ChannelItemResult.cs +++ b/MediaBrowser.Controller/Channels/ChannelItemResult.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System.Collections.Generic; namespace MediaBrowser.Controller.Channels diff --git a/MediaBrowser.Controller/Channels/ChannelItemType.cs b/MediaBrowser.Controller/Channels/ChannelItemType.cs index 833ae75fe..3ce920e23 100644 --- a/MediaBrowser.Controller/Channels/ChannelItemType.cs +++ b/MediaBrowser.Controller/Channels/ChannelItemType.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + namespace MediaBrowser.Controller.Channels { public enum ChannelItemType diff --git a/MediaBrowser.Controller/Channels/ChannelParentalRating.cs b/MediaBrowser.Controller/Channels/ChannelParentalRating.cs index 1d189446d..f77d81c16 100644 --- a/MediaBrowser.Controller/Channels/ChannelParentalRating.cs +++ b/MediaBrowser.Controller/Channels/ChannelParentalRating.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + namespace MediaBrowser.Controller.Channels { public enum ChannelParentalRating diff --git a/MediaBrowser.Controller/Channels/ChannelSearchInfo.cs b/MediaBrowser.Controller/Channels/ChannelSearchInfo.cs index c02055b90..32469d4d7 100644 --- a/MediaBrowser.Controller/Channels/ChannelSearchInfo.cs +++ b/MediaBrowser.Controller/Channels/ChannelSearchInfo.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + namespace MediaBrowser.Controller.Channels { public class ChannelSearchInfo diff --git a/MediaBrowser.Controller/Channels/IChannel.cs b/MediaBrowser.Controller/Channels/IChannel.cs index c44e20d1a..2c0eadf95 100644 --- a/MediaBrowser.Controller/Channels/IChannel.cs +++ b/MediaBrowser.Controller/Channels/IChannel.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; diff --git a/MediaBrowser.Controller/Channels/IChannelManager.cs b/MediaBrowser.Controller/Channels/IChannelManager.cs index df508fbe2..9a9d22d33 100644 --- a/MediaBrowser.Controller/Channels/IChannelManager.cs +++ b/MediaBrowser.Controller/Channels/IChannelManager.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using System.Threading; @@ -31,6 +33,7 @@ namespace MediaBrowser.Controller.Channels ChannelFeatures[] GetAllChannelFeatures(); bool EnableMediaSourceDisplay(BaseItem item); + bool CanDelete(BaseItem item); Task DeleteItem(BaseItem item); diff --git a/MediaBrowser.Controller/Channels/IHasCacheKey.cs b/MediaBrowser.Controller/Channels/IHasCacheKey.cs index d86ad0dba..bf895a0ec 100644 --- a/MediaBrowser.Controller/Channels/IHasCacheKey.cs +++ b/MediaBrowser.Controller/Channels/IHasCacheKey.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + namespace MediaBrowser.Controller.Channels { public interface IHasCacheKey diff --git a/MediaBrowser.Controller/Channels/IRequiresMediaInfoCallback.cs b/MediaBrowser.Controller/Channels/IRequiresMediaInfoCallback.cs index deee46ff7..589295543 100644 --- a/MediaBrowser.Controller/Channels/IRequiresMediaInfoCallback.cs +++ b/MediaBrowser.Controller/Channels/IRequiresMediaInfoCallback.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; diff --git a/MediaBrowser.Controller/Channels/ISearchableChannel.cs b/MediaBrowser.Controller/Channels/ISearchableChannel.cs index 48043ad7a..b627ca1c2 100644 --- a/MediaBrowser.Controller/Channels/ISearchableChannel.cs +++ b/MediaBrowser.Controller/Channels/ISearchableChannel.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; @@ -30,6 +32,7 @@ namespace MediaBrowser.Controller.Channels public interface ISupportsDelete { bool CanDelete(BaseItem item); + Task DeleteItem(string id, CancellationToken cancellationToken); } diff --git a/MediaBrowser.Controller/Channels/InternalChannelFeatures.cs b/MediaBrowser.Controller/Channels/InternalChannelFeatures.cs index 1f4a26064..1074ce435 100644 --- a/MediaBrowser.Controller/Channels/InternalChannelFeatures.cs +++ b/MediaBrowser.Controller/Channels/InternalChannelFeatures.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System.Collections.Generic; using MediaBrowser.Model.Channels; @@ -5,6 +7,14 @@ namespace MediaBrowser.Controller.Channels { public class InternalChannelFeatures { + public InternalChannelFeatures() + { + MediaTypes = new List<ChannelMediaType>(); + ContentTypes = new List<ChannelMediaContentType>(); + + DefaultSortFields = new List<ChannelItemSortField>(); + } + /// <summary> /// Gets or sets the media types. /// </summary> @@ -48,13 +58,5 @@ namespace MediaBrowser.Controller.Channels /// </summary> /// <value><c>true</c> if [supports downloading]; otherwise, <c>false</c>.</value> public bool SupportsContentDownloading { get; set; } - - public InternalChannelFeatures() - { - MediaTypes = new List<ChannelMediaType>(); - ContentTypes = new List<ChannelMediaContentType>(); - - DefaultSortFields = new List<ChannelItemSortField>(); - } } } diff --git a/MediaBrowser.Controller/Channels/InternalChannelItemQuery.cs b/MediaBrowser.Controller/Channels/InternalChannelItemQuery.cs index 6d5ca75af..7e9bb28ed 100644 --- a/MediaBrowser.Controller/Channels/InternalChannelItemQuery.cs +++ b/MediaBrowser.Controller/Channels/InternalChannelItemQuery.cs @@ -1,7 +1,8 @@ +#pragma warning disable CS1591 + using System; using MediaBrowser.Model.Channels; - namespace MediaBrowser.Controller.Channels { public class InternalChannelItemQuery diff --git a/MediaBrowser.Controller/Collections/CollectionCreationOptions.cs b/MediaBrowser.Controller/Collections/CollectionCreationOptions.cs index 1e7549d2b..f6037d05e 100644 --- a/MediaBrowser.Controller/Collections/CollectionCreationOptions.cs +++ b/MediaBrowser.Controller/Collections/CollectionCreationOptions.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using MediaBrowser.Model.Entities; @@ -6,6 +8,13 @@ namespace MediaBrowser.Controller.Collections { public class CollectionCreationOptions : IHasProviderIds { + public CollectionCreationOptions() + { + ProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); + ItemIdList = Array.Empty<string>(); + UserIds = Array.Empty<Guid>(); + } + public string Name { get; set; } public Guid? ParentId { get; set; } @@ -17,12 +26,5 @@ namespace MediaBrowser.Controller.Collections public string[] ItemIdList { get; set; } public Guid[] UserIds { get; set; } - - public CollectionCreationOptions() - { - ProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); - ItemIdList = Array.Empty<string>(); - UserIds = Array.Empty<Guid>(); - } } } diff --git a/MediaBrowser.Controller/Collections/CollectionEvents.cs b/MediaBrowser.Controller/Collections/CollectionEvents.cs index bfc6af463..ce59b4ada 100644 --- a/MediaBrowser.Controller/Collections/CollectionEvents.cs +++ b/MediaBrowser.Controller/Collections/CollectionEvents.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using MediaBrowser.Controller.Entities; diff --git a/MediaBrowser.Controller/Collections/ICollectionManager.cs b/MediaBrowser.Controller/Collections/ICollectionManager.cs index 3861ae634..a6991e2ea 100644 --- a/MediaBrowser.Controller/Collections/ICollectionManager.cs +++ b/MediaBrowser.Controller/Collections/ICollectionManager.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using System.Threading.Tasks; diff --git a/MediaBrowser.Controller/Devices/IDeviceManager.cs b/MediaBrowser.Controller/Devices/IDeviceManager.cs index 7d279230b..55e022f15 100644 --- a/MediaBrowser.Controller/Devices/IDeviceManager.cs +++ b/MediaBrowser.Controller/Devices/IDeviceManager.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using Jellyfin.Data.Entities; using MediaBrowser.Model.Devices; @@ -9,6 +11,8 @@ namespace MediaBrowser.Controller.Devices { public interface IDeviceManager { + event EventHandler<GenericEventArgs<Tuple<string, DeviceOptions>>> DeviceOptionsUpdated; + /// <summary> /// Saves the capabilities. /// </summary> @@ -44,7 +48,7 @@ namespace MediaBrowser.Controller.Devices bool CanAccessDevice(User user, string deviceId); void UpdateDeviceOptions(string deviceId, DeviceOptions options); + DeviceOptions GetDeviceOptions(string deviceId); - event EventHandler<GenericEventArgs<Tuple<string, DeviceOptions>>> DeviceOptionsUpdated; } } diff --git a/MediaBrowser.Controller/Dlna/IDlnaManager.cs b/MediaBrowser.Controller/Dlna/IDlnaManager.cs index 41a7686a3..dc2d5a356 100644 --- a/MediaBrowser.Controller/Dlna/IDlnaManager.cs +++ b/MediaBrowser.Controller/Dlna/IDlnaManager.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System.Collections.Generic; using MediaBrowser.Controller.Drawing; using MediaBrowser.Model.Dlna; diff --git a/MediaBrowser.Controller/Drawing/IImageEncoder.cs b/MediaBrowser.Controller/Drawing/IImageEncoder.cs index e09ccd204..f9b2e6fef 100644 --- a/MediaBrowser.Controller/Drawing/IImageEncoder.cs +++ b/MediaBrowser.Controller/Drawing/IImageEncoder.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using MediaBrowser.Model.Drawing; diff --git a/MediaBrowser.Controller/Drawing/IImageProcessor.cs b/MediaBrowser.Controller/Drawing/IImageProcessor.cs index 69d799165..b7edb1052 100644 --- a/MediaBrowser.Controller/Drawing/IImageProcessor.cs +++ b/MediaBrowser.Controller/Drawing/IImageProcessor.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using System.IO; diff --git a/MediaBrowser.Controller/Drawing/ImageCollageOptions.cs b/MediaBrowser.Controller/Drawing/ImageCollageOptions.cs index 3f762fad0..fe0465d0d 100644 --- a/MediaBrowser.Controller/Drawing/ImageCollageOptions.cs +++ b/MediaBrowser.Controller/Drawing/ImageCollageOptions.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + namespace MediaBrowser.Controller.Drawing { public class ImageCollageOptions @@ -7,16 +9,19 @@ namespace MediaBrowser.Controller.Drawing /// </summary> /// <value>The input paths.</value> public string[] InputPaths { get; set; } + /// <summary> /// Gets or sets the output path. /// </summary> /// <value>The output path.</value> public string OutputPath { get; set; } + /// <summary> /// Gets or sets the width. /// </summary> /// <value>The width.</value> public int Width { get; set; } + /// <summary> /// Gets or sets the height. /// </summary> diff --git a/MediaBrowser.Controller/Drawing/ImageHelper.cs b/MediaBrowser.Controller/Drawing/ImageHelper.cs index e1273fe7f..87c28d577 100644 --- a/MediaBrowser.Controller/Drawing/ImageHelper.cs +++ b/MediaBrowser.Controller/Drawing/ImageHelper.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using MediaBrowser.Controller.Entities; using MediaBrowser.Model.Drawing; diff --git a/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs b/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs index 31d2c1bd4..22105b7d7 100644 --- a/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs +++ b/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using System.IO; diff --git a/MediaBrowser.Controller/Drawing/ImageProcessorExtensions.cs b/MediaBrowser.Controller/Drawing/ImageProcessorExtensions.cs index df9050de5..d3a2b4dbf 100644 --- a/MediaBrowser.Controller/Drawing/ImageProcessorExtensions.cs +++ b/MediaBrowser.Controller/Drawing/ImageProcessorExtensions.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using MediaBrowser.Controller.Entities; using MediaBrowser.Model.Entities; diff --git a/MediaBrowser.Controller/Drawing/ImageStream.cs b/MediaBrowser.Controller/Drawing/ImageStream.cs index 74ac24ec9..46f58ec15 100644 --- a/MediaBrowser.Controller/Drawing/ImageStream.cs +++ b/MediaBrowser.Controller/Drawing/ImageStream.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.IO; using MediaBrowser.Model.Drawing; @@ -11,6 +13,7 @@ namespace MediaBrowser.Controller.Drawing /// </summary> /// <value>The stream.</value> public Stream Stream { get; set; } + /// <summary> /// Gets or sets the format. /// </summary> diff --git a/MediaBrowser.Controller/Dto/DtoOptions.cs b/MediaBrowser.Controller/Dto/DtoOptions.cs index cf301f1e4..76f20ace2 100644 --- a/MediaBrowser.Controller/Dto/DtoOptions.cs +++ b/MediaBrowser.Controller/Dto/DtoOptions.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Linq; using MediaBrowser.Model.Entities; diff --git a/MediaBrowser.Controller/Entities/AggregateFolder.cs b/MediaBrowser.Controller/Entities/AggregateFolder.cs index e1c800e61..6ebea5f44 100644 --- a/MediaBrowser.Controller/Entities/AggregateFolder.cs +++ b/MediaBrowser.Controller/Entities/AggregateFolder.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Concurrent; using System.Collections.Generic; @@ -57,6 +59,7 @@ namespace MediaBrowser.Controller.Entities private Guid[] _childrenIds = null; private readonly object _childIdsLock = new object(); + protected override List<BaseItem> LoadChildren() { lock (_childIdsLock) diff --git a/MediaBrowser.Controller/Entities/Audio/Audio.cs b/MediaBrowser.Controller/Entities/Audio/Audio.cs index 98f802b5d..2c6dea02c 100644 --- a/MediaBrowser.Controller/Entities/Audio/Audio.cs +++ b/MediaBrowser.Controller/Entities/Audio/Audio.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using System.Linq; diff --git a/MediaBrowser.Controller/Entities/Audio/IHasAlbumArtist.cs b/MediaBrowser.Controller/Entities/Audio/IHasAlbumArtist.cs index 056f31f78..f6d3cd6cc 100644 --- a/MediaBrowser.Controller/Entities/Audio/IHasAlbumArtist.cs +++ b/MediaBrowser.Controller/Entities/Audio/IHasAlbumArtist.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System.Collections.Generic; namespace MediaBrowser.Controller.Entities.Audio diff --git a/MediaBrowser.Controller/Entities/Audio/IHasMusicGenres.cs b/MediaBrowser.Controller/Entities/Audio/IHasMusicGenres.cs index 5ae056050..ac4dd1688 100644 --- a/MediaBrowser.Controller/Entities/Audio/IHasMusicGenres.cs +++ b/MediaBrowser.Controller/Entities/Audio/IHasMusicGenres.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + namespace MediaBrowser.Controller.Entities.Audio { public interface IHasMusicGenres diff --git a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs index 5a1ddeece..48cd9371a 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using System.Linq; diff --git a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs index ea5c41caa..397a68ff7 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using System.Linq; diff --git a/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs b/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs index 4f6aa0776..5a117a6b1 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using System.Text.Json.Serialization; diff --git a/MediaBrowser.Controller/Entities/AudioBook.cs b/MediaBrowser.Controller/Entities/AudioBook.cs index 11ff8a257..f4bd851e1 100644 --- a/MediaBrowser.Controller/Entities/AudioBook.cs +++ b/MediaBrowser.Controller/Entities/AudioBook.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Text.Json.Serialization; using Jellyfin.Data.Enums; @@ -15,8 +17,10 @@ namespace MediaBrowser.Controller.Entities [JsonIgnore] public string SeriesPresentationUniqueKey { get; set; } + [JsonIgnore] public string SeriesName { get; set; } + [JsonIgnore] public Guid SeriesId { get; set; } diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 9e595ddc3..24978d8dd 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using System.Globalization; diff --git a/MediaBrowser.Controller/Entities/BaseItemExtensions.cs b/MediaBrowser.Controller/Entities/BaseItemExtensions.cs index 815239be2..8a69971d0 100644 --- a/MediaBrowser.Controller/Entities/BaseItemExtensions.cs +++ b/MediaBrowser.Controller/Entities/BaseItemExtensions.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System.Linq; using MediaBrowser.Model.Entities; using MediaBrowser.Model.IO; diff --git a/MediaBrowser.Controller/Entities/BasePluginFolder.cs b/MediaBrowser.Controller/Entities/BasePluginFolder.cs index 106385bc6..ef5a5a734 100644 --- a/MediaBrowser.Controller/Entities/BasePluginFolder.cs +++ b/MediaBrowser.Controller/Entities/BasePluginFolder.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System.Text.Json.Serialization; namespace MediaBrowser.Controller.Entities @@ -26,13 +28,5 @@ namespace MediaBrowser.Controller.Entities [JsonIgnore] public override bool SupportsPeople => false; - - // public override double? GetDefaultPrimaryImageAspectRatio() - //{ - // double value = 16; - // value /= 9; - - // return value; - //} } } diff --git a/MediaBrowser.Controller/Entities/Book.cs b/MediaBrowser.Controller/Entities/Book.cs index 11c6c6e45..55945283c 100644 --- a/MediaBrowser.Controller/Entities/Book.cs +++ b/MediaBrowser.Controller/Entities/Book.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Linq; using System.Text.Json.Serialization; @@ -49,11 +51,13 @@ namespace MediaBrowser.Controller.Entities return SeriesId; } + /// <inheritdoc /> public override bool CanDownload() { return IsFileProtocol; } + /// <inheritdoc /> public override UnratedItem GetBlockUnratedType() { return UnratedItem.Book; diff --git a/MediaBrowser.Controller/Entities/CollectionFolder.cs b/MediaBrowser.Controller/Entities/CollectionFolder.cs index 5c6a9d2a2..d25545a2f 100644 --- a/MediaBrowser.Controller/Entities/CollectionFolder.cs +++ b/MediaBrowser.Controller/Entities/CollectionFolder.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using System.IO; diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index 11542c1ca..7687cf12b 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -1,5 +1,7 @@ #pragma warning disable CS1591 +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using System.Globalization; diff --git a/MediaBrowser.Controller/Entities/Genre.cs b/MediaBrowser.Controller/Entities/Genre.cs index 437def532..db6c85caf 100644 --- a/MediaBrowser.Controller/Entities/Genre.cs +++ b/MediaBrowser.Controller/Entities/Genre.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using System.Text.Json.Serialization; diff --git a/MediaBrowser.Controller/Entities/ICollectionFolder.cs b/MediaBrowser.Controller/Entities/ICollectionFolder.cs index 245b23ff0..b84a9fa6f 100644 --- a/MediaBrowser.Controller/Entities/ICollectionFolder.cs +++ b/MediaBrowser.Controller/Entities/ICollectionFolder.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; namespace MediaBrowser.Controller.Entities diff --git a/MediaBrowser.Controller/Entities/IHasMediaSources.cs b/MediaBrowser.Controller/Entities/IHasMediaSources.cs index 213c0a794..a7b60d168 100644 --- a/MediaBrowser.Controller/Entities/IHasMediaSources.cs +++ b/MediaBrowser.Controller/Entities/IHasMediaSources.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using MediaBrowser.Model.Dto; @@ -7,15 +9,19 @@ namespace MediaBrowser.Controller.Entities { public interface IHasMediaSources { + Guid Id { get; set; } + + long? RunTimeTicks { get; set; } + + string Path { get; } + /// <summary> /// Gets the media sources. /// </summary> List<MediaSourceInfo> GetMediaSources(bool enablePathSubstitution); + List<MediaStream> GetMediaStreams(); - Guid Id { get; set; } - long? RunTimeTicks { get; set; } - string Path { get; } } } diff --git a/MediaBrowser.Controller/Entities/IHasProgramAttributes.cs b/MediaBrowser.Controller/Entities/IHasProgramAttributes.cs index fd1c19c97..f747b5149 100644 --- a/MediaBrowser.Controller/Entities/IHasProgramAttributes.cs +++ b/MediaBrowser.Controller/Entities/IHasProgramAttributes.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using MediaBrowser.Model.LiveTv; namespace MediaBrowser.Controller.Entities diff --git a/MediaBrowser.Controller/Entities/IHasSeries.cs b/MediaBrowser.Controller/Entities/IHasSeries.cs index 475a2ab85..5444f1f52 100644 --- a/MediaBrowser.Controller/Entities/IHasSeries.cs +++ b/MediaBrowser.Controller/Entities/IHasSeries.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; namespace MediaBrowser.Controller.Entities @@ -10,12 +12,15 @@ namespace MediaBrowser.Controller.Entities /// <value>The name of the series.</value> string SeriesName { get; set; } + Guid SeriesId { get; set; } + + string SeriesPresentationUniqueKey { get; set; } + string FindSeriesName(); + string FindSeriesSortName(); - Guid SeriesId { get; set; } Guid FindSeriesId(); - string SeriesPresentationUniqueKey { get; set; } string FindSeriesPresentationUniqueKey(); } diff --git a/MediaBrowser.Controller/Entities/IHasStartDate.cs b/MediaBrowser.Controller/Entities/IHasStartDate.cs index 1ecde9af4..dab15eb01 100644 --- a/MediaBrowser.Controller/Entities/IHasStartDate.cs +++ b/MediaBrowser.Controller/Entities/IHasStartDate.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; namespace MediaBrowser.Controller.Entities diff --git a/MediaBrowser.Controller/Entities/IHasTrailers.cs b/MediaBrowser.Controller/Entities/IHasTrailers.cs index dd8e3c45f..d1f6f2b7e 100644 --- a/MediaBrowser.Controller/Entities/IHasTrailers.cs +++ b/MediaBrowser.Controller/Entities/IHasTrailers.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using MediaBrowser.Model.Entities; diff --git a/MediaBrowser.Controller/Entities/IItemByName.cs b/MediaBrowser.Controller/Entities/IItemByName.cs index 8ef5c8d96..cac8aa61a 100644 --- a/MediaBrowser.Controller/Entities/IItemByName.cs +++ b/MediaBrowser.Controller/Entities/IItemByName.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System.Collections.Generic; namespace MediaBrowser.Controller.Entities diff --git a/MediaBrowser.Controller/Entities/IMetadataContainer.cs b/MediaBrowser.Controller/Entities/IMetadataContainer.cs index a384c0df3..77f5cfb79 100644 --- a/MediaBrowser.Controller/Entities/IMetadataContainer.cs +++ b/MediaBrowser.Controller/Entities/IMetadataContainer.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Threading; using System.Threading.Tasks; diff --git a/MediaBrowser.Controller/Entities/ISupportsPlaceHolders.cs b/MediaBrowser.Controller/Entities/ISupportsPlaceHolders.cs index 3e96771c3..cdda8ea39 100644 --- a/MediaBrowser.Controller/Entities/ISupportsPlaceHolders.cs +++ b/MediaBrowser.Controller/Entities/ISupportsPlaceHolders.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + namespace MediaBrowser.Controller.Entities { public interface ISupportsPlaceHolders diff --git a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs index 466cda67c..904752a22 100644 --- a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs +++ b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using System.Linq; diff --git a/MediaBrowser.Controller/Entities/InternalPeopleQuery.cs b/MediaBrowser.Controller/Entities/InternalPeopleQuery.cs index 011975dd2..4e09ee573 100644 --- a/MediaBrowser.Controller/Entities/InternalPeopleQuery.cs +++ b/MediaBrowser.Controller/Entities/InternalPeopleQuery.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; namespace MediaBrowser.Controller.Entities diff --git a/MediaBrowser.Controller/Entities/ItemImageInfo.cs b/MediaBrowser.Controller/Entities/ItemImageInfo.cs index 12f5db2e0..570d8eec0 100644 --- a/MediaBrowser.Controller/Entities/ItemImageInfo.cs +++ b/MediaBrowser.Controller/Entities/ItemImageInfo.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Text.Json.Serialization; using MediaBrowser.Model.Entities; diff --git a/MediaBrowser.Controller/Entities/LinkedChild.cs b/MediaBrowser.Controller/Entities/LinkedChild.cs index 65753a26e..8e0f721e7 100644 --- a/MediaBrowser.Controller/Entities/LinkedChild.cs +++ b/MediaBrowser.Controller/Entities/LinkedChild.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using System.Globalization; diff --git a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs index c131c5430..8de88cc1b 100644 --- a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs +++ b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using System.Linq; diff --git a/MediaBrowser.Controller/Entities/MusicVideo.cs b/MediaBrowser.Controller/Entities/MusicVideo.cs index 6e7f2812d..b278a0142 100644 --- a/MediaBrowser.Controller/Entities/MusicVideo.cs +++ b/MediaBrowser.Controller/Entities/MusicVideo.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using System.Text.Json.Serialization; diff --git a/MediaBrowser.Controller/Entities/PeopleHelper.cs b/MediaBrowser.Controller/Entities/PeopleHelper.cs index c39495759..1f3758a73 100644 --- a/MediaBrowser.Controller/Entities/PeopleHelper.cs +++ b/MediaBrowser.Controller/Entities/PeopleHelper.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using System.Linq; diff --git a/MediaBrowser.Controller/Entities/Person.cs b/MediaBrowser.Controller/Entities/Person.cs index 331d17fc8..c4fcb0267 100644 --- a/MediaBrowser.Controller/Entities/Person.cs +++ b/MediaBrowser.Controller/Entities/Person.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using System.Text.Json.Serialization; diff --git a/MediaBrowser.Controller/Entities/PersonInfo.cs b/MediaBrowser.Controller/Entities/PersonInfo.cs index f3ec73b32..4ff9b0955 100644 --- a/MediaBrowser.Controller/Entities/PersonInfo.cs +++ b/MediaBrowser.Controller/Entities/PersonInfo.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using MediaBrowser.Model.Entities; diff --git a/MediaBrowser.Controller/Entities/Photo.cs b/MediaBrowser.Controller/Entities/Photo.cs index 82d0826c5..1485d4c79 100644 --- a/MediaBrowser.Controller/Entities/Photo.cs +++ b/MediaBrowser.Controller/Entities/Photo.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System.Text.Json.Serialization; using MediaBrowser.Model.Drawing; diff --git a/MediaBrowser.Controller/Entities/PhotoAlbum.cs b/MediaBrowser.Controller/Entities/PhotoAlbum.cs index b86f1ac2a..a7ecb9061 100644 --- a/MediaBrowser.Controller/Entities/PhotoAlbum.cs +++ b/MediaBrowser.Controller/Entities/PhotoAlbum.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System.Text.Json.Serialization; namespace MediaBrowser.Controller.Entities diff --git a/MediaBrowser.Controller/Entities/Share.cs b/MediaBrowser.Controller/Entities/Share.cs index a51f2b452..50f1655f3 100644 --- a/MediaBrowser.Controller/Entities/Share.cs +++ b/MediaBrowser.Controller/Entities/Share.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + namespace MediaBrowser.Controller.Entities { public interface IHasShares diff --git a/MediaBrowser.Controller/Entities/SourceType.cs b/MediaBrowser.Controller/Entities/SourceType.cs index 927483b93..be19e1bda 100644 --- a/MediaBrowser.Controller/Entities/SourceType.cs +++ b/MediaBrowser.Controller/Entities/SourceType.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + namespace MediaBrowser.Controller.Entities { public enum SourceType diff --git a/MediaBrowser.Controller/Entities/Studio.cs b/MediaBrowser.Controller/Entities/Studio.cs index 1f64de6a4..9018ddb75 100644 --- a/MediaBrowser.Controller/Entities/Studio.cs +++ b/MediaBrowser.Controller/Entities/Studio.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using System.Text.Json.Serialization; diff --git a/MediaBrowser.Controller/Entities/TV/Episode.cs b/MediaBrowser.Controller/Entities/TV/Episode.cs index 9a5f9097d..dc12fbbea 100644 --- a/MediaBrowser.Controller/Entities/TV/Episode.cs +++ b/MediaBrowser.Controller/Entities/TV/Episode.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using System.Globalization; diff --git a/MediaBrowser.Controller/Entities/TV/Season.cs b/MediaBrowser.Controller/Entities/TV/Season.cs index 2aba1d03d..93bdd6e70 100644 --- a/MediaBrowser.Controller/Entities/TV/Season.cs +++ b/MediaBrowser.Controller/Entities/TV/Season.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using System.Linq; diff --git a/MediaBrowser.Controller/Entities/TV/Series.cs b/MediaBrowser.Controller/Entities/TV/Series.cs index 23d960092..72c696c1a 100644 --- a/MediaBrowser.Controller/Entities/TV/Series.cs +++ b/MediaBrowser.Controller/Entities/TV/Series.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using System.Globalization; diff --git a/MediaBrowser.Controller/Entities/TagExtensions.cs b/MediaBrowser.Controller/Entities/TagExtensions.cs index 97f590635..2ce396daf 100644 --- a/MediaBrowser.Controller/Entities/TagExtensions.cs +++ b/MediaBrowser.Controller/Entities/TagExtensions.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Linq; diff --git a/MediaBrowser.Controller/Entities/Trailer.cs b/MediaBrowser.Controller/Entities/Trailer.cs index 83e9ce1e7..9ae8ad708 100644 --- a/MediaBrowser.Controller/Entities/Trailer.cs +++ b/MediaBrowser.Controller/Entities/Trailer.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using System.Globalization; diff --git a/MediaBrowser.Controller/Entities/UserItemData.cs b/MediaBrowser.Controller/Entities/UserItemData.cs index 3298fa2d3..db63c42e4 100644 --- a/MediaBrowser.Controller/Entities/UserItemData.cs +++ b/MediaBrowser.Controller/Entities/UserItemData.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Text.Json.Serialization; @@ -24,6 +26,7 @@ namespace MediaBrowser.Controller.Entities /// The _rating. /// </summary> private double? _rating; + /// <summary> /// Gets or sets the users 0-10 rating. /// </summary> @@ -75,11 +78,13 @@ namespace MediaBrowser.Controller.Entities /// </summary> /// <value><c>true</c> if played; otherwise, <c>false</c>.</value> public bool Played { get; set; } + /// <summary> /// Gets or sets the index of the audio stream. /// </summary> /// <value>The index of the audio stream.</value> public int? AudioStreamIndex { get; set; } + /// <summary> /// Gets or sets the index of the subtitle stream. /// </summary> diff --git a/MediaBrowser.Controller/Entities/UserRootFolder.cs b/MediaBrowser.Controller/Entities/UserRootFolder.cs index 39f4e0b6c..7f7224ae0 100644 --- a/MediaBrowser.Controller/Entities/UserRootFolder.cs +++ b/MediaBrowser.Controller/Entities/UserRootFolder.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using System.Linq; diff --git a/MediaBrowser.Controller/Entities/UserView.cs b/MediaBrowser.Controller/Entities/UserView.cs index 1fba8a30f..b1da4d64c 100644 --- a/MediaBrowser.Controller/Entities/UserView.cs +++ b/MediaBrowser.Controller/Entities/UserView.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using System.Linq; @@ -6,7 +8,6 @@ using System.Threading.Tasks; using Jellyfin.Data.Entities; using MediaBrowser.Controller.TV; using MediaBrowser.Model.Querying; -using Microsoft.Extensions.Logging; namespace MediaBrowser.Controller.Entities { diff --git a/MediaBrowser.Controller/Entities/Video.cs b/MediaBrowser.Controller/Entities/Video.cs index eeff78e10..07f381881 100644 --- a/MediaBrowser.Controller/Entities/Video.cs +++ b/MediaBrowser.Controller/Entities/Video.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using System.Globalization; diff --git a/MediaBrowser.Controller/Entities/Year.cs b/MediaBrowser.Controller/Entities/Year.cs index c88498640..b2e4d307a 100644 --- a/MediaBrowser.Controller/Entities/Year.cs +++ b/MediaBrowser.Controller/Entities/Year.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using System.Globalization; diff --git a/MediaBrowser.Controller/Extensions/StringExtensions.cs b/MediaBrowser.Controller/Extensions/StringExtensions.cs index e09543e14..3cc1f328a 100644 --- a/MediaBrowser.Controller/Extensions/StringExtensions.cs +++ b/MediaBrowser.Controller/Extensions/StringExtensions.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Globalization; using System.Linq; diff --git a/MediaBrowser.Controller/IDisplayPreferencesManager.cs b/MediaBrowser.Controller/IDisplayPreferencesManager.cs index b6bfed3e5..856b91b5d 100644 --- a/MediaBrowser.Controller/IDisplayPreferencesManager.cs +++ b/MediaBrowser.Controller/IDisplayPreferencesManager.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using Jellyfin.Data.Entities; diff --git a/MediaBrowser.Controller/IO/FileData.cs b/MediaBrowser.Controller/IO/FileData.cs index e655f50eb..9bc4cac39 100644 --- a/MediaBrowser.Controller/IO/FileData.cs +++ b/MediaBrowser.Controller/IO/FileData.cs @@ -8,28 +8,17 @@ using Microsoft.Extensions.Logging; namespace MediaBrowser.Controller.IO { /// <summary> - /// Provides low level File access that is much faster than the File/Directory api's + /// Provides low level File access that is much faster than the File/Directory api's. /// </summary> public static class FileData { - private static Dictionary<string, FileSystemMetadata> GetFileSystemDictionary(FileSystemMetadata[] list) - { - var dict = new Dictionary<string, FileSystemMetadata>(StringComparer.OrdinalIgnoreCase); - - foreach (var file in list) - { - dict[file.FullName] = file; - } - - return dict; - } - /// <summary> /// Gets the filtered file system entries. /// </summary> /// <param name="directoryService">The directory service.</param> /// <param name="path">The path.</param> /// <param name="fileSystem">The file system.</param> + /// <param name="appHost">The application host.</param> /// <param name="logger">The logger.</param> /// <param name="args">The args.</param> /// <param name="flattenFolderDepth">The flatten folder depth.</param> diff --git a/MediaBrowser.Controller/IResourceFileManager.cs b/MediaBrowser.Controller/IResourceFileManager.cs index 69a51cec8..26f0424b7 100644 --- a/MediaBrowser.Controller/IResourceFileManager.cs +++ b/MediaBrowser.Controller/IResourceFileManager.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + namespace MediaBrowser.Controller { public interface IResourceFileManager diff --git a/MediaBrowser.Controller/IServerApplicationHost.cs b/MediaBrowser.Controller/IServerApplicationHost.cs index abdb0f695..2db631157 100644 --- a/MediaBrowser.Controller/IServerApplicationHost.cs +++ b/MediaBrowser.Controller/IServerApplicationHost.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using System.Net; diff --git a/MediaBrowser.Controller/IServerApplicationPaths.cs b/MediaBrowser.Controller/IServerApplicationPaths.cs index 155bf9177..be57d6bca 100644 --- a/MediaBrowser.Controller/IServerApplicationPaths.cs +++ b/MediaBrowser.Controller/IServerApplicationPaths.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using MediaBrowser.Common.Configuration; namespace MediaBrowser.Controller @@ -81,6 +83,10 @@ namespace MediaBrowser.Controller /// <value>The internal metadata path.</value> string InternalMetadataPath { get; } + /// <summary> + /// Gets the virtual internal metadata path, either a custom path or the default. + /// </summary> + /// <value>The virtual internal metadata path.</value> string VirtualInternalMetadataPath { get; } /// <summary> diff --git a/MediaBrowser.Controller/Library/DeleteOptions.cs b/MediaBrowser.Controller/Library/DeleteOptions.cs index 2944d8259..b7417efcb 100644 --- a/MediaBrowser.Controller/Library/DeleteOptions.cs +++ b/MediaBrowser.Controller/Library/DeleteOptions.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + namespace MediaBrowser.Controller.Library { public class DeleteOptions diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs index d53b1fc8d..d2f937d4f 100644 --- a/MediaBrowser.Controller/Library/ILibraryManager.cs +++ b/MediaBrowser.Controller/Library/ILibraryManager.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using System.Threading; @@ -63,6 +65,7 @@ namespace MediaBrowser.Controller.Library /// Finds the by path. /// </summary> /// <param name="path">The path.</param> + /// <param name="isFolder"><c>true</c> is the path is a directory; otherwise <c>false</c>.</param> /// <returns>BaseItem.</returns> BaseItem FindByPath(string path, bool? isFolder); diff --git a/MediaBrowser.Controller/Library/ILibraryMonitor.cs b/MediaBrowser.Controller/Library/ILibraryMonitor.cs index 233cfb197..455054bd1 100644 --- a/MediaBrowser.Controller/Library/ILibraryMonitor.cs +++ b/MediaBrowser.Controller/Library/ILibraryMonitor.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; namespace MediaBrowser.Controller.Library diff --git a/MediaBrowser.Controller/Library/ILiveStream.cs b/MediaBrowser.Controller/Library/ILiveStream.cs index 7c9a9b20e..ff25be657 100644 --- a/MediaBrowser.Controller/Library/ILiveStream.cs +++ b/MediaBrowser.Controller/Library/ILiveStream.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System.Threading; using System.Threading.Tasks; using MediaBrowser.Model.Dto; @@ -6,8 +8,6 @@ namespace MediaBrowser.Controller.Library { public interface ILiveStream { - Task Open(CancellationToken openCancellationToken); - Task Close(); int ConsumerCount { get; set; } string OriginalStreamId { get; set; } @@ -19,5 +19,9 @@ namespace MediaBrowser.Controller.Library MediaSourceInfo MediaSource { get; set; } string UniqueId { get; } + + Task Open(CancellationToken openCancellationToken); + + Task Close(); } } diff --git a/MediaBrowser.Controller/Library/IMediaSourceManager.cs b/MediaBrowser.Controller/Library/IMediaSourceManager.cs index 94528ff77..9e7b1e608 100644 --- a/MediaBrowser.Controller/Library/IMediaSourceManager.cs +++ b/MediaBrowser.Controller/Library/IMediaSourceManager.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using System.IO; diff --git a/MediaBrowser.Controller/Library/IMetadataFileSaver.cs b/MediaBrowser.Controller/Library/IMetadataFileSaver.cs index 5b92388ce..9c6f03a23 100644 --- a/MediaBrowser.Controller/Library/IMetadataFileSaver.cs +++ b/MediaBrowser.Controller/Library/IMetadataFileSaver.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using MediaBrowser.Controller.Entities; namespace MediaBrowser.Controller.Library diff --git a/MediaBrowser.Controller/Library/IMusicManager.cs b/MediaBrowser.Controller/Library/IMusicManager.cs index 36b250ec9..d12f008e7 100644 --- a/MediaBrowser.Controller/Library/IMusicManager.cs +++ b/MediaBrowser.Controller/Library/IMusicManager.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System.Collections.Generic; using Jellyfin.Data.Entities; using MediaBrowser.Controller.Dto; diff --git a/MediaBrowser.Controller/Library/IUserDataManager.cs b/MediaBrowser.Controller/Library/IUserDataManager.cs index d08ad4cac..c6a83e4dc 100644 --- a/MediaBrowser.Controller/Library/IUserDataManager.cs +++ b/MediaBrowser.Controller/Library/IUserDataManager.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using System.Threading; @@ -28,6 +30,7 @@ namespace MediaBrowser.Controller.Library /// <param name="reason">The reason.</param> /// <param name="cancellationToken">The cancellation token.</param> void SaveUserData(Guid userId, BaseItem item, UserItemData userData, UserDataSaveReason reason, CancellationToken cancellationToken); + void SaveUserData(User user, BaseItem item, UserItemData userData, UserDataSaveReason reason, CancellationToken cancellationToken); UserItemData GetUserData(User user, BaseItem item); diff --git a/MediaBrowser.Controller/Library/IUserManager.cs b/MediaBrowser.Controller/Library/IUserManager.cs index 6685861a9..ffd9739f6 100644 --- a/MediaBrowser.Controller/Library/IUserManager.cs +++ b/MediaBrowser.Controller/Library/IUserManager.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using System.Threading.Tasks; diff --git a/MediaBrowser.Controller/Library/IUserViewManager.cs b/MediaBrowser.Controller/Library/IUserViewManager.cs index 0d7da7579..8d541e8b6 100644 --- a/MediaBrowser.Controller/Library/IUserViewManager.cs +++ b/MediaBrowser.Controller/Library/IUserViewManager.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using MediaBrowser.Controller.Dto; @@ -10,6 +12,7 @@ namespace MediaBrowser.Controller.Library public interface IUserViewManager { Folder[] GetUserViews(UserViewQuery query); + UserView GetUserSubView(Guid parentId, string type, string localizationKey, string sortName); List<Tuple<BaseItem, List<BaseItem>>> GetLatestItems(LatestItemsQuery request, DtoOptions options); diff --git a/MediaBrowser.Controller/Library/IntroInfo.cs b/MediaBrowser.Controller/Library/IntroInfo.cs index 0e761d549..283cc631c 100644 --- a/MediaBrowser.Controller/Library/IntroInfo.cs +++ b/MediaBrowser.Controller/Library/IntroInfo.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; namespace MediaBrowser.Controller.Library diff --git a/MediaBrowser.Controller/Library/ItemChangeEventArgs.cs b/MediaBrowser.Controller/Library/ItemChangeEventArgs.cs index b5c48321b..1798a4fad 100644 --- a/MediaBrowser.Controller/Library/ItemChangeEventArgs.cs +++ b/MediaBrowser.Controller/Library/ItemChangeEventArgs.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using MediaBrowser.Controller.Entities; namespace MediaBrowser.Controller.Library diff --git a/MediaBrowser.Controller/Library/ItemResolveArgs.cs b/MediaBrowser.Controller/Library/ItemResolveArgs.cs index 2e5dcc4c5..6a0dbeba2 100644 --- a/MediaBrowser.Controller/Library/ItemResolveArgs.cs +++ b/MediaBrowser.Controller/Library/ItemResolveArgs.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using System.Linq; diff --git a/MediaBrowser.Controller/Library/ItemUpdateType.cs b/MediaBrowser.Controller/Library/ItemUpdateType.cs index b62f314ba..1f3ebb499 100644 --- a/MediaBrowser.Controller/Library/ItemUpdateType.cs +++ b/MediaBrowser.Controller/Library/ItemUpdateType.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; namespace MediaBrowser.Controller.Library diff --git a/MediaBrowser.Controller/Library/LibraryManagerExtensions.cs b/MediaBrowser.Controller/Library/LibraryManagerExtensions.cs index 037b0b62c..9581603f0 100644 --- a/MediaBrowser.Controller/Library/LibraryManagerExtensions.cs +++ b/MediaBrowser.Controller/Library/LibraryManagerExtensions.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using MediaBrowser.Controller.Entities; diff --git a/MediaBrowser.Controller/Library/MetadataConfigurationStore.cs b/MediaBrowser.Controller/Library/MetadataConfigurationStore.cs index 31adbdcf3..f16304db0 100644 --- a/MediaBrowser.Controller/Library/MetadataConfigurationStore.cs +++ b/MediaBrowser.Controller/Library/MetadataConfigurationStore.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System.Collections.Generic; using MediaBrowser.Common.Configuration; using MediaBrowser.Model.Configuration; diff --git a/MediaBrowser.Controller/Library/NameExtensions.cs b/MediaBrowser.Controller/Library/NameExtensions.cs index 24d0347e9..21f33ad19 100644 --- a/MediaBrowser.Controller/Library/NameExtensions.cs +++ b/MediaBrowser.Controller/Library/NameExtensions.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using System.Linq; diff --git a/MediaBrowser.Controller/Library/PlaybackProgressEventArgs.cs b/MediaBrowser.Controller/Library/PlaybackProgressEventArgs.cs index 08cfea3c3..a2be3a42a 100644 --- a/MediaBrowser.Controller/Library/PlaybackProgressEventArgs.cs +++ b/MediaBrowser.Controller/Library/PlaybackProgressEventArgs.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using Jellyfin.Data.Entities; @@ -12,6 +14,11 @@ namespace MediaBrowser.Controller.Library /// </summary> public class PlaybackProgressEventArgs : EventArgs { + public PlaybackProgressEventArgs() + { + Users = new List<User>(); + } + public List<User> Users { get; set; } public long? PlaybackPositionTicks { get; set; } @@ -35,10 +42,5 @@ namespace MediaBrowser.Controller.Library public string PlaySessionId { get; set; } public SessionInfo Session { get; set; } - - public PlaybackProgressEventArgs() - { - Users = new List<User>(); - } } } diff --git a/MediaBrowser.Controller/Library/PlaybackStopEventArgs.cs b/MediaBrowser.Controller/Library/PlaybackStopEventArgs.cs index 12add2573..f0d77ba2d 100644 --- a/MediaBrowser.Controller/Library/PlaybackStopEventArgs.cs +++ b/MediaBrowser.Controller/Library/PlaybackStopEventArgs.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + namespace MediaBrowser.Controller.Library { public class PlaybackStopEventArgs : PlaybackProgressEventArgs diff --git a/MediaBrowser.Controller/Library/UserDataSaveEventArgs.cs b/MediaBrowser.Controller/Library/UserDataSaveEventArgs.cs index fa0192784..cd9109753 100644 --- a/MediaBrowser.Controller/Library/UserDataSaveEventArgs.cs +++ b/MediaBrowser.Controller/Library/UserDataSaveEventArgs.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using MediaBrowser.Controller.Entities; diff --git a/MediaBrowser.Controller/LiveTv/ChannelInfo.cs b/MediaBrowser.Controller/LiveTv/ChannelInfo.cs index 67d0df4fd..d7afd2118 100644 --- a/MediaBrowser.Controller/LiveTv/ChannelInfo.cs +++ b/MediaBrowser.Controller/LiveTv/ChannelInfo.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using MediaBrowser.Model.LiveTv; namespace MediaBrowser.Controller.LiveTv diff --git a/MediaBrowser.Controller/LiveTv/IListingsProvider.cs b/MediaBrowser.Controller/LiveTv/IListingsProvider.cs index 2ea0a748e..038ff2eae 100644 --- a/MediaBrowser.Controller/LiveTv/IListingsProvider.cs +++ b/MediaBrowser.Controller/LiveTv/IListingsProvider.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using System.Threading; diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs index f619b011b..079442215 100644 --- a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs +++ b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using System.Threading; @@ -105,6 +107,7 @@ namespace MediaBrowser.Controller.LiveTv /// </summary> /// <param name="id">The identifier.</param> /// <param name="mediaSourceId">The media source identifier.</param> + /// <param name="currentLiveStreams">The current live streams.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task{StreamResponseInfo}.</returns> Task<Tuple<MediaSourceInfo, ILiveStream>> GetChannelStream(string id, string mediaSourceId, List<ILiveStream> currentLiveStreams, CancellationToken cancellationToken); diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvService.cs b/MediaBrowser.Controller/LiveTv/ILiveTvService.cs index b71a76648..3ca1d165e 100644 --- a/MediaBrowser.Controller/LiveTv/ILiveTvService.cs +++ b/MediaBrowser.Controller/LiveTv/ILiveTvService.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using System.Threading; diff --git a/MediaBrowser.Controller/LiveTv/ITunerHost.cs b/MediaBrowser.Controller/LiveTv/ITunerHost.cs index 3679e4f78..ff92bf856 100644 --- a/MediaBrowser.Controller/LiveTv/ITunerHost.cs +++ b/MediaBrowser.Controller/LiveTv/ITunerHost.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; @@ -14,28 +16,37 @@ namespace MediaBrowser.Controller.LiveTv /// </summary> /// <value>The name.</value> string Name { get; } + /// <summary> /// Gets the type. /// </summary> /// <value>The type.</value> string Type { get; } + + bool IsSupported { get; } + /// <summary> /// Gets the channels. /// </summary> /// <returns>Task<IEnumerable<ChannelInfo>>.</returns> Task<List<ChannelInfo>> GetChannels(bool enableCache, CancellationToken cancellationToken); + /// <summary> /// Gets the tuner infos. /// </summary> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task<List<LiveTvTunerInfo>>.</returns> Task<List<LiveTvTunerInfo>> GetTunerInfos(CancellationToken cancellationToken); + /// <summary> /// Gets the channel stream. /// </summary> /// <param name="channelId">The channel identifier.</param> /// <param name="streamId">The stream identifier.</param> + /// <param name="currentLiveStreams">The current live streams.</param> + /// <param name="cancellationToken">The cancellation token to cancel operation.</param> Task<ILiveStream> GetChannelStream(string channelId, string streamId, List<ILiveStream> currentLiveStreams, CancellationToken cancellationToken); + /// <summary> /// Gets the channel stream media sources. /// </summary> @@ -45,10 +56,7 @@ namespace MediaBrowser.Controller.LiveTv Task<List<MediaSourceInfo>> GetChannelStreamMediaSources(string channelId, CancellationToken cancellationToken); Task<List<TunerHostInfo>> DiscoverDevices(int discoveryDurationMs, CancellationToken cancellationToken); - bool IsSupported - { - get; - } + } public interface IConfigurableTunerHost diff --git a/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs b/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs index aa7c12dd1..ec933caf3 100644 --- a/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs +++ b/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using System.Globalization; diff --git a/MediaBrowser.Controller/LiveTv/LiveTvConflictException.cs b/MediaBrowser.Controller/LiveTv/LiveTvConflictException.cs index 0e09d1aeb..881c42c73 100644 --- a/MediaBrowser.Controller/LiveTv/LiveTvConflictException.cs +++ b/MediaBrowser.Controller/LiveTv/LiveTvConflictException.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; namespace MediaBrowser.Controller.LiveTv diff --git a/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs b/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs index e1de01ff0..43af495dd 100644 --- a/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs +++ b/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using System.Globalization; diff --git a/MediaBrowser.Controller/LiveTv/LiveTvServiceStatusInfo.cs b/MediaBrowser.Controller/LiveTv/LiveTvServiceStatusInfo.cs index 67b2f0eb1..02178297b 100644 --- a/MediaBrowser.Controller/LiveTv/LiveTvServiceStatusInfo.cs +++ b/MediaBrowser.Controller/LiveTv/LiveTvServiceStatusInfo.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System.Collections.Generic; using MediaBrowser.Model.LiveTv; @@ -5,6 +7,12 @@ namespace MediaBrowser.Controller.LiveTv { public class LiveTvServiceStatusInfo { + public LiveTvServiceStatusInfo() + { + Tuners = new List<LiveTvTunerInfo>(); + IsVisible = true; + } + /// <summary> /// Gets or sets the status. /// </summary> @@ -39,11 +47,5 @@ namespace MediaBrowser.Controller.LiveTv /// </summary> /// <value><c>true</c> if this instance is visible; otherwise, <c>false</c>.</value> public bool IsVisible { get; set; } - - public LiveTvServiceStatusInfo() - { - Tuners = new List<LiveTvTunerInfo>(); - IsVisible = true; - } } } diff --git a/MediaBrowser.Controller/LiveTv/LiveTvTunerInfo.cs b/MediaBrowser.Controller/LiveTv/LiveTvTunerInfo.cs index 2857f73f6..739978e7c 100644 --- a/MediaBrowser.Controller/LiveTv/LiveTvTunerInfo.cs +++ b/MediaBrowser.Controller/LiveTv/LiveTvTunerInfo.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System.Collections.Generic; using MediaBrowser.Model.LiveTv; @@ -5,6 +7,11 @@ namespace MediaBrowser.Controller.LiveTv { public class LiveTvTunerInfo { + public LiveTvTunerInfo() + { + Clients = new List<string>(); + } + /// <summary> /// Gets or sets the type of the source. /// </summary> @@ -64,10 +71,5 @@ namespace MediaBrowser.Controller.LiveTv /// </summary> /// <value><c>true</c> if this instance can reset; otherwise, <c>false</c>.</value> public bool CanReset { get; set; } - - public LiveTvTunerInfo() - { - Clients = new List<string>(); - } } } diff --git a/MediaBrowser.Controller/LiveTv/ProgramInfo.cs b/MediaBrowser.Controller/LiveTv/ProgramInfo.cs index d06a15323..bdcffd5ca 100644 --- a/MediaBrowser.Controller/LiveTv/ProgramInfo.cs +++ b/MediaBrowser.Controller/LiveTv/ProgramInfo.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using MediaBrowser.Model.LiveTv; diff --git a/MediaBrowser.Controller/LiveTv/RecordingInfo.cs b/MediaBrowser.Controller/LiveTv/RecordingInfo.cs index b9e0218ab..303882b7e 100644 --- a/MediaBrowser.Controller/LiveTv/RecordingInfo.cs +++ b/MediaBrowser.Controller/LiveTv/RecordingInfo.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using MediaBrowser.Model.LiveTv; diff --git a/MediaBrowser.Controller/LiveTv/RecordingStatusChangedEventArgs.cs b/MediaBrowser.Controller/LiveTv/RecordingStatusChangedEventArgs.cs index 99460a686..847c0ea8c 100644 --- a/MediaBrowser.Controller/LiveTv/RecordingStatusChangedEventArgs.cs +++ b/MediaBrowser.Controller/LiveTv/RecordingStatusChangedEventArgs.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using MediaBrowser.Model.LiveTv; diff --git a/MediaBrowser.Controller/LiveTv/SeriesTimerInfo.cs b/MediaBrowser.Controller/LiveTv/SeriesTimerInfo.cs index 6e7acaae3..1343ecd98 100644 --- a/MediaBrowser.Controller/LiveTv/SeriesTimerInfo.cs +++ b/MediaBrowser.Controller/LiveTv/SeriesTimerInfo.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using MediaBrowser.Model.LiveTv; diff --git a/MediaBrowser.Controller/LiveTv/TimerInfo.cs b/MediaBrowser.Controller/LiveTv/TimerInfo.cs index df98bb6af..bcef4666d 100644 --- a/MediaBrowser.Controller/LiveTv/TimerInfo.cs +++ b/MediaBrowser.Controller/LiveTv/TimerInfo.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using System.Linq; diff --git a/MediaBrowser.Controller/LiveTv/TunerChannelMapping.cs b/MediaBrowser.Controller/LiveTv/TunerChannelMapping.cs index df3f55c26..2759b314f 100644 --- a/MediaBrowser.Controller/LiveTv/TunerChannelMapping.cs +++ b/MediaBrowser.Controller/LiveTv/TunerChannelMapping.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + namespace MediaBrowser.Controller.LiveTv { public class TunerChannelMapping diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index 67f17f7a5..9692cf921 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -30,6 +30,7 @@ <TargetFramework>netstandard2.1</TargetFramework> <GenerateAssemblyInfo>false</GenerateAssemblyInfo> <GenerateDocumentationFile>true</GenerateDocumentationFile> + <TreatWarningsAsErrors Condition=" '$(Configuration)' == 'Release' ">true</TreatWarningsAsErrors> </PropertyGroup> <!-- Code Analyzers--> diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 7b09f489e..550916f82 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using System.Globalization; diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs b/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs index b971b7c4b..68bc502a0 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using System.Globalization; diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs b/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs index 8f6fcb9ab..4cbb63e46 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using System.Linq; diff --git a/MediaBrowser.Controller/MediaEncoding/IAttachmentExtractor.cs b/MediaBrowser.Controller/MediaEncoding/IAttachmentExtractor.cs index 7c7e84de6..fbc827534 100644 --- a/MediaBrowser.Controller/MediaEncoding/IAttachmentExtractor.cs +++ b/MediaBrowser.Controller/MediaEncoding/IAttachmentExtractor.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System.IO; using System.Threading; using System.Threading.Tasks; diff --git a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs index f60e70239..17d6dc5d2 100644 --- a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs +++ b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using System.Threading; diff --git a/MediaBrowser.Controller/MediaEncoding/ISubtitleEncoder.cs b/MediaBrowser.Controller/MediaEncoding/ISubtitleEncoder.cs index 174e74f34..6ebf7f159 100644 --- a/MediaBrowser.Controller/MediaEncoding/ISubtitleEncoder.cs +++ b/MediaBrowser.Controller/MediaEncoding/ISubtitleEncoder.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System.IO; using System.Threading; using System.Threading.Tasks; @@ -12,7 +14,8 @@ namespace MediaBrowser.Controller.MediaEncoding /// Gets the subtitles. /// </summary> /// <returns>Task{Stream}.</returns> - Task<Stream> GetSubtitles(BaseItem item, + Task<Stream> GetSubtitles( + BaseItem item, string mediaSourceId, int subtitleStreamIndex, string outputFormat, @@ -25,6 +28,7 @@ namespace MediaBrowser.Controller.MediaEncoding /// Gets the subtitle language encoding parameter. /// </summary> /// <param name="path">The path.</param> + /// <param name="language">The language.</param> /// <param name="protocol">The protocol.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>System.String.</returns> diff --git a/MediaBrowser.Controller/MediaEncoding/ImageEncodingOptions.cs b/MediaBrowser.Controller/MediaEncoding/ImageEncodingOptions.cs index 361dd79dc..e7b4c8c15 100644 --- a/MediaBrowser.Controller/MediaEncoding/ImageEncodingOptions.cs +++ b/MediaBrowser.Controller/MediaEncoding/ImageEncodingOptions.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + namespace MediaBrowser.Controller.MediaEncoding { public class ImageEncodingOptions diff --git a/MediaBrowser.Controller/MediaEncoding/JobLogger.cs b/MediaBrowser.Controller/MediaEncoding/JobLogger.cs index c9f64c707..ac520c5c4 100644 --- a/MediaBrowser.Controller/MediaEncoding/JobLogger.cs +++ b/MediaBrowser.Controller/MediaEncoding/JobLogger.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Globalization; using System.IO; diff --git a/MediaBrowser.Controller/MediaEncoding/MediaEncoderHelpers.cs b/MediaBrowser.Controller/MediaEncoding/MediaEncoderHelpers.cs index 6c9bbb043..ce53c23ad 100644 --- a/MediaBrowser.Controller/MediaEncoding/MediaEncoderHelpers.cs +++ b/MediaBrowser.Controller/MediaEncoding/MediaEncoderHelpers.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using System.IO; diff --git a/MediaBrowser.Controller/MediaEncoding/MediaInfoRequest.cs b/MediaBrowser.Controller/MediaEncoding/MediaInfoRequest.cs index 39a47792a..59729de49 100644 --- a/MediaBrowser.Controller/MediaEncoding/MediaInfoRequest.cs +++ b/MediaBrowser.Controller/MediaEncoding/MediaInfoRequest.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Dto; diff --git a/MediaBrowser.Controller/Net/AuthenticatedAttribute.cs b/MediaBrowser.Controller/Net/AuthenticatedAttribute.cs index 87a7f7e10..1366fd42e 100644 --- a/MediaBrowser.Controller/Net/AuthenticatedAttribute.cs +++ b/MediaBrowser.Controller/Net/AuthenticatedAttribute.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using MediaBrowser.Model.Services; using Microsoft.AspNetCore.Http; @@ -53,7 +55,7 @@ namespace MediaBrowser.Controller.Net } public bool IgnoreLegacyAuth { get; set; } - + public bool AllowLocalOnly { get; set; } } @@ -68,7 +70,7 @@ namespace MediaBrowser.Controller.Net bool AllowLocalOnly { get; } string[] GetRoles(); - + bool IgnoreLegacyAuth { get; } } } diff --git a/MediaBrowser.Controller/Net/AuthorizationInfo.cs b/MediaBrowser.Controller/Net/AuthorizationInfo.cs index 4361e253b..735c46ef8 100644 --- a/MediaBrowser.Controller/Net/AuthorizationInfo.cs +++ b/MediaBrowser.Controller/Net/AuthorizationInfo.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using Jellyfin.Data.Entities; diff --git a/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs b/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs index a54f6d57b..916dea58b 100644 --- a/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs +++ b/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using System.Globalization; diff --git a/MediaBrowser.Controller/Net/IHttpResultFactory.cs b/MediaBrowser.Controller/Net/IHttpResultFactory.cs index 609bd5f59..8293a8714 100644 --- a/MediaBrowser.Controller/Net/IHttpResultFactory.cs +++ b/MediaBrowser.Controller/Net/IHttpResultFactory.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using System.IO; @@ -21,7 +23,9 @@ namespace MediaBrowser.Controller.Net object GetResult(string content, string contentType, IDictionary<string, string> responseHeaders = null); object GetResult(IRequest requestContext, byte[] content, string contentType, IDictionary<string, string> responseHeaders = null); + object GetResult(IRequest requestContext, Stream content, string contentType, IDictionary<string, string> responseHeaders = null); + object GetResult(IRequest requestContext, string content, string contentType, IDictionary<string, string> responseHeaders = null); object GetRedirectResult(string url); diff --git a/MediaBrowser.Controller/Net/ISessionContext.cs b/MediaBrowser.Controller/Net/ISessionContext.cs index 421ac3fe2..5da748f41 100644 --- a/MediaBrowser.Controller/Net/ISessionContext.cs +++ b/MediaBrowser.Controller/Net/ISessionContext.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using Jellyfin.Data.Entities; using MediaBrowser.Controller.Session; using MediaBrowser.Model.Services; @@ -7,9 +9,11 @@ namespace MediaBrowser.Controller.Net public interface ISessionContext { SessionInfo GetSession(object requestContext); + User GetUser(object requestContext); SessionInfo GetSession(IRequest requestContext); + User GetUser(IRequest requestContext); } } diff --git a/MediaBrowser.Controller/Net/IWebSocketConnection.cs b/MediaBrowser.Controller/Net/IWebSocketConnection.cs index 3ef8e5f6d..e87f3bca6 100644 --- a/MediaBrowser.Controller/Net/IWebSocketConnection.cs +++ b/MediaBrowser.Controller/Net/IWebSocketConnection.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + #nullable enable using System; diff --git a/MediaBrowser.Controller/Net/SecurityException.cs b/MediaBrowser.Controller/Net/SecurityException.cs index f0d0b45a0..c6347133a 100644 --- a/MediaBrowser.Controller/Net/SecurityException.cs +++ b/MediaBrowser.Controller/Net/SecurityException.cs @@ -1,3 +1,5 @@ +#nullable enable + using System; namespace MediaBrowser.Controller.Net diff --git a/MediaBrowser.Controller/Net/StaticResultOptions.cs b/MediaBrowser.Controller/Net/StaticResultOptions.cs index 85772e036..c1e9bc845 100644 --- a/MediaBrowser.Controller/Net/StaticResultOptions.cs +++ b/MediaBrowser.Controller/Net/StaticResultOptions.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using System.IO; diff --git a/MediaBrowser.Controller/Notifications/INotificationManager.cs b/MediaBrowser.Controller/Notifications/INotificationManager.cs index 44defbe0b..08d9bc12a 100644 --- a/MediaBrowser.Controller/Notifications/INotificationManager.cs +++ b/MediaBrowser.Controller/Notifications/INotificationManager.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; diff --git a/MediaBrowser.Controller/Notifications/INotificationService.cs b/MediaBrowser.Controller/Notifications/INotificationService.cs index ab5eb13cd..fa947220a 100644 --- a/MediaBrowser.Controller/Notifications/INotificationService.cs +++ b/MediaBrowser.Controller/Notifications/INotificationService.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System.Threading; using System.Threading.Tasks; using Jellyfin.Data.Entities; diff --git a/MediaBrowser.Controller/Notifications/INotificationTypeFactory.cs b/MediaBrowser.Controller/Notifications/INotificationTypeFactory.cs index 9f1d2841d..52a3e120b 100644 --- a/MediaBrowser.Controller/Notifications/INotificationTypeFactory.cs +++ b/MediaBrowser.Controller/Notifications/INotificationTypeFactory.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System.Collections.Generic; using MediaBrowser.Model.Notifications; diff --git a/MediaBrowser.Controller/Notifications/UserNotification.cs b/MediaBrowser.Controller/Notifications/UserNotification.cs index a1029589b..d768abfe7 100644 --- a/MediaBrowser.Controller/Notifications/UserNotification.cs +++ b/MediaBrowser.Controller/Notifications/UserNotification.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using Jellyfin.Data.Entities; using MediaBrowser.Model.Notifications; diff --git a/MediaBrowser.Controller/Persistence/IItemRepository.cs b/MediaBrowser.Controller/Persistence/IItemRepository.cs index 0ae1b8bbf..ebc37bd1f 100644 --- a/MediaBrowser.Controller/Persistence/IItemRepository.cs +++ b/MediaBrowser.Controller/Persistence/IItemRepository.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using System.Threading; @@ -156,15 +158,23 @@ namespace MediaBrowser.Controller.Persistence int GetCount(InternalItemsQuery query); QueryResult<(BaseItem, ItemCounts)> GetGenres(InternalItemsQuery query); + QueryResult<(BaseItem, ItemCounts)> GetMusicGenres(InternalItemsQuery query); + QueryResult<(BaseItem, ItemCounts)> GetStudios(InternalItemsQuery query); + QueryResult<(BaseItem, ItemCounts)> GetArtists(InternalItemsQuery query); + QueryResult<(BaseItem, ItemCounts)> GetAlbumArtists(InternalItemsQuery query); + QueryResult<(BaseItem, ItemCounts)> GetAllArtists(InternalItemsQuery query); List<string> GetMusicGenreNames(); + List<string> GetStudioNames(); + List<string> GetGenreNames(); + List<string> GetAllArtistNames(); } } diff --git a/MediaBrowser.Controller/Persistence/IUserDataRepository.cs b/MediaBrowser.Controller/Persistence/IUserDataRepository.cs index ba7c9fd50..81ba513ce 100644 --- a/MediaBrowser.Controller/Persistence/IUserDataRepository.cs +++ b/MediaBrowser.Controller/Persistence/IUserDataRepository.cs @@ -24,9 +24,15 @@ namespace MediaBrowser.Controller.Persistence /// </summary> /// <param name="userId">The user id.</param> /// <param name="key">The key.</param> - /// <returns>Task{UserItemData}.</returns> + /// <returns>The user data.</returns> UserItemData GetUserData(long userId, string key); + /// <summary> + /// Gets the user data. + /// </summary> + /// <param name="userId">The user id.</param> + /// <param name="keys">The keys.</param> + /// <returns>The user data.</returns> UserItemData GetUserData(long userId, List<string> keys); /// <summary> diff --git a/MediaBrowser.Controller/Persistence/MediaAttachmentQuery.cs b/MediaBrowser.Controller/Persistence/MediaAttachmentQuery.cs index e3b2d4665..e07e96f73 100644 --- a/MediaBrowser.Controller/Persistence/MediaAttachmentQuery.cs +++ b/MediaBrowser.Controller/Persistence/MediaAttachmentQuery.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; namespace MediaBrowser.Controller.Persistence diff --git a/MediaBrowser.Controller/Persistence/MediaStreamQuery.cs b/MediaBrowser.Controller/Persistence/MediaStreamQuery.cs index 7dc563b3a..f9295c8fd 100644 --- a/MediaBrowser.Controller/Persistence/MediaStreamQuery.cs +++ b/MediaBrowser.Controller/Persistence/MediaStreamQuery.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using MediaBrowser.Model.Entities; diff --git a/MediaBrowser.Controller/Playlists/IPlaylistManager.cs b/MediaBrowser.Controller/Playlists/IPlaylistManager.cs index a3e7d4a67..fbf2c5213 100644 --- a/MediaBrowser.Controller/Playlists/IPlaylistManager.cs +++ b/MediaBrowser.Controller/Playlists/IPlaylistManager.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using System.Threading.Tasks; diff --git a/MediaBrowser.Controller/Playlists/Playlist.cs b/MediaBrowser.Controller/Playlists/Playlist.cs index 0fd63770f..216dd2709 100644 --- a/MediaBrowser.Controller/Playlists/Playlist.cs +++ b/MediaBrowser.Controller/Playlists/Playlist.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using System.Globalization; diff --git a/MediaBrowser.Controller/Plugins/ILocalizablePlugin.cs b/MediaBrowser.Controller/Plugins/ILocalizablePlugin.cs index 5deb165f6..bf15fe040 100644 --- a/MediaBrowser.Controller/Plugins/ILocalizablePlugin.cs +++ b/MediaBrowser.Controller/Plugins/ILocalizablePlugin.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System.IO; using System.Reflection; diff --git a/MediaBrowser.Controller/Plugins/IPluginConfigurationPage.cs b/MediaBrowser.Controller/Plugins/IPluginConfigurationPage.cs index 077f5ab63..93eab42cc 100644 --- a/MediaBrowser.Controller/Plugins/IPluginConfigurationPage.cs +++ b/MediaBrowser.Controller/Plugins/IPluginConfigurationPage.cs @@ -42,6 +42,7 @@ namespace MediaBrowser.Controller.Plugins /// The plugin configuration. /// </summary> PluginConfiguration, + /// <summary> /// The none. /// </summary> diff --git a/MediaBrowser.Controller/Providers/AlbumInfo.cs b/MediaBrowser.Controller/Providers/AlbumInfo.cs index dbda4843f..276bcf125 100644 --- a/MediaBrowser.Controller/Providers/AlbumInfo.cs +++ b/MediaBrowser.Controller/Providers/AlbumInfo.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; diff --git a/MediaBrowser.Controller/Providers/ArtistInfo.cs b/MediaBrowser.Controller/Providers/ArtistInfo.cs index 08bf3982b..adf885baa 100644 --- a/MediaBrowser.Controller/Providers/ArtistInfo.cs +++ b/MediaBrowser.Controller/Providers/ArtistInfo.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System.Collections.Generic; namespace MediaBrowser.Controller.Providers diff --git a/MediaBrowser.Controller/Providers/BookInfo.cs b/MediaBrowser.Controller/Providers/BookInfo.cs index 03a6737c5..cce0a25fc 100644 --- a/MediaBrowser.Controller/Providers/BookInfo.cs +++ b/MediaBrowser.Controller/Providers/BookInfo.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + namespace MediaBrowser.Controller.Providers { public class BookInfo : ItemLookupInfo diff --git a/MediaBrowser.Controller/Providers/BoxSetInfo.cs b/MediaBrowser.Controller/Providers/BoxSetInfo.cs index d23f2b9bf..f43ea6717 100644 --- a/MediaBrowser.Controller/Providers/BoxSetInfo.cs +++ b/MediaBrowser.Controller/Providers/BoxSetInfo.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + namespace MediaBrowser.Controller.Providers { public class BoxSetInfo : ItemLookupInfo diff --git a/MediaBrowser.Controller/Providers/DirectoryService.cs b/MediaBrowser.Controller/Providers/DirectoryService.cs index b7640c205..f77455485 100644 --- a/MediaBrowser.Controller/Providers/DirectoryService.cs +++ b/MediaBrowser.Controller/Providers/DirectoryService.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using System.Linq; diff --git a/MediaBrowser.Controller/Providers/DynamicImageResponse.cs b/MediaBrowser.Controller/Providers/DynamicImageResponse.cs index 7c1371702..006174be8 100644 --- a/MediaBrowser.Controller/Providers/DynamicImageResponse.cs +++ b/MediaBrowser.Controller/Providers/DynamicImageResponse.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.IO; using MediaBrowser.Model.Drawing; diff --git a/MediaBrowser.Controller/Providers/EpisodeInfo.cs b/MediaBrowser.Controller/Providers/EpisodeInfo.cs index 55c41ff82..a4c8dab7e 100644 --- a/MediaBrowser.Controller/Providers/EpisodeInfo.cs +++ b/MediaBrowser.Controller/Providers/EpisodeInfo.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; diff --git a/MediaBrowser.Controller/Providers/ICustomMetadataProvider.cs b/MediaBrowser.Controller/Providers/ICustomMetadataProvider.cs index 6b4c9feb5..32a9cbef2 100644 --- a/MediaBrowser.Controller/Providers/ICustomMetadataProvider.cs +++ b/MediaBrowser.Controller/Providers/ICustomMetadataProvider.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System.Threading; using System.Threading.Tasks; using MediaBrowser.Controller.Entities; diff --git a/MediaBrowser.Controller/Providers/IDirectoryService.cs b/MediaBrowser.Controller/Providers/IDirectoryService.cs index 949a17740..f06481c7a 100644 --- a/MediaBrowser.Controller/Providers/IDirectoryService.cs +++ b/MediaBrowser.Controller/Providers/IDirectoryService.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System.Collections.Generic; using MediaBrowser.Model.IO; diff --git a/MediaBrowser.Controller/Providers/IDynamicImageProvider.cs b/MediaBrowser.Controller/Providers/IDynamicImageProvider.cs index dec327d66..ab66462fa 100644 --- a/MediaBrowser.Controller/Providers/IDynamicImageProvider.cs +++ b/MediaBrowser.Controller/Providers/IDynamicImageProvider.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; diff --git a/MediaBrowser.Controller/Providers/IHasItemChangeMonitor.cs b/MediaBrowser.Controller/Providers/IHasItemChangeMonitor.cs index 68acb3910..a0e20e312 100644 --- a/MediaBrowser.Controller/Providers/IHasItemChangeMonitor.cs +++ b/MediaBrowser.Controller/Providers/IHasItemChangeMonitor.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using MediaBrowser.Controller.Entities; namespace MediaBrowser.Controller.Providers diff --git a/MediaBrowser.Controller/Providers/IHasLookupInfo.cs b/MediaBrowser.Controller/Providers/IHasLookupInfo.cs index 4c0c38442..42cb52371 100644 --- a/MediaBrowser.Controller/Providers/IHasLookupInfo.cs +++ b/MediaBrowser.Controller/Providers/IHasLookupInfo.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + namespace MediaBrowser.Controller.Providers { public interface IHasLookupInfo<out TLookupInfoType> diff --git a/MediaBrowser.Controller/Providers/IHasOrder.cs b/MediaBrowser.Controller/Providers/IHasOrder.cs index a3db61225..9fde0e695 100644 --- a/MediaBrowser.Controller/Providers/IHasOrder.cs +++ b/MediaBrowser.Controller/Providers/IHasOrder.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + namespace MediaBrowser.Controller.Providers { public interface IHasOrder diff --git a/MediaBrowser.Controller/Providers/ILocalImageProvider.cs b/MediaBrowser.Controller/Providers/ILocalImageProvider.cs index 463c81376..c129eddb3 100644 --- a/MediaBrowser.Controller/Providers/ILocalImageProvider.cs +++ b/MediaBrowser.Controller/Providers/ILocalImageProvider.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System.Collections.Generic; using MediaBrowser.Controller.Entities; diff --git a/MediaBrowser.Controller/Providers/ILocalMetadataProvider.cs b/MediaBrowser.Controller/Providers/ILocalMetadataProvider.cs index 44fb1b394..e771c881d 100644 --- a/MediaBrowser.Controller/Providers/ILocalMetadataProvider.cs +++ b/MediaBrowser.Controller/Providers/ILocalMetadataProvider.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System.Threading; using System.Threading.Tasks; using MediaBrowser.Controller.Entities; diff --git a/MediaBrowser.Controller/Providers/IMetadataProvider.cs b/MediaBrowser.Controller/Providers/IMetadataProvider.cs index 62b16dadd..1a87e0625 100644 --- a/MediaBrowser.Controller/Providers/IMetadataProvider.cs +++ b/MediaBrowser.Controller/Providers/IMetadataProvider.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using MediaBrowser.Controller.Entities; namespace MediaBrowser.Controller.Providers diff --git a/MediaBrowser.Controller/Providers/IMetadataService.cs b/MediaBrowser.Controller/Providers/IMetadataService.cs index 21204e6d3..5f3d4274e 100644 --- a/MediaBrowser.Controller/Providers/IMetadataService.cs +++ b/MediaBrowser.Controller/Providers/IMetadataService.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Threading; using System.Threading.Tasks; diff --git a/MediaBrowser.Controller/Providers/IPreRefreshProvider.cs b/MediaBrowser.Controller/Providers/IPreRefreshProvider.cs index 28da27ae7..6d98af33e 100644 --- a/MediaBrowser.Controller/Providers/IPreRefreshProvider.cs +++ b/MediaBrowser.Controller/Providers/IPreRefreshProvider.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + namespace MediaBrowser.Controller.Providers { public interface IPreRefreshProvider : ICustomMetadataProvider diff --git a/MediaBrowser.Controller/Providers/IProviderManager.cs b/MediaBrowser.Controller/Providers/IProviderManager.cs index c77349d01..e470d77b6 100644 --- a/MediaBrowser.Controller/Providers/IProviderManager.cs +++ b/MediaBrowser.Controller/Providers/IProviderManager.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using System.IO; diff --git a/MediaBrowser.Controller/Providers/IRemoteMetadataProvider.cs b/MediaBrowser.Controller/Providers/IRemoteMetadataProvider.cs index c143b15cd..f146decb6 100644 --- a/MediaBrowser.Controller/Providers/IRemoteMetadataProvider.cs +++ b/MediaBrowser.Controller/Providers/IRemoteMetadataProvider.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; diff --git a/MediaBrowser.Controller/Providers/IRemoteSearchProvider.cs b/MediaBrowser.Controller/Providers/IRemoteSearchProvider.cs index 17ad9e4a3..9592baa7c 100644 --- a/MediaBrowser.Controller/Providers/IRemoteSearchProvider.cs +++ b/MediaBrowser.Controller/Providers/IRemoteSearchProvider.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System.Net.Http; using System.Threading; using System.Threading.Tasks; diff --git a/MediaBrowser.Controller/Providers/ImageRefreshOptions.cs b/MediaBrowser.Controller/Providers/ImageRefreshOptions.cs index 3f8c409f5..9fc379f04 100644 --- a/MediaBrowser.Controller/Providers/ImageRefreshOptions.cs +++ b/MediaBrowser.Controller/Providers/ImageRefreshOptions.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Linq; using MediaBrowser.Model.Entities; diff --git a/MediaBrowser.Controller/Providers/ItemInfo.cs b/MediaBrowser.Controller/Providers/ItemInfo.cs index d61153dfa..b50def043 100644 --- a/MediaBrowser.Controller/Providers/ItemInfo.cs +++ b/MediaBrowser.Controller/Providers/ItemInfo.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using MediaBrowser.Controller.Entities; using MediaBrowser.Model.Entities; diff --git a/MediaBrowser.Controller/Providers/ItemLookupInfo.cs b/MediaBrowser.Controller/Providers/ItemLookupInfo.cs index 4707b0c7f..49974c2a3 100644 --- a/MediaBrowser.Controller/Providers/ItemLookupInfo.cs +++ b/MediaBrowser.Controller/Providers/ItemLookupInfo.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using MediaBrowser.Model.Entities; diff --git a/MediaBrowser.Controller/Providers/LocalImageInfo.cs b/MediaBrowser.Controller/Providers/LocalImageInfo.cs index 184281025..41801862f 100644 --- a/MediaBrowser.Controller/Providers/LocalImageInfo.cs +++ b/MediaBrowser.Controller/Providers/LocalImageInfo.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using MediaBrowser.Model.Entities; using MediaBrowser.Model.IO; diff --git a/MediaBrowser.Controller/Providers/MetadataRefreshMode.cs b/MediaBrowser.Controller/Providers/MetadataRefreshMode.cs index 6d49b5510..920e3da5b 100644 --- a/MediaBrowser.Controller/Providers/MetadataRefreshMode.cs +++ b/MediaBrowser.Controller/Providers/MetadataRefreshMode.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + namespace MediaBrowser.Controller.Providers { public enum MetadataRefreshMode diff --git a/MediaBrowser.Controller/Providers/MetadataRefreshOptions.cs b/MediaBrowser.Controller/Providers/MetadataRefreshOptions.cs index 0a473b80c..b92b83701 100644 --- a/MediaBrowser.Controller/Providers/MetadataRefreshOptions.cs +++ b/MediaBrowser.Controller/Providers/MetadataRefreshOptions.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Linq; using MediaBrowser.Controller.Entities; diff --git a/MediaBrowser.Controller/Providers/MetadataResult.cs b/MediaBrowser.Controller/Providers/MetadataResult.cs index 270ea2444..1c695cafa 100644 --- a/MediaBrowser.Controller/Providers/MetadataResult.cs +++ b/MediaBrowser.Controller/Providers/MetadataResult.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using System.Globalization; diff --git a/MediaBrowser.Controller/Providers/MovieInfo.cs b/MediaBrowser.Controller/Providers/MovieInfo.cs index 5b2c3ed03..20e6b697a 100644 --- a/MediaBrowser.Controller/Providers/MovieInfo.cs +++ b/MediaBrowser.Controller/Providers/MovieInfo.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + namespace MediaBrowser.Controller.Providers { public class MovieInfo : ItemLookupInfo diff --git a/MediaBrowser.Controller/Providers/MusicVideoInfo.cs b/MediaBrowser.Controller/Providers/MusicVideoInfo.cs index 9835351fc..0b927f6eb 100644 --- a/MediaBrowser.Controller/Providers/MusicVideoInfo.cs +++ b/MediaBrowser.Controller/Providers/MusicVideoInfo.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System.Collections.Generic; namespace MediaBrowser.Controller.Providers diff --git a/MediaBrowser.Controller/Providers/PersonLookupInfo.cs b/MediaBrowser.Controller/Providers/PersonLookupInfo.cs index a6218c039..11cb71f90 100644 --- a/MediaBrowser.Controller/Providers/PersonLookupInfo.cs +++ b/MediaBrowser.Controller/Providers/PersonLookupInfo.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + namespace MediaBrowser.Controller.Providers { public class PersonLookupInfo : ItemLookupInfo diff --git a/MediaBrowser.Controller/Providers/RemoteSearchQuery.cs b/MediaBrowser.Controller/Providers/RemoteSearchQuery.cs index a2ac6c9ae..9653bc1c4 100644 --- a/MediaBrowser.Controller/Providers/RemoteSearchQuery.cs +++ b/MediaBrowser.Controller/Providers/RemoteSearchQuery.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; namespace MediaBrowser.Controller.Providers diff --git a/MediaBrowser.Controller/Providers/SeasonInfo.cs b/MediaBrowser.Controller/Providers/SeasonInfo.cs index dd2ef9ad7..2a4c1f03c 100644 --- a/MediaBrowser.Controller/Providers/SeasonInfo.cs +++ b/MediaBrowser.Controller/Providers/SeasonInfo.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; diff --git a/MediaBrowser.Controller/Providers/SeriesInfo.cs b/MediaBrowser.Controller/Providers/SeriesInfo.cs index 6c206e031..976fa175a 100644 --- a/MediaBrowser.Controller/Providers/SeriesInfo.cs +++ b/MediaBrowser.Controller/Providers/SeriesInfo.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + namespace MediaBrowser.Controller.Providers { public class SeriesInfo : ItemLookupInfo diff --git a/MediaBrowser.Controller/Providers/SongInfo.cs b/MediaBrowser.Controller/Providers/SongInfo.cs index 50615b0bd..58f76dca9 100644 --- a/MediaBrowser.Controller/Providers/SongInfo.cs +++ b/MediaBrowser.Controller/Providers/SongInfo.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; diff --git a/MediaBrowser.Controller/Providers/TrailerInfo.cs b/MediaBrowser.Controller/Providers/TrailerInfo.cs index 13f07562d..630850f9d 100644 --- a/MediaBrowser.Controller/Providers/TrailerInfo.cs +++ b/MediaBrowser.Controller/Providers/TrailerInfo.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + namespace MediaBrowser.Controller.Providers { public class TrailerInfo : ItemLookupInfo diff --git a/MediaBrowser.Controller/Resolvers/IItemResolver.cs b/MediaBrowser.Controller/Resolvers/IItemResolver.cs index a73937b3e..b99c46843 100644 --- a/MediaBrowser.Controller/Resolvers/IItemResolver.cs +++ b/MediaBrowser.Controller/Resolvers/IItemResolver.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System.Collections.Generic; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; diff --git a/MediaBrowser.Controller/Resolvers/ResolverPriority.cs b/MediaBrowser.Controller/Resolvers/ResolverPriority.cs index 1911e5c1d..ac73a5ea8 100644 --- a/MediaBrowser.Controller/Resolvers/ResolverPriority.cs +++ b/MediaBrowser.Controller/Resolvers/ResolverPriority.cs @@ -9,15 +9,22 @@ namespace MediaBrowser.Controller.Resolvers /// The first. /// </summary> First = 1, + /// <summary> /// The second. /// </summary> Second = 2, + /// <summary> /// The third. /// </summary> Third = 3, + + /// <summary> + /// The Fourth. + /// </summary> Fourth = 4, + /// <summary> /// The last. /// </summary> diff --git a/MediaBrowser.Controller/Security/AuthenticationInfo.cs b/MediaBrowser.Controller/Security/AuthenticationInfo.cs index 1d0b959b7..efac9273e 100644 --- a/MediaBrowser.Controller/Security/AuthenticationInfo.cs +++ b/MediaBrowser.Controller/Security/AuthenticationInfo.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; namespace MediaBrowser.Controller.Security diff --git a/MediaBrowser.Controller/Security/AuthenticationInfoQuery.cs b/MediaBrowser.Controller/Security/AuthenticationInfoQuery.cs index 2bd17eb26..c5f3da0b1 100644 --- a/MediaBrowser.Controller/Security/AuthenticationInfoQuery.cs +++ b/MediaBrowser.Controller/Security/AuthenticationInfoQuery.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; namespace MediaBrowser.Controller.Security diff --git a/MediaBrowser.Controller/Security/IAuthenticationRepository.cs b/MediaBrowser.Controller/Security/IAuthenticationRepository.cs index 6a9625613..883b74165 100644 --- a/MediaBrowser.Controller/Security/IAuthenticationRepository.cs +++ b/MediaBrowser.Controller/Security/IAuthenticationRepository.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using MediaBrowser.Model.Devices; using MediaBrowser.Model.Querying; @@ -29,6 +31,7 @@ namespace MediaBrowser.Controller.Security void Delete(AuthenticationInfo info); DeviceOptions GetDeviceOptions(string deviceId); + void UpdateDeviceOptions(string deviceId, DeviceOptions options); } } diff --git a/MediaBrowser.Controller/Session/AuthenticationRequest.cs b/MediaBrowser.Controller/Session/AuthenticationRequest.cs index 685ca3bdd..cc321fd22 100644 --- a/MediaBrowser.Controller/Session/AuthenticationRequest.cs +++ b/MediaBrowser.Controller/Session/AuthenticationRequest.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; namespace MediaBrowser.Controller.Session diff --git a/MediaBrowser.Controller/Session/ISessionController.cs b/MediaBrowser.Controller/Session/ISessionController.cs index 04450085b..22d6e2a04 100644 --- a/MediaBrowser.Controller/Session/ISessionController.cs +++ b/MediaBrowser.Controller/Session/ISessionController.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Threading; using System.Threading.Tasks; diff --git a/MediaBrowser.Controller/Session/ISessionManager.cs b/MediaBrowser.Controller/Session/ISessionManager.cs index e54f21050..1a1e200fa 100644 --- a/MediaBrowser.Controller/Session/ISessionManager.cs +++ b/MediaBrowser.Controller/Session/ISessionManager.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using System.Threading; diff --git a/MediaBrowser.Controller/Session/SessionEventArgs.cs b/MediaBrowser.Controller/Session/SessionEventArgs.cs index 08baaf647..097e32eae 100644 --- a/MediaBrowser.Controller/Session/SessionEventArgs.cs +++ b/MediaBrowser.Controller/Session/SessionEventArgs.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; namespace MediaBrowser.Controller.Session diff --git a/MediaBrowser.Controller/Session/SessionInfo.cs b/MediaBrowser.Controller/Session/SessionInfo.cs index 4b088998c..054fd33d9 100644 --- a/MediaBrowser.Controller/Session/SessionInfo.cs +++ b/MediaBrowser.Controller/Session/SessionInfo.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Linq; using System.Text.Json.Serialization; diff --git a/MediaBrowser.Controller/Sorting/AlphanumComparator.cs b/MediaBrowser.Controller/Sorting/AlphanumComparator.cs index de7f72d1c..70cb9eebe 100644 --- a/MediaBrowser.Controller/Sorting/AlphanumComparator.cs +++ b/MediaBrowser.Controller/Sorting/AlphanumComparator.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + #nullable enable using System; @@ -127,7 +129,7 @@ namespace MediaBrowser.Controller.Sorting } /// <inheritdoc /> - public int Compare(string x, string y) + public int Compare(string? x, string? y) { return CompareValues(x, y); } diff --git a/MediaBrowser.Controller/Sorting/SortExtensions.cs b/MediaBrowser.Controller/Sorting/SortExtensions.cs index 2a68f4678..88467814c 100644 --- a/MediaBrowser.Controller/Sorting/SortExtensions.cs +++ b/MediaBrowser.Controller/Sorting/SortExtensions.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using System.Linq; @@ -7,6 +9,7 @@ namespace MediaBrowser.Controller.Sorting public static class SortExtensions { private static readonly AlphanumComparator _comparer = new AlphanumComparator(); + public static IEnumerable<T> OrderByString<T>(this IEnumerable<T> list, Func<T, string> getName) { return list.OrderBy(getName, _comparer); diff --git a/MediaBrowser.Controller/Subtitles/ISubtitleManager.cs b/MediaBrowser.Controller/Subtitles/ISubtitleManager.cs index 39538aacd..f43d523a6 100644 --- a/MediaBrowser.Controller/Subtitles/ISubtitleManager.cs +++ b/MediaBrowser.Controller/Subtitles/ISubtitleManager.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using System.Threading; diff --git a/MediaBrowser.Controller/Subtitles/ISubtitleProvider.cs b/MediaBrowser.Controller/Subtitles/ISubtitleProvider.cs index 8ffd7c530..a633262de 100644 --- a/MediaBrowser.Controller/Subtitles/ISubtitleProvider.cs +++ b/MediaBrowser.Controller/Subtitles/ISubtitleProvider.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; diff --git a/MediaBrowser.Controller/Subtitles/SubtitleDownloadEventArgs.cs b/MediaBrowser.Controller/Subtitles/SubtitleDownloadEventArgs.cs index 5703aea17..b1d74517e 100644 --- a/MediaBrowser.Controller/Subtitles/SubtitleDownloadEventArgs.cs +++ b/MediaBrowser.Controller/Subtitles/SubtitleDownloadEventArgs.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using MediaBrowser.Controller.Entities; diff --git a/MediaBrowser.Controller/Subtitles/SubtitleResponse.cs b/MediaBrowser.Controller/Subtitles/SubtitleResponse.cs index ad6025927..a86b05778 100644 --- a/MediaBrowser.Controller/Subtitles/SubtitleResponse.cs +++ b/MediaBrowser.Controller/Subtitles/SubtitleResponse.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System.IO; namespace MediaBrowser.Controller.Subtitles diff --git a/MediaBrowser.Controller/Subtitles/SubtitleSearchRequest.cs b/MediaBrowser.Controller/Subtitles/SubtitleSearchRequest.cs index a202723b9..7d3c20e8f 100644 --- a/MediaBrowser.Controller/Subtitles/SubtitleSearchRequest.cs +++ b/MediaBrowser.Controller/Subtitles/SubtitleSearchRequest.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using MediaBrowser.Controller.Providers; diff --git a/MediaBrowser.Controller/Sync/IHasDynamicAccess.cs b/MediaBrowser.Controller/Sync/IHasDynamicAccess.cs index d6bac23be..e7395b136 100644 --- a/MediaBrowser.Controller/Sync/IHasDynamicAccess.cs +++ b/MediaBrowser.Controller/Sync/IHasDynamicAccess.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System.Threading; using System.Threading.Tasks; using MediaBrowser.Model.Sync; diff --git a/MediaBrowser.Controller/Sync/IServerSyncProvider.cs b/MediaBrowser.Controller/Sync/IServerSyncProvider.cs index 8b2d5d779..c97fd7044 100644 --- a/MediaBrowser.Controller/Sync/IServerSyncProvider.cs +++ b/MediaBrowser.Controller/Sync/IServerSyncProvider.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.IO; using System.Threading; diff --git a/MediaBrowser.Controller/Sync/ISyncProvider.cs b/MediaBrowser.Controller/Sync/ISyncProvider.cs index 56f6f3729..950cc73e8 100644 --- a/MediaBrowser.Controller/Sync/ISyncProvider.cs +++ b/MediaBrowser.Controller/Sync/ISyncProvider.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System.Collections.Generic; using MediaBrowser.Model.Sync; diff --git a/MediaBrowser.Controller/Sync/SyncedFileInfo.cs b/MediaBrowser.Controller/Sync/SyncedFileInfo.cs index 687a46d78..a626738fb 100644 --- a/MediaBrowser.Controller/Sync/SyncedFileInfo.cs +++ b/MediaBrowser.Controller/Sync/SyncedFileInfo.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System.Collections.Generic; using MediaBrowser.Model.MediaInfo; @@ -5,6 +7,11 @@ namespace MediaBrowser.Controller.Sync { public class SyncedFileInfo { + public SyncedFileInfo() + { + RequiredHttpHeaders = new Dictionary<string, string>(); + } + /// <summary> /// Gets or sets the path. /// </summary> @@ -12,25 +19,23 @@ namespace MediaBrowser.Controller.Sync public string Path { get; set; } public string[] PathParts { get; set; } + /// <summary> /// Gets or sets the protocol. /// </summary> /// <value>The protocol.</value> public MediaProtocol Protocol { get; set; } + /// <summary> /// Gets or sets the required HTTP headers. /// </summary> /// <value>The required HTTP headers.</value> public Dictionary<string, string> RequiredHttpHeaders { get; set; } + /// <summary> /// Gets or sets the identifier. /// </summary> /// <value>The identifier.</value> public string Id { get; set; } - - public SyncedFileInfo() - { - RequiredHttpHeaders = new Dictionary<string, string>(); - } } } diff --git a/MediaBrowser.Controller/SyncPlay/ISyncPlayController.cs b/MediaBrowser.Controller/SyncPlay/ISyncPlayController.cs index 45c543806..60d17fe36 100644 --- a/MediaBrowser.Controller/SyncPlay/ISyncPlayController.cs +++ b/MediaBrowser.Controller/SyncPlay/ISyncPlayController.cs @@ -64,4 +64,4 @@ namespace MediaBrowser.Controller.SyncPlay /// <value>The group info for the clients.</value> GroupInfoView GetInfo(); } -} \ No newline at end of file +} diff --git a/MediaBrowser.Controller/TV/ITVSeriesManager.cs b/MediaBrowser.Controller/TV/ITVSeriesManager.cs index 09a0f6fea..291dea04e 100644 --- a/MediaBrowser.Controller/TV/ITVSeriesManager.cs +++ b/MediaBrowser.Controller/TV/ITVSeriesManager.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Model.Querying; -- cgit v1.2.3 From 5ec1a979b2bb501edb8836c0170cd10e5dd2d292 Mon Sep 17 00:00:00 2001 From: Bond_009 <bond.009@outlook.com> Date: Sat, 22 Aug 2020 21:57:28 +0200 Subject: Remove extra newline --- MediaBrowser.Controller/Authentication/AuthenticationResult.cs | 1 - 1 file changed, 1 deletion(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/Authentication/AuthenticationResult.cs b/MediaBrowser.Controller/Authentication/AuthenticationResult.cs index bdebd76ab..4249a9a66 100644 --- a/MediaBrowser.Controller/Authentication/AuthenticationResult.cs +++ b/MediaBrowser.Controller/Authentication/AuthenticationResult.cs @@ -1,6 +1,5 @@ #pragma warning disable CS1591 - using MediaBrowser.Controller.Session; using MediaBrowser.Model.Dto; -- cgit v1.2.3 From c4d8275fc1ad29823788043750e2f3f8e8b8244e Mon Sep 17 00:00:00 2001 From: Bond_009 <bond.009@outlook.com> Date: Sun, 23 Aug 2020 00:26:32 +0200 Subject: Fix duplicate --- MediaBrowser.Controller/Entities/Folder.cs | 2 -- 1 file changed, 2 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index 7687cf12b..11542c1ca 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -1,7 +1,5 @@ #pragma warning disable CS1591 -#pragma warning disable CS1591 - using System; using System.Collections.Generic; using System.Globalization; -- cgit v1.2.3 From 71c33d09c4a71ac9fcd390237986dee969109510 Mon Sep 17 00:00:00 2001 From: Patrick Barron <barronpm@gmail.com> Date: Mon, 24 Aug 2020 20:34:33 -0400 Subject: Document IEventConsumer --- MediaBrowser.Controller/Events/IEventConsumer.cs | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/Events/IEventConsumer.cs b/MediaBrowser.Controller/Events/IEventConsumer.cs index 3cefe2f9c..5c4ab5d8d 100644 --- a/MediaBrowser.Controller/Events/IEventConsumer.cs +++ b/MediaBrowser.Controller/Events/IEventConsumer.cs @@ -3,9 +3,18 @@ using System.Threading.Tasks; namespace MediaBrowser.Controller.Events { + /// <summary> + /// An interface representing a type that consumes events of type <c>T</c>. + /// </summary> + /// <typeparam name="T">The type of events this consumes.</typeparam> public interface IEventConsumer<in T> where T : EventArgs { + /// <summary> + /// A method that is called when an event of type <c>T</c> is fired. + /// </summary> + /// <param name="eventArgs">The event.</param> + /// <returns>A task representing the consumption of the event.</returns> Task OnEvent(T eventArgs); } } -- cgit v1.2.3 From 2eb9a3670bc63c06c464c487eb3d7b59de310dfe Mon Sep 17 00:00:00 2001 From: Patrick Barron <barronpm@gmail.com> Date: Mon, 24 Aug 2020 20:34:42 -0400 Subject: Document PlaybackStartEventArgs --- MediaBrowser.Controller/Library/PlaybackStartEventArgs.cs | 3 +++ 1 file changed, 3 insertions(+) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/Library/PlaybackStartEventArgs.cs b/MediaBrowser.Controller/Library/PlaybackStartEventArgs.cs index 3aa9c2895..ac372bceb 100644 --- a/MediaBrowser.Controller/Library/PlaybackStartEventArgs.cs +++ b/MediaBrowser.Controller/Library/PlaybackStartEventArgs.cs @@ -1,5 +1,8 @@ namespace MediaBrowser.Controller.Library { + /// <summary> + /// An event that occurs when playback is started. + /// </summary> public class PlaybackStartEventArgs : PlaybackProgressEventArgs { } -- cgit v1.2.3 From b5bbbb9cefb7b360e12b44522d6494bfb4c0f848 Mon Sep 17 00:00:00 2001 From: Patrick Barron <barronpm@gmail.com> Date: Mon, 24 Aug 2020 20:34:53 -0400 Subject: Document SubtitleDownloadFailureEventArgs --- .../Subtitles/SubtitleDownloadFailureEventArgs.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/Subtitles/SubtitleDownloadFailureEventArgs.cs b/MediaBrowser.Controller/Subtitles/SubtitleDownloadFailureEventArgs.cs index 7687bf5b6..ce8141219 100644 --- a/MediaBrowser.Controller/Subtitles/SubtitleDownloadFailureEventArgs.cs +++ b/MediaBrowser.Controller/Subtitles/SubtitleDownloadFailureEventArgs.cs @@ -3,12 +3,24 @@ using MediaBrowser.Controller.Entities; namespace MediaBrowser.Controller.Subtitles { + /// <summary> + /// An event that occurs when subtitle downloading fails. + /// </summary> public class SubtitleDownloadFailureEventArgs : EventArgs { + /// <summary> + /// Gets or sets the item. + /// </summary> public BaseItem Item { get; set; } + /// <summary> + /// Gets or sets the provider. + /// </summary> public string Provider { get; set; } + /// <summary> + /// Gets or sets the exception. + /// </summary> public Exception Exception { get; set; } } } -- cgit v1.2.3 From 670c41ee8900da32f0936a9a1f45d73e0508432b Mon Sep 17 00:00:00 2001 From: crobibero <cody@robibe.ro> Date: Tue, 25 Aug 2020 21:33:19 -0600 Subject: Properly pack project license --- Emby.Naming/Emby.Naming.csproj | 12 +- Jellyfin.Data/Jellyfin.Data.csproj | 12 +- LICENSE | 339 --------------------- LICENSE.txt | 339 +++++++++++++++++++++ MediaBrowser.Common/MediaBrowser.Common.csproj | 12 +- .../MediaBrowser.Controller.csproj | 12 +- MediaBrowser.Model/MediaBrowser.Model.csproj | 12 +- 7 files changed, 394 insertions(+), 344 deletions(-) delete mode 100644 LICENSE create mode 100644 LICENSE.txt (limited to 'MediaBrowser.Controller') diff --git a/Emby.Naming/Emby.Naming.csproj b/Emby.Naming/Emby.Naming.csproj index 14aac1a4a..810895757 100644 --- a/Emby.Naming/Emby.Naming.csproj +++ b/Emby.Naming/Emby.Naming.csproj @@ -24,10 +24,20 @@ <Authors>Jellyfin Contributors</Authors> <PackageId>Jellyfin.Naming</PackageId> <VersionPrefix>10.7.0</VersionPrefix> - <PackageLicenseUrl>https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt</PackageLicenseUrl> <RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl> </PropertyGroup> + <PropertyGroup> + <PackageLicenseFile>LICENSE.txt</PackageLicenseFile> + </PropertyGroup> + + <ItemGroup> + <None Include="../LICENSE.txt"> + <PackagePath>LICENSE.txt</PackagePath> + <Pack>true</Pack> + </None> + </ItemGroup> + <!-- Code Analyzers--> <ItemGroup Condition=" '$(Configuration)' == 'Debug' "> <!-- TODO: <PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.8" PrivateAssets="All" /> --> diff --git a/Jellyfin.Data/Jellyfin.Data.csproj b/Jellyfin.Data/Jellyfin.Data.csproj index 64a1dc57a..0b4bbb562 100644 --- a/Jellyfin.Data/Jellyfin.Data.csproj +++ b/Jellyfin.Data/Jellyfin.Data.csproj @@ -11,10 +11,20 @@ <Authors>Jellyfin Contributors</Authors> <PackageId>Jellyfin.Data</PackageId> <VersionPrefix>10.7.0</VersionPrefix> - <PackageLicenseUrl>https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt</PackageLicenseUrl> <RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl> </PropertyGroup> + <PropertyGroup> + <PackageLicenseFile>LICENSE.txt</PackageLicenseFile> + </PropertyGroup> + + <ItemGroup> + <None Include="../LICENSE.txt"> + <PackagePath>LICENSE.txt</PackagePath> + <Pack>true</Pack> + </None> + </ItemGroup> + <PropertyGroup Condition=" '$(Configuration)' == 'Debug' "> <CodeAnalysisRuleSet>../jellyfin.ruleset</CodeAnalysisRuleSet> </PropertyGroup> diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 4522ba065..000000000 --- a/LICENSE +++ /dev/null @@ -1,339 +0,0 @@ -GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - {{description}} - Copyright (C) {{year}} {{fullname}} - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - {signature of Ty Coon}, 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 000000000..4522ba065 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,339 @@ +GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + {{description}} + Copyright (C) {{year}} {{fullname}} + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + {signature of Ty Coon}, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/MediaBrowser.Common/MediaBrowser.Common.csproj b/MediaBrowser.Common/MediaBrowser.Common.csproj index 04100eba4..3716b66a0 100644 --- a/MediaBrowser.Common/MediaBrowser.Common.csproj +++ b/MediaBrowser.Common/MediaBrowser.Common.csproj @@ -9,10 +9,20 @@ <Authors>Jellyfin Contributors</Authors> <PackageId>Jellyfin.Common</PackageId> <VersionPrefix>10.7.0</VersionPrefix> - <PackageLicenseUrl>https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt</PackageLicenseUrl> <RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl> </PropertyGroup> + <PropertyGroup> + <PackageLicenseFile>LICENSE.txt</PackageLicenseFile> + </PropertyGroup> + + <ItemGroup> + <None Include="../LICENSE.txt"> + <PackagePath>LICENSE.txt</PackagePath> + <Pack>true</Pack> + </None> + </ItemGroup> + <ItemGroup> <ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj" /> </ItemGroup> diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index c155c6668..1763d240b 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -9,10 +9,20 @@ <Authors>Jellyfin Contributors</Authors> <PackageId>Jellyfin.Controller</PackageId> <VersionPrefix>10.7.0</VersionPrefix> - <PackageLicenseUrl>https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt</PackageLicenseUrl> <RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl> </PropertyGroup> + <PropertyGroup> + <PackageLicenseFile>LICENSE.txt</PackageLicenseFile> + </PropertyGroup> + + <ItemGroup> + <None Include="../LICENSE.txt"> + <PackagePath>LICENSE.txt</PackagePath> + <Pack>true</Pack> + </None> + </ItemGroup> + <ItemGroup> <PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.1.6" /> <PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="3.1.6" /> diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj index 2cb89f77f..f40b90d89 100644 --- a/MediaBrowser.Model/MediaBrowser.Model.csproj +++ b/MediaBrowser.Model/MediaBrowser.Model.csproj @@ -9,10 +9,20 @@ <Authors>Jellyfin Contributors</Authors> <PackageId>Jellyfin.Model</PackageId> <VersionPrefix>10.7.0</VersionPrefix> - <PackageLicenseUrl>https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt</PackageLicenseUrl> <RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl> </PropertyGroup> + <PropertyGroup> + <PackageLicenseFile>LICENSE.txt</PackageLicenseFile> + </PropertyGroup> + + <ItemGroup> + <None Include="../LICENSE.txt"> + <PackagePath>LICENSE.txt</PackagePath> + <Pack>true</Pack> + </None> + </ItemGroup> + <PropertyGroup> <TargetFrameworks>netstandard2.0;netstandard2.1</TargetFrameworks> <GenerateAssemblyInfo>false</GenerateAssemblyInfo> -- cgit v1.2.3 From 5f60da29c737cae4ee298f9fbeae971740f8a5ba Mon Sep 17 00:00:00 2001 From: crobibero <cody@robibe.ro> Date: Wed, 26 Aug 2020 07:36:57 -0600 Subject: switch to spdx --- Emby.Naming/Emby.Naming.csproj | 12 +----------- Jellyfin.Data/Jellyfin.Data.csproj | 12 +----------- MediaBrowser.Common/MediaBrowser.Common.csproj | 12 +----------- MediaBrowser.Controller/MediaBrowser.Controller.csproj | 12 +----------- MediaBrowser.Model/MediaBrowser.Model.csproj | 12 +----------- 5 files changed, 5 insertions(+), 55 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Naming/Emby.Naming.csproj b/Emby.Naming/Emby.Naming.csproj index 810895757..cad5001e1 100644 --- a/Emby.Naming/Emby.Naming.csproj +++ b/Emby.Naming/Emby.Naming.csproj @@ -25,19 +25,9 @@ <PackageId>Jellyfin.Naming</PackageId> <VersionPrefix>10.7.0</VersionPrefix> <RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl> + <PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression> </PropertyGroup> - <PropertyGroup> - <PackageLicenseFile>LICENSE.txt</PackageLicenseFile> - </PropertyGroup> - - <ItemGroup> - <None Include="../LICENSE.txt"> - <PackagePath>LICENSE.txt</PackagePath> - <Pack>true</Pack> - </None> - </ItemGroup> - <!-- Code Analyzers--> <ItemGroup Condition=" '$(Configuration)' == 'Debug' "> <!-- TODO: <PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.8" PrivateAssets="All" /> --> diff --git a/Jellyfin.Data/Jellyfin.Data.csproj b/Jellyfin.Data/Jellyfin.Data.csproj index 0b4bbb562..18b5bb522 100644 --- a/Jellyfin.Data/Jellyfin.Data.csproj +++ b/Jellyfin.Data/Jellyfin.Data.csproj @@ -12,19 +12,9 @@ <PackageId>Jellyfin.Data</PackageId> <VersionPrefix>10.7.0</VersionPrefix> <RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl> + <PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression> </PropertyGroup> - <PropertyGroup> - <PackageLicenseFile>LICENSE.txt</PackageLicenseFile> - </PropertyGroup> - - <ItemGroup> - <None Include="../LICENSE.txt"> - <PackagePath>LICENSE.txt</PackagePath> - <Pack>true</Pack> - </None> - </ItemGroup> - <PropertyGroup Condition=" '$(Configuration)' == 'Debug' "> <CodeAnalysisRuleSet>../jellyfin.ruleset</CodeAnalysisRuleSet> </PropertyGroup> diff --git a/MediaBrowser.Common/MediaBrowser.Common.csproj b/MediaBrowser.Common/MediaBrowser.Common.csproj index 3716b66a0..e8ec75349 100644 --- a/MediaBrowser.Common/MediaBrowser.Common.csproj +++ b/MediaBrowser.Common/MediaBrowser.Common.csproj @@ -10,19 +10,9 @@ <PackageId>Jellyfin.Common</PackageId> <VersionPrefix>10.7.0</VersionPrefix> <RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl> + <PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression> </PropertyGroup> - <PropertyGroup> - <PackageLicenseFile>LICENSE.txt</PackageLicenseFile> - </PropertyGroup> - - <ItemGroup> - <None Include="../LICENSE.txt"> - <PackagePath>LICENSE.txt</PackagePath> - <Pack>true</Pack> - </None> - </ItemGroup> - <ItemGroup> <ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj" /> </ItemGroup> diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index 1763d240b..9c86dba24 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -10,19 +10,9 @@ <PackageId>Jellyfin.Controller</PackageId> <VersionPrefix>10.7.0</VersionPrefix> <RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl> + <PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression> </PropertyGroup> - <PropertyGroup> - <PackageLicenseFile>LICENSE.txt</PackageLicenseFile> - </PropertyGroup> - - <ItemGroup> - <None Include="../LICENSE.txt"> - <PackagePath>LICENSE.txt</PackagePath> - <Pack>true</Pack> - </None> - </ItemGroup> - <ItemGroup> <PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.1.6" /> <PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="3.1.6" /> diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj index f40b90d89..81cecf2c7 100644 --- a/MediaBrowser.Model/MediaBrowser.Model.csproj +++ b/MediaBrowser.Model/MediaBrowser.Model.csproj @@ -10,19 +10,9 @@ <PackageId>Jellyfin.Model</PackageId> <VersionPrefix>10.7.0</VersionPrefix> <RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl> + <PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression> </PropertyGroup> - <PropertyGroup> - <PackageLicenseFile>LICENSE.txt</PackageLicenseFile> - </PropertyGroup> - - <ItemGroup> - <None Include="../LICENSE.txt"> - <PackagePath>LICENSE.txt</PackagePath> - <Pack>true</Pack> - </None> - </ItemGroup> - <PropertyGroup> <TargetFrameworks>netstandard2.0;netstandard2.1</TargetFrameworks> <GenerateAssemblyInfo>false</GenerateAssemblyInfo> -- cgit v1.2.3 From b02650ec2f812500e99c03a80425d548fc5cfc0c Mon Sep 17 00:00:00 2001 From: crobibero <cody@robibe.ro> Date: Wed, 26 Aug 2020 07:39:01 -0600 Subject: use proper spdx --- Emby.Naming/Emby.Naming.csproj | 2 +- Jellyfin.Data/Jellyfin.Data.csproj | 2 +- MediaBrowser.Common/MediaBrowser.Common.csproj | 2 +- MediaBrowser.Controller/MediaBrowser.Controller.csproj | 2 +- MediaBrowser.Model/MediaBrowser.Model.csproj | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Naming/Emby.Naming.csproj b/Emby.Naming/Emby.Naming.csproj index cad5001e1..5e2c6e3e3 100644 --- a/Emby.Naming/Emby.Naming.csproj +++ b/Emby.Naming/Emby.Naming.csproj @@ -25,7 +25,7 @@ <PackageId>Jellyfin.Naming</PackageId> <VersionPrefix>10.7.0</VersionPrefix> <RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl> - <PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression> + <PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression> </PropertyGroup> <!-- Code Analyzers--> diff --git a/Jellyfin.Data/Jellyfin.Data.csproj b/Jellyfin.Data/Jellyfin.Data.csproj index 18b5bb522..e8065419d 100644 --- a/Jellyfin.Data/Jellyfin.Data.csproj +++ b/Jellyfin.Data/Jellyfin.Data.csproj @@ -12,7 +12,7 @@ <PackageId>Jellyfin.Data</PackageId> <VersionPrefix>10.7.0</VersionPrefix> <RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl> - <PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression> + <PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression> </PropertyGroup> <PropertyGroup Condition=" '$(Configuration)' == 'Debug' "> diff --git a/MediaBrowser.Common/MediaBrowser.Common.csproj b/MediaBrowser.Common/MediaBrowser.Common.csproj index e8ec75349..deb674e45 100644 --- a/MediaBrowser.Common/MediaBrowser.Common.csproj +++ b/MediaBrowser.Common/MediaBrowser.Common.csproj @@ -10,7 +10,7 @@ <PackageId>Jellyfin.Common</PackageId> <VersionPrefix>10.7.0</VersionPrefix> <RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl> - <PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression> + <PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression> </PropertyGroup> <ItemGroup> diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index 9c86dba24..df92eda38 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -10,7 +10,7 @@ <PackageId>Jellyfin.Controller</PackageId> <VersionPrefix>10.7.0</VersionPrefix> <RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl> - <PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression> + <PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression> </PropertyGroup> <ItemGroup> diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj index 81cecf2c7..b0f99cef2 100644 --- a/MediaBrowser.Model/MediaBrowser.Model.csproj +++ b/MediaBrowser.Model/MediaBrowser.Model.csproj @@ -10,7 +10,7 @@ <PackageId>Jellyfin.Model</PackageId> <VersionPrefix>10.7.0</VersionPrefix> <RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl> - <PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression> + <PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression> </PropertyGroup> <PropertyGroup> -- cgit v1.2.3 From e653eef44ff5dd7e568816d43b9e0d50b2293387 Mon Sep 17 00:00:00 2001 From: Bond_009 <bond.009@outlook.com> Date: Mon, 31 Aug 2020 22:20:19 +0200 Subject: Fix some warnings --- Emby.Dlna/ContentDirectory/ControlHandler.cs | 2 +- Emby.Dlna/Didl/DidlBuilder.cs | 4 +- .../AppBase/BaseConfigurationManager.cs | 2 +- Emby.Server.Implementations/ApplicationHost.cs | 12 +++-- .../Channels/ChannelManager.cs | 2 +- Emby.Server.Implementations/Dto/DtoService.cs | 2 +- Emby.Server.Implementations/IO/FileRefresher.cs | 7 +-- Emby.Server.Implementations/IO/LibraryMonitor.cs | 2 +- .../IO/ManagedFileSystem.cs | 32 ------------ Emby.Server.Implementations/IO/StreamHelper.cs | 32 +----------- .../LiveTv/EmbyTV/DirectRecorder.cs | 21 +++++--- .../LiveTv/EmbyTV/EmbyTV.cs | 22 +------- .../LiveTv/EmbyTV/EncodedRecorder.cs | 43 ++++------------ .../LiveTv/Listings/SchedulesDirect.cs | 23 +++++---- .../ScheduledTasks/Tasks/DeleteCacheFileTask.cs | 59 ++++++++++------------ .../ScheduledTasks/Tasks/PluginUpdateTask.cs | 42 +++++++-------- .../ScheduledTasks/Triggers/DailyTrigger.cs | 12 ++--- .../ScheduledTasks/Triggers/IntervalTrigger.cs | 14 ++--- .../ScheduledTasks/Triggers/StartupTrigger.cs | 15 +++--- .../ScheduledTasks/Triggers/WeeklyTrigger.cs | 17 +++---- MediaBrowser.Controller/LiveTv/ChannelInfo.cs | 1 + MediaBrowser.Model/IO/FileSystemMetadata.cs | 2 +- MediaBrowser.Model/IO/IFileSystem.cs | 4 +- MediaBrowser.Model/IO/IShortcutHandler.cs | 1 - MediaBrowser.Model/IO/IStreamHelper.cs | 2 - MediaBrowser.Model/IO/IZipClient.cs | 1 + .../Plugins/Tmdb/People/TmdbPersonImageProvider.cs | 8 +-- .../Plugins/Tmdb/People/TmdbPersonProvider.cs | 18 +++++-- 28 files changed, 156 insertions(+), 246 deletions(-) (limited to 'MediaBrowser.Controller') 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 a2d6e2c9e..8b73e3610 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -275,6 +275,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) @@ -304,16 +308,16 @@ namespace Emby.Server.Implementations } /// <inheritdoc /> - public Version ApplicationVersion { get; } = typeof(ApplicationHost).Assembly.GetName().Version; + public Version ApplicationVersion { get; } /// <inheritdoc /> - public string ApplicationVersionString { get; } = typeof(ApplicationHost).Assembly.GetName().Version.ToString(3); + public string ApplicationVersionString { get; } /// <summary> /// Gets the current application user agent. /// </summary> /// <value>The application user agent.</value> - public string ApplicationUserAgent => Name.Replace(' ', '-') + "/" + ApplicationVersionString; + public string ApplicationUserAgent { get; } /// <summary> /// Gets the email address for use within a comment section of a user agent field. @@ -1403,7 +1407,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 } } + /// <inheritdoc /> 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<byte>.Shared.Rent(bufferSize); @@ -83,37 +81,9 @@ namespace Emby.Server.Implementations.IO } } - public async Task<int> CopyToAsync(Stream source, Stream destination, CancellationToken cancellationToken) - { - byte[] buffer = ArrayPool<byte>.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<byte>.Shared.Return(buffer); - } - } - public async Task CopyToAsync(Stream source, Stream destination, long copyLength, CancellationToken cancellationToken) { - byte[] buffer = ArrayPool<byte>.Shared.Rent(StreamCopyToBufferSize); + byte[] buffer = ArrayPool<byte>.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; - - await _streamHelper.CopyUntilCancelled(response.Content, output, 81920, cancellationToken).ConfigureAwait(false); + using var durationToken = new CancellationTokenSource(duration); + using var cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, durationToken.Token); + + 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<ActiveRecordingInfo> 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<MediaSourceInfo>(json); - - mediaSource.Id = Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture) + "_" + mediaSource.Id; - - return mediaSource; - } - public async Task<List<MediaSourceInfo>> 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<bool> _taskCompletionSource = new TaskCompletionSource<bool>(); + private bool _hasExited; private Stream _logFileStream; private string _targetPath; private Process _process; - private readonly IJsonSerializer _json; - private readonly TaskCompletionSource<bool> _taskCompletionSource = new TaskCompletionSource<bool>(); - 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<EncodingOptions>("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<string>(); - - 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 /// <summary> /// Processes the exited. /// </summary> - 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<SchedulesDirect> _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<SchedulesDirect> 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<HttpResponseInfo> Post(HttpRequestOptions options, + private async Task<HttpResponseInfo> 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<HttpResponseInfo> Get(HttpRequestOptions options, + private async Task<HttpResponseInfo> 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<string> GetTokenInternal(string username, string password, + private async Task<string> GetTokenInternal( + string username, + string password, CancellationToken cancellationToken) { var httpOptions = new HttpRequestOptions() 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. /// </summary> /// <value>The application paths.</value> - private IApplicationPaths ApplicationPaths { get; set; } - + private readonly IApplicationPaths _applicationPaths; private readonly ILogger<DeleteCacheFileTask> _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; } + /// <inheritdoc /> + public string Name => _localization.GetLocalizedString("TaskCleanCache"); + + /// <inheritdoc /> + public string Description => _localization.GetLocalizedString("TaskCleanCacheDescription"); + + /// <inheritdoc /> + public string Category => _localization.GetLocalizedString("TasksMaintenanceCategory"); + + /// <inheritdoc /> + public string Key => "DeleteCacheFiles"; + + /// <inheritdoc /> + public bool IsHidden => false; + + /// <inheritdoc /> + public bool IsEnabled => true; + + /// <inheritdoc /> + public bool IsLogged => true; + /// <summary> /// Creates the triggers that define when the task will run. /// </summary> /// <returns>IEnumerable{BaseTaskTrigger}.</returns> public IEnumerable<TaskTriggerInfo> 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; } - /// <summary> /// Deletes the cache files from directory with a last write time less than a given date. /// </summary> @@ -164,26 +182,5 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks _logger.LogError(ex, "Error deleting file {path}", path); } } - - /// <inheritdoc /> - public string Name => _localization.GetLocalizedString("TaskCleanCache"); - - /// <inheritdoc /> - public string Description => _localization.GetLocalizedString("TaskCleanCacheDescription"); - - /// <inheritdoc /> - public string Category => _localization.GetLocalizedString("TasksMaintenanceCategory"); - - /// <inheritdoc /> - public string Key => "DeleteCacheFiles"; - - /// <inheritdoc /> - public bool IsHidden => false; - - /// <inheritdoc /> - public bool IsEnabled => true; - - /// <inheritdoc /> - 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; } + /// <inheritdoc /> + public string Name => _localization.GetLocalizedString("TaskUpdatePlugins"); + + /// <inheritdoc /> + public string Description => _localization.GetLocalizedString("TaskUpdatePluginsDescription"); + + /// <inheritdoc /> + public string Category => _localization.GetLocalizedString("TasksApplicationCategory"); + + /// <inheritdoc /> + public string Key => "PluginUpdates"; + + /// <inheritdoc /> + public bool IsHidden => false; + + /// <inheritdoc /> + public bool IsEnabled => true; + + /// <inheritdoc /> + public bool IsLogged => true; + /// <summary> /// Creates the triggers that define when the task will run. /// </summary> @@ -98,26 +119,5 @@ namespace Emby.Server.Implementations.ScheduledTasks progress.Report(100); } - - /// <inheritdoc /> - public string Name => _localization.GetLocalizedString("TaskUpdatePlugins"); - - /// <inheritdoc /> - public string Description => _localization.GetLocalizedString("TaskUpdatePluginsDescription"); - - /// <inheritdoc /> - public string Category => _localization.GetLocalizedString("TasksApplicationCategory"); - - /// <inheritdoc /> - public string Key => "PluginUpdates"; - - /// <inheritdoc /> - public bool IsHidden => false; - - /// <inheritdoc /> - public bool IsEnabled => true; - - /// <inheritdoc /> - 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 { /// <summary> - /// Get the time of day to trigger the task to run. + /// Occurs when [triggered]. + /// </summary> + public event EventHandler<EventArgs> Triggered; + + /// <summary> + /// Gets or sets the time of day to trigger the task to run. /// </summary> /// <value>The time of day.</value> public TimeSpan TimeOfDay { get; set; } @@ -69,11 +74,6 @@ namespace Emby.Server.Implementations.ScheduledTasks } } - /// <summary> - /// Occurs when [triggered]. - /// </summary> - public event EventHandler<EventArgs> Triggered; - /// <summary> /// Called when [triggered]. /// </summary> 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 /// </summary> public class IntervalTrigger : ITaskTrigger { + private DateTime _lastStartDate; + + /// <summary> + /// Occurs when [triggered]. + /// </summary> + public event EventHandler<EventArgs> Triggered; + /// <summary> /// Gets or sets the interval. /// </summary> @@ -28,8 +35,6 @@ namespace Emby.Server.Implementations.ScheduledTasks /// <value>The timer.</value> private Timer Timer { get; set; } - private DateTime _lastStartDate; - /// <summary> /// Stars waiting for the trigger action. /// </summary> @@ -88,11 +93,6 @@ namespace Emby.Server.Implementations.ScheduledTasks } } - /// <summary> - /// Occurs when [triggered]. - /// </summary> - public event EventHandler<EventArgs> Triggered; - /// <summary> /// Called when [triggered]. /// </summary> 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 /// </summary> public class StartupTrigger : ITaskTrigger { + /// <summary> + /// Occurs when [triggered]. + /// </summary> + public event EventHandler<EventArgs> Triggered; + public int DelayMs { get; set; } /// <summary> @@ -48,20 +53,12 @@ namespace Emby.Server.Implementations.ScheduledTasks { } - /// <summary> - /// Occurs when [triggered]. - /// </summary> - public event EventHandler<EventArgs> Triggered; - /// <summary> /// Called when [triggered]. /// </summary> 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 { /// <summary> - /// Get the time of day to trigger the task to run. + /// Occurs when [triggered]. + /// </summary> + public event EventHandler<EventArgs> Triggered; + + /// <summary> + /// Gets or sets the time of day to trigger the task to run. /// </summary> /// <value>The time of day.</value> public TimeSpan TimeOfDay { get; set; } @@ -95,20 +100,12 @@ namespace Emby.Server.Implementations.ScheduledTasks } } - /// <summary> - /// Occurs when [triggered]. - /// </summary> - public event EventHandler<EventArgs> Triggered; - /// <summary> /// Called when [triggered]. /// </summary> private void OnTriggered() { - if (Triggered != null) - { - Triggered(this, EventArgs.Empty); - } + Triggered?.Invoke(this, EventArgs.Empty); } } } 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 /// </summary> /// <value><c>null</c> if [has image] contains no value, <c>true</c> if [has image]; otherwise, <c>false</c>.</value> public bool? HasImage { get; set; } + /// <summary> /// Gets or sets a value indicating whether this instance is favorite. /// </summary> 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; } /// <summary> - /// Gets a value indicating whether this instance is directory. + /// Gets or sets a value indicating whether this instance is directory. /// </summary> /// <value><c>true</c> if this instance is directory; otherwise, <c>false</c>.</value> 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<string> 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<FileSystemMetadata> 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 /// </summary> /// <param name="shortcutPath">The shortcut path.</param> /// <param name="targetPath">The target path.</param> - /// <returns>System.String.</returns> 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<int> 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); /// <summary> 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; + + /// <inheritdoc /> public string Name => ProviderName; - public static string ProviderName => TmdbUtils.ProviderName; + /// <inheritdoc /> + 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<HttpResponseMessage> 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<IEnumerable<RemoteSearchResult>> GetSearchResults(PersonLookupInfo searchInfo, CancellationToken cancellationToken) @@ -95,7 +97,11 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.People return new List<RemoteSearchResult>(); } - 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"); - /// <summary> /// Gets the TMDB id. /// </summary> @@ -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) -- cgit v1.2.3 From e3377564288598742dbf64f396ed38e42b6b2915 Mon Sep 17 00:00:00 2001 From: Claus Vium <clausvium@gmail.com> Date: Wed, 2 Sep 2020 12:22:14 +0200 Subject: Remove ServiceStack and related stuff --- Emby.Server.Implementations/ApplicationHost.cs | 8 +- .../HttpServer/FileWriter.cs | 250 ------- .../HttpServer/HttpListenerHost.cs | 233 +------ .../HttpServer/HttpResultFactory.cs | 721 --------------------- .../HttpServer/RangeRequestWriter.cs | 212 ------ .../HttpServer/ResponseFilter.cs | 113 ---- .../HttpServer/Security/AuthService.cs | 213 +----- .../HttpServer/Security/AuthorizationContext.cs | 21 +- .../HttpServer/Security/SessionContext.cs | 20 +- .../HttpServer/StreamWriter.cs | 120 ---- Emby.Server.Implementations/Services/HttpResult.cs | 64 -- .../Services/RequestHelper.cs | 51 -- .../Services/ResponseHelper.cs | 141 ---- .../Services/ServiceController.cs | 202 ------ .../Services/ServiceExec.cs | 230 ------- .../Services/ServiceHandler.cs | 212 ------ .../Services/ServiceMethod.cs | 20 - .../Services/ServicePath.cs | 550 ---------------- .../Services/StringMapTypeDeserializer.cs | 118 ---- .../Services/UrlExtensions.cs | 27 - .../SocketSharp/WebSocketSharpRequest.cs | 248 ------- .../Extensions/HttpContextExtensions.cs | 55 +- .../MediaEncoding/EncodingJobOptions.cs | 30 - .../Net/AuthenticatedAttribute.cs | 76 --- MediaBrowser.Controller/Net/IAuthService.cs | 17 - .../Net/IAuthorizationContext.cs | 3 +- MediaBrowser.Controller/Net/IHasResultFactory.cs | 17 - MediaBrowser.Controller/Net/IHttpResultFactory.cs | 82 --- MediaBrowser.Controller/Net/IHttpServer.cs | 9 +- MediaBrowser.Controller/Net/ISessionContext.cs | 6 +- MediaBrowser.Controller/Net/StaticResultOptions.cs | 44 -- MediaBrowser.Model/Services/ApiMemberAttribute.cs | 65 -- MediaBrowser.Model/Services/IAsyncStreamWriter.cs | 13 - MediaBrowser.Model/Services/IHasHeaders.cs | 11 - MediaBrowser.Model/Services/IHasRequestFilter.cs | 24 - MediaBrowser.Model/Services/IHttpRequest.cs | 17 - MediaBrowser.Model/Services/IHttpResult.cs | 35 - MediaBrowser.Model/Services/IRequest.cs | 93 --- .../Services/IRequiresRequestStream.cs | 14 - MediaBrowser.Model/Services/IService.cs | 15 - MediaBrowser.Model/Services/IStreamWriter.cs | 11 - .../Services/QueryParamCollection.cs | 147 ----- MediaBrowser.Model/Services/RouteAttribute.cs | 163 ----- MediaBrowser.Model/Session/PlayRequest.cs | 1 - .../HttpServer/ResponseFilterTests.cs | 18 - 45 files changed, 91 insertions(+), 4649 deletions(-) delete mode 100644 Emby.Server.Implementations/HttpServer/FileWriter.cs delete mode 100644 Emby.Server.Implementations/HttpServer/HttpResultFactory.cs delete mode 100644 Emby.Server.Implementations/HttpServer/RangeRequestWriter.cs delete mode 100644 Emby.Server.Implementations/HttpServer/ResponseFilter.cs delete mode 100644 Emby.Server.Implementations/HttpServer/StreamWriter.cs delete mode 100644 Emby.Server.Implementations/Services/HttpResult.cs delete mode 100644 Emby.Server.Implementations/Services/RequestHelper.cs delete mode 100644 Emby.Server.Implementations/Services/ResponseHelper.cs delete mode 100644 Emby.Server.Implementations/Services/ServiceController.cs delete mode 100644 Emby.Server.Implementations/Services/ServiceExec.cs delete mode 100644 Emby.Server.Implementations/Services/ServiceHandler.cs delete mode 100644 Emby.Server.Implementations/Services/ServiceMethod.cs delete mode 100644 Emby.Server.Implementations/Services/ServicePath.cs delete mode 100644 Emby.Server.Implementations/Services/StringMapTypeDeserializer.cs delete mode 100644 Emby.Server.Implementations/Services/UrlExtensions.cs delete mode 100644 Emby.Server.Implementations/SocketSharp/WebSocketSharpRequest.cs delete mode 100644 MediaBrowser.Controller/Net/AuthenticatedAttribute.cs delete mode 100644 MediaBrowser.Controller/Net/IHasResultFactory.cs delete mode 100644 MediaBrowser.Controller/Net/IHttpResultFactory.cs delete mode 100644 MediaBrowser.Controller/Net/StaticResultOptions.cs delete mode 100644 MediaBrowser.Model/Services/ApiMemberAttribute.cs delete mode 100644 MediaBrowser.Model/Services/IAsyncStreamWriter.cs delete mode 100644 MediaBrowser.Model/Services/IHasHeaders.cs delete mode 100644 MediaBrowser.Model/Services/IHasRequestFilter.cs delete mode 100644 MediaBrowser.Model/Services/IHttpRequest.cs delete mode 100644 MediaBrowser.Model/Services/IHttpResult.cs delete mode 100644 MediaBrowser.Model/Services/IRequest.cs delete mode 100644 MediaBrowser.Model/Services/IRequiresRequestStream.cs delete mode 100644 MediaBrowser.Model/Services/IService.cs delete mode 100644 MediaBrowser.Model/Services/IStreamWriter.cs delete mode 100644 MediaBrowser.Model/Services/QueryParamCollection.cs delete mode 100644 MediaBrowser.Model/Services/RouteAttribute.cs delete mode 100644 tests/Jellyfin.Server.Implementations.Tests/HttpServer/ResponseFilterTests.cs (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index e9b063277..4f47d1999 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -41,7 +41,6 @@ using Emby.Server.Implementations.QuickConnect; using Emby.Server.Implementations.ScheduledTasks; using Emby.Server.Implementations.Security; using Emby.Server.Implementations.Serialization; -using Emby.Server.Implementations.Services; using Emby.Server.Implementations.Session; using Emby.Server.Implementations.SyncPlay; using Emby.Server.Implementations.TV; @@ -90,7 +89,6 @@ using MediaBrowser.Model.IO; using MediaBrowser.Model.MediaInfo; using MediaBrowser.Model.Net; using MediaBrowser.Model.Serialization; -using MediaBrowser.Model.Services; using MediaBrowser.Model.System; using MediaBrowser.Model.Tasks; using MediaBrowser.Providers.Chapters; @@ -544,8 +542,6 @@ namespace Emby.Server.Implementations ServiceCollection.AddSingleton<IZipClient, ZipClient>(); - ServiceCollection.AddSingleton<IHttpResultFactory, HttpResultFactory>(); - ServiceCollection.AddSingleton<IServerApplicationHost>(this); ServiceCollection.AddSingleton<IServerApplicationPaths>(ApplicationPaths); @@ -581,7 +577,6 @@ namespace Emby.Server.Implementations ServiceCollection.AddSingleton<ISearchEngine, SearchEngine>(); - ServiceCollection.AddSingleton<ServiceController>(); ServiceCollection.AddSingleton<IHttpServer, HttpListenerHost>(); ServiceCollection.AddSingleton<IImageProcessor, ImageProcessor>(); @@ -757,7 +752,6 @@ namespace Emby.Server.Implementations CollectionFolder.XmlSerializer = _xmlSerializer; CollectionFolder.JsonSerializer = Resolve<IJsonSerializer>(); CollectionFolder.ApplicationHost = this; - AuthenticatedAttribute.AuthService = Resolve<IAuthService>(); } /// <summary> @@ -777,7 +771,7 @@ namespace Emby.Server.Implementations .Where(i => i != null) .ToArray(); - _httpServer.Init(GetExportTypes<IService>(), GetExports<IWebSocketListener>(), GetUrlPrefixes()); + _httpServer.Init(GetExports<IWebSocketListener>(), GetUrlPrefixes()); Resolve<ILibraryManager>().AddParts( GetExports<IResolverIgnoreRule>(), diff --git a/Emby.Server.Implementations/HttpServer/FileWriter.cs b/Emby.Server.Implementations/HttpServer/FileWriter.cs deleted file mode 100644 index 6fce8de44..000000000 --- a/Emby.Server.Implementations/HttpServer/FileWriter.cs +++ /dev/null @@ -1,250 +0,0 @@ -#pragma warning disable CS1591 - -using System; -using System.Collections.Generic; -using System.Globalization; -using System.IO; -using System.Linq; -using System.Net; -using System.Runtime.InteropServices; -using System.Threading; -using System.Threading.Tasks; -using MediaBrowser.Model.IO; -using MediaBrowser.Model.Services; -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Logging; -using Microsoft.Net.Http.Headers; - -namespace Emby.Server.Implementations.HttpServer -{ - public class FileWriter : IHttpResult - { - private static readonly CultureInfo UsCulture = CultureInfo.ReadOnly(new CultureInfo("en-US")); - - private static readonly string[] _skipLogExtensions = { - ".js", - ".html", - ".css" - }; - - private readonly IStreamHelper _streamHelper; - private readonly ILogger _logger; - - /// <summary> - /// The _options. - /// </summary> - private readonly IDictionary<string, string> _options = new Dictionary<string, string>(); - - /// <summary> - /// The _requested ranges. - /// </summary> - private List<KeyValuePair<long, long?>> _requestedRanges; - - public FileWriter(string path, string contentType, string rangeHeader, ILogger logger, IFileSystem fileSystem, IStreamHelper streamHelper) - { - if (string.IsNullOrEmpty(contentType)) - { - throw new ArgumentNullException(nameof(contentType)); - } - - _streamHelper = streamHelper; - - Path = path; - _logger = logger; - RangeHeader = rangeHeader; - - Headers[HeaderNames.ContentType] = contentType; - - TotalContentLength = fileSystem.GetFileInfo(path).Length; - Headers[HeaderNames.AcceptRanges] = "bytes"; - - if (string.IsNullOrWhiteSpace(rangeHeader)) - { - Headers[HeaderNames.ContentLength] = TotalContentLength.ToString(CultureInfo.InvariantCulture); - StatusCode = HttpStatusCode.OK; - } - else - { - StatusCode = HttpStatusCode.PartialContent; - SetRangeValues(); - } - - FileShare = FileShare.Read; - Cookies = new List<Cookie>(); - } - - private string RangeHeader { get; set; } - - private bool IsHeadRequest { get; set; } - - private long RangeStart { get; set; } - - private long RangeEnd { get; set; } - - private long RangeLength { get; set; } - - public long TotalContentLength { get; set; } - - public Action OnComplete { get; set; } - - public Action OnError { get; set; } - - public List<Cookie> Cookies { get; private set; } - - public FileShare FileShare { get; set; } - - /// <summary> - /// Gets the options. - /// </summary> - /// <value>The options.</value> - public IDictionary<string, string> Headers => _options; - - public string Path { get; set; } - - /// <summary> - /// Gets the requested ranges. - /// </summary> - /// <value>The requested ranges.</value> - protected List<KeyValuePair<long, long?>> RequestedRanges - { - get - { - if (_requestedRanges == null) - { - _requestedRanges = new List<KeyValuePair<long, long?>>(); - - // Example: bytes=0-,32-63 - var ranges = RangeHeader.Split('=')[1].Split(','); - - foreach (var range in ranges) - { - var vals = range.Split('-'); - - long start = 0; - long? end = null; - - if (!string.IsNullOrEmpty(vals[0])) - { - start = long.Parse(vals[0], UsCulture); - } - - if (!string.IsNullOrEmpty(vals[1])) - { - end = long.Parse(vals[1], UsCulture); - } - - _requestedRanges.Add(new KeyValuePair<long, long?>(start, end)); - } - } - - return _requestedRanges; - } - } - - public string ContentType { get; set; } - - public IRequest RequestContext { get; set; } - - public object Response { get; set; } - - public int Status { get; set; } - - public HttpStatusCode StatusCode - { - get => (HttpStatusCode)Status; - set => Status = (int)value; - } - - /// <summary> - /// Sets the range values. - /// </summary> - private void SetRangeValues() - { - var requestedRange = RequestedRanges[0]; - - // If the requested range is "0-", we can optimize by just doing a stream copy - if (!requestedRange.Value.HasValue) - { - RangeEnd = TotalContentLength - 1; - } - else - { - RangeEnd = requestedRange.Value.Value; - } - - RangeStart = requestedRange.Key; - RangeLength = 1 + RangeEnd - RangeStart; - - // Content-Length is the length of what we're serving, not the original content - var lengthString = RangeLength.ToString(CultureInfo.InvariantCulture); - Headers[HeaderNames.ContentLength] = lengthString; - var rangeString = $"bytes {RangeStart}-{RangeEnd}/{TotalContentLength}"; - Headers[HeaderNames.ContentRange] = rangeString; - - _logger.LogDebug("Setting range response values for {0}. RangeRequest: {1} Content-Length: {2}, Content-Range: {3}", Path, RangeHeader, lengthString, rangeString); - } - - public async Task WriteToAsync(HttpResponse response, CancellationToken cancellationToken) - { - try - { - // Headers only - if (IsHeadRequest) - { - return; - } - - var path = Path; - var offset = RangeStart; - var count = RangeLength; - - if (string.IsNullOrWhiteSpace(RangeHeader) || RangeStart <= 0 && RangeEnd >= TotalContentLength - 1) - { - var extension = System.IO.Path.GetExtension(path); - - if (extension == null || !_skipLogExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase)) - { - _logger.LogDebug("Transmit file {0}", path); - } - - offset = 0; - count = 0; - } - - await TransmitFile(response.Body, path, offset, count, FileShare, cancellationToken).ConfigureAwait(false); - } - finally - { - OnComplete?.Invoke(); - } - } - - public async Task TransmitFile(Stream stream, string path, long offset, long count, FileShare fileShare, CancellationToken cancellationToken) - { - var fileOptions = FileOptions.SequentialScan; - - // use non-async filestream along with read due to https://github.com/dotnet/corefx/issues/6039 - if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - fileOptions |= FileOptions.Asynchronous; - } - - using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read, fileShare, IODefaults.FileStreamBufferSize, fileOptions)) - { - if (offset > 0) - { - fs.Position = offset; - } - - if (count > 0) - { - await _streamHelper.CopyToAsync(fs, stream, count, cancellationToken).ConfigureAwait(false); - } - else - { - await fs.CopyToAsync(stream, IODefaults.CopyToBufferSize, cancellationToken).ConfigureAwait(false); - } - } - } - } -} diff --git a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs index fe39bb4b2..30cb7dd3a 100644 --- a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs +++ b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs @@ -7,11 +7,8 @@ using System.IO; using System.Linq; using System.Net.Sockets; using System.Net.WebSockets; -using System.Reflection; using System.Threading; using System.Threading.Tasks; -using Emby.Server.Implementations.Services; -using Emby.Server.Implementations.SocketSharp; using Jellyfin.Data.Events; using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Net; @@ -20,8 +17,6 @@ using MediaBrowser.Controller.Authentication; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Net; using MediaBrowser.Model.Globalization; -using MediaBrowser.Model.Serialization; -using MediaBrowser.Model.Services; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Extensions; using Microsoft.AspNetCore.WebUtilities; @@ -29,7 +24,6 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Primitives; -using ServiceStack.Text.Jsv; namespace Emby.Server.Implementations.HttpServer { @@ -46,13 +40,9 @@ namespace Emby.Server.Implementations.HttpServer private readonly IServerConfigurationManager _config; private readonly INetworkManager _networkManager; private readonly IServerApplicationHost _appHost; - private readonly IJsonSerializer _jsonSerializer; - private readonly IXmlSerializer _xmlSerializer; - private readonly Func<Type, Func<string, object>> _funcParseFn; private readonly string _defaultRedirectPath; private readonly string _baseUrlPrefix; - private readonly Dictionary<Type, Type> _serviceOperationsMap = new Dictionary<Type, Type>(); private readonly IHostEnvironment _hostEnvironment; private IWebSocketListener[] _webSocketListeners = Array.Empty<IWebSocketListener>(); @@ -64,10 +54,7 @@ namespace Emby.Server.Implementations.HttpServer IServerConfigurationManager config, IConfiguration configuration, INetworkManager networkManager, - IJsonSerializer jsonSerializer, - IXmlSerializer xmlSerializer, ILocalizationManager localizationManager, - ServiceController serviceController, IHostEnvironment hostEnvironment, ILoggerFactory loggerFactory) { @@ -77,36 +64,21 @@ namespace Emby.Server.Implementations.HttpServer _defaultRedirectPath = configuration[DefaultRedirectKey]; _baseUrlPrefix = _config.Configuration.BaseUrl; _networkManager = networkManager; - _jsonSerializer = jsonSerializer; - _xmlSerializer = xmlSerializer; - ServiceController = serviceController; _hostEnvironment = hostEnvironment; _loggerFactory = loggerFactory; - _funcParseFn = t => s => JsvReader.GetParseFn(t)(s); - Instance = this; - ResponseFilters = Array.Empty<Action<IRequest, HttpResponse, object>>(); GlobalResponse = localizationManager.GetLocalizedString("StartupEmbyServerIsLoading"); } public event EventHandler<GenericEventArgs<IWebSocketConnection>> WebSocketConnected; - public Action<IRequest, HttpResponse, object>[] ResponseFilters { get; set; } - public static HttpListenerHost Instance { get; protected set; } public string[] UrlPrefixes { get; private set; } public string GlobalResponse { get; set; } - public ServiceController ServiceController { get; } - - public object CreateInstance(Type type) - { - return _appHost.CreateInstance(type); - } - private static string NormalizeUrlPath(string path) { if (path.Length > 0 && path[0] == '/') @@ -121,58 +93,6 @@ namespace Emby.Server.Implementations.HttpServer } } - /// <summary> - /// Applies the request filters. Returns whether or not the request has been handled - /// and no more processing should be done. - /// </summary> - /// <returns></returns> - public void ApplyRequestFilters(IRequest req, HttpResponse res, object requestDto) - { - // Exec all RequestFilter attributes with Priority < 0 - var attributes = GetRequestFilterAttributes(requestDto.GetType()); - - int count = attributes.Count; - int i = 0; - for (; i < count && attributes[i].Priority < 0; i++) - { - var attribute = attributes[i]; - attribute.RequestFilter(req, res, requestDto); - } - - // Exec remaining RequestFilter attributes with Priority >= 0 - for (; i < count && attributes[i].Priority >= 0; i++) - { - var attribute = attributes[i]; - attribute.RequestFilter(req, res, requestDto); - } - } - - public Type GetServiceTypeByRequest(Type requestType) - { - _serviceOperationsMap.TryGetValue(requestType, out var serviceType); - return serviceType; - } - - public void AddServiceInfo(Type serviceType, Type requestType) - { - _serviceOperationsMap[requestType] = serviceType; - } - - private List<IHasRequestFilter> GetRequestFilterAttributes(Type requestDtoType) - { - var attributes = requestDtoType.GetCustomAttributes(true).OfType<IHasRequestFilter>().ToList(); - - var serviceType = GetServiceTypeByRequest(requestDtoType); - if (serviceType != null) - { - attributes.AddRange(serviceType.GetCustomAttributes(true).OfType<IHasRequestFilter>()); - } - - attributes.Sort((x, y) => x.Priority - y.Priority); - - return attributes; - } - private static Exception GetActualException(Exception ex) { if (ex is AggregateException agg) @@ -210,7 +130,7 @@ namespace Emby.Server.Implementations.HttpServer } } - private async Task ErrorHandler(Exception ex, IRequest httpReq, int statusCode, string urlToLog, bool ignoreStackTrace) + private async Task ErrorHandler(Exception ex, HttpContext httpContext, int statusCode, string urlToLog, bool ignoreStackTrace) { if (ignoreStackTrace) { @@ -221,7 +141,7 @@ namespace Emby.Server.Implementations.HttpServer _logger.LogError(ex, "Error processing request. URL: {Url}", urlToLog); } - var httpRes = httpReq.Response; + var httpRes = httpContext.Response; if (httpRes.HasStarted) { @@ -395,24 +315,22 @@ namespace Emby.Server.Implementations.HttpServer return WebSocketRequestHandler(context); } - var request = context.Request; - var response = context.Response; - var localPath = context.Request.Path.ToString(); - - var req = new WebSocketSharpRequest(request, response, request.Path); - return RequestHandler(req, request.GetDisplayUrl(), request.Host.ToString(), localPath, context.RequestAborted); + return RequestHandler(context, context.RequestAborted); } /// <summary> /// Overridable method that can be used to implement a custom handler. /// </summary> - private async Task RequestHandler(IHttpRequest httpReq, string urlString, string host, string localPath, CancellationToken cancellationToken) + private async Task RequestHandler(HttpContext httpContext, CancellationToken cancellationToken) { var stopWatch = new Stopwatch(); stopWatch.Start(); - var httpRes = httpReq.Response; + var httpRes = httpContext.Response; + var host = httpContext.Request.Host.ToString(); + var localPath = httpContext.Request.Path.ToString(); + var urlString = httpContext.Request.GetDisplayUrl(); string urlToLog = GetUrlToLog(urlString); - string remoteIp = httpReq.RemoteIp; + string remoteIp = httpContext.Request.RemoteIp(); try { @@ -432,7 +350,7 @@ namespace Emby.Server.Implementations.HttpServer return; } - if (!ValidateRequest(remoteIp, httpReq.IsLocal)) + if (!ValidateRequest(remoteIp, httpContext.Request.IsLocal())) { httpRes.StatusCode = 403; httpRes.ContentType = "text/plain"; @@ -440,16 +358,16 @@ namespace Emby.Server.Implementations.HttpServer return; } - if (!ValidateSsl(httpReq.RemoteIp, urlString)) + if (!ValidateSsl(httpContext.Request.RemoteIp(), urlString)) { - RedirectToSecureUrl(httpReq, httpRes, urlString); + RedirectToSecureUrl(httpRes, urlString); return; } - if (string.Equals(httpReq.Verb, "OPTIONS", StringComparison.OrdinalIgnoreCase)) + if (string.Equals(httpContext.Request.Method, "OPTIONS", StringComparison.OrdinalIgnoreCase)) { httpRes.StatusCode = 200; - foreach (var (key, value) in GetDefaultCorsHeaders(httpReq)) + foreach (var (key, value) in GetDefaultCorsHeaders(httpContext)) { httpRes.Headers.Add(key, value); } @@ -483,15 +401,7 @@ namespace Emby.Server.Implementations.HttpServer } } - var handler = GetServiceHandler(httpReq); - if (handler != null) - { - await handler.ProcessRequestAsync(this, httpReq, httpRes, cancellationToken).ConfigureAwait(false); - } - else - { - throw new FileNotFoundException(); - } + throw new FileNotFoundException(); } catch (Exception requestEx) { @@ -500,7 +410,7 @@ namespace Emby.Server.Implementations.HttpServer var requestInnerEx = GetActualException(requestEx); var statusCode = GetStatusCode(requestInnerEx); - foreach (var (key, value) in GetDefaultCorsHeaders(httpReq)) + foreach (var (key, value) in GetDefaultCorsHeaders(httpContext)) { if (!httpRes.Headers.ContainsKey(key)) { @@ -525,7 +435,7 @@ namespace Emby.Server.Implementations.HttpServer throw; } - await ErrorHandler(requestInnerEx, httpReq, statusCode, urlToLog, ignoreStackTrace).ConfigureAwait(false); + await ErrorHandler(requestInnerEx, httpContext, statusCode, urlToLog, ignoreStackTrace).ConfigureAwait(false); } catch (Exception handlerException) { @@ -596,12 +506,12 @@ namespace Emby.Server.Implementations.HttpServer /// </summary> /// <param name="req"></param> /// <returns></returns> - public IDictionary<string, string> GetDefaultCorsHeaders(IRequest req) + public IDictionary<string, string> GetDefaultCorsHeaders(HttpContext httpContext) { - var origin = req.Headers["Origin"]; + var origin = httpContext.Request.Headers["Origin"]; if (origin == StringValues.Empty) { - origin = req.Headers["Host"]; + origin = httpContext.Request.Headers["Host"]; if (origin == StringValues.Empty) { origin = "*"; @@ -616,23 +526,7 @@ namespace Emby.Server.Implementations.HttpServer return headers; } - // Entry point for HttpListener - public ServiceHandler GetServiceHandler(IHttpRequest httpReq) - { - var pathInfo = httpReq.PathInfo; - - pathInfo = ServiceHandler.GetSanitizedPathInfo(pathInfo, out string contentType); - var restPath = ServiceController.GetRestPathForRequest(httpReq.HttpMethod, pathInfo); - if (restPath != null) - { - return new ServiceHandler(restPath, contentType); - } - - _logger.LogError("Could not find handler for {PathInfo}", pathInfo); - return null; - } - - private void RedirectToSecureUrl(IHttpRequest httpReq, HttpResponse httpRes, string url) + private void RedirectToSecureUrl(HttpResponse httpRes, string url) { if (Uri.TryCreate(url, UriKind.Absolute, out Uri uri)) { @@ -650,95 +544,12 @@ namespace Emby.Server.Implementations.HttpServer /// <summary> /// Adds the rest handlers. /// </summary> - /// <param name="serviceTypes">The service types to register with the <see cref="ServiceController"/>.</param> /// <param name="listeners">The web socket listeners.</param> /// <param name="urlPrefixes">The URL prefixes. See <see cref="UrlPrefixes"/>.</param> - public void Init(IEnumerable<Type> serviceTypes, IEnumerable<IWebSocketListener> listeners, IEnumerable<string> urlPrefixes) + public void Init(IEnumerable<IWebSocketListener> listeners, IEnumerable<string> urlPrefixes) { _webSocketListeners = listeners.ToArray(); UrlPrefixes = urlPrefixes.ToArray(); - - ServiceController.Init(this, serviceTypes); - - ResponseFilters = new Action<IRequest, HttpResponse, object>[] - { - new ResponseFilter(this, _logger).FilterResponse - }; - } - - public RouteAttribute[] GetRouteAttributes(Type requestType) - { - var routes = requestType.GetTypeInfo().GetCustomAttributes<RouteAttribute>(true).ToList(); - var clone = routes.ToList(); - - foreach (var route in clone) - { - routes.Add(new RouteAttribute(NormalizeCustomRoutePath(route.Path), route.Verbs) - { - Notes = route.Notes, - Priority = route.Priority, - Summary = route.Summary - }); - - routes.Add(new RouteAttribute(NormalizeEmbyRoutePath(route.Path), route.Verbs) - { - Notes = route.Notes, - Priority = route.Priority, - Summary = route.Summary - }); - - routes.Add(new RouteAttribute(NormalizeMediaBrowserRoutePath(route.Path), route.Verbs) - { - Notes = route.Notes, - Priority = route.Priority, - Summary = route.Summary - }); - } - - return routes.ToArray(); - } - - public Func<string, object> GetParseFn(Type propertyType) - { - return _funcParseFn(propertyType); - } - - public void SerializeToJson(object o, Stream stream) - { - _jsonSerializer.SerializeToStream(o, stream); - } - - public void SerializeToXml(object o, Stream stream) - { - _xmlSerializer.SerializeToStream(o, stream); - } - - public Task<object> DeserializeXml(Type type, Stream stream) - { - return Task.FromResult(_xmlSerializer.DeserializeFromStream(type, stream)); - } - - public Task<object> DeserializeJson(Type type, Stream stream) - { - return _jsonSerializer.DeserializeFromStreamAsync(stream, type); - } - - private string NormalizeEmbyRoutePath(string path) - { - _logger.LogDebug("Normalizing /emby route"); - return _baseUrlPrefix + "/emby" + NormalizeUrlPath(path); - } - - private string NormalizeMediaBrowserRoutePath(string path) - { - _logger.LogDebug("Normalizing /mediabrowser route"); - return _baseUrlPrefix + "/mediabrowser" + NormalizeUrlPath(path); - } - - private string NormalizeCustomRoutePath(string path) - { - _logger.LogDebug("Normalizing custom route {0}", path); - return _baseUrlPrefix + NormalizeUrlPath(path); } /// <summary> diff --git a/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs b/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs deleted file mode 100644 index 688216373..000000000 --- a/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs +++ /dev/null @@ -1,721 +0,0 @@ -#pragma warning disable CS1591 - -using System; -using System.Collections.Generic; -using System.Globalization; -using System.IO; -using System.IO.Compression; -using System.Net; -using System.Runtime.Serialization; -using System.Text; -using System.Threading.Tasks; -using System.Xml; -using Emby.Server.Implementations.Services; -using MediaBrowser.Controller.Net; -using MediaBrowser.Model.IO; -using MediaBrowser.Model.Serialization; -using MediaBrowser.Model.Services; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Primitives; -using Microsoft.Net.Http.Headers; -using IRequest = MediaBrowser.Model.Services.IRequest; -using MimeTypes = MediaBrowser.Model.Net.MimeTypes; - -namespace Emby.Server.Implementations.HttpServer -{ - /// <summary> - /// Class HttpResultFactory. - /// </summary> - public class HttpResultFactory : IHttpResultFactory - { - // Last-Modified and If-Modified-Since must follow strict date format, - // see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/If-Modified-Since - private const string HttpDateFormat = "ddd, dd MMM yyyy HH:mm:ss \"GMT\""; - // We specifically use en-US culture because both day of week and month names require it - private static readonly CultureInfo _enUSculture = new CultureInfo("en-US", false); - - /// <summary> - /// The logger. - /// </summary> - private readonly ILogger<HttpResultFactory> _logger; - private readonly IFileSystem _fileSystem; - private readonly IJsonSerializer _jsonSerializer; - private readonly IStreamHelper _streamHelper; - - /// <summary> - /// Initializes a new instance of the <see cref="HttpResultFactory" /> class. - /// </summary> - public HttpResultFactory(ILoggerFactory loggerfactory, IFileSystem fileSystem, IJsonSerializer jsonSerializer, IStreamHelper streamHelper) - { - _fileSystem = fileSystem; - _jsonSerializer = jsonSerializer; - _streamHelper = streamHelper; - _logger = loggerfactory.CreateLogger<HttpResultFactory>(); - } - - /// <summary> - /// Gets the result. - /// </summary> - /// <param name="requestContext">The request context.</param> - /// <param name="content">The content.</param> - /// <param name="contentType">Type of the content.</param> - /// <param name="responseHeaders">The response headers.</param> - /// <returns>System.Object.</returns> - public object GetResult(IRequest requestContext, byte[] content, string contentType, IDictionary<string, string> responseHeaders = null) - { - return GetHttpResult(requestContext, content, contentType, true, responseHeaders); - } - - public object GetResult(string content, string contentType, IDictionary<string, string> responseHeaders = null) - { - return GetHttpResult(null, content, contentType, true, responseHeaders); - } - - public object GetResult(IRequest requestContext, Stream content, string contentType, IDictionary<string, string> responseHeaders = null) - { - return GetHttpResult(requestContext, content, contentType, true, responseHeaders); - } - - public object GetResult(IRequest requestContext, string content, string contentType, IDictionary<string, string> responseHeaders = null) - { - return GetHttpResult(requestContext, content, contentType, true, responseHeaders); - } - - public object GetRedirectResult(string url) - { - var responseHeaders = new Dictionary<string, string>(); - responseHeaders[HeaderNames.Location] = url; - - var result = new HttpResult(Array.Empty<byte>(), "text/plain", HttpStatusCode.Redirect); - - AddResponseHeaders(result, responseHeaders); - - return result; - } - - /// <summary> - /// Gets the HTTP result. - /// </summary> - private IHasHeaders GetHttpResult(IRequest requestContext, Stream content, string contentType, bool addCachePrevention, IDictionary<string, string> responseHeaders = null) - { - var result = new StreamWriter(content, contentType); - - if (responseHeaders == null) - { - responseHeaders = new Dictionary<string, string>(); - } - - if (addCachePrevention && !responseHeaders.TryGetValue(HeaderNames.Expires, out _)) - { - responseHeaders[HeaderNames.Expires] = "0"; - } - - AddResponseHeaders(result, responseHeaders); - - return result; - } - - /// <summary> - /// Gets the HTTP result. - /// </summary> - private IHasHeaders GetHttpResult(IRequest requestContext, byte[] content, string contentType, bool addCachePrevention, IDictionary<string, string> responseHeaders = null) - { - string compressionType = null; - bool isHeadRequest = false; - - if (requestContext != null) - { - compressionType = GetCompressionType(requestContext, content, contentType); - isHeadRequest = string.Equals(requestContext.Verb, "head", StringComparison.OrdinalIgnoreCase); - } - - IHasHeaders result; - if (string.IsNullOrEmpty(compressionType)) - { - var contentLength = content.Length; - - if (isHeadRequest) - { - content = Array.Empty<byte>(); - } - - result = new StreamWriter(content, contentType, contentLength); - } - else - { - result = GetCompressedResult(content, compressionType, responseHeaders, isHeadRequest, contentType); - } - - if (responseHeaders == null) - { - responseHeaders = new Dictionary<string, string>(); - } - - if (addCachePrevention && !responseHeaders.TryGetValue(HeaderNames.Expires, out string _)) - { - responseHeaders[HeaderNames.Expires] = "0"; - } - - AddResponseHeaders(result, responseHeaders); - - return result; - } - - /// <summary> - /// Gets the HTTP result. - /// </summary> - private IHasHeaders GetHttpResult(IRequest requestContext, string content, string contentType, bool addCachePrevention, IDictionary<string, string> responseHeaders = null) - { - IHasHeaders result; - - var bytes = Encoding.UTF8.GetBytes(content); - - var compressionType = requestContext == null ? null : GetCompressionType(requestContext, bytes, contentType); - - var isHeadRequest = requestContext == null ? false : string.Equals(requestContext.Verb, "head", StringComparison.OrdinalIgnoreCase); - - if (string.IsNullOrEmpty(compressionType)) - { - var contentLength = bytes.Length; - - if (isHeadRequest) - { - bytes = Array.Empty<byte>(); - } - - result = new StreamWriter(bytes, contentType, contentLength); - } - else - { - result = GetCompressedResult(bytes, compressionType, responseHeaders, isHeadRequest, contentType); - } - - if (responseHeaders == null) - { - responseHeaders = new Dictionary<string, string>(); - } - - if (addCachePrevention && !responseHeaders.TryGetValue(HeaderNames.Expires, out string _)) - { - responseHeaders[HeaderNames.Expires] = "0"; - } - - AddResponseHeaders(result, responseHeaders); - - return result; - } - - /// <summary> - /// Gets the optimized result. - /// </summary> - /// <typeparam name="T"></typeparam> - public object GetResult<T>(IRequest requestContext, T result, IDictionary<string, string> responseHeaders = null) - where T : class - { - if (result == null) - { - throw new ArgumentNullException(nameof(result)); - } - - if (responseHeaders == null) - { - responseHeaders = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); - } - - responseHeaders[HeaderNames.Expires] = "0"; - - return ToOptimizedResultInternal(requestContext, result, responseHeaders); - } - - private string GetCompressionType(IRequest request, byte[] content, string responseContentType) - { - if (responseContentType == null) - { - return null; - } - - // Per apple docs, hls manifests must be compressed - if (!responseContentType.StartsWith("text/", StringComparison.OrdinalIgnoreCase) && - responseContentType.IndexOf("json", StringComparison.OrdinalIgnoreCase) == -1 && - responseContentType.IndexOf("javascript", StringComparison.OrdinalIgnoreCase) == -1 && - responseContentType.IndexOf("xml", StringComparison.OrdinalIgnoreCase) == -1 && - responseContentType.IndexOf("application/x-mpegURL", StringComparison.OrdinalIgnoreCase) == -1) - { - return null; - } - - if (content.Length < 1024) - { - return null; - } - - return GetCompressionType(request); - } - - private static string GetCompressionType(IRequest request) - { - var acceptEncoding = request.Headers[HeaderNames.AcceptEncoding].ToString(); - - if (!string.IsNullOrEmpty(acceptEncoding)) - { - // if (_brotliCompressor != null && acceptEncoding.IndexOf("br", StringComparison.OrdinalIgnoreCase) != -1) - // return "br"; - - if (acceptEncoding.Contains("deflate", StringComparison.OrdinalIgnoreCase)) - { - return "deflate"; - } - - if (acceptEncoding.Contains("gzip", StringComparison.OrdinalIgnoreCase)) - { - return "gzip"; - } - } - - return null; - } - - /// <summary> - /// Returns the optimized result for the IRequestContext. - /// Does not use or store results in any cache. - /// </summary> - /// <param name="request"></param> - /// <param name="dto"></param> - /// <returns></returns> - public object ToOptimizedResult<T>(IRequest request, T dto) - { - return ToOptimizedResultInternal(request, dto); - } - - private object ToOptimizedResultInternal<T>(IRequest request, T dto, IDictionary<string, string> responseHeaders = null) - { - // TODO: @bond use Span and .Equals - var contentType = request.ResponseContentType?.Split(';')[0].Trim().ToLowerInvariant(); - - switch (contentType) - { - case "application/xml": - case "text/xml": - case "text/xml; charset=utf-8": //"text/xml; charset=utf-8" also matches xml - return GetHttpResult(request, SerializeToXmlString(dto), contentType, false, responseHeaders); - - case "application/json": - case "text/json": - return GetHttpResult(request, _jsonSerializer.SerializeToString(dto), contentType, false, responseHeaders); - default: - break; - } - - var isHeadRequest = string.Equals(request.Verb, "head", StringComparison.OrdinalIgnoreCase); - - var ms = new MemoryStream(); - var writerFn = RequestHelper.GetResponseWriter(HttpListenerHost.Instance, contentType); - - writerFn(dto, ms); - - ms.Position = 0; - - if (isHeadRequest) - { - using (ms) - { - return GetHttpResult(request, Array.Empty<byte>(), contentType, true, responseHeaders); - } - } - - return GetHttpResult(request, ms, contentType, true, responseHeaders); - } - - private IHasHeaders GetCompressedResult( - byte[] content, - string requestedCompressionType, - IDictionary<string, string> responseHeaders, - bool isHeadRequest, - string contentType) - { - if (responseHeaders == null) - { - responseHeaders = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); - } - - content = Compress(content, requestedCompressionType); - responseHeaders[HeaderNames.ContentEncoding] = requestedCompressionType; - - responseHeaders[HeaderNames.Vary] = HeaderNames.AcceptEncoding; - - var contentLength = content.Length; - - if (isHeadRequest) - { - var result = new StreamWriter(Array.Empty<byte>(), contentType, contentLength); - AddResponseHeaders(result, responseHeaders); - return result; - } - else - { - var result = new StreamWriter(content, contentType, contentLength); - AddResponseHeaders(result, responseHeaders); - return result; - } - } - - private byte[] Compress(byte[] bytes, string compressionType) - { - if (string.Equals(compressionType, "deflate", StringComparison.OrdinalIgnoreCase)) - { - return Deflate(bytes); - } - - if (string.Equals(compressionType, "gzip", StringComparison.OrdinalIgnoreCase)) - { - return GZip(bytes); - } - - throw new NotSupportedException(compressionType); - } - - private static byte[] Deflate(byte[] bytes) - { - // In .NET FX incompat-ville, you can't access compressed bytes without closing DeflateStream - // Which means we must use MemoryStream since you have to use ToArray() on a closed Stream - using (var ms = new MemoryStream()) - using (var zipStream = new DeflateStream(ms, CompressionMode.Compress)) - { - zipStream.Write(bytes, 0, bytes.Length); - zipStream.Dispose(); - - return ms.ToArray(); - } - } - - private static byte[] GZip(byte[] buffer) - { - using (var ms = new MemoryStream()) - using (var zipStream = new GZipStream(ms, CompressionMode.Compress)) - { - zipStream.Write(buffer, 0, buffer.Length); - zipStream.Dispose(); - - return ms.ToArray(); - } - } - - private static string SerializeToXmlString(object from) - { - using (var ms = new MemoryStream()) - { - var xwSettings = new XmlWriterSettings(); - xwSettings.Encoding = new UTF8Encoding(false); - xwSettings.OmitXmlDeclaration = false; - - using (var xw = XmlWriter.Create(ms, xwSettings)) - { - var serializer = new DataContractSerializer(from.GetType()); - serializer.WriteObject(xw, from); - xw.Flush(); - ms.Seek(0, SeekOrigin.Begin); - using (var reader = new StreamReader(ms)) - { - return reader.ReadToEnd(); - } - } - } - } - - /// <summary> - /// Pres the process optimized result. - /// </summary> - private object GetCachedResult(IRequest requestContext, IDictionary<string, string> responseHeaders, StaticResultOptions options) - { - bool noCache = requestContext.Headers[HeaderNames.CacheControl].ToString().IndexOf("no-cache", StringComparison.OrdinalIgnoreCase) != -1; - AddCachingHeaders(responseHeaders, options.CacheDuration, noCache, options.DateLastModified); - - if (!noCache) - { - if (!DateTime.TryParseExact(requestContext.Headers[HeaderNames.IfModifiedSince], HttpDateFormat, _enUSculture, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal, out var ifModifiedSinceHeader)) - { - _logger.LogDebug("Failed to parse If-Modified-Since header date: {0}", requestContext.Headers[HeaderNames.IfModifiedSince]); - return null; - } - - if (IsNotModified(ifModifiedSinceHeader, options.CacheDuration, options.DateLastModified)) - { - AddAgeHeader(responseHeaders, options.DateLastModified); - - var result = new HttpResult(Array.Empty<byte>(), options.ContentType ?? "text/html", HttpStatusCode.NotModified); - - AddResponseHeaders(result, responseHeaders); - - return result; - } - } - - return null; - } - - public Task<object> GetStaticFileResult(IRequest requestContext, - string path, - FileShare fileShare = FileShare.Read) - { - if (string.IsNullOrEmpty(path)) - { - throw new ArgumentNullException(nameof(path)); - } - - return GetStaticFileResult(requestContext, new StaticFileResultOptions - { - Path = path, - FileShare = fileShare - }); - } - - public Task<object> GetStaticFileResult(IRequest requestContext, StaticFileResultOptions options) - { - var path = options.Path; - var fileShare = options.FileShare; - - if (string.IsNullOrEmpty(path)) - { - throw new ArgumentException("Path can't be empty.", nameof(options)); - } - - if (fileShare != FileShare.Read && fileShare != FileShare.ReadWrite) - { - throw new ArgumentException("FileShare must be either Read or ReadWrite"); - } - - if (string.IsNullOrEmpty(options.ContentType)) - { - options.ContentType = MimeTypes.GetMimeType(path); - } - - if (!options.DateLastModified.HasValue) - { - options.DateLastModified = _fileSystem.GetLastWriteTimeUtc(path); - } - - options.ContentFactory = () => Task.FromResult(GetFileStream(path, fileShare)); - - options.ResponseHeaders = options.ResponseHeaders ?? new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); - - return GetStaticResult(requestContext, options); - } - - /// <summary> - /// Gets the file stream. - /// </summary> - /// <param name="path">The path.</param> - /// <param name="fileShare">The file share.</param> - /// <returns>Stream.</returns> - private Stream GetFileStream(string path, FileShare fileShare) - { - return new FileStream(path, FileMode.Open, FileAccess.Read, fileShare); - } - - public Task<object> GetStaticResult(IRequest requestContext, - Guid cacheKey, - DateTime? lastDateModified, - TimeSpan? cacheDuration, - string contentType, - Func<Task<Stream>> factoryFn, - IDictionary<string, string> responseHeaders = null, - bool isHeadRequest = false) - { - return GetStaticResult(requestContext, new StaticResultOptions - { - CacheDuration = cacheDuration, - ContentFactory = factoryFn, - ContentType = contentType, - DateLastModified = lastDateModified, - IsHeadRequest = isHeadRequest, - ResponseHeaders = responseHeaders - }); - } - - public async Task<object> GetStaticResult(IRequest requestContext, StaticResultOptions options) - { - options.ResponseHeaders = options.ResponseHeaders ?? new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); - - var contentType = options.ContentType; - if (!StringValues.IsNullOrEmpty(requestContext.Headers[HeaderNames.IfModifiedSince])) - { - // See if the result is already cached in the browser - var result = GetCachedResult(requestContext, options.ResponseHeaders, options); - - if (result != null) - { - return result; - } - } - - // TODO: We don't really need the option value - var isHeadRequest = options.IsHeadRequest || string.Equals(requestContext.Verb, "HEAD", StringComparison.OrdinalIgnoreCase); - var factoryFn = options.ContentFactory; - var responseHeaders = options.ResponseHeaders; - AddCachingHeaders(responseHeaders, options.CacheDuration, false, options.DateLastModified); - AddAgeHeader(responseHeaders, options.DateLastModified); - - var rangeHeader = requestContext.Headers[HeaderNames.Range]; - - if (!isHeadRequest && !string.IsNullOrEmpty(options.Path)) - { - var hasHeaders = new FileWriter(options.Path, contentType, rangeHeader, _logger, _fileSystem, _streamHelper) - { - OnComplete = options.OnComplete, - OnError = options.OnError, - FileShare = options.FileShare - }; - - AddResponseHeaders(hasHeaders, options.ResponseHeaders); - return hasHeaders; - } - - var stream = await factoryFn().ConfigureAwait(false); - - var totalContentLength = options.ContentLength; - if (!totalContentLength.HasValue) - { - try - { - totalContentLength = stream.Length; - } - catch (NotSupportedException) - { - } - } - - if (!string.IsNullOrWhiteSpace(rangeHeader) && totalContentLength.HasValue) - { - var hasHeaders = new RangeRequestWriter(rangeHeader, totalContentLength.Value, stream, contentType, isHeadRequest) - { - OnComplete = options.OnComplete - }; - - AddResponseHeaders(hasHeaders, options.ResponseHeaders); - return hasHeaders; - } - else - { - if (totalContentLength.HasValue) - { - responseHeaders["Content-Length"] = totalContentLength.Value.ToString(CultureInfo.InvariantCulture); - } - - if (isHeadRequest) - { - using (stream) - { - return GetHttpResult(requestContext, Array.Empty<byte>(), contentType, true, responseHeaders); - } - } - - var hasHeaders = new StreamWriter(stream, contentType) - { - OnComplete = options.OnComplete, - OnError = options.OnError - }; - - AddResponseHeaders(hasHeaders, options.ResponseHeaders); - return hasHeaders; - } - } - - /// <summary> - /// Adds the caching responseHeaders. - /// </summary> - private void AddCachingHeaders( - IDictionary<string, string> responseHeaders, - TimeSpan? cacheDuration, - bool noCache, - DateTime? lastModifiedDate) - { - if (noCache) - { - responseHeaders[HeaderNames.CacheControl] = "no-cache, no-store, must-revalidate"; - responseHeaders[HeaderNames.Pragma] = "no-cache, no-store, must-revalidate"; - return; - } - - if (cacheDuration.HasValue) - { - responseHeaders[HeaderNames.CacheControl] = "public, max-age=" + cacheDuration.Value.TotalSeconds; - } - else - { - responseHeaders[HeaderNames.CacheControl] = "public"; - } - - if (lastModifiedDate.HasValue) - { - responseHeaders[HeaderNames.LastModified] = lastModifiedDate.Value.ToUniversalTime().ToString(HttpDateFormat, _enUSculture); - } - } - - /// <summary> - /// Adds the age header. - /// </summary> - /// <param name="responseHeaders">The responseHeaders.</param> - /// <param name="lastDateModified">The last date modified.</param> - private static void AddAgeHeader(IDictionary<string, string> responseHeaders, DateTime? lastDateModified) - { - if (lastDateModified.HasValue) - { - responseHeaders[HeaderNames.Age] = Convert.ToInt64((DateTime.UtcNow - lastDateModified.Value).TotalSeconds).ToString(CultureInfo.InvariantCulture); - } - } - - /// <summary> - /// Determines whether [is not modified] [the specified if modified since]. - /// </summary> - /// <param name="ifModifiedSince">If modified since.</param> - /// <param name="cacheDuration">Duration of the cache.</param> - /// <param name="dateModified">The date modified.</param> - /// <returns><c>true</c> if [is not modified] [the specified if modified since]; otherwise, <c>false</c>.</returns> - private bool IsNotModified(DateTime ifModifiedSince, TimeSpan? cacheDuration, DateTime? dateModified) - { - if (dateModified.HasValue) - { - var lastModified = NormalizeDateForComparison(dateModified.Value); - ifModifiedSince = NormalizeDateForComparison(ifModifiedSince); - - return lastModified <= ifModifiedSince; - } - - if (cacheDuration.HasValue) - { - var cacheExpirationDate = ifModifiedSince.Add(cacheDuration.Value); - - if (DateTime.UtcNow < cacheExpirationDate) - { - return true; - } - } - - return false; - } - - - /// <summary> - /// When the browser sends the IfModifiedDate, it's precision is limited to seconds, so this will account for that. - /// </summary> - /// <param name="date">The date.</param> - /// <returns>DateTime.</returns> - private static DateTime NormalizeDateForComparison(DateTime date) - { - return new DateTime(date.Year, date.Month, date.Day, date.Hour, date.Minute, date.Second, date.Kind); - } - - /// <summary> - /// Adds the response headers. - /// </summary> - /// <param name="hasHeaders">The has options.</param> - /// <param name="responseHeaders">The response headers.</param> - private static void AddResponseHeaders(IHasHeaders hasHeaders, IEnumerable<KeyValuePair<string, string>> responseHeaders) - { - foreach (var item in responseHeaders) - { - hasHeaders.Headers[item.Key] = item.Value; - } - } - } -} diff --git a/Emby.Server.Implementations/HttpServer/RangeRequestWriter.cs b/Emby.Server.Implementations/HttpServer/RangeRequestWriter.cs deleted file mode 100644 index 980c2cd3a..000000000 --- a/Emby.Server.Implementations/HttpServer/RangeRequestWriter.cs +++ /dev/null @@ -1,212 +0,0 @@ -#pragma warning disable CS1591 - -using System; -using System.Buffers; -using System.Collections.Generic; -using System.Globalization; -using System.IO; -using System.Net; -using System.Threading; -using System.Threading.Tasks; -using MediaBrowser.Model.Services; -using Microsoft.Net.Http.Headers; - -namespace Emby.Server.Implementations.HttpServer -{ - public class RangeRequestWriter : IAsyncStreamWriter, IHttpResult - { - private const int BufferSize = 81920; - - private readonly Dictionary<string, string> _options = new Dictionary<string, string>(); - - private List<KeyValuePair<long, long?>> _requestedRanges; - - /// <summary> - /// Initializes a new instance of the <see cref="RangeRequestWriter" /> class. - /// </summary> - /// <param name="rangeHeader">The range header.</param> - /// <param name="contentLength">The content length.</param> - /// <param name="source">The source.</param> - /// <param name="contentType">Type of the content.</param> - /// <param name="isHeadRequest">if set to <c>true</c> [is head request].</param> - public RangeRequestWriter(string rangeHeader, long contentLength, Stream source, string contentType, bool isHeadRequest) - { - if (string.IsNullOrEmpty(contentType)) - { - throw new ArgumentNullException(nameof(contentType)); - } - - RangeHeader = rangeHeader; - SourceStream = source; - IsHeadRequest = isHeadRequest; - - ContentType = contentType; - Headers[HeaderNames.ContentType] = contentType; - Headers[HeaderNames.AcceptRanges] = "bytes"; - StatusCode = HttpStatusCode.PartialContent; - - SetRangeValues(contentLength); - } - - /// <summary> - /// Gets or sets the source stream. - /// </summary> - /// <value>The source stream.</value> - private Stream SourceStream { get; set; } - private string RangeHeader { get; set; } - private bool IsHeadRequest { get; set; } - - private long RangeStart { get; set; } - private long RangeEnd { get; set; } - private long RangeLength { get; set; } - private long TotalContentLength { get; set; } - - public Action OnComplete { get; set; } - - /// <summary> - /// Additional HTTP Headers - /// </summary> - /// <value>The headers.</value> - public IDictionary<string, string> Headers => _options; - - /// <summary> - /// Gets the requested ranges. - /// </summary> - /// <value>The requested ranges.</value> - protected List<KeyValuePair<long, long?>> RequestedRanges - { - get - { - if (_requestedRanges == null) - { - _requestedRanges = new List<KeyValuePair<long, long?>>(); - - // Example: bytes=0-,32-63 - var ranges = RangeHeader.Split('=')[1].Split(','); - - foreach (var range in ranges) - { - var vals = range.Split('-'); - - long start = 0; - long? end = null; - - if (!string.IsNullOrEmpty(vals[0])) - { - start = long.Parse(vals[0], CultureInfo.InvariantCulture); - } - - if (!string.IsNullOrEmpty(vals[1])) - { - end = long.Parse(vals[1], CultureInfo.InvariantCulture); - } - - _requestedRanges.Add(new KeyValuePair<long, long?>(start, end)); - } - } - - return _requestedRanges; - } - } - - public string ContentType { get; set; } - - public IRequest RequestContext { get; set; } - - public object Response { get; set; } - - public int Status { get; set; } - - public HttpStatusCode StatusCode - { - get => (HttpStatusCode)Status; - set => Status = (int)value; - } - - /// <summary> - /// Sets the range values. - /// </summary> - private void SetRangeValues(long contentLength) - { - var requestedRange = RequestedRanges[0]; - - TotalContentLength = contentLength; - - // If the requested range is "0-", we can optimize by just doing a stream copy - if (!requestedRange.Value.HasValue) - { - RangeEnd = TotalContentLength - 1; - } - else - { - RangeEnd = requestedRange.Value.Value; - } - - RangeStart = requestedRange.Key; - RangeLength = 1 + RangeEnd - RangeStart; - - Headers[HeaderNames.ContentLength] = RangeLength.ToString(CultureInfo.InvariantCulture); - Headers[HeaderNames.ContentRange] = $"bytes {RangeStart}-{RangeEnd}/{TotalContentLength}"; - - if (RangeStart > 0 && SourceStream.CanSeek) - { - SourceStream.Position = RangeStart; - } - } - - public async Task WriteToAsync(Stream responseStream, CancellationToken cancellationToken) - { - try - { - // Headers only - if (IsHeadRequest) - { - return; - } - - using (var source = SourceStream) - { - // If the requested range is "0-", we can optimize by just doing a stream copy - if (RangeEnd >= TotalContentLength - 1) - { - await source.CopyToAsync(responseStream, BufferSize, cancellationToken).ConfigureAwait(false); - } - else - { - await CopyToInternalAsync(source, responseStream, RangeLength, cancellationToken).ConfigureAwait(false); - } - } - } - finally - { - OnComplete?.Invoke(); - } - } - - private static async Task CopyToInternalAsync(Stream source, Stream destination, long copyLength, CancellationToken cancellationToken) - { - var array = ArrayPool<byte>.Shared.Rent(BufferSize); - try - { - int bytesRead; - while ((bytesRead = await source.ReadAsync(array, 0, array.Length, cancellationToken).ConfigureAwait(false)) != 0) - { - var bytesToCopy = Math.Min(bytesRead, copyLength); - - await destination.WriteAsync(array, 0, Convert.ToInt32(bytesToCopy), cancellationToken).ConfigureAwait(false); - - copyLength -= bytesToCopy; - - if (copyLength <= 0) - { - break; - } - } - } - finally - { - ArrayPool<byte>.Shared.Return(array); - } - } - } -} diff --git a/Emby.Server.Implementations/HttpServer/ResponseFilter.cs b/Emby.Server.Implementations/HttpServer/ResponseFilter.cs deleted file mode 100644 index a8cd2ac8f..000000000 --- a/Emby.Server.Implementations/HttpServer/ResponseFilter.cs +++ /dev/null @@ -1,113 +0,0 @@ -using System; -using System.Globalization; -using System.Text; -using MediaBrowser.Controller.Net; -using MediaBrowser.Model.Services; -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Logging; -using Microsoft.Net.Http.Headers; - -namespace Emby.Server.Implementations.HttpServer -{ - /// <summary> - /// Class ResponseFilter. - /// </summary> - public class ResponseFilter - { - private readonly IHttpServer _server; - private readonly ILogger _logger; - - /// <summary> - /// Initializes a new instance of the <see cref="ResponseFilter"/> class. - /// </summary> - /// <param name="server">The HTTP server.</param> - /// <param name="logger">The logger.</param> - public ResponseFilter(IHttpServer server, ILogger logger) - { - _server = server; - _logger = logger; - } - - /// <summary> - /// Filters the response. - /// </summary> - /// <param name="req">The req.</param> - /// <param name="res">The res.</param> - /// <param name="dto">The dto.</param> - public void FilterResponse(IRequest req, HttpResponse res, object dto) - { - foreach(var (key, value) in _server.GetDefaultCorsHeaders(req)) - { - res.Headers.Add(key, value); - } - // Try to prevent compatibility view - res.Headers["Access-Control-Allow-Headers"] = "Accept, Accept-Language, Authorization, Cache-Control, " + - "Content-Disposition, Content-Encoding, Content-Language, Content-Length, Content-MD5, Content-Range, " + - "Content-Type, Cookie, 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"; - - if (dto is Exception exception) - { - _logger.LogError(exception, "Error processing request for {RawUrl}", req.RawUrl); - - if (!string.IsNullOrEmpty(exception.Message)) - { - var error = exception.Message.Replace(Environment.NewLine, " ", StringComparison.Ordinal); - error = RemoveControlCharacters(error); - - res.Headers.Add("X-Application-Error-Code", error); - } - } - - if (dto is IHasHeaders hasHeaders) - { - if (!hasHeaders.Headers.ContainsKey(HeaderNames.Server)) - { - hasHeaders.Headers[HeaderNames.Server] = "Microsoft-NetCore/2.0, UPnP/1.0 DLNADOC/1.50"; - } - - // Content length has to be explicitly set on on HttpListenerResponse or it won't be happy - if (hasHeaders.Headers.TryGetValue(HeaderNames.ContentLength, out string contentLength) - && !string.IsNullOrEmpty(contentLength)) - { - var length = long.Parse(contentLength, CultureInfo.InvariantCulture); - - if (length > 0) - { - res.ContentLength = length; - } - } - } - } - - /// <summary> - /// Removes the control characters. - /// </summary> - /// <param name="inString">The in string.</param> - /// <returns>System.String.</returns> - public static string RemoveControlCharacters(string inString) - { - if (inString == null) - { - return null; - } - else if (inString.Length == 0) - { - return inString; - } - - var newString = new StringBuilder(inString.Length); - - foreach (var ch in inString) - { - if (!char.IsControl(ch)) - { - newString.Append(ch); - } - } - - return newString.ToString(); - } - } -} diff --git a/Emby.Server.Implementations/HttpServer/Security/AuthService.cs b/Emby.Server.Implementations/HttpServer/Security/AuthService.cs index 76c1d9bac..68d981ad1 100644 --- a/Emby.Server.Implementations/HttpServer/Security/AuthService.cs +++ b/Emby.Server.Implementations/HttpServer/Security/AuthService.cs @@ -1,17 +1,7 @@ #pragma warning disable CS1591 -using System; -using System.Linq; -using Emby.Server.Implementations.SocketSharp; -using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; -using MediaBrowser.Common.Net; -using MediaBrowser.Controller.Authentication; -using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Net; -using MediaBrowser.Controller.Security; -using MediaBrowser.Controller.Session; -using MediaBrowser.Model.Services; using Microsoft.AspNetCore.Http; namespace Emby.Server.Implementations.HttpServer.Security @@ -19,32 +9,11 @@ namespace Emby.Server.Implementations.HttpServer.Security public class AuthService : IAuthService { private readonly IAuthorizationContext _authorizationContext; - private readonly ISessionManager _sessionManager; - private readonly IServerConfigurationManager _config; - private readonly INetworkManager _networkManager; public AuthService( - IAuthorizationContext authorizationContext, - IServerConfigurationManager config, - ISessionManager sessionManager, - INetworkManager networkManager) + IAuthorizationContext authorizationContext) { _authorizationContext = authorizationContext; - _config = config; - _sessionManager = sessionManager; - _networkManager = networkManager; - } - - public void Authenticate(IRequest request, IAuthenticationAttributes authAttributes) - { - ValidateUser(request, authAttributes); - } - - public User Authenticate(HttpRequest request, IAuthenticationAttributes authAttributes) - { - var req = new WebSocketSharpRequest(request, null, request.Path); - var user = ValidateUser(req, authAttributes); - return user; } public AuthorizationInfo Authenticate(HttpRequest request) @@ -62,185 +31,5 @@ namespace Emby.Server.Implementations.HttpServer.Security return auth; } - - private User ValidateUser(IRequest request, IAuthenticationAttributes authAttributes) - { - // This code is executed before the service - var auth = _authorizationContext.GetAuthorizationInfo(request); - - if (!IsExemptFromAuthenticationToken(authAttributes, request)) - { - ValidateSecurityToken(request, auth.Token); - } - - if (authAttributes.AllowLocalOnly && !request.IsLocal) - { - throw new SecurityException("Operation not found."); - } - - var user = auth.User; - - if (user == null && auth.UserId != Guid.Empty) - { - throw new AuthenticationException("User with Id " + auth.UserId + " not found"); - } - - if (user != null) - { - ValidateUserAccess(user, request, authAttributes); - } - - var info = GetTokenInfo(request); - - if (!IsExemptFromRoles(auth, authAttributes, request, info)) - { - var roles = authAttributes.GetRoles(); - - ValidateRoles(roles, user); - } - - if (!string.IsNullOrEmpty(auth.DeviceId) && - !string.IsNullOrEmpty(auth.Client) && - !string.IsNullOrEmpty(auth.Device)) - { - _sessionManager.LogSessionActivity( - auth.Client, - auth.Version, - auth.DeviceId, - auth.Device, - request.RemoteIp, - user); - } - - return user; - } - - private void ValidateUserAccess( - User user, - IRequest request, - IAuthenticationAttributes authAttributes) - { - if (user.HasPermission(PermissionKind.IsDisabled)) - { - throw new SecurityException("User account has been disabled."); - } - - if (!user.HasPermission(PermissionKind.EnableRemoteAccess) && !_networkManager.IsInLocalNetwork(request.RemoteIp)) - { - throw new SecurityException("User account has been disabled."); - } - - if (!user.HasPermission(PermissionKind.IsAdministrator) - && !authAttributes.EscapeParentalControl - && !user.IsParentalScheduleAllowed()) - { - request.Response.Headers.Add("X-Application-Error-Code", "ParentalControl"); - - throw new SecurityException("This user account is not allowed access at this time."); - } - } - - private bool IsExemptFromAuthenticationToken(IAuthenticationAttributes authAttribtues, IRequest request) - { - if (!_config.Configuration.IsStartupWizardCompleted && authAttribtues.AllowBeforeStartupWizard) - { - return true; - } - - if (authAttribtues.AllowLocal && request.IsLocal) - { - return true; - } - - if (authAttribtues.AllowLocalOnly && request.IsLocal) - { - return true; - } - - if (authAttribtues.IgnoreLegacyAuth) - { - return true; - } - - return false; - } - - private bool IsExemptFromRoles(AuthorizationInfo auth, IAuthenticationAttributes authAttribtues, IRequest request, AuthenticationInfo tokenInfo) - { - if (!_config.Configuration.IsStartupWizardCompleted && authAttribtues.AllowBeforeStartupWizard) - { - return true; - } - - if (authAttribtues.AllowLocal && request.IsLocal) - { - return true; - } - - if (authAttribtues.AllowLocalOnly && request.IsLocal) - { - return true; - } - - if (string.IsNullOrEmpty(auth.Token)) - { - return true; - } - - if (tokenInfo != null && tokenInfo.UserId.Equals(Guid.Empty)) - { - return true; - } - - return false; - } - - private static void ValidateRoles(string[] roles, User user) - { - if (roles.Contains("admin", StringComparer.OrdinalIgnoreCase)) - { - if (user == null || !user.HasPermission(PermissionKind.IsAdministrator)) - { - throw new SecurityException("User does not have admin access."); - } - } - - if (roles.Contains("delete", StringComparer.OrdinalIgnoreCase)) - { - if (user == null || !user.HasPermission(PermissionKind.EnableContentDeletion)) - { - throw new SecurityException("User does not have delete access."); - } - } - - if (roles.Contains("download", StringComparer.OrdinalIgnoreCase)) - { - if (user == null || !user.HasPermission(PermissionKind.EnableContentDownloading)) - { - throw new SecurityException("User does not have download access."); - } - } - } - - private static AuthenticationInfo GetTokenInfo(IRequest request) - { - request.Items.TryGetValue("OriginalAuthenticationInfo", out var info); - return info as AuthenticationInfo; - } - - private void ValidateSecurityToken(IRequest request, string token) - { - if (string.IsNullOrEmpty(token)) - { - throw new AuthenticationException("Access token is required."); - } - - var info = GetTokenInfo(request); - - if (info == null) - { - throw new AuthenticationException("Access token is invalid or expired."); - } - } } } diff --git a/Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs b/Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs index fb93fae3e..eec8ac486 100644 --- a/Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs +++ b/Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs @@ -7,7 +7,6 @@ using System.Net; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Net; using MediaBrowser.Controller.Security; -using MediaBrowser.Model.Services; using Microsoft.AspNetCore.Http; using Microsoft.Net.Http.Headers; @@ -26,12 +25,12 @@ namespace Emby.Server.Implementations.HttpServer.Security public AuthorizationInfo GetAuthorizationInfo(object requestContext) { - return GetAuthorizationInfo((IRequest)requestContext); + return GetAuthorizationInfo((HttpContext)requestContext); } - public AuthorizationInfo GetAuthorizationInfo(IRequest requestContext) + public AuthorizationInfo GetAuthorizationInfo(HttpContext requestContext) { - if (requestContext.Items.TryGetValue("AuthorizationInfo", out var cached)) + if (requestContext.Request.HttpContext.Items.TryGetValue("AuthorizationInfo", out var cached)) { return (AuthorizationInfo)cached; } @@ -52,18 +51,18 @@ namespace Emby.Server.Implementations.HttpServer.Security /// </summary> /// <param name="httpReq">The HTTP req.</param> /// <returns>Dictionary{System.StringSystem.String}.</returns> - private AuthorizationInfo GetAuthorization(IRequest httpReq) + private AuthorizationInfo GetAuthorization(HttpContext httpReq) { var auth = GetAuthorizationDictionary(httpReq); var (authInfo, originalAuthInfo) = - GetAuthorizationInfoFromDictionary(auth, httpReq.Headers, httpReq.QueryString); + GetAuthorizationInfoFromDictionary(auth, httpReq.Request.Headers, httpReq.Request.Query); if (originalAuthInfo != null) { - httpReq.Items["OriginalAuthenticationInfo"] = originalAuthInfo; + httpReq.Request.HttpContext.Items["OriginalAuthenticationInfo"] = originalAuthInfo; } - httpReq.Items["AuthorizationInfo"] = authInfo; + httpReq.Request.HttpContext.Items["AuthorizationInfo"] = authInfo; return authInfo; } @@ -203,13 +202,13 @@ namespace Emby.Server.Implementations.HttpServer.Security /// </summary> /// <param name="httpReq">The HTTP req.</param> /// <returns>Dictionary{System.StringSystem.String}.</returns> - private Dictionary<string, string> GetAuthorizationDictionary(IRequest httpReq) + private Dictionary<string, string> GetAuthorizationDictionary(HttpContext httpReq) { - var auth = httpReq.Headers["X-Emby-Authorization"]; + var auth = httpReq.Request.Headers["X-Emby-Authorization"]; if (string.IsNullOrEmpty(auth)) { - auth = httpReq.Headers[HeaderNames.Authorization]; + auth = httpReq.Request.Headers[HeaderNames.Authorization]; } return GetAuthorization(auth); diff --git a/Emby.Server.Implementations/HttpServer/Security/SessionContext.cs b/Emby.Server.Implementations/HttpServer/Security/SessionContext.cs index 03fcfa53d..8777c59b7 100644 --- a/Emby.Server.Implementations/HttpServer/Security/SessionContext.cs +++ b/Emby.Server.Implementations/HttpServer/Security/SessionContext.cs @@ -2,11 +2,11 @@ using System; using Jellyfin.Data.Entities; +using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Net; -using MediaBrowser.Controller.Security; using MediaBrowser.Controller.Session; -using MediaBrowser.Model.Services; +using Microsoft.AspNetCore.Http; namespace Emby.Server.Implementations.HttpServer.Security { @@ -23,26 +23,20 @@ namespace Emby.Server.Implementations.HttpServer.Security _sessionManager = sessionManager; } - public SessionInfo GetSession(IRequest requestContext) + public SessionInfo GetSession(HttpContext requestContext) { var authorization = _authContext.GetAuthorizationInfo(requestContext); var user = authorization.User; - return _sessionManager.LogSessionActivity(authorization.Client, authorization.Version, authorization.DeviceId, authorization.Device, requestContext.RemoteIp, user); - } - - private AuthenticationInfo GetTokenInfo(IRequest request) - { - request.Items.TryGetValue("OriginalAuthenticationInfo", out var info); - return info as AuthenticationInfo; + return _sessionManager.LogSessionActivity(authorization.Client, authorization.Version, authorization.DeviceId, authorization.Device, requestContext.Request.RemoteIp(), user); } public SessionInfo GetSession(object requestContext) { - return GetSession((IRequest)requestContext); + return GetSession((HttpContext)requestContext); } - public User GetUser(IRequest requestContext) + public User GetUser(HttpContext requestContext) { var session = GetSession(requestContext); @@ -51,7 +45,7 @@ namespace Emby.Server.Implementations.HttpServer.Security public User GetUser(object requestContext) { - return GetUser((IRequest)requestContext); + return GetUser((HttpContext)requestContext); } } } diff --git a/Emby.Server.Implementations/HttpServer/StreamWriter.cs b/Emby.Server.Implementations/HttpServer/StreamWriter.cs deleted file mode 100644 index 00e3ab8fe..000000000 --- a/Emby.Server.Implementations/HttpServer/StreamWriter.cs +++ /dev/null @@ -1,120 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.IO; -using System.Threading; -using System.Threading.Tasks; -using MediaBrowser.Model.Services; -using Microsoft.Net.Http.Headers; - -namespace Emby.Server.Implementations.HttpServer -{ - /// <summary> - /// Class StreamWriter. - /// </summary> - public class StreamWriter : IAsyncStreamWriter, IHasHeaders - { - /// <summary> - /// The options. - /// </summary> - private readonly IDictionary<string, string> _options = new Dictionary<string, string>(); - - /// <summary> - /// Initializes a new instance of the <see cref="StreamWriter" /> class. - /// </summary> - /// <param name="source">The source.</param> - /// <param name="contentType">Type of the content.</param> - public StreamWriter(Stream source, string contentType) - { - if (string.IsNullOrEmpty(contentType)) - { - throw new ArgumentNullException(nameof(contentType)); - } - - SourceStream = source; - - Headers["Content-Type"] = contentType; - - if (source.CanSeek) - { - Headers[HeaderNames.ContentLength] = source.Length.ToString(CultureInfo.InvariantCulture); - } - - Headers[HeaderNames.ContentType] = contentType; - } - - /// <summary> - /// Initializes a new instance of the <see cref="StreamWriter"/> class. - /// </summary> - /// <param name="source">The source.</param> - /// <param name="contentType">Type of the content.</param> - /// <param name="contentLength">The content length.</param> - public StreamWriter(byte[] source, string contentType, int contentLength) - { - if (string.IsNullOrEmpty(contentType)) - { - throw new ArgumentNullException(nameof(contentType)); - } - - SourceBytes = source; - - Headers[HeaderNames.ContentLength] = contentLength.ToString(CultureInfo.InvariantCulture); - Headers[HeaderNames.ContentType] = contentType; - } - - /// <summary> - /// Gets or sets the source stream. - /// </summary> - /// <value>The source stream.</value> - private Stream SourceStream { get; set; } - - private byte[] SourceBytes { get; set; } - - /// <summary> - /// Gets the options. - /// </summary> - /// <value>The options.</value> - public IDictionary<string, string> Headers => _options; - - /// <summary> - /// Fires when complete. - /// </summary> - public Action OnComplete { get; set; } - - /// <summary> - /// Fires when an error occours. - /// </summary> - public Action OnError { get; set; } - - /// <inheritdoc /> - public async Task WriteToAsync(Stream responseStream, CancellationToken cancellationToken) - { - try - { - var bytes = SourceBytes; - - if (bytes != null) - { - await responseStream.WriteAsync(bytes, 0, bytes.Length, cancellationToken).ConfigureAwait(false); - } - else - { - using (var src = SourceStream) - { - await src.CopyToAsync(responseStream, cancellationToken).ConfigureAwait(false); - } - } - } - catch - { - OnError?.Invoke(); - - throw; - } - finally - { - OnComplete?.Invoke(); - } - } - } -} diff --git a/Emby.Server.Implementations/Services/HttpResult.cs b/Emby.Server.Implementations/Services/HttpResult.cs deleted file mode 100644 index 8ba86f756..000000000 --- a/Emby.Server.Implementations/Services/HttpResult.cs +++ /dev/null @@ -1,64 +0,0 @@ -#pragma warning disable CS1591 - -using System.Collections.Generic; -using System.IO; -using System.Net; -using System.Threading; -using System.Threading.Tasks; -using MediaBrowser.Model.Services; - -namespace Emby.Server.Implementations.Services -{ - public class HttpResult - : IHttpResult, IAsyncStreamWriter - { - public HttpResult(object response, string contentType, HttpStatusCode statusCode) - { - this.Headers = new Dictionary<string, string>(); - - this.Response = response; - this.ContentType = contentType; - this.StatusCode = statusCode; - } - - public object Response { get; set; } - - public string ContentType { get; set; } - - public IDictionary<string, string> Headers { get; private set; } - - public int Status { get; set; } - - public HttpStatusCode StatusCode - { - get => (HttpStatusCode)Status; - set => Status = (int)value; - } - - public IRequest RequestContext { get; set; } - - public async Task WriteToAsync(Stream responseStream, CancellationToken cancellationToken) - { - var response = RequestContext?.Response; - - if (this.Response is byte[] bytesResponse) - { - var contentLength = bytesResponse.Length; - - if (response != null) - { - response.ContentLength = contentLength; - } - - if (contentLength > 0) - { - await responseStream.WriteAsync(bytesResponse, 0, contentLength, cancellationToken).ConfigureAwait(false); - } - - return; - } - - await ResponseHelper.WriteObject(this.RequestContext, this.Response, response).ConfigureAwait(false); - } - } -} diff --git a/Emby.Server.Implementations/Services/RequestHelper.cs b/Emby.Server.Implementations/Services/RequestHelper.cs deleted file mode 100644 index 1f9c7fc22..000000000 --- a/Emby.Server.Implementations/Services/RequestHelper.cs +++ /dev/null @@ -1,51 +0,0 @@ -#pragma warning disable CS1591 - -using System; -using System.IO; -using System.Threading.Tasks; -using Emby.Server.Implementations.HttpServer; - -namespace Emby.Server.Implementations.Services -{ - public class RequestHelper - { - public static Func<Type, Stream, Task<object>> GetRequestReader(HttpListenerHost host, string contentType) - { - switch (GetContentTypeWithoutEncoding(contentType)) - { - case "application/xml": - case "text/xml": - case "text/xml; charset=utf-8": //"text/xml; charset=utf-8" also matches xml - return host.DeserializeXml; - - case "application/json": - case "text/json": - return host.DeserializeJson; - } - - return null; - } - - public static Action<object, Stream> GetResponseWriter(HttpListenerHost host, string contentType) - { - switch (GetContentTypeWithoutEncoding(contentType)) - { - case "application/xml": - case "text/xml": - case "text/xml; charset=utf-8": //"text/xml; charset=utf-8" also matches xml - return host.SerializeToXml; - - case "application/json": - case "text/json": - return host.SerializeToJson; - } - - return null; - } - - private static string GetContentTypeWithoutEncoding(string contentType) - { - return contentType?.Split(';')[0].ToLowerInvariant().Trim(); - } - } -} diff --git a/Emby.Server.Implementations/Services/ResponseHelper.cs b/Emby.Server.Implementations/Services/ResponseHelper.cs deleted file mode 100644 index a329b531d..000000000 --- a/Emby.Server.Implementations/Services/ResponseHelper.cs +++ /dev/null @@ -1,141 +0,0 @@ -#pragma warning disable CS1591 - -using System; -using System.Globalization; -using System.IO; -using System.Net; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using Emby.Server.Implementations.HttpServer; -using MediaBrowser.Model.Services; -using Microsoft.AspNetCore.Http; - -namespace Emby.Server.Implementations.Services -{ - public static class ResponseHelper - { - public static Task WriteToResponse(HttpResponse response, IRequest request, object result, CancellationToken cancellationToken) - { - if (result == null) - { - if (response.StatusCode == (int)HttpStatusCode.OK) - { - response.StatusCode = (int)HttpStatusCode.NoContent; - } - - response.ContentLength = 0; - return Task.CompletedTask; - } - - var httpResult = result as IHttpResult; - if (httpResult != null) - { - httpResult.RequestContext = request; - request.ResponseContentType = httpResult.ContentType ?? request.ResponseContentType; - } - - var defaultContentType = request.ResponseContentType; - - if (httpResult != null) - { - if (httpResult.RequestContext == null) - { - httpResult.RequestContext = request; - } - - response.StatusCode = httpResult.Status; - } - - if (result is IHasHeaders responseOptions) - { - foreach (var responseHeaders in responseOptions.Headers) - { - if (string.Equals(responseHeaders.Key, "Content-Length", StringComparison.OrdinalIgnoreCase)) - { - response.ContentLength = long.Parse(responseHeaders.Value, CultureInfo.InvariantCulture); - continue; - } - - response.Headers.Add(responseHeaders.Key, responseHeaders.Value); - } - } - - // ContentType='text/html' is the default for a HttpResponse - // Do not override if another has been set - if (response.ContentType == null || response.ContentType == "text/html") - { - response.ContentType = defaultContentType; - } - - if (response.ContentType == "application/json") - { - response.ContentType += "; charset=utf-8"; - } - - switch (result) - { - case IAsyncStreamWriter asyncStreamWriter: - return asyncStreamWriter.WriteToAsync(response.Body, cancellationToken); - case IStreamWriter streamWriter: - streamWriter.WriteTo(response.Body); - return Task.CompletedTask; - case FileWriter fileWriter: - return fileWriter.WriteToAsync(response, cancellationToken); - case Stream stream: - return CopyStream(stream, response.Body); - case byte[] bytes: - response.ContentType = "application/octet-stream"; - response.ContentLength = bytes.Length; - - if (bytes.Length > 0) - { - return response.Body.WriteAsync(bytes, 0, bytes.Length, cancellationToken); - } - - return Task.CompletedTask; - case string responseText: - var responseTextAsBytes = Encoding.UTF8.GetBytes(responseText); - response.ContentLength = responseTextAsBytes.Length; - - if (responseTextAsBytes.Length > 0) - { - return response.Body.WriteAsync(responseTextAsBytes, 0, responseTextAsBytes.Length, cancellationToken); - } - - return Task.CompletedTask; - } - - return WriteObject(request, result, response); - } - - private static async Task CopyStream(Stream src, Stream dest) - { - using (src) - { - await src.CopyToAsync(dest).ConfigureAwait(false); - } - } - - public static async Task WriteObject(IRequest request, object result, HttpResponse response) - { - var contentType = request.ResponseContentType; - var serializer = RequestHelper.GetResponseWriter(HttpListenerHost.Instance, contentType); - - using (var ms = new MemoryStream()) - { - serializer(result, ms); - - ms.Position = 0; - - var contentLength = ms.Length; - response.ContentLength = contentLength; - - if (contentLength > 0) - { - await ms.CopyToAsync(response.Body).ConfigureAwait(false); - } - } - } - } -} diff --git a/Emby.Server.Implementations/Services/ServiceController.cs b/Emby.Server.Implementations/Services/ServiceController.cs deleted file mode 100644 index 47e7261e8..000000000 --- a/Emby.Server.Implementations/Services/ServiceController.cs +++ /dev/null @@ -1,202 +0,0 @@ -#pragma warning disable CS1591 - -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Threading.Tasks; -using Emby.Server.Implementations.HttpServer; -using MediaBrowser.Model.Services; -using Microsoft.Extensions.Logging; - -namespace Emby.Server.Implementations.Services -{ - public delegate object ActionInvokerFn(object intance, object request); - - public delegate void VoidActionInvokerFn(object intance, object request); - - public class ServiceController - { - private readonly ILogger<ServiceController> _logger; - - /// <summary> - /// Initializes a new instance of the <see cref="ServiceController"/> class. - /// </summary> - /// <param name="logger">The <see cref="ServiceController"/> logger.</param> - public ServiceController(ILogger<ServiceController> logger) - { - _logger = logger; - } - - public void Init(HttpListenerHost appHost, IEnumerable<Type> serviceTypes) - { - foreach (var serviceType in serviceTypes) - { - RegisterService(appHost, serviceType); - } - } - - public void RegisterService(HttpListenerHost appHost, Type serviceType) - { - // Make sure the provided type implements IService - if (!typeof(IService).IsAssignableFrom(serviceType)) - { - _logger.LogWarning("Tried to register a service that does not implement IService: {ServiceType}", serviceType); - return; - } - - var processedReqs = new HashSet<Type>(); - - var actions = ServiceExecGeneral.Reset(serviceType); - - foreach (var mi in serviceType.GetActions()) - { - var requestType = mi.GetParameters()[0].ParameterType; - if (processedReqs.Contains(requestType)) - { - continue; - } - - processedReqs.Add(requestType); - - ServiceExecGeneral.CreateServiceRunnersFor(requestType, actions); - - // var returnMarker = GetTypeWithGenericTypeDefinitionOf(requestType, typeof(IReturn<>)); - // var responseType = returnMarker != null ? - // GetGenericArguments(returnMarker)[0] - // : mi.ReturnType != typeof(object) && mi.ReturnType != typeof(void) ? - // mi.ReturnType - // : Type.GetType(requestType.FullName + "Response"); - - RegisterRestPaths(appHost, requestType, serviceType); - - appHost.AddServiceInfo(serviceType, requestType); - } - } - - public readonly RestPath.RestPathMap RestPathMap = new RestPath.RestPathMap(); - - public void RegisterRestPaths(HttpListenerHost appHost, Type requestType, Type serviceType) - { - var attrs = appHost.GetRouteAttributes(requestType); - foreach (var attr in attrs) - { - var restPath = new RestPath(appHost.CreateInstance, appHost.GetParseFn, requestType, serviceType, attr.Path, attr.Verbs, attr.IsHidden, attr.Summary, attr.Description); - - RegisterRestPath(restPath); - } - } - - private static readonly char[] InvalidRouteChars = new[] { '?', '&' }; - - public void RegisterRestPath(RestPath restPath) - { - if (restPath.Path[0] != '/') - { - throw new ArgumentException( - string.Format( - CultureInfo.InvariantCulture, - "Route '{0}' on '{1}' must start with a '/'", - restPath.Path, - restPath.RequestType.GetMethodName())); - } - - if (restPath.Path.IndexOfAny(InvalidRouteChars) != -1) - { - throw new ArgumentException( - string.Format( - CultureInfo.InvariantCulture, - "Route '{0}' on '{1}' contains invalid chars. ", - restPath.Path, - restPath.RequestType.GetMethodName())); - } - - if (RestPathMap.TryGetValue(restPath.FirstMatchHashKey, out List<RestPath> pathsAtFirstMatch)) - { - pathsAtFirstMatch.Add(restPath); - } - else - { - RestPathMap[restPath.FirstMatchHashKey] = new List<RestPath>() { restPath }; - } - } - - public RestPath GetRestPathForRequest(string httpMethod, string pathInfo) - { - var matchUsingPathParts = RestPath.GetPathPartsForMatching(pathInfo); - - List<RestPath> firstMatches; - - var yieldedHashMatches = RestPath.GetFirstMatchHashKeys(matchUsingPathParts); - foreach (var potentialHashMatch in yieldedHashMatches) - { - if (!this.RestPathMap.TryGetValue(potentialHashMatch, out firstMatches)) - { - continue; - } - - var bestScore = -1; - RestPath bestMatch = null; - foreach (var restPath in firstMatches) - { - var score = restPath.MatchScore(httpMethod, matchUsingPathParts); - if (score > bestScore) - { - bestScore = score; - bestMatch = restPath; - } - } - - if (bestScore > 0 && bestMatch != null) - { - return bestMatch; - } - } - - var yieldedWildcardMatches = RestPath.GetFirstMatchWildCardHashKeys(matchUsingPathParts); - foreach (var potentialHashMatch in yieldedWildcardMatches) - { - if (!this.RestPathMap.TryGetValue(potentialHashMatch, out firstMatches)) - { - continue; - } - - var bestScore = -1; - RestPath bestMatch = null; - foreach (var restPath in firstMatches) - { - var score = restPath.MatchScore(httpMethod, matchUsingPathParts); - if (score > bestScore) - { - bestScore = score; - bestMatch = restPath; - } - } - - if (bestScore > 0 && bestMatch != null) - { - return bestMatch; - } - } - - return null; - } - - public Task<object> Execute(HttpListenerHost httpHost, object requestDto, IRequest req) - { - var requestType = requestDto.GetType(); - req.OperationName = requestType.Name; - - var serviceType = httpHost.GetServiceTypeByRequest(requestType); - - var service = httpHost.CreateInstance(serviceType); - - if (service is IRequiresRequest serviceRequiresContext) - { - serviceRequiresContext.Request = req; - } - - // Executes the service and returns the result - return ServiceExecGeneral.Execute(serviceType, req, service, requestDto, requestType.GetMethodName()); - } - } -} diff --git a/Emby.Server.Implementations/Services/ServiceExec.cs b/Emby.Server.Implementations/Services/ServiceExec.cs deleted file mode 100644 index 7b970627e..000000000 --- a/Emby.Server.Implementations/Services/ServiceExec.cs +++ /dev/null @@ -1,230 +0,0 @@ -#pragma warning disable CS1591 - -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Linq.Expressions; -using System.Reflection; -using System.Threading.Tasks; -using MediaBrowser.Model.Services; - -namespace Emby.Server.Implementations.Services -{ - public static class ServiceExecExtensions - { - public static string[] AllVerbs = new[] { - "OPTIONS", "GET", "HEAD", "POST", "PUT", "DELETE", "TRACE", "CONNECT", // RFC 2616 - "PROPFIND", "PROPPATCH", "MKCOL", "COPY", "MOVE", "LOCK", "UNLOCK", // RFC 2518 - "VERSION-CONTROL", "REPORT", "CHECKOUT", "CHECKIN", "UNCHECKOUT", - "MKWORKSPACE", "UPDATE", "LABEL", "MERGE", "BASELINE-CONTROL", "MKACTIVITY", // RFC 3253 - "ORDERPATCH", // RFC 3648 - "ACL", // RFC 3744 - "PATCH", // https://datatracker.ietf.org/doc/draft-dusseault-http-patch/ - "SEARCH", // https://datatracker.ietf.org/doc/draft-reschke-webdav-search/ - "BCOPY", "BDELETE", "BMOVE", "BPROPFIND", "BPROPPATCH", "NOTIFY", - "POLL", "SUBSCRIBE", "UNSUBSCRIBE" - }; - - public static List<MethodInfo> GetActions(this Type serviceType) - { - var list = new List<MethodInfo>(); - - foreach (var mi in serviceType.GetRuntimeMethods()) - { - if (!mi.IsPublic) - { - continue; - } - - if (mi.IsStatic) - { - continue; - } - - if (mi.GetParameters().Length != 1) - { - continue; - } - - var actionName = mi.Name; - if (!AllVerbs.Contains(actionName, StringComparer.OrdinalIgnoreCase)) - { - continue; - } - - list.Add(mi); - } - - return list; - } - } - - internal static class ServiceExecGeneral - { - private static Dictionary<string, ServiceMethod> execMap = new Dictionary<string, ServiceMethod>(); - - public static void CreateServiceRunnersFor(Type requestType, List<ServiceMethod> actions) - { - foreach (var actionCtx in actions) - { - if (execMap.ContainsKey(actionCtx.Id)) - { - continue; - } - - execMap[actionCtx.Id] = actionCtx; - } - } - - public static Task<object> Execute(Type serviceType, IRequest request, object instance, object requestDto, string requestName) - { - var actionName = request.Verb ?? "POST"; - - if (execMap.TryGetValue(ServiceMethod.Key(serviceType, actionName, requestName), out ServiceMethod actionContext)) - { - if (actionContext.RequestFilters != null) - { - foreach (var requestFilter in actionContext.RequestFilters) - { - requestFilter.RequestFilter(request, request.Response, requestDto); - if (request.Response.HasStarted) - { - Task.FromResult<object>(null); - } - } - } - - var response = actionContext.ServiceAction(instance, requestDto); - - if (response is Task taskResponse) - { - return GetTaskResult(taskResponse); - } - - return Task.FromResult(response); - } - - var expectedMethodName = actionName.Substring(0, 1) + actionName.Substring(1).ToLowerInvariant(); - throw new NotImplementedException( - string.Format( - CultureInfo.InvariantCulture, - "Could not find method named {1}({0}) or Any({0}) on Service {2}", - requestDto.GetType().GetMethodName(), - expectedMethodName, - serviceType.GetMethodName())); - } - - private static async Task<object> GetTaskResult(Task task) - { - try - { - if (task is Task<object> taskObject) - { - return await taskObject.ConfigureAwait(false); - } - - await task.ConfigureAwait(false); - - var type = task.GetType().GetTypeInfo(); - if (!type.IsGenericType) - { - return null; - } - - var resultProperty = type.GetDeclaredProperty("Result"); - if (resultProperty == null) - { - return null; - } - - var result = resultProperty.GetValue(task); - - // hack alert - if (result.GetType().Name.IndexOf("voidtaskresult", StringComparison.OrdinalIgnoreCase) != -1) - { - return null; - } - - return result; - } - catch (TypeAccessException) - { - return null; // return null for void Task's - } - } - - public static List<ServiceMethod> Reset(Type serviceType) - { - var actions = new List<ServiceMethod>(); - - foreach (var mi in serviceType.GetActions()) - { - var actionName = mi.Name; - var args = mi.GetParameters(); - - var requestType = args[0].ParameterType; - var actionCtx = new ServiceMethod - { - Id = ServiceMethod.Key(serviceType, actionName, requestType.GetMethodName()) - }; - - actionCtx.ServiceAction = CreateExecFn(serviceType, requestType, mi); - - var reqFilters = new List<IHasRequestFilter>(); - - foreach (var attr in mi.GetCustomAttributes(true)) - { - if (attr is IHasRequestFilter hasReqFilter) - { - reqFilters.Add(hasReqFilter); - } - } - - if (reqFilters.Count > 0) - { - actionCtx.RequestFilters = reqFilters.OrderBy(i => i.Priority).ToArray(); - } - - actions.Add(actionCtx); - } - - return actions; - } - - private static ActionInvokerFn CreateExecFn(Type serviceType, Type requestType, MethodInfo mi) - { - var serviceParam = Expression.Parameter(typeof(object), "serviceObj"); - var serviceStrong = Expression.Convert(serviceParam, serviceType); - - var requestDtoParam = Expression.Parameter(typeof(object), "requestDto"); - var requestDtoStrong = Expression.Convert(requestDtoParam, requestType); - - Expression callExecute = Expression.Call( - serviceStrong, mi, requestDtoStrong); - - if (mi.ReturnType != typeof(void)) - { - var executeFunc = Expression.Lambda<ActionInvokerFn>( - callExecute, - serviceParam, - requestDtoParam).Compile(); - - return executeFunc; - } - else - { - var executeFunc = Expression.Lambda<VoidActionInvokerFn>( - callExecute, - serviceParam, - requestDtoParam).Compile(); - - return (service, request) => - { - executeFunc(service, request); - return null; - }; - } - } - } -} diff --git a/Emby.Server.Implementations/Services/ServiceHandler.cs b/Emby.Server.Implementations/Services/ServiceHandler.cs deleted file mode 100644 index b4166f771..000000000 --- a/Emby.Server.Implementations/Services/ServiceHandler.cs +++ /dev/null @@ -1,212 +0,0 @@ -#pragma warning disable CS1591 - -using System; -using System.Collections.Generic; -using System.Net.Mime; -using System.Reflection; -using System.Threading; -using System.Threading.Tasks; -using Emby.Server.Implementations.HttpServer; -using MediaBrowser.Common.Extensions; -using MediaBrowser.Model.Services; -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Logging; - -namespace Emby.Server.Implementations.Services -{ - public class ServiceHandler - { - private RestPath _restPath; - - private string _responseContentType; - - internal ServiceHandler(RestPath restPath, string responseContentType) - { - _restPath = restPath; - _responseContentType = responseContentType; - } - - protected static Task<object> CreateContentTypeRequest(HttpListenerHost host, IRequest httpReq, Type requestType, string contentType) - { - if (!string.IsNullOrEmpty(contentType) && httpReq.ContentLength > 0) - { - var deserializer = RequestHelper.GetRequestReader(host, contentType); - if (deserializer != null) - { - return deserializer.Invoke(requestType, httpReq.InputStream); - } - } - - return Task.FromResult(host.CreateInstance(requestType)); - } - - public static string GetSanitizedPathInfo(string pathInfo, out string contentType) - { - contentType = null; - var pos = pathInfo.LastIndexOf('.'); - if (pos != -1) - { - var format = pathInfo.AsSpan().Slice(pos + 1); - contentType = GetFormatContentType(format); - if (contentType != null) - { - pathInfo = pathInfo.Substring(0, pos); - } - } - - return pathInfo; - } - - private static string GetFormatContentType(ReadOnlySpan<char> format) - { - if (format.Equals("json", StringComparison.Ordinal)) - { - return MediaTypeNames.Application.Json; - } - else if (format.Equals("xml", StringComparison.Ordinal)) - { - return MediaTypeNames.Application.Xml; - } - - return null; - } - - public async Task ProcessRequestAsync(HttpListenerHost httpHost, IRequest httpReq, HttpResponse httpRes, CancellationToken cancellationToken) - { - httpReq.Items["__route"] = _restPath; - - if (_responseContentType != null) - { - httpReq.ResponseContentType = _responseContentType; - } - - var request = await CreateRequest(httpHost, httpReq, _restPath).ConfigureAwait(false); - - httpHost.ApplyRequestFilters(httpReq, httpRes, request); - - httpRes.HttpContext.SetServiceStackRequest(httpReq); - var response = await httpHost.ServiceController.Execute(httpHost, request, httpReq).ConfigureAwait(false); - - // Apply response filters - foreach (var responseFilter in httpHost.ResponseFilters) - { - responseFilter(httpReq, httpRes, response); - } - - await ResponseHelper.WriteToResponse(httpRes, httpReq, response, cancellationToken).ConfigureAwait(false); - } - - public static async Task<object> CreateRequest(HttpListenerHost host, IRequest httpReq, RestPath restPath) - { - var requestType = restPath.RequestType; - - if (RequireqRequestStream(requestType)) - { - // Used by IRequiresRequestStream - var requestParams = GetRequestParams(httpReq.Response.HttpContext.Request); - var request = ServiceHandler.CreateRequest(httpReq, restPath, requestParams, host.CreateInstance(requestType)); - - var rawReq = (IRequiresRequestStream)request; - rawReq.RequestStream = httpReq.InputStream; - return rawReq; - } - else - { - var requestParams = GetFlattenedRequestParams(httpReq.Response.HttpContext.Request); - - var requestDto = await CreateContentTypeRequest(host, httpReq, restPath.RequestType, httpReq.ContentType).ConfigureAwait(false); - - return CreateRequest(httpReq, restPath, requestParams, requestDto); - } - } - - public static bool RequireqRequestStream(Type requestType) - { - var requiresRequestStreamTypeInfo = typeof(IRequiresRequestStream).GetTypeInfo(); - - return requiresRequestStreamTypeInfo.IsAssignableFrom(requestType.GetTypeInfo()); - } - - public static object CreateRequest(IRequest httpReq, RestPath restPath, Dictionary<string, string> requestParams, object requestDto) - { - var pathInfo = !restPath.IsWildCardPath - ? GetSanitizedPathInfo(httpReq.PathInfo, out _) - : httpReq.PathInfo; - - return restPath.CreateRequest(pathInfo, requestParams, requestDto); - } - - /// <summary> - /// Duplicate Params are given a unique key by appending a #1 suffix - /// </summary> - private static Dictionary<string, string> GetRequestParams(HttpRequest request) - { - var map = new Dictionary<string, string>(); - - foreach (var pair in request.Query) - { - var values = pair.Value; - if (values.Count == 1) - { - map[pair.Key] = values[0]; - } - else - { - for (var i = 0; i < values.Count; i++) - { - map[pair.Key + (i == 0 ? string.Empty : "#" + i)] = values[i]; - } - } - } - - if ((IsMethod(request.Method, "POST") || IsMethod(request.Method, "PUT")) - && request.HasFormContentType) - { - foreach (var pair in request.Form) - { - var values = pair.Value; - if (values.Count == 1) - { - map[pair.Key] = values[0]; - } - else - { - for (var i = 0; i < values.Count; i++) - { - map[pair.Key + (i == 0 ? string.Empty : "#" + i)] = values[i]; - } - } - } - } - - return map; - } - - private static bool IsMethod(string method, string expected) - => string.Equals(method, expected, StringComparison.OrdinalIgnoreCase); - - /// <summary> - /// Duplicate params have their values joined together in a comma-delimited string. - /// </summary> - private static Dictionary<string, string> GetFlattenedRequestParams(HttpRequest request) - { - var map = new Dictionary<string, string>(); - - foreach (var pair in request.Query) - { - map[pair.Key] = pair.Value; - } - - if ((IsMethod(request.Method, "POST") || IsMethod(request.Method, "PUT")) - && request.HasFormContentType) - { - foreach (var pair in request.Form) - { - map[pair.Key] = pair.Value; - } - } - - return map; - } - } -} diff --git a/Emby.Server.Implementations/Services/ServiceMethod.cs b/Emby.Server.Implementations/Services/ServiceMethod.cs deleted file mode 100644 index 5116cc04f..000000000 --- a/Emby.Server.Implementations/Services/ServiceMethod.cs +++ /dev/null @@ -1,20 +0,0 @@ -#pragma warning disable CS1591 - -using System; - -namespace Emby.Server.Implementations.Services -{ - public class ServiceMethod - { - public string Id { get; set; } - - public ActionInvokerFn ServiceAction { get; set; } - - public MediaBrowser.Model.Services.IHasRequestFilter[] RequestFilters { get; set; } - - public static string Key(Type serviceType, string method, string requestDtoName) - { - return serviceType.FullName + " " + method.ToUpperInvariant() + " " + requestDtoName; - } - } -} diff --git a/Emby.Server.Implementations/Services/ServicePath.cs b/Emby.Server.Implementations/Services/ServicePath.cs deleted file mode 100644 index 0d4728b43..000000000 --- a/Emby.Server.Implementations/Services/ServicePath.cs +++ /dev/null @@ -1,550 +0,0 @@ -#pragma warning disable CS1591 - -using System; -using System.Collections.Generic; -using System.Globalization; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Text; -using System.Text.Json.Serialization; - -namespace Emby.Server.Implementations.Services -{ - public class RestPath - { - private const string WildCard = "*"; - private const char WildCardChar = '*'; - private const string PathSeperator = "/"; - private const char PathSeperatorChar = '/'; - private const char ComponentSeperator = '.'; - private const string VariablePrefix = "{"; - - private readonly bool[] componentsWithSeparators; - - private readonly string restPath; - public bool IsWildCardPath { get; private set; } - - private readonly string[] literalsToMatch; - - private readonly string[] variablesNames; - - private readonly bool[] isWildcard; - private readonly int wildcardCount = 0; - - internal static string[] IgnoreAttributesNamed = new[] - { - nameof(JsonIgnoreAttribute) - }; - - private static Type _excludeType = typeof(Stream); - - public int VariableArgsCount { get; set; } - - /// <summary> - /// The number of segments separated by '/' determinable by path.Split('/').Length - /// e.g. /path/to/here.ext == 3 - /// </summary> - public int PathComponentsCount { get; set; } - - /// <summary> - /// Gets or sets the total number of segments after subparts have been exploded ('.') - /// e.g. /path/to/here.ext == 4. - /// </summary> - public int TotalComponentsCount { get; set; } - - public string[] Verbs { get; private set; } - - public Type RequestType { get; private set; } - - public Type ServiceType { get; private set; } - - public string Path => this.restPath; - - public string Summary { get; private set; } - - public string Description { get; private set; } - - public bool IsHidden { get; private set; } - - public static string[] GetPathPartsForMatching(string pathInfo) - { - return pathInfo.ToLowerInvariant().Split(new[] { PathSeperatorChar }, StringSplitOptions.RemoveEmptyEntries); - } - - public static List<string> GetFirstMatchHashKeys(string[] pathPartsForMatching) - { - var hashPrefix = pathPartsForMatching.Length + PathSeperator; - return GetPotentialMatchesWithPrefix(hashPrefix, pathPartsForMatching); - } - - public static List<string> GetFirstMatchWildCardHashKeys(string[] pathPartsForMatching) - { - const string HashPrefix = WildCard + PathSeperator; - return GetPotentialMatchesWithPrefix(HashPrefix, pathPartsForMatching); - } - - private static List<string> GetPotentialMatchesWithPrefix(string hashPrefix, string[] pathPartsForMatching) - { - var list = new List<string>(); - - foreach (var part in pathPartsForMatching) - { - list.Add(hashPrefix + part); - - if (part.IndexOf(ComponentSeperator, StringComparison.Ordinal) == -1) - { - continue; - } - - var subParts = part.Split(ComponentSeperator); - foreach (var subPart in subParts) - { - list.Add(hashPrefix + subPart); - } - } - - return list; - } - - public RestPath(Func<Type, object> createInstanceFn, Func<Type, Func<string, object>> getParseFn, Type requestType, Type serviceType, string path, string verbs, bool isHidden = false, string summary = null, string description = null) - { - this.RequestType = requestType; - this.ServiceType = serviceType; - this.Summary = summary; - this.IsHidden = isHidden; - this.Description = description; - this.restPath = path; - - this.Verbs = string.IsNullOrWhiteSpace(verbs) ? ServiceExecExtensions.AllVerbs : verbs.ToUpperInvariant().Split(new[] { ' ', ',' }, StringSplitOptions.RemoveEmptyEntries); - - var componentsList = new List<string>(); - - // We only split on '.' if the restPath has them. Allows for /{action}.{type} - var hasSeparators = new List<bool>(); - foreach (var component in this.restPath.Split(PathSeperatorChar)) - { - if (string.IsNullOrEmpty(component)) - { - continue; - } - - if (component.IndexOf(VariablePrefix, StringComparison.OrdinalIgnoreCase) != -1 - && component.IndexOf(ComponentSeperator, StringComparison.Ordinal) != -1) - { - hasSeparators.Add(true); - componentsList.AddRange(component.Split(ComponentSeperator)); - } - else - { - hasSeparators.Add(false); - componentsList.Add(component); - } - } - - var components = componentsList.ToArray(); - this.TotalComponentsCount = components.Length; - - this.literalsToMatch = new string[this.TotalComponentsCount]; - this.variablesNames = new string[this.TotalComponentsCount]; - this.isWildcard = new bool[this.TotalComponentsCount]; - this.componentsWithSeparators = hasSeparators.ToArray(); - this.PathComponentsCount = this.componentsWithSeparators.Length; - string firstLiteralMatch = null; - - for (var i = 0; i < components.Length; i++) - { - var component = components[i]; - - if (component.StartsWith(VariablePrefix, StringComparison.Ordinal)) - { - var variableName = component.Substring(1, component.Length - 2); - if (variableName[variableName.Length - 1] == WildCardChar) - { - this.isWildcard[i] = true; - variableName = variableName.Substring(0, variableName.Length - 1); - } - - this.variablesNames[i] = variableName; - this.VariableArgsCount++; - } - else - { - this.literalsToMatch[i] = component.ToLowerInvariant(); - - if (firstLiteralMatch == null) - { - firstLiteralMatch = this.literalsToMatch[i]; - } - } - } - - for (var i = 0; i < components.Length - 1; i++) - { - if (!this.isWildcard[i]) - { - continue; - } - - if (this.literalsToMatch[i + 1] == null) - { - throw new ArgumentException( - "A wildcard path component must be at the end of the path or followed by a literal path component."); - } - } - - this.wildcardCount = this.isWildcard.Length; - this.IsWildCardPath = this.wildcardCount > 0; - - this.FirstMatchHashKey = !this.IsWildCardPath - ? this.PathComponentsCount + PathSeperator + firstLiteralMatch - : WildCardChar + PathSeperator + firstLiteralMatch; - - this.typeDeserializer = new StringMapTypeDeserializer(createInstanceFn, getParseFn, this.RequestType); - - _propertyNamesMap = new HashSet<string>( - GetSerializableProperties(RequestType).Select(x => x.Name), - StringComparer.OrdinalIgnoreCase); - } - - internal static IEnumerable<PropertyInfo> GetSerializableProperties(Type type) - { - foreach (var prop in GetPublicProperties(type)) - { - if (prop.GetMethod == null - || _excludeType == prop.PropertyType) - { - continue; - } - - var ignored = false; - foreach (var attr in prop.GetCustomAttributes(true)) - { - if (IgnoreAttributesNamed.Contains(attr.GetType().Name)) - { - ignored = true; - break; - } - } - - if (!ignored) - { - yield return prop; - } - } - } - - private static IEnumerable<PropertyInfo> GetPublicProperties(Type type) - { - if (type.IsInterface) - { - var propertyInfos = new List<PropertyInfo>(); - var considered = new List<Type>() - { - type - }; - var queue = new Queue<Type>(); - queue.Enqueue(type); - - while (queue.Count > 0) - { - var subType = queue.Dequeue(); - foreach (var subInterface in subType.GetTypeInfo().ImplementedInterfaces) - { - if (considered.Contains(subInterface)) - { - continue; - } - - considered.Add(subInterface); - queue.Enqueue(subInterface); - } - - var newPropertyInfos = GetTypesPublicProperties(subType) - .Where(x => !propertyInfos.Contains(x)); - - propertyInfos.InsertRange(0, newPropertyInfos); - } - - return propertyInfos; - } - - return GetTypesPublicProperties(type) - .Where(x => x.GetIndexParameters().Length == 0); - } - - private static IEnumerable<PropertyInfo> GetTypesPublicProperties(Type subType) - { - foreach (var pi in subType.GetRuntimeProperties()) - { - var mi = pi.GetMethod ?? pi.SetMethod; - if (mi != null && mi.IsStatic) - { - continue; - } - - yield return pi; - } - } - - /// <summary> - /// Provide for quick lookups based on hashes that can be determined from a request url. - /// </summary> - public string FirstMatchHashKey { get; private set; } - - private readonly StringMapTypeDeserializer typeDeserializer; - - private readonly HashSet<string> _propertyNamesMap; - - public int MatchScore(string httpMethod, string[] withPathInfoParts) - { - var isMatch = IsMatch(httpMethod, withPathInfoParts, out var wildcardMatchCount); - if (!isMatch) - { - return -1; - } - - // Routes with least wildcard matches get the highest score - var score = Math.Max(100 - wildcardMatchCount, 1) * 1000 - // Routes with less variable (and more literal) matches - + Math.Max(10 - VariableArgsCount, 1) * 100; - - // Exact verb match is better than ANY - if (Verbs.Length == 1 && string.Equals(httpMethod, Verbs[0], StringComparison.OrdinalIgnoreCase)) - { - score += 10; - } - else - { - score += 1; - } - - return score; - } - - /// <summary> - /// For performance withPathInfoParts should already be a lower case string - /// to minimize redundant matching operations. - /// </summary> - public bool IsMatch(string httpMethod, string[] withPathInfoParts, out int wildcardMatchCount) - { - wildcardMatchCount = 0; - - if (withPathInfoParts.Length != this.PathComponentsCount && !this.IsWildCardPath) - { - return false; - } - - if (!Verbs.Contains(httpMethod, StringComparer.OrdinalIgnoreCase)) - { - return false; - } - - if (!ExplodeComponents(ref withPathInfoParts)) - { - return false; - } - - if (this.TotalComponentsCount != withPathInfoParts.Length && !this.IsWildCardPath) - { - return false; - } - - int pathIx = 0; - for (var i = 0; i < this.TotalComponentsCount; i++) - { - if (this.isWildcard[i]) - { - if (i < this.TotalComponentsCount - 1) - { - // Continue to consume up until a match with the next literal - while (pathIx < withPathInfoParts.Length - && !string.Equals(withPathInfoParts[pathIx], this.literalsToMatch[i + 1], StringComparison.InvariantCultureIgnoreCase)) - { - pathIx++; - wildcardMatchCount++; - } - - // Ensure there are still enough parts left to match the remainder - if ((withPathInfoParts.Length - pathIx) < (this.TotalComponentsCount - i - 1)) - { - return false; - } - } - else - { - // A wildcard at the end matches the remainder of path - wildcardMatchCount += withPathInfoParts.Length - pathIx; - pathIx = withPathInfoParts.Length; - } - } - else - { - var literalToMatch = this.literalsToMatch[i]; - if (literalToMatch == null) - { - // Matching an ordinary (non-wildcard) variable consumes a single part - pathIx++; - continue; - } - - if (withPathInfoParts.Length <= pathIx - || !string.Equals(withPathInfoParts[pathIx], literalToMatch, StringComparison.InvariantCultureIgnoreCase)) - { - return false; - } - - pathIx++; - } - } - - return pathIx == withPathInfoParts.Length; - } - - private bool ExplodeComponents(ref string[] withPathInfoParts) - { - var totalComponents = new List<string>(); - for (var i = 0; i < withPathInfoParts.Length; i++) - { - var component = withPathInfoParts[i]; - if (string.IsNullOrEmpty(component)) - { - continue; - } - - if (this.PathComponentsCount != this.TotalComponentsCount - && this.componentsWithSeparators[i]) - { - var subComponents = component.Split(ComponentSeperator); - if (subComponents.Length < 2) - { - return false; - } - - totalComponents.AddRange(subComponents); - } - else - { - totalComponents.Add(component); - } - } - - withPathInfoParts = totalComponents.ToArray(); - return true; - } - - public object CreateRequest(string pathInfo, Dictionary<string, string> queryStringAndFormData, object fromInstance) - { - var requestComponents = pathInfo.Split(new[] { PathSeperatorChar }, StringSplitOptions.RemoveEmptyEntries); - - ExplodeComponents(ref requestComponents); - - if (requestComponents.Length != this.TotalComponentsCount) - { - var isValidWildCardPath = this.IsWildCardPath - && requestComponents.Length >= this.TotalComponentsCount - this.wildcardCount; - - if (!isValidWildCardPath) - { - throw new ArgumentException( - string.Format( - CultureInfo.InvariantCulture, - "Path Mismatch: Request Path '{0}' has invalid number of components compared to: '{1}'", - pathInfo, - this.restPath)); - } - } - - var requestKeyValuesMap = new Dictionary<string, string>(); - var pathIx = 0; - for (var i = 0; i < this.TotalComponentsCount; i++) - { - var variableName = this.variablesNames[i]; - if (variableName == null) - { - pathIx++; - continue; - } - - if (!this._propertyNamesMap.Contains(variableName)) - { - if (string.Equals("ignore", variableName, StringComparison.OrdinalIgnoreCase)) - { - pathIx++; - continue; - } - - throw new ArgumentException("Could not find property " - + variableName + " on " + RequestType.GetMethodName()); - } - - var value = requestComponents.Length > pathIx ? requestComponents[pathIx] : null; // wildcard has arg mismatch - if (value != null && this.isWildcard[i]) - { - if (i == this.TotalComponentsCount - 1) - { - // Wildcard at end of path definition consumes all the rest - var sb = new StringBuilder(); - sb.Append(value); - for (var j = pathIx + 1; j < requestComponents.Length; j++) - { - sb.Append(PathSeperatorChar) - .Append(requestComponents[j]); - } - - value = sb.ToString(); - } - else - { - // Wildcard in middle of path definition consumes up until it - // hits a match for the next element in the definition (which must be a literal) - // It may consume 0 or more path parts - var stopLiteral = i == this.TotalComponentsCount - 1 ? null : this.literalsToMatch[i + 1]; - if (!string.Equals(requestComponents[pathIx], stopLiteral, StringComparison.OrdinalIgnoreCase)) - { - var sb = new StringBuilder(value); - pathIx++; - while (!string.Equals(requestComponents[pathIx], stopLiteral, StringComparison.OrdinalIgnoreCase)) - { - sb.Append(PathSeperatorChar) - .Append(requestComponents[pathIx++]); - } - - value = sb.ToString(); - } - else - { - value = null; - } - } - } - else - { - // Variable consumes single path item - pathIx++; - } - - requestKeyValuesMap[variableName] = value; - } - - if (queryStringAndFormData != null) - { - // Query String and form data can override variable path matches - // path variables < query string < form data - foreach (var name in queryStringAndFormData) - { - requestKeyValuesMap[name.Key] = name.Value; - } - } - - return this.typeDeserializer.PopulateFromMap(fromInstance, requestKeyValuesMap); - } - - public class RestPathMap : SortedDictionary<string, List<RestPath>> - { - public RestPathMap() : base(StringComparer.OrdinalIgnoreCase) - { - } - } - } -} diff --git a/Emby.Server.Implementations/Services/StringMapTypeDeserializer.cs b/Emby.Server.Implementations/Services/StringMapTypeDeserializer.cs deleted file mode 100644 index 165bb0fc4..000000000 --- a/Emby.Server.Implementations/Services/StringMapTypeDeserializer.cs +++ /dev/null @@ -1,118 +0,0 @@ -#pragma warning disable CS1591 - -using System; -using System.Collections.Generic; -using System.Reflection; -using MediaBrowser.Common.Extensions; - -namespace Emby.Server.Implementations.Services -{ - /// <summary> - /// Serializer cache of delegates required to create a type from a string map (e.g. for REST urls) - /// </summary> - public class StringMapTypeDeserializer - { - internal class PropertySerializerEntry - { - public PropertySerializerEntry(Action<object, object> propertySetFn, Func<string, object> propertyParseStringFn, Type propertyType) - { - PropertySetFn = propertySetFn; - PropertyParseStringFn = propertyParseStringFn; - PropertyType = propertyType; - } - - public Action<object, object> PropertySetFn { get; private set; } - - public Func<string, object> PropertyParseStringFn { get; private set; } - - public Type PropertyType { get; private set; } - } - - private readonly Type type; - private readonly Dictionary<string, PropertySerializerEntry> propertySetterMap - = new Dictionary<string, PropertySerializerEntry>(StringComparer.OrdinalIgnoreCase); - - public Func<string, object> GetParseFn(Type propertyType) - { - if (propertyType == typeof(string)) - { - return s => s; - } - - return _GetParseFn(propertyType); - } - - private readonly Func<Type, object> _CreateInstanceFn; - private readonly Func<Type, Func<string, object>> _GetParseFn; - - public StringMapTypeDeserializer(Func<Type, object> createInstanceFn, Func<Type, Func<string, object>> getParseFn, Type type) - { - _CreateInstanceFn = createInstanceFn; - _GetParseFn = getParseFn; - this.type = type; - - foreach (var propertyInfo in RestPath.GetSerializableProperties(type)) - { - var propertySetFn = TypeAccessor.GetSetPropertyMethod(propertyInfo); - var propertyType = propertyInfo.PropertyType; - var propertyParseStringFn = GetParseFn(propertyType); - var propertySerializer = new PropertySerializerEntry(propertySetFn, propertyParseStringFn, propertyType); - - propertySetterMap[propertyInfo.Name] = propertySerializer; - } - } - - public object PopulateFromMap(object instance, IDictionary<string, string> keyValuePairs) - { - PropertySerializerEntry propertySerializerEntry = null; - - if (instance == null) - { - instance = _CreateInstanceFn(type); - } - - foreach (var pair in keyValuePairs) - { - string propertyName = pair.Key; - string propertyTextValue = pair.Value; - - if (propertyTextValue == null - || !propertySetterMap.TryGetValue(propertyName, out propertySerializerEntry) - || propertySerializerEntry.PropertySetFn == null) - { - continue; - } - - if (propertySerializerEntry.PropertyType == typeof(bool)) - { - // InputExtensions.cs#530 MVC Checkbox helper emits extra hidden input field, generating 2 values, first is the real value - propertyTextValue = StringExtensions.LeftPart(propertyTextValue, ',').ToString(); - } - - var value = propertySerializerEntry.PropertyParseStringFn(propertyTextValue); - if (value == null) - { - continue; - } - - propertySerializerEntry.PropertySetFn(instance, value); - } - - return instance; - } - } - - internal static class TypeAccessor - { - public static Action<object, object> GetSetPropertyMethod(PropertyInfo propertyInfo) - { - if (!propertyInfo.CanWrite || propertyInfo.GetIndexParameters().Length > 0) - { - return null; - } - - var setMethodInfo = propertyInfo.SetMethod; - return (instance, value) => setMethodInfo.Invoke(instance, new[] { value }); - } - } -} diff --git a/Emby.Server.Implementations/Services/UrlExtensions.cs b/Emby.Server.Implementations/Services/UrlExtensions.cs deleted file mode 100644 index 92e36b60e..000000000 --- a/Emby.Server.Implementations/Services/UrlExtensions.cs +++ /dev/null @@ -1,27 +0,0 @@ -#pragma warning disable CS1591 - -using System; -using MediaBrowser.Common.Extensions; - -namespace Emby.Server.Implementations.Services -{ - /// <summary> - /// Donated by Ivan Korneliuk from his post: - /// http://korneliuk.blogspot.com/2012/08/servicestack-reusing-dtos.html - /// - /// Modified to only allow using routes matching the supplied HTTP Verb. - /// </summary> - public static class UrlExtensions - { - public static string GetMethodName(this Type type) - { - var typeName = type.FullName != null // can be null, e.g. generic types - ? StringExtensions.LeftPart(type.FullName, "[[", StringComparison.Ordinal).ToString() // Generic Fullname - .Replace(type.Namespace + ".", string.Empty, StringComparison.Ordinal) // Trim Namespaces - .Replace("+", ".", StringComparison.Ordinal) // Convert nested into normal type - : type.Name; - - return type.IsGenericParameter ? "'" + typeName : typeName; - } - } -} diff --git a/Emby.Server.Implementations/SocketSharp/WebSocketSharpRequest.cs b/Emby.Server.Implementations/SocketSharp/WebSocketSharpRequest.cs deleted file mode 100644 index ae1a8d0b7..000000000 --- a/Emby.Server.Implementations/SocketSharp/WebSocketSharpRequest.cs +++ /dev/null @@ -1,248 +0,0 @@ -#pragma warning disable CS1591 - -using System; -using System.Collections.Generic; -using System.IO; -using System.Net; -using System.Net.Mime; -using MediaBrowser.Common.Extensions; -using MediaBrowser.Common.Net; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.Extensions; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Primitives; -using Microsoft.Net.Http.Headers; -using IHttpRequest = MediaBrowser.Model.Services.IHttpRequest; - -namespace Emby.Server.Implementations.SocketSharp -{ - public class WebSocketSharpRequest : IHttpRequest - { - private const string FormUrlEncoded = "application/x-www-form-urlencoded"; - private const string MultiPartFormData = "multipart/form-data"; - private const string Soap11 = "text/xml; charset=utf-8"; - - private string _remoteIp; - private Dictionary<string, object> _items; - private string _responseContentType; - - public WebSocketSharpRequest(HttpRequest httpRequest, HttpResponse httpResponse, string operationName) - { - this.OperationName = operationName; - this.Request = httpRequest; - this.Response = httpResponse; - } - - public string Accept => StringValues.IsNullOrEmpty(Request.Headers[HeaderNames.Accept]) ? null : Request.Headers[HeaderNames.Accept].ToString(); - - public string Authorization => StringValues.IsNullOrEmpty(Request.Headers[HeaderNames.Authorization]) ? null : Request.Headers[HeaderNames.Authorization].ToString(); - - public HttpRequest Request { get; } - - public HttpResponse Response { get; } - - public string OperationName { get; set; } - - public string RawUrl => Request.GetEncodedPathAndQuery(); - - public string AbsoluteUri => Request.GetDisplayUrl().TrimEnd('/'); - - public string RemoteIp - { - get - { - if (_remoteIp != null) - { - return _remoteIp; - } - - IPAddress ip; - - // "Real" remote ip might be in X-Forwarded-For of X-Real-Ip - // (if the server is behind a reverse proxy for example) - if (!IPAddress.TryParse(GetHeader(CustomHeaderNames.XForwardedFor), out ip)) - { - if (!IPAddress.TryParse(GetHeader(CustomHeaderNames.XRealIP), out ip)) - { - ip = Request.HttpContext.Connection.RemoteIpAddress; - - // Default to the loopback address if no RemoteIpAddress is specified (i.e. during integration tests) - ip ??= IPAddress.Loopback; - } - } - - return _remoteIp = NormalizeIp(ip).ToString(); - } - } - - public string[] AcceptTypes => Request.Headers.GetCommaSeparatedValues(HeaderNames.Accept); - - public Dictionary<string, object> Items => _items ?? (_items = new Dictionary<string, object>()); - - public string ResponseContentType - { - get => - _responseContentType - ?? (_responseContentType = GetResponseContentType(Request)); - set => _responseContentType = value; - } - - public string PathInfo => Request.Path.Value; - - public string UserAgent => Request.Headers[HeaderNames.UserAgent]; - - public IHeaderDictionary Headers => Request.Headers; - - public IQueryCollection QueryString => Request.Query; - - public bool IsLocal => - (Request.HttpContext.Connection.LocalIpAddress == null - && Request.HttpContext.Connection.RemoteIpAddress == null) - || Request.HttpContext.Connection.LocalIpAddress.Equals(Request.HttpContext.Connection.RemoteIpAddress); - - public string HttpMethod => Request.Method; - - public string Verb => HttpMethod; - - public string ContentType => Request.ContentType; - - public Uri UrlReferrer => Request.GetTypedHeaders().Referer; - - public Stream InputStream => Request.Body; - - public long ContentLength => Request.ContentLength ?? 0; - - private string GetHeader(string name) => Request.Headers[name].ToString(); - - private static IPAddress NormalizeIp(IPAddress ip) - { - if (ip.IsIPv4MappedToIPv6) - { - return ip.MapToIPv4(); - } - - return ip; - } - - public static string GetResponseContentType(HttpRequest httpReq) - { - var specifiedContentType = GetQueryStringContentType(httpReq); - if (!string.IsNullOrEmpty(specifiedContentType)) - { - return specifiedContentType; - } - - const string ServerDefaultContentType = MediaTypeNames.Application.Json; - - var acceptContentTypes = httpReq.Headers.GetCommaSeparatedValues(HeaderNames.Accept); - string defaultContentType = null; - if (HasAnyOfContentTypes(httpReq, FormUrlEncoded, MultiPartFormData)) - { - defaultContentType = ServerDefaultContentType; - } - - var acceptsAnything = false; - var hasDefaultContentType = defaultContentType != null; - if (acceptContentTypes != null) - { - foreach (ReadOnlySpan<char> acceptsType in acceptContentTypes) - { - ReadOnlySpan<char> contentType = acceptsType; - var index = contentType.IndexOf(';'); - if (index != -1) - { - contentType = contentType.Slice(0, index); - } - - contentType = contentType.Trim(); - acceptsAnything = contentType.Equals("*/*", StringComparison.OrdinalIgnoreCase); - - if (acceptsAnything) - { - break; - } - } - - if (acceptsAnything) - { - if (hasDefaultContentType) - { - return defaultContentType; - } - else - { - return ServerDefaultContentType; - } - } - } - - if (acceptContentTypes == null && httpReq.ContentType == Soap11) - { - return Soap11; - } - - // We could also send a '406 Not Acceptable', but this is allowed also - return ServerDefaultContentType; - } - - public static bool HasAnyOfContentTypes(HttpRequest request, params string[] contentTypes) - { - if (contentTypes == null || request.ContentType == null) - { - return false; - } - - foreach (var contentType in contentTypes) - { - if (IsContentType(request, contentType)) - { - return true; - } - } - - return false; - } - - public static bool IsContentType(HttpRequest request, string contentType) - { - return request.ContentType.StartsWith(contentType, StringComparison.OrdinalIgnoreCase); - } - - private static string GetQueryStringContentType(HttpRequest httpReq) - { - ReadOnlySpan<char> format = httpReq.Query["format"].ToString(); - if (format == ReadOnlySpan<char>.Empty) - { - const int FormatMaxLength = 4; - ReadOnlySpan<char> pi = httpReq.Path.ToString(); - if (pi == null || pi.Length <= FormatMaxLength) - { - return null; - } - - if (pi[0] == '/') - { - pi = pi.Slice(1); - } - - format = pi.LeftPart('/'); - if (format.Length > FormatMaxLength) - { - return null; - } - } - - format = format.LeftPart('.'); - if (format.Contains("json", StringComparison.OrdinalIgnoreCase)) - { - return "application/json"; - } - else if (format.Contains("xml", StringComparison.OrdinalIgnoreCase)) - { - return "application/xml"; - } - - return null; - } - } -} diff --git a/MediaBrowser.Common/Extensions/HttpContextExtensions.cs b/MediaBrowser.Common/Extensions/HttpContextExtensions.cs index d746207c7..76db68885 100644 --- a/MediaBrowser.Common/Extensions/HttpContextExtensions.cs +++ b/MediaBrowser.Common/Extensions/HttpContextExtensions.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Model.Services; +using System.Net; +using MediaBrowser.Common.Net; using Microsoft.AspNetCore.Http; namespace MediaBrowser.Common.Extensions @@ -8,26 +9,54 @@ namespace MediaBrowser.Common.Extensions /// </summary> public static class HttpContextExtensions { - private const string ServiceStackRequest = "ServiceStackRequest"; - /// <summary> - /// Set the ServiceStack request. + /// Checks the origin of the HTTP request. /// </summary> - /// <param name="httpContext">The HttpContext instance.</param> - /// <param name="request">The service stack request instance.</param> - public static void SetServiceStackRequest(this HttpContext httpContext, IRequest request) + /// <param name="request">The incoming HTTP request.</param> + /// <returns><c>true</c> if the request is coming from LAN, <c>false</c> otherwise.</returns> + public static bool IsLocal(this HttpRequest request) { - httpContext.Items[ServiceStackRequest] = request; + return (request.HttpContext.Connection.LocalIpAddress == null + && request.HttpContext.Connection.RemoteIpAddress == null) + || request.HttpContext.Connection.LocalIpAddress.Equals(request.HttpContext.Connection.RemoteIpAddress); } /// <summary> - /// Get the ServiceStack request. + /// Extracts the remote IP address of the caller of the HTTP request. /// </summary> - /// <param name="httpContext">The HttpContext instance.</param> - /// <returns>The service stack request instance.</returns> - public static IRequest GetServiceStackRequest(this HttpContext httpContext) + /// <param name="request">The HTTP request.</param> + /// <returns>The remote caller IP address.</returns> + public static string RemoteIp(this HttpRequest request) { - return (IRequest)httpContext.Items[ServiceStackRequest]; + if (string.IsNullOrEmpty(request.HttpContext.Items["RemoteIp"].ToString())) + { + return request.HttpContext.Items["RemoteIp"].ToString(); + } + + IPAddress ip; + + // "Real" remote ip might be in X-Forwarded-For of X-Real-Ip + // (if the server is behind a reverse proxy for example) + if (!IPAddress.TryParse(request.Headers[CustomHeaderNames.XForwardedFor].ToString(), out ip)) + { + if (!IPAddress.TryParse(request.Headers[CustomHeaderNames.XRealIP].ToString(), out ip)) + { + ip = request.HttpContext.Connection.RemoteIpAddress; + + // Default to the loopback address if no RemoteIpAddress is specified (i.e. during integration tests) + ip ??= IPAddress.Loopback; + } + } + + if (ip.IsIPv4MappedToIPv6) + { + ip = ip.MapToIPv4(); + } + + var normalizedIp = ip.ToString(); + + request.HttpContext.Items["RemoteIp"] = normalizedIp; + return normalizedIp; } } } diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs b/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs index 4cbb63e46..1f3abe8f4 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; using System.Linq; using MediaBrowser.Model.Dlna; -using MediaBrowser.Model.Services; namespace MediaBrowser.Controller.MediaEncoding { @@ -63,26 +62,20 @@ namespace MediaBrowser.Controller.MediaEncoding /// Gets or sets the id. /// </summary> /// <value>The id.</value> - [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] public Guid Id { get; set; } - [ApiMember(Name = "MediaSourceId", Description = "The media version id, if playing an alternate version", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] public string MediaSourceId { get; set; } - [ApiMember(Name = "DeviceId", Description = "The device id of the client requesting. Used to stop encoding processes when needed.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] public string DeviceId { get; set; } - [ApiMember(Name = "Container", Description = "Container", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")] public string Container { get; set; } /// <summary> /// Gets or sets the audio codec. /// </summary> /// <value>The audio codec.</value> - [ApiMember(Name = "AudioCodec", Description = "Optional. Specify a audio codec to encode to, e.g. mp3. If omitted the server will auto-select using the url's extension. Options: aac, mp3, vorbis, wma.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] public string AudioCodec { get; set; } - [ApiMember(Name = "EnableAutoStreamCopy", Description = "Whether or not to allow automatic stream copy if requested values match the original source. Defaults to true.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")] public bool EnableAutoStreamCopy { get; set; } public bool AllowVideoStreamCopy { get; set; } @@ -95,7 +88,6 @@ namespace MediaBrowser.Controller.MediaEncoding /// Gets or sets the audio sample rate. /// </summary> /// <value>The audio sample rate.</value> - [ApiMember(Name = "AudioSampleRate", Description = "Optional. Specify a specific audio sample rate, e.g. 44100", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")] public int? AudioSampleRate { get; set; } public int? MaxAudioBitDepth { get; set; } @@ -104,105 +96,86 @@ namespace MediaBrowser.Controller.MediaEncoding /// Gets or sets the audio bit rate. /// </summary> /// <value>The audio bit rate.</value> - [ApiMember(Name = "AudioBitRate", Description = "Optional. Specify an audio bitrate to encode to, e.g. 128000. If omitted this will be left to encoder defaults.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")] public int? AudioBitRate { get; set; } /// <summary> /// Gets or sets the audio channels. /// </summary> /// <value>The audio channels.</value> - [ApiMember(Name = "AudioChannels", Description = "Optional. Specify a specific number of audio channels to encode to, e.g. 2", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")] public int? AudioChannels { get; set; } - [ApiMember(Name = "MaxAudioChannels", Description = "Optional. Specify a maximum number of audio channels to encode to, e.g. 2", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")] public int? MaxAudioChannels { get; set; } - [ApiMember(Name = "Static", Description = "Optional. If true, the original file will be streamed statically without any encoding. Use either no url extension or the original file extension. true/false", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")] public bool Static { get; set; } /// <summary> /// Gets or sets the profile. /// </summary> /// <value>The profile.</value> - [ApiMember(Name = "Profile", Description = "Optional. Specify a specific an encoder profile (varies by encoder), e.g. main, baseline, high.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] public string Profile { get; set; } /// <summary> /// Gets or sets the level. /// </summary> /// <value>The level.</value> - [ApiMember(Name = "Level", Description = "Optional. Specify a level for the encoder profile (varies by encoder), e.g. 3, 3.1.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] public string Level { get; set; } /// <summary> /// Gets or sets the framerate. /// </summary> /// <value>The framerate.</value> - [ApiMember(Name = "Framerate", Description = "Optional. A specific video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements.", IsRequired = false, DataType = "double", ParameterType = "query", Verb = "GET")] public float? Framerate { get; set; } - [ApiMember(Name = "MaxFramerate", Description = "Optional. A specific maximum video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements.", IsRequired = false, DataType = "double", ParameterType = "query", Verb = "GET")] public float? MaxFramerate { get; set; } - [ApiMember(Name = "CopyTimestamps", Description = "Whether or not to copy timestamps when transcoding with an offset. Defaults to false.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")] public bool CopyTimestamps { get; set; } /// <summary> /// Gets or sets the start time ticks. /// </summary> /// <value>The start time ticks.</value> - [ApiMember(Name = "StartTimeTicks", Description = "Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")] public long? StartTimeTicks { get; set; } /// <summary> /// Gets or sets the width. /// </summary> /// <value>The width.</value> - [ApiMember(Name = "Width", Description = "Optional. The fixed horizontal resolution of the encoded video.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")] public int? Width { get; set; } /// <summary> /// Gets or sets the height. /// </summary> /// <value>The height.</value> - [ApiMember(Name = "Height", Description = "Optional. The fixed vertical resolution of the encoded video.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")] public int? Height { get; set; } /// <summary> /// Gets or sets the width of the max. /// </summary> /// <value>The width of the max.</value> - [ApiMember(Name = "MaxWidth", Description = "Optional. The maximum horizontal resolution of the encoded video.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")] public int? MaxWidth { get; set; } /// <summary> /// Gets or sets the height of the max. /// </summary> /// <value>The height of the max.</value> - [ApiMember(Name = "MaxHeight", Description = "Optional. The maximum vertical resolution of the encoded video.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")] public int? MaxHeight { get; set; } /// <summary> /// Gets or sets the video bit rate. /// </summary> /// <value>The video bit rate.</value> - [ApiMember(Name = "VideoBitRate", Description = "Optional. Specify a video bitrate to encode to, e.g. 500000. If omitted this will be left to encoder defaults.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")] public int? VideoBitRate { get; set; } /// <summary> /// Gets or sets the index of the subtitle stream. /// </summary> /// <value>The index of the subtitle stream.</value> - [ApiMember(Name = "SubtitleStreamIndex", Description = "Optional. The index of the subtitle stream to use. If omitted no subtitles will be used.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")] public int? SubtitleStreamIndex { get; set; } - [ApiMember(Name = "SubtitleMethod", Description = "Optional. Specify the subtitle delivery method.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] public SubtitleDeliveryMethod SubtitleMethod { get; set; } - [ApiMember(Name = "MaxRefFrames", Description = "Optional.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")] public int? MaxRefFrames { get; set; } - [ApiMember(Name = "MaxVideoBitDepth", Description = "Optional.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")] public int? MaxVideoBitDepth { get; set; } public bool RequireAvc { get; set; } @@ -223,7 +196,6 @@ namespace MediaBrowser.Controller.MediaEncoding /// Gets or sets the video codec. /// </summary> /// <value>The video codec.</value> - [ApiMember(Name = "VideoCodec", Description = "Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vpx, wmv.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] public string VideoCodec { get; set; } public string SubtitleCodec { get; set; } @@ -234,14 +206,12 @@ namespace MediaBrowser.Controller.MediaEncoding /// Gets or sets the index of the audio stream. /// </summary> /// <value>The index of the audio stream.</value> - [ApiMember(Name = "AudioStreamIndex", Description = "Optional. The index of the audio stream to use. If omitted the first audio stream will be used.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")] public int? AudioStreamIndex { get; set; } /// <summary> /// Gets or sets the index of the video stream. /// </summary> /// <value>The index of the video stream.</value> - [ApiMember(Name = "VideoStreamIndex", Description = "Optional. The index of the video stream to use. If omitted the first video stream will be used.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")] public int? VideoStreamIndex { get; set; } public EncodingContext Context { get; set; } diff --git a/MediaBrowser.Controller/Net/AuthenticatedAttribute.cs b/MediaBrowser.Controller/Net/AuthenticatedAttribute.cs deleted file mode 100644 index 1366fd42e..000000000 --- a/MediaBrowser.Controller/Net/AuthenticatedAttribute.cs +++ /dev/null @@ -1,76 +0,0 @@ -#pragma warning disable CS1591 - -using System; -using MediaBrowser.Model.Services; -using Microsoft.AspNetCore.Http; - -namespace MediaBrowser.Controller.Net -{ - public class AuthenticatedAttribute : Attribute, IHasRequestFilter, IAuthenticationAttributes - { - public static IAuthService AuthService { get; set; } - - /// <summary> - /// Gets or sets the roles. - /// </summary> - /// <value>The roles.</value> - public string Roles { get; set; } - - /// <summary> - /// Gets or sets a value indicating whether [escape parental control]. - /// </summary> - /// <value><c>true</c> if [escape parental control]; otherwise, <c>false</c>.</value> - public bool EscapeParentalControl { get; set; } - - /// <summary> - /// Gets or sets a value indicating whether [allow before startup wizard]. - /// </summary> - /// <value><c>true</c> if [allow before startup wizard]; otherwise, <c>false</c>.</value> - public bool AllowBeforeStartupWizard { get; set; } - - public bool AllowLocal { get; set; } - - /// <summary> - /// The request filter is executed before the service. - /// </summary> - /// <param name="request">The http request wrapper.</param> - /// <param name="response">The http response wrapper.</param> - /// <param name="requestDto">The request DTO.</param> - public void RequestFilter(IRequest request, HttpResponse response, object requestDto) - { - AuthService.Authenticate(request, this); - } - - /// <summary> - /// Order in which Request Filters are executed. - /// <0 Executed before global request filters - /// >0 Executed after global request filters - /// </summary> - /// <value>The priority.</value> - public int Priority => 0; - - public string[] GetRoles() - { - return (Roles ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); - } - - public bool IgnoreLegacyAuth { get; set; } - - public bool AllowLocalOnly { get; set; } - } - - public interface IAuthenticationAttributes - { - bool EscapeParentalControl { get; } - - bool AllowBeforeStartupWizard { get; } - - bool AllowLocal { get; } - - bool AllowLocalOnly { get; } - - string[] GetRoles(); - - bool IgnoreLegacyAuth { get; } - } -} diff --git a/MediaBrowser.Controller/Net/IAuthService.cs b/MediaBrowser.Controller/Net/IAuthService.cs index 2055a656a..04b2e13e8 100644 --- a/MediaBrowser.Controller/Net/IAuthService.cs +++ b/MediaBrowser.Controller/Net/IAuthService.cs @@ -1,7 +1,5 @@ #nullable enable -using Jellyfin.Data.Entities; -using MediaBrowser.Model.Services; using Microsoft.AspNetCore.Http; namespace MediaBrowser.Controller.Net @@ -11,21 +9,6 @@ namespace MediaBrowser.Controller.Net /// </summary> public interface IAuthService { - /// <summary> - /// Authenticate and authorize request. - /// </summary> - /// <param name="request">Request.</param> - /// <param name="authAttribtutes">Authorization attributes.</param> - void Authenticate(IRequest request, IAuthenticationAttributes authAttribtutes); - - /// <summary> - /// Authenticate and authorize request. - /// </summary> - /// <param name="request">Request.</param> - /// <param name="authAttribtutes">Authorization attributes.</param> - /// <returns>Authenticated user.</returns> - User? Authenticate(HttpRequest request, IAuthenticationAttributes authAttribtutes); - /// <summary> /// Authenticate request. /// </summary> diff --git a/MediaBrowser.Controller/Net/IAuthorizationContext.cs b/MediaBrowser.Controller/Net/IAuthorizationContext.cs index 37a7425b9..4d2f5f5e3 100644 --- a/MediaBrowser.Controller/Net/IAuthorizationContext.cs +++ b/MediaBrowser.Controller/Net/IAuthorizationContext.cs @@ -1,4 +1,3 @@ -using MediaBrowser.Model.Services; using Microsoft.AspNetCore.Http; namespace MediaBrowser.Controller.Net @@ -20,7 +19,7 @@ namespace MediaBrowser.Controller.Net /// </summary> /// <param name="requestContext">The request context.</param> /// <returns>AuthorizationInfo.</returns> - AuthorizationInfo GetAuthorizationInfo(IRequest requestContext); + AuthorizationInfo GetAuthorizationInfo(HttpContext requestContext); /// <summary> /// Gets the authorization information. diff --git a/MediaBrowser.Controller/Net/IHasResultFactory.cs b/MediaBrowser.Controller/Net/IHasResultFactory.cs deleted file mode 100644 index b8cf8cd78..000000000 --- a/MediaBrowser.Controller/Net/IHasResultFactory.cs +++ /dev/null @@ -1,17 +0,0 @@ -using MediaBrowser.Model.Services; - -namespace MediaBrowser.Controller.Net -{ - /// <summary> - /// Interface IHasResultFactory - /// Services that require a ResultFactory should implement this - /// </summary> - public interface IHasResultFactory : IRequiresRequest - { - /// <summary> - /// Gets or sets the result factory. - /// </summary> - /// <value>The result factory.</value> - IHttpResultFactory ResultFactory { get; set; } - } -} diff --git a/MediaBrowser.Controller/Net/IHttpResultFactory.cs b/MediaBrowser.Controller/Net/IHttpResultFactory.cs deleted file mode 100644 index 8293a8714..000000000 --- a/MediaBrowser.Controller/Net/IHttpResultFactory.cs +++ /dev/null @@ -1,82 +0,0 @@ -#pragma warning disable CS1591 - -using System; -using System.Collections.Generic; -using System.IO; -using System.Threading.Tasks; -using MediaBrowser.Model.Services; - -namespace MediaBrowser.Controller.Net -{ - /// <summary> - /// Interface IHttpResultFactory. - /// </summary> - public interface IHttpResultFactory - { - /// <summary> - /// Gets the result. - /// </summary> - /// <param name="content">The content.</param> - /// <param name="contentType">Type of the content.</param> - /// <param name="responseHeaders">The response headers.</param> - /// <returns>System.Object.</returns> - object GetResult(string content, string contentType, IDictionary<string, string> responseHeaders = null); - - object GetResult(IRequest requestContext, byte[] content, string contentType, IDictionary<string, string> responseHeaders = null); - - object GetResult(IRequest requestContext, Stream content, string contentType, IDictionary<string, string> responseHeaders = null); - - object GetResult(IRequest requestContext, string content, string contentType, IDictionary<string, string> responseHeaders = null); - - object GetRedirectResult(string url); - - object GetResult<T>(IRequest requestContext, T result, IDictionary<string, string> responseHeaders = null) - where T : class; - - /// <summary> - /// Gets the static result. - /// </summary> - /// <param name="requestContext">The request context.</param> - /// <param name="cacheKey">The cache key.</param> - /// <param name="lastDateModified">The last date modified.</param> - /// <param name="cacheDuration">Duration of the cache.</param> - /// <param name="contentType">Type of the content.</param> - /// <param name="factoryFn">The factory fn.</param> - /// <param name="responseHeaders">The response headers.</param> - /// <param name="isHeadRequest">if set to <c>true</c> [is head request].</param> - /// <returns>System.Object.</returns> - Task<object> GetStaticResult(IRequest requestContext, - Guid cacheKey, - DateTime? lastDateModified, - TimeSpan? cacheDuration, - string contentType, Func<Task<Stream>> factoryFn, - IDictionary<string, string> responseHeaders = null, - bool isHeadRequest = false); - - /// <summary> - /// Gets the static result. - /// </summary> - /// <param name="requestContext">The request context.</param> - /// <param name="options">The options.</param> - /// <returns>System.Object.</returns> - Task<object> GetStaticResult(IRequest requestContext, StaticResultOptions options); - - /// <summary> - /// Gets the static file result. - /// </summary> - /// <param name="requestContext">The request context.</param> - /// <param name="path">The path.</param> - /// <param name="fileShare">The file share.</param> - /// <returns>System.Object.</returns> - Task<object> GetStaticFileResult(IRequest requestContext, string path, FileShare fileShare = FileShare.Read); - - /// <summary> - /// Gets the static file result. - /// </summary> - /// <param name="requestContext">The request context.</param> - /// <param name="options">The options.</param> - /// <returns>System.Object.</returns> - Task<object> GetStaticFileResult(IRequest requestContext, - StaticFileResultOptions options); - } -} diff --git a/MediaBrowser.Controller/Net/IHttpServer.cs b/MediaBrowser.Controller/Net/IHttpServer.cs index b04ebda8c..845f27045 100644 --- a/MediaBrowser.Controller/Net/IHttpServer.cs +++ b/MediaBrowser.Controller/Net/IHttpServer.cs @@ -2,7 +2,6 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; using Jellyfin.Data.Events; -using MediaBrowser.Model.Services; using Microsoft.AspNetCore.Http; namespace MediaBrowser.Controller.Net @@ -26,7 +25,7 @@ namespace MediaBrowser.Controller.Net /// <summary> /// Inits this instance. /// </summary> - void Init(IEnumerable<Type> serviceTypes, IEnumerable<IWebSocketListener> listener, IEnumerable<string> urlPrefixes); + void Init(IEnumerable<IWebSocketListener> listener, IEnumerable<string> urlPrefixes); /// <summary> /// If set, all requests will respond with this message. @@ -43,8 +42,8 @@ namespace MediaBrowser.Controller.Net /// <summary> /// Get the default CORS headers. /// </summary> - /// <param name="req"></param> - /// <returns></returns> - IDictionary<string, string> GetDefaultCorsHeaders(IRequest req); + /// <param name="req">The HTTP context of the current request.</param> + /// <returns>The default CORS headers for the context.</returns> + IDictionary<string, string> GetDefaultCorsHeaders(HttpContext httpContext); } } diff --git a/MediaBrowser.Controller/Net/ISessionContext.cs b/MediaBrowser.Controller/Net/ISessionContext.cs index 5da748f41..a60dc2ea1 100644 --- a/MediaBrowser.Controller/Net/ISessionContext.cs +++ b/MediaBrowser.Controller/Net/ISessionContext.cs @@ -2,7 +2,7 @@ using Jellyfin.Data.Entities; using MediaBrowser.Controller.Session; -using MediaBrowser.Model.Services; +using Microsoft.AspNetCore.Http; namespace MediaBrowser.Controller.Net { @@ -12,8 +12,8 @@ namespace MediaBrowser.Controller.Net User GetUser(object requestContext); - SessionInfo GetSession(IRequest requestContext); + SessionInfo GetSession(HttpContext requestContext); - User GetUser(IRequest requestContext); + User GetUser(HttpContext requestContext); } } diff --git a/MediaBrowser.Controller/Net/StaticResultOptions.cs b/MediaBrowser.Controller/Net/StaticResultOptions.cs deleted file mode 100644 index c1e9bc845..000000000 --- a/MediaBrowser.Controller/Net/StaticResultOptions.cs +++ /dev/null @@ -1,44 +0,0 @@ -#pragma warning disable CS1591 - -using System; -using System.Collections.Generic; -using System.IO; -using System.Threading.Tasks; - -namespace MediaBrowser.Controller.Net -{ - public class StaticResultOptions - { - public string ContentType { get; set; } - - public TimeSpan? CacheDuration { get; set; } - - public DateTime? DateLastModified { get; set; } - - public Func<Task<Stream>> ContentFactory { get; set; } - - public bool IsHeadRequest { get; set; } - - public IDictionary<string, string> ResponseHeaders { get; set; } - - public Action OnComplete { get; set; } - - public Action OnError { get; set; } - - public string Path { get; set; } - - public long? ContentLength { get; set; } - - public FileShare FileShare { get; set; } - - public StaticResultOptions() - { - ResponseHeaders = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); - FileShare = FileShare.Read; - } - } - - public class StaticFileResultOptions : StaticResultOptions - { - } -} diff --git a/MediaBrowser.Model/Services/ApiMemberAttribute.cs b/MediaBrowser.Model/Services/ApiMemberAttribute.cs deleted file mode 100644 index 63f3ecd55..000000000 --- a/MediaBrowser.Model/Services/ApiMemberAttribute.cs +++ /dev/null @@ -1,65 +0,0 @@ -#nullable disable -using System; - -namespace MediaBrowser.Model.Services -{ - /// <summary> - /// Identifies a single API endpoint. - /// </summary> - [AttributeUsage(AttributeTargets.Property, AllowMultiple = true, Inherited = true)] - public class ApiMemberAttribute : Attribute - { - /// <summary> - /// Gets or sets verb to which applies attribute. By default applies to all verbs. - /// </summary> - public string Verb { get; set; } - - /// <summary> - /// Gets or sets parameter type: It can be only one of the following: path, query, body, form, or header. - /// </summary> - public string ParameterType { get; set; } - - /// <summary> - /// Gets or sets unique name for the parameter. Each name must be unique, even if they are associated with different paramType values. - /// </summary> - /// <remarks> - /// <para> - /// Other notes on the name field: - /// If paramType is body, the name is used only for UI and codegeneration. - /// If paramType is path, the name field must correspond to the associated path segment from the path field in the api object. - /// If paramType is query, the name field corresponds to the query param name. - /// </para> - /// </remarks> - public string Name { get; set; } - - /// <summary> - /// Gets or sets the human-readable description for the parameter. - /// </summary> - public string Description { get; set; } - - /// <summary> - /// For path, query, and header paramTypes, this field must be a primitive. For body, this can be a complex or container datatype. - /// </summary> - public string DataType { get; set; } - - /// <summary> - /// For path, this is always true. Otherwise, this field tells the client whether or not the field must be supplied. - /// </summary> - public bool IsRequired { get; set; } - - /// <summary> - /// For query params, this specifies that a comma-separated list of values can be passed to the API. For path and body types, this field cannot be true. - /// </summary> - public bool AllowMultiple { get; set; } - - /// <summary> - /// Gets or sets route to which applies attribute, matches using StartsWith. By default applies to all routes. - /// </summary> - public string Route { get; set; } - - /// <summary> - /// Whether to exclude this property from being included in the ModelSchema. - /// </summary> - public bool ExcludeInSchema { get; set; } - } -} diff --git a/MediaBrowser.Model/Services/IAsyncStreamWriter.cs b/MediaBrowser.Model/Services/IAsyncStreamWriter.cs deleted file mode 100644 index afbca78a2..000000000 --- a/MediaBrowser.Model/Services/IAsyncStreamWriter.cs +++ /dev/null @@ -1,13 +0,0 @@ -#pragma warning disable CS1591 - -using System.IO; -using System.Threading; -using System.Threading.Tasks; - -namespace MediaBrowser.Model.Services -{ - public interface IAsyncStreamWriter - { - Task WriteToAsync(Stream responseStream, CancellationToken cancellationToken); - } -} diff --git a/MediaBrowser.Model/Services/IHasHeaders.cs b/MediaBrowser.Model/Services/IHasHeaders.cs deleted file mode 100644 index 313f34b41..000000000 --- a/MediaBrowser.Model/Services/IHasHeaders.cs +++ /dev/null @@ -1,11 +0,0 @@ -#pragma warning disable CS1591 - -using System.Collections.Generic; - -namespace MediaBrowser.Model.Services -{ - public interface IHasHeaders - { - IDictionary<string, string> Headers { get; } - } -} diff --git a/MediaBrowser.Model/Services/IHasRequestFilter.cs b/MediaBrowser.Model/Services/IHasRequestFilter.cs deleted file mode 100644 index b83d3b075..000000000 --- a/MediaBrowser.Model/Services/IHasRequestFilter.cs +++ /dev/null @@ -1,24 +0,0 @@ -#pragma warning disable CS1591 - -using Microsoft.AspNetCore.Http; - -namespace MediaBrowser.Model.Services -{ - public interface IHasRequestFilter - { - /// <summary> - /// Gets the order in which Request Filters are executed. - /// <0 Executed before global request filters. - /// >0 Executed after global request filters. - /// </summary> - int Priority { get; } - - /// <summary> - /// The request filter is executed before the service. - /// </summary> - /// <param name="req">The http request wrapper.</param> - /// <param name="res">The http response wrapper.</param> - /// <param name="requestDto">The request DTO.</param> - void RequestFilter(IRequest req, HttpResponse res, object requestDto); - } -} diff --git a/MediaBrowser.Model/Services/IHttpRequest.cs b/MediaBrowser.Model/Services/IHttpRequest.cs deleted file mode 100644 index 3ea65195c..000000000 --- a/MediaBrowser.Model/Services/IHttpRequest.cs +++ /dev/null @@ -1,17 +0,0 @@ -#pragma warning disable CS1591 - -namespace MediaBrowser.Model.Services -{ - public interface IHttpRequest : IRequest - { - /// <summary> - /// Gets the HTTP Verb. - /// </summary> - string HttpMethod { get; } - - /// <summary> - /// Gets the value of the Accept HTTP Request Header. - /// </summary> - string Accept { get; } - } -} diff --git a/MediaBrowser.Model/Services/IHttpResult.cs b/MediaBrowser.Model/Services/IHttpResult.cs deleted file mode 100644 index abc581d8e..000000000 --- a/MediaBrowser.Model/Services/IHttpResult.cs +++ /dev/null @@ -1,35 +0,0 @@ -#nullable disable -#pragma warning disable CS1591 - -using System.Net; - -namespace MediaBrowser.Model.Services -{ - public interface IHttpResult : IHasHeaders - { - /// <summary> - /// The HTTP Response Status. - /// </summary> - int Status { get; set; } - - /// <summary> - /// The HTTP Response Status Code. - /// </summary> - HttpStatusCode StatusCode { get; set; } - - /// <summary> - /// The HTTP Response ContentType. - /// </summary> - string ContentType { get; set; } - - /// <summary> - /// Response DTO. - /// </summary> - object Response { get; set; } - - /// <summary> - /// Holds the request call context. - /// </summary> - IRequest RequestContext { get; set; } - } -} diff --git a/MediaBrowser.Model/Services/IRequest.cs b/MediaBrowser.Model/Services/IRequest.cs deleted file mode 100644 index 8bc1d3668..000000000 --- a/MediaBrowser.Model/Services/IRequest.cs +++ /dev/null @@ -1,93 +0,0 @@ -#nullable disable -#pragma warning disable CS1591 - -using System; -using System.Collections.Generic; -using System.IO; -using Microsoft.AspNetCore.Http; - -namespace MediaBrowser.Model.Services -{ - public interface IRequest - { - HttpResponse Response { get; } - - /// <summary> - /// The name of the service being called (e.g. Request DTO Name) - /// </summary> - string OperationName { get; set; } - - /// <summary> - /// The Verb / HttpMethod or Action for this request - /// </summary> - string Verb { get; } - - /// <summary> - /// The request ContentType. - /// </summary> - string ContentType { get; } - - bool IsLocal { get; } - - string UserAgent { get; } - - /// <summary> - /// The expected Response ContentType for this request. - /// </summary> - string ResponseContentType { get; set; } - - /// <summary> - /// Attach any data to this request that all filters and services can access. - /// </summary> - Dictionary<string, object> Items { get; } - - IHeaderDictionary Headers { get; } - - IQueryCollection QueryString { get; } - - string RawUrl { get; } - - string AbsoluteUri { get; } - - /// <summary> - /// The Remote Ip as reported by X-Forwarded-For, X-Real-IP or Request.UserHostAddress - /// </summary> - string RemoteIp { get; } - - /// <summary> - /// The value of the Authorization Header used to send the Api Key, null if not available. - /// </summary> - string Authorization { get; } - - string[] AcceptTypes { get; } - - string PathInfo { get; } - - Stream InputStream { get; } - - long ContentLength { get; } - - /// <summary> - /// The value of the Referrer, null if not available. - /// </summary> - Uri UrlReferrer { get; } - } - - public interface IHttpFile - { - string Name { get; } - - string FileName { get; } - - long ContentLength { get; } - - string ContentType { get; } - - Stream InputStream { get; } - } - - public interface IRequiresRequest - { - IRequest Request { get; set; } - } -} diff --git a/MediaBrowser.Model/Services/IRequiresRequestStream.cs b/MediaBrowser.Model/Services/IRequiresRequestStream.cs deleted file mode 100644 index 3e5f2da42..000000000 --- a/MediaBrowser.Model/Services/IRequiresRequestStream.cs +++ /dev/null @@ -1,14 +0,0 @@ -#pragma warning disable CS1591 - -using System.IO; - -namespace MediaBrowser.Model.Services -{ - public interface IRequiresRequestStream - { - /// <summary> - /// The raw Http Request Input Stream. - /// </summary> - Stream RequestStream { get; set; } - } -} diff --git a/MediaBrowser.Model/Services/IService.cs b/MediaBrowser.Model/Services/IService.cs deleted file mode 100644 index 5233f57ab..000000000 --- a/MediaBrowser.Model/Services/IService.cs +++ /dev/null @@ -1,15 +0,0 @@ -#pragma warning disable CS1591 - -namespace MediaBrowser.Model.Services -{ - // marker interface - public interface IService - { - } - - public interface IReturn { } - - public interface IReturn<T> : IReturn { } - - public interface IReturnVoid : IReturn { } -} diff --git a/MediaBrowser.Model/Services/IStreamWriter.cs b/MediaBrowser.Model/Services/IStreamWriter.cs deleted file mode 100644 index 3ebfef66b..000000000 --- a/MediaBrowser.Model/Services/IStreamWriter.cs +++ /dev/null @@ -1,11 +0,0 @@ -#pragma warning disable CS1591 - -using System.IO; - -namespace MediaBrowser.Model.Services -{ - public interface IStreamWriter - { - void WriteTo(Stream responseStream); - } -} diff --git a/MediaBrowser.Model/Services/QueryParamCollection.cs b/MediaBrowser.Model/Services/QueryParamCollection.cs deleted file mode 100644 index bdb0cabdf..000000000 --- a/MediaBrowser.Model/Services/QueryParamCollection.cs +++ /dev/null @@ -1,147 +0,0 @@ -#nullable disable -#pragma warning disable CS1591 - -using System; -using System.Collections.Generic; -using System.Linq; -using MediaBrowser.Model.Dto; - -namespace MediaBrowser.Model.Services -{ - // Remove this garbage class, it's just a bastard copy of NameValueCollection - public class QueryParamCollection : List<NameValuePair> - { - public QueryParamCollection() - { - } - - private static StringComparison GetStringComparison() - { - return StringComparison.OrdinalIgnoreCase; - } - - /// <summary> - /// Adds a new query parameter. - /// </summary> - public void Add(string key, string value) - { - Add(new NameValuePair(key, value)); - } - - private void Set(string key, string value) - { - if (string.IsNullOrEmpty(value)) - { - var parameters = GetItems(key); - - foreach (var p in parameters) - { - Remove(p); - } - - return; - } - - foreach (var pair in this) - { - var stringComparison = GetStringComparison(); - - if (string.Equals(key, pair.Name, stringComparison)) - { - pair.Value = value; - return; - } - } - - Add(key, value); - } - - private string Get(string name) - { - var stringComparison = GetStringComparison(); - - foreach (var pair in this) - { - if (string.Equals(pair.Name, name, stringComparison)) - { - return pair.Value; - } - } - - return null; - } - - private List<NameValuePair> GetItems(string name) - { - var stringComparison = GetStringComparison(); - - var list = new List<NameValuePair>(); - - foreach (var pair in this) - { - if (string.Equals(pair.Name, name, stringComparison)) - { - list.Add(pair); - } - } - - return list; - } - - public virtual List<string> GetValues(string name) - { - var stringComparison = GetStringComparison(); - - var list = new List<string>(); - - foreach (var pair in this) - { - if (string.Equals(pair.Name, name, stringComparison)) - { - list.Add(pair.Value); - } - } - - return list; - } - - public IEnumerable<string> Keys - { - get - { - var keys = new string[this.Count]; - - for (var i = 0; i < keys.Length; i++) - { - keys[i] = this[i].Name; - } - - return keys; - } - } - - /// <summary> - /// Gets or sets a query parameter value by name. A query may contain multiple values of the same name - /// (i.e. "x=1&x=2"), in which case the value is an array, which works for both getting and setting. - /// </summary> - /// <param name="name">The query parameter name.</param> - /// <returns>The query parameter value or array of values.</returns> - public string this[string name] - { - get => Get(name); - set => Set(name, value); - } - - private string GetQueryStringValue(NameValuePair pair) - { - return pair.Name + "=" + pair.Value; - } - - public override string ToString() - { - var vals = this.Select(GetQueryStringValue).ToArray(); - - return string.Join("&", vals); - } - } -} diff --git a/MediaBrowser.Model/Services/RouteAttribute.cs b/MediaBrowser.Model/Services/RouteAttribute.cs deleted file mode 100644 index f8bf51112..000000000 --- a/MediaBrowser.Model/Services/RouteAttribute.cs +++ /dev/null @@ -1,163 +0,0 @@ -#nullable disable -#pragma warning disable CS1591 - -using System; - -namespace MediaBrowser.Model.Services -{ - [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)] - public class RouteAttribute : Attribute - { - /// <summary> - /// <para>Initializes an instance of the <see cref="RouteAttribute"/> class.</para> - /// </summary> - /// <param name="path"> - /// <para>The path template to map to the request. See - /// <see cref="Path">RouteAttribute.Path</see> - /// for details on the correct format.</para> - /// </param> - public RouteAttribute(string path) - : this(path, null) - { - } - - /// <summary> - /// <para>Initializes an instance of the <see cref="RouteAttribute"/> class.</para> - /// </summary> - /// <param name="path"> - /// <para>The path template to map to the request. See - /// <see cref="Path">RouteAttribute.Path</see> - /// for details on the correct format.</para> - /// </param> - /// <param name="verbs">A comma-delimited list of HTTP verbs supported by the - /// service. If unspecified, all verbs are assumed to be supported.</param> - public RouteAttribute(string path, string verbs) - { - Path = path; - Verbs = verbs; - } - - /// <summary> - /// Gets or sets the path template to be mapped to the request. - /// </summary> - /// <value> - /// A <see cref="String"/> value providing the path mapped to - /// the request. Never <see langword="null"/>. - /// </value> - /// <remarks> - /// <para>Some examples of valid paths are:</para> - /// - /// <list> - /// <item>"/Inventory"</item> - /// <item>"/Inventory/{Category}/{ItemId}"</item> - /// <item>"/Inventory/{ItemPath*}"</item> - /// </list> - /// - /// <para>Variables are specified within "{}" - /// brackets. Each variable in the path is mapped to the same-named property - /// on the request DTO. At runtime, ServiceStack will parse the - /// request URL, extract the variable values, instantiate the request DTO, - /// and assign the variable values into the corresponding request properties, - /// prior to passing the request DTO to the service object for processing.</para> - /// - /// <para>It is not necessary to specify all request properties as - /// variables in the path. For unspecified properties, callers may provide - /// values in the query string. For example: the URL - /// "http://services/Inventory?Category=Books&ItemId=12345" causes the same - /// request DTO to be processed as "http://services/Inventory/Books/12345", - /// provided that the paths "/Inventory" (which supports the first URL) and - /// "/Inventory/{Category}/{ItemId}" (which supports the second URL) - /// are both mapped to the request DTO.</para> - /// - /// <para>Please note that while it is possible to specify property values - /// in the query string, it is generally considered to be less RESTful and - /// less desirable than to specify them as variables in the path. Using the - /// query string to specify property values may also interfere with HTTP - /// caching.</para> - /// - /// <para>The final variable in the path may contain a "*" suffix - /// to grab all remaining segments in the path portion of the request URL and assign - /// them to a single property on the request DTO. - /// For example, if the path "/Inventory/{ItemPath*}" is mapped to the request DTO, - /// then the request URL "http://services/Inventory/Books/12345" will result - /// in a request DTO whose ItemPath property contains "Books/12345". - /// You may only specify one such variable in the path, and it must be positioned at - /// the end of the path.</para> - /// </remarks> - public string Path { get; set; } - - /// <summary> - /// Gets or sets short summary of what the route does. - /// </summary> - public string Summary { get; set; } - - public string Description { get; set; } - - public bool IsHidden { get; set; } - - /// <summary> - /// Gets or sets longer text to explain the behaviour of the route. - /// </summary> - public string Notes { get; set; } - - /// <summary> - /// Gets or sets a comma-delimited list of HTTP verbs supported by the service, such as - /// "GET,PUT,POST,DELETE". - /// </summary> - /// <value> - /// A <see cref="String"/> providing a comma-delimited list of HTTP verbs supported - /// by the service, <see langword="null"/> or empty if all verbs are supported. - /// </value> - public string Verbs { get; set; } - - /// <summary> - /// Used to rank the precedences of route definitions in reverse routing. - /// i.e. Priorities below 0 are auto-generated have less precedence. - /// </summary> - public int Priority { get; set; } - - protected bool Equals(RouteAttribute other) - { - return base.Equals(other) - && string.Equals(Path, other.Path) - && string.Equals(Summary, other.Summary) - && string.Equals(Notes, other.Notes) - && string.Equals(Verbs, other.Verbs) - && Priority == other.Priority; - } - - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) - { - return false; - } - - if (ReferenceEquals(this, obj)) - { - return true; - } - - if (obj.GetType() != this.GetType()) - { - return false; - } - - return Equals((RouteAttribute)obj); - } - - public override int GetHashCode() - { - unchecked - { - var hashCode = base.GetHashCode(); - hashCode = (hashCode * 397) ^ (Path != null ? Path.GetHashCode() : 0); - hashCode = (hashCode * 397) ^ (Summary != null ? Summary.GetHashCode() : 0); - hashCode = (hashCode * 397) ^ (Notes != null ? Notes.GetHashCode() : 0); - hashCode = (hashCode * 397) ^ (Verbs != null ? Verbs.GetHashCode() : 0); - hashCode = (hashCode * 397) ^ Priority; - return hashCode; - } - } - } -} diff --git a/MediaBrowser.Model/Session/PlayRequest.cs b/MediaBrowser.Model/Session/PlayRequest.cs index eeb25c2e8..6a66465a2 100644 --- a/MediaBrowser.Model/Session/PlayRequest.cs +++ b/MediaBrowser.Model/Session/PlayRequest.cs @@ -2,7 +2,6 @@ #pragma warning disable CS1591 using System; -using MediaBrowser.Model.Services; namespace MediaBrowser.Model.Session { diff --git a/tests/Jellyfin.Server.Implementations.Tests/HttpServer/ResponseFilterTests.cs b/tests/Jellyfin.Server.Implementations.Tests/HttpServer/ResponseFilterTests.cs deleted file mode 100644 index 39bd94b59..000000000 --- a/tests/Jellyfin.Server.Implementations.Tests/HttpServer/ResponseFilterTests.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Emby.Server.Implementations.HttpServer; -using Xunit; - -namespace Jellyfin.Server.Implementations.Tests.HttpServer -{ - public class ResponseFilterTests - { - [Theory] - [InlineData(null, null)] - [InlineData("", "")] - [InlineData("This is a clean string.", "This is a clean string.")] - [InlineData("This isn't \n\ra clean string.", "This isn't a clean string.")] - public void RemoveControlCharacters_ValidArgs_Correct(string? input, string? result) - { - Assert.Equal(result, ResponseFilter.RemoveControlCharacters(input)); - } - } -} -- cgit v1.2.3 From 12710cdf423c038c076c8bd351706e73f3a27899 Mon Sep 17 00:00:00 2001 From: Claus Vium <clausvium@gmail.com> Date: Wed, 2 Sep 2020 13:06:14 +0200 Subject: More fixes --- Emby.Server.Implementations/HttpServer/HttpListenerHost.cs | 14 -------------- .../HttpServer/Security/AuthorizationContext.cs | 5 ----- MediaBrowser.Controller/Net/IAuthorizationContext.cs | 7 ------- MediaBrowser.Controller/Net/IHttpServer.cs | 2 +- 4 files changed, 1 insertion(+), 27 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs index 30cb7dd3a..acd7e67db 100644 --- a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs +++ b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs @@ -79,20 +79,6 @@ namespace Emby.Server.Implementations.HttpServer public string GlobalResponse { get; set; } - private static string NormalizeUrlPath(string path) - { - if (path.Length > 0 && path[0] == '/') - { - // If the path begins with a leading slash, just return it as-is - return path; - } - else - { - // If the path does not begin with a leading slash, append one for consistency - return "/" + path; - } - } - private static Exception GetActualException(Exception ex) { if (ex is AggregateException agg) diff --git a/Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs b/Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs index eec8ac486..4b407dd9d 100644 --- a/Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs +++ b/Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs @@ -23,11 +23,6 @@ namespace Emby.Server.Implementations.HttpServer.Security _userManager = userManager; } - public AuthorizationInfo GetAuthorizationInfo(object requestContext) - { - return GetAuthorizationInfo((HttpContext)requestContext); - } - public AuthorizationInfo GetAuthorizationInfo(HttpContext requestContext) { if (requestContext.Request.HttpContext.Items.TryGetValue("AuthorizationInfo", out var cached)) diff --git a/MediaBrowser.Controller/Net/IAuthorizationContext.cs b/MediaBrowser.Controller/Net/IAuthorizationContext.cs index 4d2f5f5e3..0d310548d 100644 --- a/MediaBrowser.Controller/Net/IAuthorizationContext.cs +++ b/MediaBrowser.Controller/Net/IAuthorizationContext.cs @@ -7,13 +7,6 @@ namespace MediaBrowser.Controller.Net /// </summary> public interface IAuthorizationContext { - /// <summary> - /// Gets the authorization information. - /// </summary> - /// <param name="requestContext">The request context.</param> - /// <returns>AuthorizationInfo.</returns> - AuthorizationInfo GetAuthorizationInfo(object requestContext); - /// <summary> /// Gets the authorization information. /// </summary> diff --git a/MediaBrowser.Controller/Net/IHttpServer.cs b/MediaBrowser.Controller/Net/IHttpServer.cs index 845f27045..637dd2be3 100644 --- a/MediaBrowser.Controller/Net/IHttpServer.cs +++ b/MediaBrowser.Controller/Net/IHttpServer.cs @@ -42,7 +42,7 @@ namespace MediaBrowser.Controller.Net /// <summary> /// Get the default CORS headers. /// </summary> - /// <param name="req">The HTTP context of the current request.</param> + /// <param name="httpContext">The HTTP context of the current request.</param> /// <returns>The default CORS headers for the context.</returns> IDictionary<string, string> GetDefaultCorsHeaders(HttpContext httpContext); } -- cgit v1.2.3 From 208b00fbb17d7744cdb632323dc3dbb8099b5cca Mon Sep 17 00:00:00 2001 From: Erwin de Haan <EraYaN@users.noreply.github.com> Date: Wed, 2 Sep 2020 20:11:31 +0200 Subject: Add the item path to the ItemLookupInfo class. This is important for the Shoko Anime Meatdata provider plugin. --- MediaBrowser.Controller/Entities/BaseItem.cs | 1 + MediaBrowser.Controller/Providers/ItemLookupInfo.cs | 6 ++++++ 2 files changed, 7 insertions(+) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 24978d8dd..a5c22e50f 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -2633,6 +2633,7 @@ namespace MediaBrowser.Controller.Entities { return new T { + Path = Path, MetadataCountryCode = GetPreferredMetadataCountryCode(), MetadataLanguage = GetPreferredMetadataLanguage(), Name = GetNameForMetadataLookup(), diff --git a/MediaBrowser.Controller/Providers/ItemLookupInfo.cs b/MediaBrowser.Controller/Providers/ItemLookupInfo.cs index 49974c2a3..b777cc1d3 100644 --- a/MediaBrowser.Controller/Providers/ItemLookupInfo.cs +++ b/MediaBrowser.Controller/Providers/ItemLookupInfo.cs @@ -14,6 +14,12 @@ namespace MediaBrowser.Controller.Providers /// <value>The name.</value> public string Name { get; set; } + /// <summary> + /// Gets or sets the path. + /// </summary> + /// <value>The path.</value> + public string Path { get; set; } + /// <summary> /// Gets or sets the metadata language. /// </summary> -- cgit v1.2.3 From 346581bb2ab8e5c93d83e0a486d3d705b54c7d08 Mon Sep 17 00:00:00 2001 From: Erwin de Haan <EraYaN@users.noreply.github.com> Date: Wed, 2 Sep 2020 22:42:00 +0200 Subject: Fixes for CI Nuget package pushing and CI triggers Also adds SourceLink support and symbols that are pushed to Nuget. Add symbols to main nuget packages for unstable builds (Azure Artifacts does not support symbols outside of the main package) SourceLink will enable stepping during debugging. --- .ci/azure-pipelines-package.yml | 36 +++++++++++++++++----- .ci/azure-pipelines.yml | 14 ++++++--- Emby.Naming/Emby.Naming.csproj | 13 ++++++++ Jellyfin.Data/Jellyfin.Data.csproj | 9 ++++++ MediaBrowser.Common/MediaBrowser.Common.csproj | 10 ++++++ .../MediaBrowser.Controller.csproj | 10 ++++++ MediaBrowser.Model/MediaBrowser.Model.csproj | 10 ++++++ 7 files changed, 91 insertions(+), 11 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/.ci/azure-pipelines-package.yml b/.ci/azure-pipelines-package.yml index cfe76d463..2d83320b5 100644 --- a/.ci/azure-pipelines-package.yml +++ b/.ci/azure-pipelines-package.yml @@ -138,14 +138,14 @@ jobs: commands: sudo nohup -n /srv/repository/collect-server.azure.sh /srv/repository/incoming/azure $(Build.BuildNumber) unstable & - task: SSH@0 - displayName: 'Update Stable Repository' + displayName: 'Update Stable Repository' continueOnError: true condition: startsWith(variables['Build.SourceBranch'], 'refs/tags') inputs: sshEndpoint: repository runOptions: 'commands' commands: sudo nohup -n /srv/repository/collect-server.azure.sh /srv/repository/incoming/azure $(Build.BuildNumber) & - + - job: PublishNuget displayName: 'Publish NuGet packages' dependsOn: @@ -175,7 +175,7 @@ jobs: MediaBrowser.Model/MediaBrowser.Model.csproj Emby.Naming/Emby.Naming.csproj custom: 'pack' - arguments: '--version-suffix $(Build.BuildNumber) -o $(Build.ArtifactStagingDirectory)' + arguments: '--version-suffix $(Build.BuildNumber) -o $(Build.ArtifactStagingDirectory) -p:Stability=Unstable' - task: PublishBuildArtifacts@1 displayName: 'Publish Nuget packages' @@ -183,10 +183,32 @@ jobs: pathToPublish: $(Build.ArtifactStagingDirectory) artifactName: Jellyfin Nuget Packages + - task: NuGetAuthenticate@0 + displayName: 'Authenticate to stable Nuget feed' + condition: startsWith(variables['Build.SourceBranch'], 'refs/tags/v') + inputs: + nuGetServiceConnections: 'NugetOrg' + - task: NuGetCommand@2 - displayName: 'Push Nuget packages to feed' - condition: startsWith(variables['Build.SourceBranch'], 'refs/tags') + displayName: 'Push Nuget packages to stable feed' + condition: startsWith(variables['Build.SourceBranch'], 'refs/tags/v') + inputs: + command: 'push' + packagesToPush: '$(Build.ArtifactStagingDirectory)/**/*.nupkg;$(Build.ArtifactStagingDirectory)/**/*.snupkg' + nuGetFeedType: 'external' + publishFeedCredentials: 'NugetOrg' + allowPackageConflicts: true # This ignores an error if the version already exists + + - task: NuGetAuthenticate@0 + displayName: 'Authenticate to unstable Nuget feed' + condition: startsWith(variables['Build.SourceBranch'], 'refs/heads/master') + + - task: NuGetCommand@2 + displayName: 'Push Nuget packages to unstable feed' + condition: startsWith(variables['Build.SourceBranch'], 'refs/heads/master') inputs: command: 'push' - packagesToPush: '$(Build.ArtifactStagingDirectory)/**/*.nupkg' - includeNugetOrg: 'true' + packagesToPush: '$(Build.ArtifactStagingDirectory)/**/*.nupkg;!$(Build.ArtifactStagingDirectory)/**/*.symbols.nupkg' # No symbols since Azure Artifact does not support it + nuGetFeedType: 'internal' + publishVstsFeed: '7cce6c46-d610-45e3-9fb7-65a6bfd1b671/a5746b79-f369-42db-93ff-59cd066f9327' + allowPackageConflicts: true # This ignores an error if the version already exists diff --git a/.ci/azure-pipelines.yml b/.ci/azure-pipelines.yml index 0c86c0171..6f5f3ff2b 100644 --- a/.ci/azure-pipelines.yml +++ b/.ci/azure-pipelines.yml @@ -13,15 +13,21 @@ pr: trigger: batch: true + branches: + include: + - '*' + tags: + include: + - 'v*' jobs: -- ${{ if not(or(startsWith(variables['Build.SourceBranch'], 'refs/tags'), startsWith(variables['Build.SourceBranch'], 'refs/heads/master'))) }}: +- ${{ if not(or(startsWith(variables['Build.SourceBranch'], 'refs/tags/v'), startsWith(variables['Build.SourceBranch'], 'refs/heads/master'))) }}: - template: azure-pipelines-main.yml parameters: LinuxImage: 'ubuntu-latest' RestoreBuildProjects: $(RestoreBuildProjects) -- ${{ if not(or(startsWith(variables['Build.SourceBranch'], 'refs/tags'), startsWith(variables['Build.SourceBranch'], 'refs/heads/master'))) }}: +- ${{ if not(or(startsWith(variables['Build.SourceBranch'], 'refs/tags/v'), startsWith(variables['Build.SourceBranch'], 'refs/heads/master'))) }}: - template: azure-pipelines-test.yml parameters: ImageNames: @@ -29,7 +35,7 @@ jobs: Windows: 'windows-latest' macOS: 'macos-latest' -- ${{ if not(or(startsWith(variables['Build.SourceBranch'], 'refs/tags'), startsWith(variables['Build.SourceBranch'], 'refs/heads/master'))) }}: +- ${{ if not(or(startsWith(variables['Build.SourceBranch'], 'refs/tags/v'), startsWith(variables['Build.SourceBranch'], 'refs/heads/master'))) }}: - template: azure-pipelines-abi.yml parameters: Packages: @@ -47,5 +53,5 @@ jobs: AssemblyFileName: MediaBrowser.Common.dll LinuxImage: 'ubuntu-latest' -- ${{ if or(startsWith(variables['Build.SourceBranch'], 'refs/tags'), startsWith(variables['Build.SourceBranch'], 'refs/heads/master')) }}: +- ${{ if or(startsWith(variables['Build.SourceBranch'], 'refs/tags/v'), startsWith(variables['Build.SourceBranch'], 'refs/heads/master')) }}: - template: azure-pipelines-package.yml diff --git a/Emby.Naming/Emby.Naming.csproj b/Emby.Naming/Emby.Naming.csproj index 5e2c6e3e3..6857f9952 100644 --- a/Emby.Naming/Emby.Naming.csproj +++ b/Emby.Naming/Emby.Naming.csproj @@ -10,6 +10,15 @@ <GenerateAssemblyInfo>false</GenerateAssemblyInfo> <GenerateDocumentationFile>true</GenerateDocumentationFile> <TreatWarningsAsErrors>true</TreatWarningsAsErrors> + <PublishRepositoryUrl>true</PublishRepositoryUrl> + <EmbedUntrackedSources>true</EmbedUntrackedSources> + <IncludeSymbols>true</IncludeSymbols> + <SymbolPackageFormat>snupkg</SymbolPackageFormat> + </PropertyGroup> + + <PropertyGroup Condition=" '$(Stability)'=='Unstable'"> + <!-- Include all symbols in the main nupkg until Azure Artifact Feed starts supporting ingesting NuGet symbol packages. --> + <AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder> </PropertyGroup> <ItemGroup> @@ -28,6 +37,10 @@ <PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression> </PropertyGroup> + <ItemGroup> + <PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All"/> + </ItemGroup> + <!-- Code Analyzers--> <ItemGroup Condition=" '$(Configuration)' == 'Debug' "> <!-- TODO: <PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.8" PrivateAssets="All" /> --> diff --git a/Jellyfin.Data/Jellyfin.Data.csproj b/Jellyfin.Data/Jellyfin.Data.csproj index e8065419d..547771faa 100644 --- a/Jellyfin.Data/Jellyfin.Data.csproj +++ b/Jellyfin.Data/Jellyfin.Data.csproj @@ -5,6 +5,15 @@ <GenerateAssemblyInfo>false</GenerateAssemblyInfo> <GenerateDocumentationFile>true</GenerateDocumentationFile> <TreatWarningsAsErrors Condition=" '$(Configuration)' == 'Release' ">true</TreatWarningsAsErrors> + <PublishRepositoryUrl>true</PublishRepositoryUrl> + <EmbedUntrackedSources>true</EmbedUntrackedSources> + <IncludeSymbols>true</IncludeSymbols> + <SymbolPackageFormat>snupkg</SymbolPackageFormat> + </PropertyGroup> + + <PropertyGroup Condition=" '$(Stability)'=='Unstable'"> + <!-- Include all symbols in the main nupkg until Azure Artifact Feed starts supporting ingesting NuGet symbol packages. --> + <AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder> </PropertyGroup> <PropertyGroup> diff --git a/MediaBrowser.Common/MediaBrowser.Common.csproj b/MediaBrowser.Common/MediaBrowser.Common.csproj index deb674e45..6e258371c 100644 --- a/MediaBrowser.Common/MediaBrowser.Common.csproj +++ b/MediaBrowser.Common/MediaBrowser.Common.csproj @@ -18,6 +18,7 @@ </ItemGroup> <ItemGroup> + <PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All"/> <PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.1.6" /> <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="3.1.6" /> <PackageReference Include="Microsoft.Net.Http.Headers" Version="2.2.8" /> @@ -32,6 +33,15 @@ <GenerateAssemblyInfo>false</GenerateAssemblyInfo> <GenerateDocumentationFile>true</GenerateDocumentationFile> <TreatWarningsAsErrors>true</TreatWarningsAsErrors> + <PublishRepositoryUrl>true</PublishRepositoryUrl> + <EmbedUntrackedSources>true</EmbedUntrackedSources> + <IncludeSymbols>true</IncludeSymbols> + <SymbolPackageFormat>snupkg</SymbolPackageFormat> + </PropertyGroup> + + <PropertyGroup Condition=" '$(Stability)'=='Unstable'"> + <!-- Include all symbols in the main nupkg until Azure Artifact Feed starts supporting ingesting NuGet symbol packages. --> + <AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder> </PropertyGroup> <!-- Code analyzers--> diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index df92eda38..3674181b1 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -14,6 +14,7 @@ </PropertyGroup> <ItemGroup> + <PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All"/> <PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.1.6" /> <PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="3.1.6" /> </ItemGroup> @@ -32,6 +33,15 @@ <GenerateAssemblyInfo>false</GenerateAssemblyInfo> <GenerateDocumentationFile>true</GenerateDocumentationFile> <TreatWarningsAsErrors Condition=" '$(Configuration)' == 'Release' ">true</TreatWarningsAsErrors> + <PublishRepositoryUrl>true</PublishRepositoryUrl> + <EmbedUntrackedSources>true</EmbedUntrackedSources> + <IncludeSymbols>true</IncludeSymbols> + <SymbolPackageFormat>snupkg</SymbolPackageFormat> + </PropertyGroup> + + <PropertyGroup Condition=" '$(Stability)'=='Unstable'"> + <!-- Include all symbols in the main nupkg until Azure Artifact Feed starts supporting ingesting NuGet symbol packages. --> + <AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder> </PropertyGroup> <!-- Code Analyzers--> diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj index 0491c9072..4ae38ade9 100644 --- a/MediaBrowser.Model/MediaBrowser.Model.csproj +++ b/MediaBrowser.Model/MediaBrowser.Model.csproj @@ -20,9 +20,19 @@ <TreatWarningsAsErrors Condition=" '$(Configuration)' == 'Release' ">true</TreatWarningsAsErrors> <Nullable>enable</Nullable> <LangVersion>latest</LangVersion> + <PublishRepositoryUrl>true</PublishRepositoryUrl> + <EmbedUntrackedSources>true</EmbedUntrackedSources> + <IncludeSymbols>true</IncludeSymbols> + <SymbolPackageFormat>snupkg</SymbolPackageFormat> + </PropertyGroup> + + <PropertyGroup Condition=" '$(Stability)'=='Unstable'"> + <!-- Include all symbols in the main nupkg until Azure Artifact Feed starts supporting ingesting NuGet symbol packages. --> + <AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder> </PropertyGroup> <ItemGroup> + <PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All"/> <PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.2.0" /> <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="3.1.6" /> <PackageReference Include="System.Globalization" Version="4.3.0" /> -- cgit v1.2.3 From 5813f8073c5bbe67a6071aed7084adc68f38fd48 Mon Sep 17 00:00:00 2001 From: Claus Vium <clausvium@gmail.com> Date: Thu, 3 Sep 2020 00:31:42 +0200 Subject: Move HttpListenerHost middleware up the pipeline --- Emby.Server.Implementations/ApplicationHost.cs | 2 +- .../HttpServer/HttpListenerHost.cs | 348 +++------------------ Jellyfin.Server/Startup.cs | 30 +- .../Extensions/HttpContextExtensions.cs | 2 +- MediaBrowser.Controller/Net/IHttpServer.cs | 7 +- 5 files changed, 78 insertions(+), 311 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index 4f47d1999..5ed0ad415 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -501,7 +501,7 @@ namespace Emby.Server.Implementations } public Task ExecuteHttpHandlerAsync(HttpContext context, Func<Task> next) - => _httpServer.RequestHandler(context); + => _httpServer.RequestHandler(context, next); /// <summary> /// Registers services/resources with the service collection that will be available via DI. diff --git a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs index 4165cdb96..27369960b 100644 --- a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs +++ b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs @@ -2,26 +2,17 @@ using System; using System.Collections.Generic; -using System.Diagnostics; -using System.IO; using System.Linq; -using System.Net.Sockets; using System.Net.WebSockets; -using System.Threading; using System.Threading.Tasks; using Jellyfin.Data.Events; using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Net; -using MediaBrowser.Controller; -using MediaBrowser.Controller.Authentication; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Net; using MediaBrowser.Model.Globalization; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.Extensions; -using Microsoft.AspNetCore.WebUtilities; using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Primitives; @@ -39,32 +30,25 @@ namespace Emby.Server.Implementations.HttpServer private readonly ILoggerFactory _loggerFactory; private readonly IServerConfigurationManager _config; private readonly INetworkManager _networkManager; - private readonly IServerApplicationHost _appHost; private readonly string _defaultRedirectPath; private readonly string _baseUrlPrefix; - private readonly IHostEnvironment _hostEnvironment; - private IWebSocketListener[] _webSocketListeners = Array.Empty<IWebSocketListener>(); private bool _disposed = false; public HttpListenerHost( - IServerApplicationHost applicationHost, ILogger<HttpListenerHost> logger, IServerConfigurationManager config, IConfiguration configuration, INetworkManager networkManager, ILocalizationManager localizationManager, - IHostEnvironment hostEnvironment, ILoggerFactory loggerFactory) { - _appHost = applicationHost; _logger = logger; _config = config; _defaultRedirectPath = configuration[DefaultRedirectKey]; _baseUrlPrefix = _config.Configuration.BaseUrl; _networkManager = networkManager; - _hostEnvironment = hostEnvironment; _loggerFactory = loggerFactory; Instance = this; @@ -79,122 +63,6 @@ namespace Emby.Server.Implementations.HttpServer public string GlobalResponse { get; set; } - private static Exception GetActualException(Exception ex) - { - if (ex is AggregateException agg) - { - var inner = agg.InnerException; - if (inner != null) - { - return GetActualException(inner); - } - else - { - var inners = agg.InnerExceptions; - if (inners.Count > 0) - { - return GetActualException(inners[0]); - } - } - } - - return ex; - } - - private int GetStatusCode(Exception ex) - { - switch (ex) - { - case ArgumentException _: return 400; - case AuthenticationException _: return 401; - case SecurityException _: return 403; - case DirectoryNotFoundException _: - case FileNotFoundException _: - case ResourceNotFoundException _: return 404; - case MethodNotAllowedException _: return 405; - default: return 500; - } - } - - private async Task ErrorHandler(Exception ex, HttpContext httpContext, int statusCode, string urlToLog, bool ignoreStackTrace) - { - if (ignoreStackTrace) - { - _logger.LogError("Error processing request: {Message}. URL: {Url}", ex.Message.TrimEnd('.'), urlToLog); - } - else - { - _logger.LogError(ex, "Error processing request. URL: {Url}", urlToLog); - } - - var httpRes = httpContext.Response; - - if (httpRes.HasStarted) - { - return; - } - - httpRes.StatusCode = statusCode; - - var errContent = _hostEnvironment.IsDevelopment() - ? (NormalizeExceptionMessage(ex) ?? string.Empty) - : "Error processing request."; - httpRes.ContentType = "text/plain"; - httpRes.ContentLength = errContent.Length; - await httpRes.WriteAsync(errContent).ConfigureAwait(false); - } - - private string NormalizeExceptionMessage(Exception ex) - { - // Do not expose the exception message for AuthenticationException - if (ex is AuthenticationException) - { - return null; - } - - // Strip any information we don't want to reveal - return ex.Message - ?.Replace(_config.ApplicationPaths.ProgramSystemPath, string.Empty, StringComparison.OrdinalIgnoreCase) - .Replace(_config.ApplicationPaths.ProgramDataPath, string.Empty, StringComparison.OrdinalIgnoreCase); - } - - public static string RemoveQueryStringByKey(string url, string key) - { - var uri = new Uri(url); - - // this gets all the query string key value pairs as a collection - var newQueryString = QueryHelpers.ParseQuery(uri.Query); - - var originalCount = newQueryString.Count; - - if (originalCount == 0) - { - return url; - } - - // this removes the key if exists - newQueryString.Remove(key); - - if (originalCount == newQueryString.Count) - { - return url; - } - - // this gets the page path from root without QueryString - string pagePathWithoutQueryString = url.Split(new[] { '?' }, StringSplitOptions.RemoveEmptyEntries)[0]; - - return newQueryString.Count > 0 - ? QueryHelpers.AddQueryString(pagePathWithoutQueryString, newQueryString.ToDictionary(kv => kv.Key, kv => kv.Value.ToString())) - : pagePathWithoutQueryString; - } - - private static string GetUrlToLog(string url) - { - url = RemoveQueryStringByKey(url, "api_key"); - - return url; - } - private static string NormalizeConfiguredLocalAddress(string address) { var add = address.AsSpan().Trim('/'); @@ -267,187 +135,90 @@ namespace Emby.Server.Implementations.HttpServer return true; } - /// <summary> - /// Validate a connection from a remote IP address to a URL to see if a redirection to HTTPS is required. - /// </summary> - /// <returns>True if the request is valid, or false if the request is not valid and an HTTPS redirect is required.</returns> - private bool ValidateSsl(string remoteIp, string urlString) - { - if (_config.Configuration.RequireHttps - && _appHost.ListenWithHttps - && !urlString.Contains("https://", StringComparison.OrdinalIgnoreCase)) - { - // These are hacks, but if these ever occur on ipv6 in the local network they could be incorrectly redirected - if (urlString.IndexOf("system/ping", StringComparison.OrdinalIgnoreCase) != -1 - || urlString.IndexOf("dlna/", StringComparison.OrdinalIgnoreCase) != -1) - { - return true; - } - - if (!_networkManager.IsInLocalNetwork(remoteIp)) - { - return false; - } - } - - return true; - } - /// <inheritdoc /> - public Task RequestHandler(HttpContext context) + public Task RequestHandler(HttpContext context, Func<Task> next) { if (context.WebSockets.IsWebSocketRequest) { return WebSocketRequestHandler(context); } - return RequestHandler(context, context.RequestAborted); + return HttpRequestHandler(context, next); } /// <summary> /// Overridable method that can be used to implement a custom handler. /// </summary> - private async Task RequestHandler(HttpContext httpContext, CancellationToken cancellationToken) + private async Task HttpRequestHandler(HttpContext httpContext, Func<Task> next) { - var stopWatch = new Stopwatch(); - stopWatch.Start(); + var cancellationToken = httpContext.RequestAborted; var httpRes = httpContext.Response; var host = httpContext.Request.Host.ToString(); var localPath = httpContext.Request.Path.ToString(); - var urlString = httpContext.Request.GetDisplayUrl(); - string urlToLog = GetUrlToLog(urlString); string remoteIp = httpContext.Request.RemoteIp(); - try + if (_disposed) { - if (_disposed) - { - httpRes.StatusCode = 503; - httpRes.ContentType = "text/plain"; - await httpRes.WriteAsync("Server shutting down", cancellationToken).ConfigureAwait(false); - return; - } - - if (!ValidateHost(host)) - { - httpRes.StatusCode = 400; - httpRes.ContentType = "text/plain"; - await httpRes.WriteAsync("Invalid host", cancellationToken).ConfigureAwait(false); - return; - } - - if (!ValidateRequest(remoteIp, httpContext.Request.IsLocal())) - { - httpRes.StatusCode = 403; - httpRes.ContentType = "text/plain"; - await httpRes.WriteAsync("Forbidden", cancellationToken).ConfigureAwait(false); - return; - } - - if (!ValidateSsl(httpContext.Request.RemoteIp(), urlString)) - { - RedirectToSecureUrl(httpRes, urlString); - return; - } - - if (string.Equals(httpContext.Request.Method, "OPTIONS", StringComparison.OrdinalIgnoreCase)) - { - httpRes.StatusCode = 200; - foreach (var (key, value) in GetDefaultCorsHeaders(httpContext)) - { - httpRes.Headers.Add(key, value); - } - - httpRes.ContentType = "text/plain"; - await httpRes.WriteAsync(string.Empty, cancellationToken).ConfigureAwait(false); - return; - } - - if (string.Equals(localPath, _baseUrlPrefix + "/", StringComparison.OrdinalIgnoreCase) - || string.Equals(localPath, _baseUrlPrefix, StringComparison.OrdinalIgnoreCase) - || string.Equals(localPath, "/", StringComparison.OrdinalIgnoreCase) - || string.IsNullOrEmpty(localPath) - || !localPath.StartsWith(_baseUrlPrefix, StringComparison.OrdinalIgnoreCase)) - { - // Always redirect back to the default path if the base prefix is invalid or missing - _logger.LogDebug("Normalizing a URL at {0}", localPath); - httpRes.Redirect(_baseUrlPrefix + "/" + _defaultRedirectPath); - return; - } + httpRes.StatusCode = 503; + httpRes.ContentType = "text/plain"; + await httpRes.WriteAsync("Server shutting down", cancellationToken).ConfigureAwait(false); + return; + } - if (!string.IsNullOrEmpty(GlobalResponse)) - { - // We don't want the address pings in ApplicationHost to fail - if (localPath.IndexOf("system/ping", StringComparison.OrdinalIgnoreCase) == -1) - { - httpRes.StatusCode = 503; - httpRes.ContentType = "text/html"; - await httpRes.WriteAsync(GlobalResponse, cancellationToken).ConfigureAwait(false); - return; - } - } + if (!ValidateHost(host)) + { + httpRes.StatusCode = 400; + httpRes.ContentType = "text/plain"; + await httpRes.WriteAsync("Invalid host", cancellationToken).ConfigureAwait(false); + return; + } - throw new FileNotFoundException(); + if (!ValidateRequest(remoteIp, httpContext.Request.IsLocal())) + { + httpRes.StatusCode = 403; + httpRes.ContentType = "text/plain"; + await httpRes.WriteAsync("Forbidden", cancellationToken).ConfigureAwait(false); + return; } - catch (Exception requestEx) + + if (string.Equals(httpContext.Request.Method, "OPTIONS", StringComparison.OrdinalIgnoreCase)) { - try + httpRes.StatusCode = 200; + foreach (var (key, value) in GetDefaultCorsHeaders(httpContext)) { - var requestInnerEx = GetActualException(requestEx); - var statusCode = GetStatusCode(requestInnerEx); - - foreach (var (key, value) in GetDefaultCorsHeaders(httpContext)) - { - if (!httpRes.Headers.ContainsKey(key)) - { - httpRes.Headers.Add(key, value); - } - } - - bool ignoreStackTrace = - requestInnerEx is SocketException - || requestInnerEx is IOException - || requestInnerEx is OperationCanceledException - || requestInnerEx is SecurityException - || requestInnerEx is AuthenticationException - || requestInnerEx is FileNotFoundException; - - // Do not handle 500 server exceptions manually when in development mode. - // Instead, re-throw the exception so it can be handled by the DeveloperExceptionPageMiddleware. - // However, do not use the DeveloperExceptionPageMiddleware when the stack trace should be ignored, - // because it will log the stack trace when it handles the exception. - if (statusCode == 500 && !ignoreStackTrace && _hostEnvironment.IsDevelopment()) - { - throw; - } - - await ErrorHandler(requestInnerEx, httpContext, statusCode, urlToLog, ignoreStackTrace).ConfigureAwait(false); + httpRes.Headers.Add(key, value); } - catch (Exception handlerException) - { - var aggregateEx = new AggregateException("Error while handling request exception", requestEx, handlerException); - _logger.LogError(aggregateEx, "Error while handling exception in response to {Url}", urlToLog); - if (_hostEnvironment.IsDevelopment()) - { - throw aggregateEx; - } - } + httpRes.ContentType = "text/plain"; + await httpRes.WriteAsync(string.Empty, cancellationToken).ConfigureAwait(false); + return; } - finally + + if (string.Equals(localPath, _baseUrlPrefix + "/", StringComparison.OrdinalIgnoreCase) + || string.Equals(localPath, _baseUrlPrefix, StringComparison.OrdinalIgnoreCase) + || string.Equals(localPath, "/", StringComparison.OrdinalIgnoreCase) + || string.IsNullOrEmpty(localPath) + || !localPath.StartsWith(_baseUrlPrefix, StringComparison.OrdinalIgnoreCase)) { - if (httpRes.StatusCode >= 500) - { - _logger.LogDebug("Sending HTTP Response 500 in response to {Url}", urlToLog); - } + // Always redirect back to the default path if the base prefix is invalid or missing + _logger.LogDebug("Normalizing a URL at {0}", localPath); + httpRes.Redirect(_baseUrlPrefix + "/" + _defaultRedirectPath); + return; + } - stopWatch.Stop(); - var elapsed = stopWatch.Elapsed; - if (elapsed.TotalMilliseconds > 500) + if (!string.IsNullOrEmpty(GlobalResponse)) + { + // We don't want the address pings in ApplicationHost to fail + if (localPath.IndexOf("system/ping", StringComparison.OrdinalIgnoreCase) == -1) { - _logger.LogWarning("HTTP Response {StatusCode} to {RemoteIp}. Time (slow): {Elapsed:g}. {Url}", httpRes.StatusCode, remoteIp, elapsed, urlToLog); + httpRes.StatusCode = 503; + httpRes.ContentType = "text/html"; + await httpRes.WriteAsync(GlobalResponse, cancellationToken).ConfigureAwait(false); + return; } } + + await next().ConfigureAwait(false); } private async Task WebSocketRequestHandler(HttpContext context) @@ -508,21 +279,6 @@ namespace Emby.Server.Implementations.HttpServer return headers; } - private void RedirectToSecureUrl(HttpResponse httpRes, string url) - { - if (Uri.TryCreate(url, UriKind.Absolute, out Uri uri)) - { - var builder = new UriBuilder(uri) - { - Port = _config.Configuration.PublicHttpsPort, - Scheme = "https" - }; - url = builder.Uri.ToString(); - } - - httpRes.Redirect(url); - } - /// <summary> /// Adds the rest handlers. /// </summary> diff --git a/Jellyfin.Server/Startup.cs b/Jellyfin.Server/Startup.cs index cbc1c040c..81243902a 100644 --- a/Jellyfin.Server/Startup.cs +++ b/Jellyfin.Server/Startup.cs @@ -23,17 +23,19 @@ namespace Jellyfin.Server public class Startup { private readonly IServerConfigurationManager _serverConfigurationManager; - private readonly IApplicationHost _applicationHost; + private readonly IServerApplicationHost _serverApplicationHost; /// <summary> /// Initializes a new instance of the <see cref="Startup" /> class. /// </summary> /// <param name="serverConfigurationManager">The server configuration manager.</param> - /// <param name="applicationHost">The application host.</param> - public Startup(IServerConfigurationManager serverConfigurationManager, IApplicationHost applicationHost) + /// <param name="serverApplicationHost">The server application host.</param> + public Startup( + IServerConfigurationManager serverConfigurationManager, + IServerApplicationHost serverApplicationHost) { _serverConfigurationManager = serverConfigurationManager; - _applicationHost = applicationHost; + _serverApplicationHost = serverApplicationHost; } /// <summary> @@ -44,7 +46,9 @@ namespace Jellyfin.Server { services.AddResponseCompression(); services.AddHttpContextAccessor(); - services.AddJellyfinApi(_serverConfigurationManager.Configuration.BaseUrl.TrimStart('/'), _applicationHost.GetApiPluginAssemblies()); + services.AddJellyfinApi( + _serverConfigurationManager.Configuration.BaseUrl.TrimStart('/'), + _serverApplicationHost.GetApiPluginAssemblies()); services.AddJellyfinApiSwagger(); @@ -53,7 +57,9 @@ namespace Jellyfin.Server services.AddJellyfinApiAuthorization(); - var productHeader = new ProductInfoHeaderValue(_applicationHost.Name.Replace(' ', '-'), _applicationHost.ApplicationVersionString); + var productHeader = new ProductInfoHeaderValue( + _serverApplicationHost.Name.Replace(' ', '-'), + _serverApplicationHost.ApplicationVersionString); services .AddHttpClient(NamedClient.Default, c => { @@ -64,7 +70,7 @@ namespace Jellyfin.Server services.AddHttpClient(NamedClient.MusicBrainz, c => { c.DefaultRequestHeaders.UserAgent.Add(productHeader); - c.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue($"({_applicationHost.ApplicationUserAgentAddress})")); + c.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue($"({_serverApplicationHost.ApplicationUserAgentAddress})")); }) .ConfigurePrimaryHttpMessageHandler(x => new DefaultHttpClientHandler()); } @@ -93,7 +99,11 @@ namespace Jellyfin.Server app.UseResponseCompression(); - // TODO app.UseMiddleware<WebSocketMiddleware>(); + if (_serverConfigurationManager.Configuration.RequireHttps + && _serverApplicationHost.ListenWithHttps) + { + app.UseHttpsRedirection(); + } app.UseAuthentication(); app.UseJellyfinApiSwagger(_serverConfigurationManager); @@ -106,6 +116,8 @@ namespace Jellyfin.Server app.UseHttpMetrics(); } + app.Use(serverApplicationHost.ExecuteHttpHandlerAsync); + app.UseEndpoints(endpoints => { endpoints.MapControllers(); @@ -115,8 +127,6 @@ namespace Jellyfin.Server } }); - app.Use(serverApplicationHost.ExecuteHttpHandlerAsync); - // Add type descriptor for legacy datetime parsing. TypeDescriptor.AddAttributes(typeof(DateTime?), new TypeConverterAttribute(typeof(DateTimeTypeConverter))); } diff --git a/MediaBrowser.Common/Extensions/HttpContextExtensions.cs b/MediaBrowser.Common/Extensions/HttpContextExtensions.cs index 86c3b3536..e0cf3f9ac 100644 --- a/MediaBrowser.Common/Extensions/HttpContextExtensions.cs +++ b/MediaBrowser.Common/Extensions/HttpContextExtensions.cs @@ -28,7 +28,7 @@ namespace MediaBrowser.Common.Extensions /// <returns>The remote caller IP address.</returns> public static string RemoteIp(this HttpRequest request) { - var cachedRemoteIp = request.HttpContext.Items["RemoteIp"].ToString(); + var cachedRemoteIp = request.HttpContext.Items["RemoteIp"]?.ToString(); if (!string.IsNullOrEmpty(cachedRemoteIp)) { return cachedRemoteIp; diff --git a/MediaBrowser.Controller/Net/IHttpServer.cs b/MediaBrowser.Controller/Net/IHttpServer.cs index 637dd2be3..6739f2fa6 100644 --- a/MediaBrowser.Controller/Net/IHttpServer.cs +++ b/MediaBrowser.Controller/Net/IHttpServer.cs @@ -35,9 +35,10 @@ namespace MediaBrowser.Controller.Net /// <summary> /// The HTTP request handler. /// </summary> - /// <param name="context"></param> - /// <returns></returns> - Task RequestHandler(HttpContext context); + /// <param name="context">The current HTTP context.</param> + /// <param name="next">The next middleware in the ASP.NET pipeline.</param> + /// <returns>The task.</returns> + Task RequestHandler(HttpContext context, Func<Task> next); /// <summary> /// Get the default CORS headers. -- cgit v1.2.3 From 571d0570f5560bde79d21c33173742f6a31e24cf Mon Sep 17 00:00:00 2001 From: Claus Vium <clausvium@gmail.com> Date: Thu, 3 Sep 2020 11:32:22 +0200 Subject: Kill HttpListenerHost --- Emby.Server.Implementations/ApplicationHost.cs | 19 +- .../ConfigurationOptions.cs | 2 +- .../HttpServer/HttpListenerHost.cs | 315 --------------------- .../HttpServer/WebSocketManager.cs | 102 +++++++ .../Session/SessionWebSocketListener.cs | 12 +- .../Extensions/ApiApplicationBuilderExtensions.cs | 61 ++++ .../Middleware/BaseUrlRedirectionMiddleware.cs | 62 ++++ .../Middleware/CorsOptionsResponseMiddleware.cs | 69 +++++ .../IpBasedAccessValidationMiddleware.cs | 76 +++++ .../Middleware/LanFilteringMiddleware.cs | 76 +++++ .../Middleware/ServerStartupMessageMiddleware.cs | 38 +++ .../Middleware/WebSocketHandlerMiddleware.cs | 40 +++ Jellyfin.Server/Program.cs | 4 +- Jellyfin.Server/Startup.cs | 12 +- .../Extensions/ConfigurationExtensions.cs | 6 + MediaBrowser.Controller/IServerApplicationHost.cs | 3 +- MediaBrowser.Controller/Net/IHttpServer.cs | 50 ---- MediaBrowser.Controller/Net/IWebSocketManager.cs | 32 +++ 18 files changed, 589 insertions(+), 390 deletions(-) delete mode 100644 Emby.Server.Implementations/HttpServer/HttpListenerHost.cs create mode 100644 Emby.Server.Implementations/HttpServer/WebSocketManager.cs create mode 100644 Jellyfin.Server/Middleware/BaseUrlRedirectionMiddleware.cs create mode 100644 Jellyfin.Server/Middleware/CorsOptionsResponseMiddleware.cs create mode 100644 Jellyfin.Server/Middleware/IpBasedAccessValidationMiddleware.cs create mode 100644 Jellyfin.Server/Middleware/LanFilteringMiddleware.cs create mode 100644 Jellyfin.Server/Middleware/ServerStartupMessageMiddleware.cs create mode 100644 Jellyfin.Server/Middleware/WebSocketHandlerMiddleware.cs delete mode 100644 MediaBrowser.Controller/Net/IHttpServer.cs create mode 100644 MediaBrowser.Controller/Net/IWebSocketManager.cs (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index 5ed0ad415..c8af6b73a 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -96,12 +96,12 @@ using MediaBrowser.Providers.Manager; using MediaBrowser.Providers.Plugins.TheTvdb; using MediaBrowser.Providers.Subtitles; using MediaBrowser.XbmcMetadata.Providers; -using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Prometheus.DotNetRuntime; using OperatingSystem = MediaBrowser.Common.System.OperatingSystem; +using WebSocketManager = Emby.Server.Implementations.HttpServer.WebSocketManager; namespace Emby.Server.Implementations { @@ -122,9 +122,11 @@ namespace Emby.Server.Implementations private IMediaEncoder _mediaEncoder; private ISessionManager _sessionManager; - private IHttpServer _httpServer; + private IWebSocketManager _webSocketManager; private IHttpClient _httpClient; + private string[] _urlPrefixes; + /// <summary> /// Gets a value indicating whether this instance can self restart. /// </summary> @@ -444,7 +446,6 @@ namespace Emby.Server.Implementations Logger.LogInformation("Executed all pre-startup entry points in {Elapsed:g}", stopWatch.Elapsed); Logger.LogInformation("Core startup complete"); - _httpServer.GlobalResponse = null; stopWatch.Restart(); await Task.WhenAll(StartEntryPoints(entryPoints, false)).ConfigureAwait(false); @@ -500,9 +501,6 @@ namespace Emby.Server.Implementations RegisterServices(); } - public Task ExecuteHttpHandlerAsync(HttpContext context, Func<Task> next) - => _httpServer.RequestHandler(context, next); - /// <summary> /// Registers services/resources with the service collection that will be available via DI. /// </summary> @@ -577,7 +575,7 @@ namespace Emby.Server.Implementations ServiceCollection.AddSingleton<ISearchEngine, SearchEngine>(); - ServiceCollection.AddSingleton<IHttpServer, HttpListenerHost>(); + ServiceCollection.AddSingleton<IWebSocketManager, WebSocketManager>(); ServiceCollection.AddSingleton<IImageProcessor, ImageProcessor>(); @@ -650,7 +648,7 @@ namespace Emby.Server.Implementations _mediaEncoder = Resolve<IMediaEncoder>(); _sessionManager = Resolve<ISessionManager>(); - _httpServer = Resolve<IHttpServer>(); + _webSocketManager = Resolve<IWebSocketManager>(); _httpClient = Resolve<IHttpClient>(); ((AuthenticationRepository)Resolve<IAuthenticationRepository>()).Initialize(); @@ -771,7 +769,8 @@ namespace Emby.Server.Implementations .Where(i => i != null) .ToArray(); - _httpServer.Init(GetExports<IWebSocketListener>(), GetUrlPrefixes()); + _urlPrefixes = GetUrlPrefixes().ToArray(); + _webSocketManager.Init(GetExports<IWebSocketListener>()); Resolve<ILibraryManager>().AddParts( GetExports<IResolverIgnoreRule>(), @@ -937,7 +936,7 @@ namespace Emby.Server.Implementations } } - if (!_httpServer.UrlPrefixes.SequenceEqual(GetUrlPrefixes(), StringComparer.OrdinalIgnoreCase)) + if (!_urlPrefixes.SequenceEqual(GetUrlPrefixes(), StringComparer.OrdinalIgnoreCase)) { requiresRestart = true; } diff --git a/Emby.Server.Implementations/ConfigurationOptions.cs b/Emby.Server.Implementations/ConfigurationOptions.cs index 64ccff53b..fde6fa115 100644 --- a/Emby.Server.Implementations/ConfigurationOptions.cs +++ b/Emby.Server.Implementations/ConfigurationOptions.cs @@ -15,7 +15,7 @@ namespace Emby.Server.Implementations public static Dictionary<string, string> DefaultConfiguration => new Dictionary<string, string> { { HostWebClientKey, bool.TrueString }, - { HttpListenerHost.DefaultRedirectKey, "web/index.html" }, + { DefaultRedirectKey, "web/index.html" }, { FfmpegProbeSizeKey, "1G" }, { FfmpegAnalyzeDurationKey, "200M" }, { PlaylistsAllowDuplicatesKey, bool.TrueString }, diff --git a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs deleted file mode 100644 index 27369960b..000000000 --- a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs +++ /dev/null @@ -1,315 +0,0 @@ -#pragma warning disable CS1591 - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net.WebSockets; -using System.Threading.Tasks; -using Jellyfin.Data.Events; -using MediaBrowser.Common.Extensions; -using MediaBrowser.Common.Net; -using MediaBrowser.Controller.Configuration; -using MediaBrowser.Controller.Net; -using MediaBrowser.Model.Globalization; -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Primitives; - -namespace Emby.Server.Implementations.HttpServer -{ - public class HttpListenerHost : IHttpServer - { - /// <summary> - /// The key for a setting that specifies the default redirect path - /// to use for requests where the URL base prefix is invalid or missing. - /// </summary> - public const string DefaultRedirectKey = "HttpListenerHost:DefaultRedirectPath"; - - private readonly ILogger<HttpListenerHost> _logger; - private readonly ILoggerFactory _loggerFactory; - private readonly IServerConfigurationManager _config; - private readonly INetworkManager _networkManager; - private readonly string _defaultRedirectPath; - private readonly string _baseUrlPrefix; - - private IWebSocketListener[] _webSocketListeners = Array.Empty<IWebSocketListener>(); - private bool _disposed = false; - - public HttpListenerHost( - ILogger<HttpListenerHost> logger, - IServerConfigurationManager config, - IConfiguration configuration, - INetworkManager networkManager, - ILocalizationManager localizationManager, - ILoggerFactory loggerFactory) - { - _logger = logger; - _config = config; - _defaultRedirectPath = configuration[DefaultRedirectKey]; - _baseUrlPrefix = _config.Configuration.BaseUrl; - _networkManager = networkManager; - _loggerFactory = loggerFactory; - - Instance = this; - GlobalResponse = localizationManager.GetLocalizedString("StartupEmbyServerIsLoading"); - } - - public event EventHandler<GenericEventArgs<IWebSocketConnection>> WebSocketConnected; - - public static HttpListenerHost Instance { get; protected set; } - - public string[] UrlPrefixes { get; private set; } - - public string GlobalResponse { get; set; } - - private static string NormalizeConfiguredLocalAddress(string address) - { - var add = address.AsSpan().Trim('/'); - int index = add.IndexOf('/'); - if (index != -1) - { - add = add.Slice(index + 1); - } - - return add.TrimStart('/').ToString(); - } - - private bool ValidateHost(string host) - { - var hosts = _config - .Configuration - .LocalNetworkAddresses - .Select(NormalizeConfiguredLocalAddress) - .ToList(); - - if (hosts.Count == 0) - { - return true; - } - - host ??= string.Empty; - - if (_networkManager.IsInPrivateAddressSpace(host)) - { - hosts.Add("localhost"); - hosts.Add("127.0.0.1"); - - return hosts.Any(i => host.IndexOf(i, StringComparison.OrdinalIgnoreCase) != -1); - } - - return true; - } - - private bool ValidateRequest(string remoteIp, bool isLocal) - { - if (isLocal) - { - return true; - } - - if (_config.Configuration.EnableRemoteAccess) - { - var addressFilter = _config.Configuration.RemoteIPFilter.Where(i => !string.IsNullOrWhiteSpace(i)).ToArray(); - - if (addressFilter.Length > 0 && !_networkManager.IsInLocalNetwork(remoteIp)) - { - if (_config.Configuration.IsRemoteIPFilterBlacklist) - { - return !_networkManager.IsAddressInSubnets(remoteIp, addressFilter); - } - else - { - return _networkManager.IsAddressInSubnets(remoteIp, addressFilter); - } - } - } - else - { - if (!_networkManager.IsInLocalNetwork(remoteIp)) - { - return false; - } - } - - return true; - } - - /// <inheritdoc /> - public Task RequestHandler(HttpContext context, Func<Task> next) - { - if (context.WebSockets.IsWebSocketRequest) - { - return WebSocketRequestHandler(context); - } - - return HttpRequestHandler(context, next); - } - - /// <summary> - /// Overridable method that can be used to implement a custom handler. - /// </summary> - private async Task HttpRequestHandler(HttpContext httpContext, Func<Task> next) - { - var cancellationToken = httpContext.RequestAborted; - var httpRes = httpContext.Response; - var host = httpContext.Request.Host.ToString(); - var localPath = httpContext.Request.Path.ToString(); - string remoteIp = httpContext.Request.RemoteIp(); - - if (_disposed) - { - httpRes.StatusCode = 503; - httpRes.ContentType = "text/plain"; - await httpRes.WriteAsync("Server shutting down", cancellationToken).ConfigureAwait(false); - return; - } - - if (!ValidateHost(host)) - { - httpRes.StatusCode = 400; - httpRes.ContentType = "text/plain"; - await httpRes.WriteAsync("Invalid host", cancellationToken).ConfigureAwait(false); - return; - } - - if (!ValidateRequest(remoteIp, httpContext.Request.IsLocal())) - { - httpRes.StatusCode = 403; - httpRes.ContentType = "text/plain"; - await httpRes.WriteAsync("Forbidden", cancellationToken).ConfigureAwait(false); - return; - } - - if (string.Equals(httpContext.Request.Method, "OPTIONS", StringComparison.OrdinalIgnoreCase)) - { - httpRes.StatusCode = 200; - foreach (var (key, value) in GetDefaultCorsHeaders(httpContext)) - { - httpRes.Headers.Add(key, value); - } - - httpRes.ContentType = "text/plain"; - await httpRes.WriteAsync(string.Empty, cancellationToken).ConfigureAwait(false); - return; - } - - if (string.Equals(localPath, _baseUrlPrefix + "/", StringComparison.OrdinalIgnoreCase) - || string.Equals(localPath, _baseUrlPrefix, StringComparison.OrdinalIgnoreCase) - || string.Equals(localPath, "/", StringComparison.OrdinalIgnoreCase) - || string.IsNullOrEmpty(localPath) - || !localPath.StartsWith(_baseUrlPrefix, StringComparison.OrdinalIgnoreCase)) - { - // Always redirect back to the default path if the base prefix is invalid or missing - _logger.LogDebug("Normalizing a URL at {0}", localPath); - httpRes.Redirect(_baseUrlPrefix + "/" + _defaultRedirectPath); - return; - } - - if (!string.IsNullOrEmpty(GlobalResponse)) - { - // We don't want the address pings in ApplicationHost to fail - if (localPath.IndexOf("system/ping", StringComparison.OrdinalIgnoreCase) == -1) - { - httpRes.StatusCode = 503; - httpRes.ContentType = "text/html"; - await httpRes.WriteAsync(GlobalResponse, cancellationToken).ConfigureAwait(false); - return; - } - } - - await next().ConfigureAwait(false); - } - - private async Task WebSocketRequestHandler(HttpContext context) - { - if (_disposed) - { - return; - } - - try - { - _logger.LogInformation("WS {IP} request", context.Connection.RemoteIpAddress); - - WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync().ConfigureAwait(false); - - using var connection = new WebSocketConnection( - _loggerFactory.CreateLogger<WebSocketConnection>(), - webSocket, - context.Connection.RemoteIpAddress, - context.Request.Query) - { - OnReceive = ProcessWebSocketMessageReceived - }; - - WebSocketConnected?.Invoke(this, new GenericEventArgs<IWebSocketConnection>(connection)); - - await connection.ProcessAsync().ConfigureAwait(false); - _logger.LogInformation("WS {IP} closed", context.Connection.RemoteIpAddress); - } - catch (Exception ex) // Otherwise ASP.Net will ignore the exception - { - _logger.LogError(ex, "WS {IP} WebSocketRequestHandler error", context.Connection.RemoteIpAddress); - if (!context.Response.HasStarted) - { - context.Response.StatusCode = 500; - } - } - } - - /// <inheritdoc /> - public IDictionary<string, string> GetDefaultCorsHeaders(HttpContext httpContext) - { - var origin = httpContext.Request.Headers["Origin"]; - if (origin == StringValues.Empty) - { - origin = httpContext.Request.Headers["Host"]; - if (origin == StringValues.Empty) - { - origin = "*"; - } - } - - var headers = new Dictionary<string, string>(); - headers.Add("Access-Control-Allow-Origin", origin); - headers.Add("Access-Control-Allow-Credentials", "true"); - headers.Add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, PATCH, OPTIONS"); - headers.Add("Access-Control-Allow-Headers", "Content-Type, Authorization, Range, X-MediaBrowser-Token, X-Emby-Authorization, Cookie"); - return headers; - } - - /// <summary> - /// Adds the rest handlers. - /// </summary> - /// <param name="listeners">The web socket listeners.</param> - /// <param name="urlPrefixes">The URL prefixes. See <see cref="UrlPrefixes"/>.</param> - public void Init(IEnumerable<IWebSocketListener> listeners, IEnumerable<string> urlPrefixes) - { - _webSocketListeners = listeners.ToArray(); - UrlPrefixes = urlPrefixes.ToArray(); - } - - /// <summary> - /// Processes the web socket message received. - /// </summary> - /// <param name="result">The result.</param> - private Task ProcessWebSocketMessageReceived(WebSocketMessageInfo result) - { - if (_disposed) - { - return Task.CompletedTask; - } - - IEnumerable<Task> GetTasks() - { - foreach (var x in _webSocketListeners) - { - yield return x.ProcessMessageAsync(result); - } - } - - return Task.WhenAll(GetTasks()); - } - } -} diff --git a/Emby.Server.Implementations/HttpServer/WebSocketManager.cs b/Emby.Server.Implementations/HttpServer/WebSocketManager.cs new file mode 100644 index 000000000..89c1b7ea0 --- /dev/null +++ b/Emby.Server.Implementations/HttpServer/WebSocketManager.cs @@ -0,0 +1,102 @@ +#pragma warning disable CS1591 + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.WebSockets; +using System.Threading.Tasks; +using Jellyfin.Data.Events; +using MediaBrowser.Controller.Net; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Logging; + +namespace Emby.Server.Implementations.HttpServer +{ + public class WebSocketManager : IWebSocketManager + { + private readonly ILogger<WebSocketManager> _logger; + private readonly ILoggerFactory _loggerFactory; + + private IWebSocketListener[] _webSocketListeners = Array.Empty<IWebSocketListener>(); + private bool _disposed = false; + + public WebSocketManager( + ILogger<WebSocketManager> logger, + ILoggerFactory loggerFactory) + { + _logger = logger; + _loggerFactory = loggerFactory; + } + + public event EventHandler<GenericEventArgs<IWebSocketConnection>> WebSocketConnected; + + /// <inheritdoc /> + public async Task WebSocketRequestHandler(HttpContext context) + { + if (_disposed) + { + return; + } + + try + { + _logger.LogInformation("WS {IP} request", context.Connection.RemoteIpAddress); + + WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync().ConfigureAwait(false); + + using var connection = new WebSocketConnection( + _loggerFactory.CreateLogger<WebSocketConnection>(), + webSocket, + context.Connection.RemoteIpAddress, + context.Request.Query) + { + OnReceive = ProcessWebSocketMessageReceived + }; + + WebSocketConnected?.Invoke(this, new GenericEventArgs<IWebSocketConnection>(connection)); + + await connection.ProcessAsync().ConfigureAwait(false); + _logger.LogInformation("WS {IP} closed", context.Connection.RemoteIpAddress); + } + catch (Exception ex) // Otherwise ASP.Net will ignore the exception + { + _logger.LogError(ex, "WS {IP} WebSocketRequestHandler error", context.Connection.RemoteIpAddress); + if (!context.Response.HasStarted) + { + context.Response.StatusCode = 500; + } + } + } + + /// <summary> + /// Adds the rest handlers. + /// </summary> + /// <param name="listeners">The web socket listeners.</param> + public void Init(IEnumerable<IWebSocketListener> listeners) + { + _webSocketListeners = listeners.ToArray(); + } + + /// <summary> + /// Processes the web socket message received. + /// </summary> + /// <param name="result">The result.</param> + private Task ProcessWebSocketMessageReceived(WebSocketMessageInfo result) + { + if (_disposed) + { + return Task.CompletedTask; + } + + IEnumerable<Task> GetTasks() + { + foreach (var x in _webSocketListeners) + { + yield return x.ProcessMessageAsync(result); + } + } + + return Task.WhenAll(GetTasks()); + } + } +} diff --git a/Emby.Server.Implementations/Session/SessionWebSocketListener.cs b/Emby.Server.Implementations/Session/SessionWebSocketListener.cs index 1da7a6473..15c2af220 100644 --- a/Emby.Server.Implementations/Session/SessionWebSocketListener.cs +++ b/Emby.Server.Implementations/Session/SessionWebSocketListener.cs @@ -44,7 +44,7 @@ namespace Emby.Server.Implementations.Session private readonly ILogger<SessionWebSocketListener> _logger; private readonly ILoggerFactory _loggerFactory; - private readonly IHttpServer _httpServer; + private readonly IWebSocketManager _webSocketManager; /// <summary> /// The KeepAlive cancellation token. @@ -72,19 +72,19 @@ namespace Emby.Server.Implementations.Session /// <param name="logger">The logger.</param> /// <param name="sessionManager">The session manager.</param> /// <param name="loggerFactory">The logger factory.</param> - /// <param name="httpServer">The HTTP server.</param> + /// <param name="webSocketManager">The HTTP server.</param> public SessionWebSocketListener( ILogger<SessionWebSocketListener> logger, ISessionManager sessionManager, ILoggerFactory loggerFactory, - IHttpServer httpServer) + IWebSocketManager webSocketManager) { _logger = logger; _sessionManager = sessionManager; _loggerFactory = loggerFactory; - _httpServer = httpServer; + _webSocketManager = webSocketManager; - httpServer.WebSocketConnected += OnServerManagerWebSocketConnected; + webSocketManager.WebSocketConnected += OnServerManagerWebSocketConnected; } private async void OnServerManagerWebSocketConnected(object sender, GenericEventArgs<IWebSocketConnection> e) @@ -121,7 +121,7 @@ namespace Emby.Server.Implementations.Session /// <inheritdoc /> public void Dispose() { - _httpServer.WebSocketConnected -= OnServerManagerWebSocketConnected; + _webSocketManager.WebSocketConnected -= OnServerManagerWebSocketConnected; StopKeepAlive(); } diff --git a/Jellyfin.Server/Extensions/ApiApplicationBuilderExtensions.cs b/Jellyfin.Server/Extensions/ApiApplicationBuilderExtensions.cs index 745567703..33a8d7532 100644 --- a/Jellyfin.Server/Extensions/ApiApplicationBuilderExtensions.cs +++ b/Jellyfin.Server/Extensions/ApiApplicationBuilderExtensions.cs @@ -1,3 +1,4 @@ +using Jellyfin.Server.Middleware; using MediaBrowser.Controller.Configuration; using Microsoft.AspNetCore.Builder; @@ -46,5 +47,65 @@ namespace Jellyfin.Server.Extensions c.RoutePrefix = $"{baseUrl}api-docs/redoc"; }); } + + /// <summary> + /// Adds IP based access validation to the application pipeline. + /// </summary> + /// <param name="appBuilder">The application builder.</param> + /// <returns>The updated application builder.</returns> + public static IApplicationBuilder UseIpBasedAccessValidation(this IApplicationBuilder appBuilder) + { + return appBuilder.UseMiddleware<IpBasedAccessValidationMiddleware>(); + } + + /// <summary> + /// Adds LAN based access filtering to the application pipeline. + /// </summary> + /// <param name="appBuilder">The application builder.</param> + /// <returns>The updated application builder.</returns> + public static IApplicationBuilder UseLanFiltering(this IApplicationBuilder appBuilder) + { + return appBuilder.UseMiddleware<LanFilteringMiddleware>(); + } + + /// <summary> + /// Adds CORS OPTIONS request handling to the application pipeline. + /// </summary> + /// <param name="appBuilder">The application builder.</param> + /// <returns>The updated application builder.</returns> + public static IApplicationBuilder UseCorsOptionsResponse(this IApplicationBuilder appBuilder) + { + return appBuilder.UseMiddleware<CorsOptionsResponseMiddleware>(); + } + + /// <summary> + /// Adds base url redirection to the application pipeline. + /// </summary> + /// <param name="appBuilder">The application builder.</param> + /// <returns>The updated application builder.</returns> + public static IApplicationBuilder UseBaseUrlRedirection(this IApplicationBuilder appBuilder) + { + return appBuilder.UseMiddleware<BaseUrlRedirectionMiddleware>(); + } + + /// <summary> + /// Adds a custom message during server startup to the application pipeline. + /// </summary> + /// <param name="appBuilder">The application builder.</param> + /// <returns>The updated application builder.</returns> + public static IApplicationBuilder UseServerStartupMessage(this IApplicationBuilder appBuilder) + { + return appBuilder.UseMiddleware<ServerStartupMessageMiddleware>(); + } + + /// <summary> + /// Adds a WebSocket request handler to the application pipeline. + /// </summary> + /// <param name="appBuilder">The application builder.</param> + /// <returns>The updated application builder.</returns> + public static IApplicationBuilder UseWebSocketHandler(this IApplicationBuilder appBuilder) + { + return appBuilder.UseMiddleware<WebSocketHandlerMiddleware>(); + } } } diff --git a/Jellyfin.Server/Middleware/BaseUrlRedirectionMiddleware.cs b/Jellyfin.Server/Middleware/BaseUrlRedirectionMiddleware.cs new file mode 100644 index 000000000..9316737bd --- /dev/null +++ b/Jellyfin.Server/Middleware/BaseUrlRedirectionMiddleware.cs @@ -0,0 +1,62 @@ +using System; +using System.Threading.Tasks; +using MediaBrowser.Controller.Configuration; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; +using ConfigurationExtensions = MediaBrowser.Controller.Extensions.ConfigurationExtensions; + +namespace Jellyfin.Server.Middleware +{ + /// <summary> + /// Redirect requests without baseurl prefix to the baseurl prefixed URL. + /// </summary> + public class BaseUrlRedirectionMiddleware + { + private readonly RequestDelegate _next; + private readonly ILogger<BaseUrlRedirectionMiddleware> _logger; + private readonly IConfiguration _configuration; + + /// <summary> + /// Initializes a new instance of the <see cref="BaseUrlRedirectionMiddleware"/> class. + /// </summary> + /// <param name="next">The next delegate in the pipeline.</param> + /// <param name="logger">The logger.</param> + /// <param name="configuration">The application configuration.</param> + public BaseUrlRedirectionMiddleware( + RequestDelegate next, + ILogger<BaseUrlRedirectionMiddleware> logger, + IConfiguration configuration) + { + _next = next; + _logger = logger; + _configuration = configuration; + } + + /// <summary> + /// Executes the middleware action. + /// </summary> + /// <param name="httpContext">The current HTTP context.</param> + /// <param name="serverConfigurationManager">The server configuration manager.</param> + /// <returns>The async task.</returns> + public async Task Invoke(HttpContext httpContext, IServerConfigurationManager serverConfigurationManager) + { + var localPath = httpContext.Request.Path.ToString(); + var baseUrlPrefix = serverConfigurationManager.Configuration.BaseUrl; + + if (string.Equals(localPath, baseUrlPrefix + "/", StringComparison.OrdinalIgnoreCase) + || string.Equals(localPath, baseUrlPrefix, StringComparison.OrdinalIgnoreCase) + || string.Equals(localPath, "/", StringComparison.OrdinalIgnoreCase) + || string.IsNullOrEmpty(localPath) + || !localPath.StartsWith(baseUrlPrefix, StringComparison.OrdinalIgnoreCase)) + { + // Always redirect back to the default path if the base prefix is invalid or missing + _logger.LogDebug("Normalizing an URL at {LocalPath}", localPath); + httpContext.Response.Redirect(baseUrlPrefix + "/" + _configuration[ConfigurationExtensions.DefaultRedirectKey]); + return; + } + + await _next(httpContext).ConfigureAwait(false); + } + } +} diff --git a/Jellyfin.Server/Middleware/CorsOptionsResponseMiddleware.cs b/Jellyfin.Server/Middleware/CorsOptionsResponseMiddleware.cs new file mode 100644 index 000000000..8214f8907 --- /dev/null +++ b/Jellyfin.Server/Middleware/CorsOptionsResponseMiddleware.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; +using System.Net.Mime; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Primitives; + +namespace Jellyfin.Server.Middleware +{ + /// <summary> + /// Middleware for handling OPTIONS requests. + /// </summary> + public class CorsOptionsResponseMiddleware + { + private readonly RequestDelegate _next; + + /// <summary> + /// Initializes a new instance of the <see cref="CorsOptionsResponseMiddleware"/> class. + /// </summary> + /// <param name="next">The next delegate in the pipeline.</param> + public CorsOptionsResponseMiddleware(RequestDelegate next) + { + _next = next; + } + + /// <summary> + /// Executes the middleware action. + /// </summary> + /// <param name="httpContext">The current HTTP context.</param> + /// <returns>The async task.</returns> + public async Task Invoke(HttpContext httpContext) + { + if (string.Equals(httpContext.Request.Method, HttpMethods.Options, StringComparison.OrdinalIgnoreCase)) + { + httpContext.Response.StatusCode = 200; + foreach (var (key, value) in GetDefaultCorsHeaders(httpContext)) + { + httpContext.Response.Headers.Add(key, value); + } + + httpContext.Response.ContentType = MediaTypeNames.Text.Plain; + await httpContext.Response.WriteAsync(string.Empty, httpContext.RequestAborted).ConfigureAwait(false); + return; + } + + await _next(httpContext).ConfigureAwait(false); + } + + private static IDictionary<string, string> GetDefaultCorsHeaders(HttpContext httpContext) + { + var origin = httpContext.Request.Headers["Origin"]; + if (origin == StringValues.Empty) + { + origin = httpContext.Request.Headers["Host"]; + if (origin == StringValues.Empty) + { + origin = "*"; + } + } + + var headers = new Dictionary<string, string>(); + headers.Add("Access-Control-Allow-Origin", origin); + headers.Add("Access-Control-Allow-Credentials", "true"); + headers.Add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, PATCH, OPTIONS"); + headers.Add("Access-Control-Allow-Headers", "Content-Type, Authorization, Range, X-MediaBrowser-Token, X-Emby-Authorization, Cookie"); + return headers; + } + } +} diff --git a/Jellyfin.Server/Middleware/IpBasedAccessValidationMiddleware.cs b/Jellyfin.Server/Middleware/IpBasedAccessValidationMiddleware.cs new file mode 100644 index 000000000..59b5fb1ed --- /dev/null +++ b/Jellyfin.Server/Middleware/IpBasedAccessValidationMiddleware.cs @@ -0,0 +1,76 @@ +using System.Linq; +using System.Threading.Tasks; +using MediaBrowser.Common.Extensions; +using MediaBrowser.Common.Net; +using MediaBrowser.Controller.Configuration; +using Microsoft.AspNetCore.Http; + +namespace Jellyfin.Server.Middleware +{ + /// <summary> + /// Validates the IP of requests coming from local networks wrt. remote access. + /// </summary> + public class IpBasedAccessValidationMiddleware + { + private readonly RequestDelegate _next; + + /// <summary> + /// Initializes a new instance of the <see cref="IpBasedAccessValidationMiddleware"/> class. + /// </summary> + /// <param name="next">The next delegate in the pipeline.</param> + public IpBasedAccessValidationMiddleware(RequestDelegate next) + { + _next = next; + } + + /// <summary> + /// Executes the middleware action. + /// </summary> + /// <param name="httpContext">The current HTTP context.</param> + /// <param name="networkManager">The network manager.</param> + /// <param name="serverConfigurationManager">The server configuration manager.</param> + /// <returns>The async task.</returns> + public async Task Invoke(HttpContext httpContext, INetworkManager networkManager, IServerConfigurationManager serverConfigurationManager) + { + if (httpContext.Request.IsLocal()) + { + await _next(httpContext).ConfigureAwait(false); + return; + } + + var remoteIp = httpContext.Request.RemoteIp(); + + if (serverConfigurationManager.Configuration.EnableRemoteAccess) + { + var addressFilter = serverConfigurationManager.Configuration.RemoteIPFilter.Where(i => !string.IsNullOrWhiteSpace(i)).ToArray(); + + if (addressFilter.Length > 0 && !networkManager.IsInLocalNetwork(remoteIp)) + { + if (serverConfigurationManager.Configuration.IsRemoteIPFilterBlacklist) + { + if (networkManager.IsAddressInSubnets(remoteIp, addressFilter)) + { + return; + } + } + else + { + if (!networkManager.IsAddressInSubnets(remoteIp, addressFilter)) + { + return; + } + } + } + } + else + { + if (!networkManager.IsInLocalNetwork(remoteIp)) + { + return; + } + } + + await _next(httpContext).ConfigureAwait(false); + } + } +} diff --git a/Jellyfin.Server/Middleware/LanFilteringMiddleware.cs b/Jellyfin.Server/Middleware/LanFilteringMiddleware.cs new file mode 100644 index 000000000..9d795145a --- /dev/null +++ b/Jellyfin.Server/Middleware/LanFilteringMiddleware.cs @@ -0,0 +1,76 @@ +using System; +using System.Linq; +using System.Threading.Tasks; +using MediaBrowser.Common.Net; +using MediaBrowser.Controller.Configuration; +using Microsoft.AspNetCore.Http; + +namespace Jellyfin.Server.Middleware +{ + /// <summary> + /// Validates the LAN host IP based on application configuration. + /// </summary> + public class LanFilteringMiddleware + { + private readonly RequestDelegate _next; + + /// <summary> + /// Initializes a new instance of the <see cref="LanFilteringMiddleware"/> class. + /// </summary> + /// <param name="next">The next delegate in the pipeline.</param> + public LanFilteringMiddleware(RequestDelegate next) + { + _next = next; + } + + /// <summary> + /// Executes the middleware action. + /// </summary> + /// <param name="httpContext">The current HTTP context.</param> + /// <param name="networkManager">The network manager.</param> + /// <param name="serverConfigurationManager">The server configuration manager.</param> + /// <returns>The async task.</returns> + public async Task Invoke(HttpContext httpContext, INetworkManager networkManager, IServerConfigurationManager serverConfigurationManager) + { + var currentHost = httpContext.Request.Host.ToString(); + var hosts = serverConfigurationManager + .Configuration + .LocalNetworkAddresses + .Select(NormalizeConfiguredLocalAddress) + .ToList(); + + if (hosts.Count == 0) + { + await _next(httpContext).ConfigureAwait(false); + return; + } + + currentHost ??= string.Empty; + + if (networkManager.IsInPrivateAddressSpace(currentHost)) + { + hosts.Add("localhost"); + hosts.Add("127.0.0.1"); + + if (hosts.All(i => currentHost.IndexOf(i, StringComparison.OrdinalIgnoreCase) == -1)) + { + return; + } + } + + await _next(httpContext).ConfigureAwait(false); + } + + private static string NormalizeConfiguredLocalAddress(string address) + { + var add = address.AsSpan().Trim('/'); + int index = add.IndexOf('/'); + if (index != -1) + { + add = add.Slice(index + 1); + } + + return add.TrimStart('/').ToString(); + } + } +} diff --git a/Jellyfin.Server/Middleware/ServerStartupMessageMiddleware.cs b/Jellyfin.Server/Middleware/ServerStartupMessageMiddleware.cs new file mode 100644 index 000000000..4f347d6d3 --- /dev/null +++ b/Jellyfin.Server/Middleware/ServerStartupMessageMiddleware.cs @@ -0,0 +1,38 @@ +using System.Net.Mime; +using System.Threading.Tasks; +using MediaBrowser.Model.Globalization; +using Microsoft.AspNetCore.Http; + +namespace Jellyfin.Server.Middleware +{ + /// <summary> + /// Shows a custom message during server startup. + /// </summary> + public class ServerStartupMessageMiddleware + { + private readonly RequestDelegate _next; + + /// <summary> + /// Initializes a new instance of the <see cref="ServerStartupMessageMiddleware"/> class. + /// </summary> + /// <param name="next">The next delegate in the pipeline.</param> + public ServerStartupMessageMiddleware(RequestDelegate next) + { + _next = next; + } + + /// <summary> + /// Executes the middleware action. + /// </summary> + /// <param name="httpContext">The current HTTP context.</param> + /// <param name="localizationManager">The localization manager.</param> + /// <returns>The async task.</returns> + public async Task Invoke(HttpContext httpContext, ILocalizationManager localizationManager) + { + var message = localizationManager.GetLocalizedString("StartupEmbyServerIsLoading"); + httpContext.Response.StatusCode = StatusCodes.Status503ServiceUnavailable; + httpContext.Response.ContentType = MediaTypeNames.Text.Html; + await httpContext.Response.WriteAsync(message, httpContext.RequestAborted).ConfigureAwait(false); + } + } +} diff --git a/Jellyfin.Server/Middleware/WebSocketHandlerMiddleware.cs b/Jellyfin.Server/Middleware/WebSocketHandlerMiddleware.cs new file mode 100644 index 000000000..b7a5d2b34 --- /dev/null +++ b/Jellyfin.Server/Middleware/WebSocketHandlerMiddleware.cs @@ -0,0 +1,40 @@ +using System.Threading.Tasks; +using MediaBrowser.Controller.Net; +using Microsoft.AspNetCore.Http; + +namespace Jellyfin.Server.Middleware +{ + /// <summary> + /// Handles WebSocket requests. + /// </summary> + public class WebSocketHandlerMiddleware + { + private readonly RequestDelegate _next; + + /// <summary> + /// Initializes a new instance of the <see cref="WebSocketHandlerMiddleware"/> class. + /// </summary> + /// <param name="next">The next delegate in the pipeline.</param> + public WebSocketHandlerMiddleware(RequestDelegate next) + { + _next = next; + } + + /// <summary> + /// Executes the middleware action. + /// </summary> + /// <param name="httpContext">The current HTTP context.</param> + /// <param name="webSocketManager">The WebSocket connection manager.</param> + /// <returns>The async task.</returns> + public async Task Invoke(HttpContext httpContext, IWebSocketManager webSocketManager) + { + if (!httpContext.WebSockets.IsWebSocketRequest) + { + await _next(httpContext).ConfigureAwait(false); + return; + } + + await webSocketManager.WebSocketRequestHandler(httpContext).ConfigureAwait(false); + } + } +} diff --git a/Jellyfin.Server/Program.cs b/Jellyfin.Server/Program.cs index 14cc5f4c2..b9a90f9db 100644 --- a/Jellyfin.Server/Program.cs +++ b/Jellyfin.Server/Program.cs @@ -11,7 +11,6 @@ using System.Threading; using System.Threading.Tasks; using CommandLine; using Emby.Server.Implementations; -using Emby.Server.Implementations.HttpServer; using Emby.Server.Implementations.IO; using Emby.Server.Implementations.Networking; using Jellyfin.Api.Controllers; @@ -28,6 +27,7 @@ using Microsoft.Extensions.Logging.Abstractions; using Serilog; using Serilog.Extensions.Logging; using SQLitePCL; +using ConfigurationExtensions = MediaBrowser.Controller.Extensions.ConfigurationExtensions; using ILogger = Microsoft.Extensions.Logging.ILogger; namespace Jellyfin.Server @@ -594,7 +594,7 @@ namespace Jellyfin.Server var inMemoryDefaultConfig = ConfigurationOptions.DefaultConfiguration; if (startupConfig != null && !startupConfig.HostWebClient()) { - inMemoryDefaultConfig[HttpListenerHost.DefaultRedirectKey] = "api-docs/swagger"; + inMemoryDefaultConfig[ConfigurationExtensions.DefaultRedirectKey] = "api-docs/swagger"; } return config diff --git a/Jellyfin.Server/Startup.cs b/Jellyfin.Server/Startup.cs index 9316ab79e..80f679420 100644 --- a/Jellyfin.Server/Startup.cs +++ b/Jellyfin.Server/Startup.cs @@ -84,11 +84,9 @@ namespace Jellyfin.Server /// </summary> /// <param name="app">The application builder.</param> /// <param name="env">The webhost environment.</param> - /// <param name="serverApplicationHost">The server application host.</param> public void Configure( IApplicationBuilder app, - IWebHostEnvironment env, - IServerApplicationHost serverApplicationHost) + IWebHostEnvironment env) { if (env.IsDevelopment()) { @@ -120,7 +118,11 @@ namespace Jellyfin.Server app.UseHttpMetrics(); } - app.Use(serverApplicationHost.ExecuteHttpHandlerAsync); + app.UseLanFiltering(); + app.UseIpBasedAccessValidation(); + app.UseCorsOptionsResponse(); + app.UseBaseUrlRedirection(); + app.UseWebSocketHandler(); app.UseEndpoints(endpoints => { @@ -131,6 +133,8 @@ namespace Jellyfin.Server } }); + app.UseServerStartupMessage(); + // Add type descriptor for legacy datetime parsing. TypeDescriptor.AddAttributes(typeof(DateTime?), new TypeConverterAttribute(typeof(DateTimeTypeConverter))); } diff --git a/MediaBrowser.Controller/Extensions/ConfigurationExtensions.cs b/MediaBrowser.Controller/Extensions/ConfigurationExtensions.cs index 4c2209b67..f9285c768 100644 --- a/MediaBrowser.Controller/Extensions/ConfigurationExtensions.cs +++ b/MediaBrowser.Controller/Extensions/ConfigurationExtensions.cs @@ -8,6 +8,12 @@ namespace MediaBrowser.Controller.Extensions /// </summary> public static class ConfigurationExtensions { + /// <summary> + /// The key for a setting that specifies the default redirect path + /// to use for requests where the URL base prefix is invalid or missing.. + /// </summary> + public const string DefaultRedirectKey = "DefaultRedirectPath"; + /// <summary> /// The key for a setting that indicates whether the application should host web client content. /// </summary> diff --git a/MediaBrowser.Controller/IServerApplicationHost.cs b/MediaBrowser.Controller/IServerApplicationHost.cs index 39b896c0f..d482c19d9 100644 --- a/MediaBrowser.Controller/IServerApplicationHost.cs +++ b/MediaBrowser.Controller/IServerApplicationHost.cs @@ -117,8 +117,7 @@ namespace MediaBrowser.Controller IEnumerable<WakeOnLanInfo> GetWakeOnLanInfo(); string ExpandVirtualPath(string path); - string ReverseVirtualPath(string path); - Task ExecuteHttpHandlerAsync(HttpContext context, Func<Task> next); + string ReverseVirtualPath(string path); } } diff --git a/MediaBrowser.Controller/Net/IHttpServer.cs b/MediaBrowser.Controller/Net/IHttpServer.cs deleted file mode 100644 index 6739f2fa6..000000000 --- a/MediaBrowser.Controller/Net/IHttpServer.cs +++ /dev/null @@ -1,50 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Threading.Tasks; -using Jellyfin.Data.Events; -using Microsoft.AspNetCore.Http; - -namespace MediaBrowser.Controller.Net -{ - /// <summary> - /// Interface IHttpServer. - /// </summary> - public interface IHttpServer - { - /// <summary> - /// Gets the URL prefix. - /// </summary> - /// <value>The URL prefix.</value> - string[] UrlPrefixes { get; } - - /// <summary> - /// Occurs when [web socket connected]. - /// </summary> - event EventHandler<GenericEventArgs<IWebSocketConnection>> WebSocketConnected; - - /// <summary> - /// Inits this instance. - /// </summary> - void Init(IEnumerable<IWebSocketListener> listener, IEnumerable<string> urlPrefixes); - - /// <summary> - /// If set, all requests will respond with this message. - /// </summary> - string GlobalResponse { get; set; } - - /// <summary> - /// The HTTP request handler. - /// </summary> - /// <param name="context">The current HTTP context.</param> - /// <param name="next">The next middleware in the ASP.NET pipeline.</param> - /// <returns>The task.</returns> - Task RequestHandler(HttpContext context, Func<Task> next); - - /// <summary> - /// Get the default CORS headers. - /// </summary> - /// <param name="httpContext">The HTTP context of the current request.</param> - /// <returns>The default CORS headers for the context.</returns> - IDictionary<string, string> GetDefaultCorsHeaders(HttpContext httpContext); - } -} diff --git a/MediaBrowser.Controller/Net/IWebSocketManager.cs b/MediaBrowser.Controller/Net/IWebSocketManager.cs new file mode 100644 index 000000000..e9f00ae88 --- /dev/null +++ b/MediaBrowser.Controller/Net/IWebSocketManager.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Jellyfin.Data.Events; +using Microsoft.AspNetCore.Http; + +namespace MediaBrowser.Controller.Net +{ + /// <summary> + /// Interface IHttpServer. + /// </summary> + public interface IWebSocketManager + { + /// <summary> + /// Occurs when [web socket connected]. + /// </summary> + event EventHandler<GenericEventArgs<IWebSocketConnection>> WebSocketConnected; + + /// <summary> + /// Inits this instance. + /// </summary> + /// <param name="listeners">The websocket listeners.</param> + void Init(IEnumerable<IWebSocketListener> listeners); + + /// <summary> + /// The HTTP request handler. + /// </summary> + /// <param name="context">The current HTTP context.</param> + /// <returns>The task.</returns> + Task WebSocketRequestHandler(HttpContext context); + } +} -- cgit v1.2.3 From 2f79c3095bb742136ff83141f42e344b33c3a45f Mon Sep 17 00:00:00 2001 From: Claus Vium <clausvium@gmail.com> Date: Thu, 3 Sep 2020 11:54:38 +0200 Subject: Fix startup message --- Emby.Server.Implementations/ApplicationHost.cs | 4 +++- .../Middleware/ServerStartupMessageMiddleware.cs | 13 ++++++++++++- Jellyfin.Server/Startup.cs | 3 +-- MediaBrowser.Controller/IServerApplicationHost.cs | 2 ++ 4 files changed, 18 insertions(+), 4 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index c8af6b73a..8e9a581ea 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -132,6 +132,8 @@ namespace Emby.Server.Implementations /// </summary> public bool CanSelfRestart => _startupOptions.RestartPath != null; + public bool CoreStartupHasCompleted { get; private set; } + public virtual bool CanLaunchWebBrowser { get @@ -446,7 +448,7 @@ namespace Emby.Server.Implementations Logger.LogInformation("Executed all pre-startup entry points in {Elapsed:g}", stopWatch.Elapsed); Logger.LogInformation("Core startup complete"); - + CoreStartupHasCompleted = true; stopWatch.Restart(); await Task.WhenAll(StartEntryPoints(entryPoints, false)).ConfigureAwait(false); Logger.LogInformation("Executed all post-startup entry points in {Elapsed:g}", stopWatch.Elapsed); diff --git a/Jellyfin.Server/Middleware/ServerStartupMessageMiddleware.cs b/Jellyfin.Server/Middleware/ServerStartupMessageMiddleware.cs index 4f347d6d3..ea81c03a2 100644 --- a/Jellyfin.Server/Middleware/ServerStartupMessageMiddleware.cs +++ b/Jellyfin.Server/Middleware/ServerStartupMessageMiddleware.cs @@ -1,5 +1,6 @@ using System.Net.Mime; using System.Threading.Tasks; +using MediaBrowser.Controller; using MediaBrowser.Model.Globalization; using Microsoft.AspNetCore.Http; @@ -25,10 +26,20 @@ namespace Jellyfin.Server.Middleware /// Executes the middleware action. /// </summary> /// <param name="httpContext">The current HTTP context.</param> + /// <param name="serverApplicationHost">The server application host.</param> /// <param name="localizationManager">The localization manager.</param> /// <returns>The async task.</returns> - public async Task Invoke(HttpContext httpContext, ILocalizationManager localizationManager) + public async Task Invoke( + HttpContext httpContext, + IServerApplicationHost serverApplicationHost, + ILocalizationManager localizationManager) { + if (serverApplicationHost.CoreStartupHasCompleted) + { + await _next(httpContext).ConfigureAwait(false); + return; + } + var message = localizationManager.GetLocalizedString("StartupEmbyServerIsLoading"); httpContext.Response.StatusCode = StatusCodes.Status503ServiceUnavailable; httpContext.Response.ContentType = MediaTypeNames.Text.Html; diff --git a/Jellyfin.Server/Startup.cs b/Jellyfin.Server/Startup.cs index 80f679420..c197888da 100644 --- a/Jellyfin.Server/Startup.cs +++ b/Jellyfin.Server/Startup.cs @@ -123,6 +123,7 @@ namespace Jellyfin.Server app.UseCorsOptionsResponse(); app.UseBaseUrlRedirection(); app.UseWebSocketHandler(); + app.UseServerStartupMessage(); app.UseEndpoints(endpoints => { @@ -133,8 +134,6 @@ namespace Jellyfin.Server } }); - app.UseServerStartupMessage(); - // Add type descriptor for legacy datetime parsing. TypeDescriptor.AddAttributes(typeof(DateTime?), new TypeConverterAttribute(typeof(DateTimeTypeConverter))); } diff --git a/MediaBrowser.Controller/IServerApplicationHost.cs b/MediaBrowser.Controller/IServerApplicationHost.cs index d482c19d9..9f4c00e1c 100644 --- a/MediaBrowser.Controller/IServerApplicationHost.cs +++ b/MediaBrowser.Controller/IServerApplicationHost.cs @@ -20,6 +20,8 @@ namespace MediaBrowser.Controller IServiceProvider ServiceProvider { get; } + bool CoreStartupHasCompleted { get; } + bool CanLaunchWebBrowser { get; } /// <summary> -- cgit v1.2.3 From abc527329d16bb33aefa051a48e0d0cefe5f2df7 Mon Sep 17 00:00:00 2001 From: Claus Vium <clausvium@gmail.com> Date: Thu, 3 Sep 2020 14:49:02 +0200 Subject: Sort by SortName after scanning --- MediaBrowser.Controller/Entities/BaseItem.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 72574d613..2cc4824ad 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -1621,7 +1621,8 @@ namespace MediaBrowser.Controller.Entities await Task.WhenAll(tasks).ConfigureAwait(false); - item.ThemeVideoIds = newThemeVideoIds; + // They are expected to be sorted by SortName + item.ThemeVideoIds = newThemeVideos.OrderBy(i => i.SortName).Select(i => i.Id).ToArray(); return themeVideosChanged; } @@ -1658,7 +1659,8 @@ namespace MediaBrowser.Controller.Entities await Task.WhenAll(tasks).ConfigureAwait(false); - item.ThemeSongIds = newThemeSongIds; + // They are expected to be sorted by SortName + item.ThemeSongIds = newThemeSongs.OrderBy(i => i.SortName).Select(i => i.Id).ToArray(); return themeSongsChanged; } -- cgit v1.2.3 From cf87b3afb7c64bd1102dc9bd445f75a4042e0442 Mon Sep 17 00:00:00 2001 From: BaronGreenback <jimcartlidge@yahoo.co.uk> Date: Mon, 7 Sep 2020 12:28:48 +0100 Subject: Remove excess code. --- Emby.Server.Implementations/ApplicationHost.cs | 4 ---- Emby.Server.Implementations/Udp/UdpServer.cs | 6 ------ MediaBrowser.Controller/IServerApplicationHost.cs | 2 -- 3 files changed, 12 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index c37e87d96..318a853c5 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -1431,10 +1431,6 @@ namespace Emby.Server.Implementations } } - public virtual void EnableLoopback(string appName) - { - } - private bool _disposed = false; /// <summary> diff --git a/Emby.Server.Implementations/Udp/UdpServer.cs b/Emby.Server.Implementations/Udp/UdpServer.cs index 73fcbcec3..b7a59cee2 100644 --- a/Emby.Server.Implementations/Udp/UdpServer.cs +++ b/Emby.Server.Implementations/Udp/UdpServer.cs @@ -68,12 +68,6 @@ namespace Emby.Server.Implementations.Udp { _logger.LogError(ex, "Error sending response message"); } - - var parts = messageText.Split('|'); - if (parts.Length > 1) - { - _appHost.EnableLoopback(parts[1]); - } } else { diff --git a/MediaBrowser.Controller/IServerApplicationHost.cs b/MediaBrowser.Controller/IServerApplicationHost.cs index 9f4c00e1c..cfad17fb7 100644 --- a/MediaBrowser.Controller/IServerApplicationHost.cs +++ b/MediaBrowser.Controller/IServerApplicationHost.cs @@ -114,8 +114,6 @@ namespace MediaBrowser.Controller /// <exception cref="NotSupportedException"><see cref="CanLaunchWebBrowser"/> is false.</exception> void LaunchUrl(string url); - void EnableLoopback(string appName); - IEnumerable<WakeOnLanInfo> GetWakeOnLanInfo(); string ExpandVirtualPath(string path); -- cgit v1.2.3 From 48e1cf9fd7e2e7f4821d1255e5943deb305ec0be Mon Sep 17 00:00:00 2001 From: Bond_009 <bond.009@outlook.com> Date: Wed, 9 Sep 2020 13:38:27 +0200 Subject: Minor performance improvements to item saving --- .../Data/BaseSqliteRepository.cs | 13 +++- .../Data/SqliteItemRepository.cs | 73 +++++++++++++--------- .../Library/LibraryManager.cs | 39 ++++++------ .../Security/AuthenticationRepository.cs | 5 +- MediaBrowser.Controller/Library/ILibraryManager.cs | 2 +- 5 files changed, 77 insertions(+), 55 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs index 8a3716380..0fb050a7a 100644 --- a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs +++ b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs @@ -143,8 +143,17 @@ namespace Emby.Server.Implementations.Data public IStatement PrepareStatement(IDatabaseConnection connection, string sql) => connection.PrepareStatement(sql); - public IEnumerable<IStatement> PrepareAll(IDatabaseConnection connection, IEnumerable<string> sql) - => sql.Select(connection.PrepareStatement); + public IStatement[] PrepareAll(IDatabaseConnection connection, IReadOnlyList<string> sql) + { + int len = sql.Count; + IStatement[] statements = new IStatement[len]; + for (int i = 0; i < len; i++) + { + statements[i] = connection.PrepareStatement(sql[i]); + } + + return statements; + } protected bool TableExists(ManagedConnection connection, string name) { diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index 5bf740cfc..fd8c4a795 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -560,7 +560,7 @@ namespace Emby.Server.Implementations.Data { SaveItemCommandText, "delete from AncestorIds where ItemId=@ItemId" - }).ToList(); + }); using (var saveItemStatement = statements[0]) using (var deleteAncestorsStatement = statements[1]) @@ -2925,7 +2925,7 @@ namespace Emby.Server.Implementations.Data { connection.RunInTransaction(db => { - var statements = PrepareAll(db, statementTexts).ToList(); + var statements = PrepareAll(db, statementTexts); if (!isReturningZeroItems) { @@ -3329,7 +3329,7 @@ namespace Emby.Server.Implementations.Data { connection.RunInTransaction(db => { - var statements = PrepareAll(db, statementTexts).ToList(); + var statements = PrepareAll(db, statementTexts); if (!isReturningZeroItems) { @@ -3718,26 +3718,31 @@ namespace Emby.Server.Implementations.Data statement?.TryBind("@MaxPremiereDate", query.MaxPremiereDate.Value); } + StringBuilder clauseBuilder = new StringBuilder(); + const string Or = " OR "; + var trailerTypes = query.TrailerTypes; int trailerTypesLen = trailerTypes.Length; if (trailerTypesLen > 0) { - const string Or = " OR "; - StringBuilder clause = new StringBuilder("(", trailerTypesLen * 32); + clauseBuilder.Append('('); + for (int i = 0; i < trailerTypesLen; i++) { var paramName = "@TrailerTypes" + i; - clause.Append("TrailerTypes like ") + clauseBuilder.Append("TrailerTypes like ") .Append(paramName) .Append(Or); statement?.TryBind(paramName, "%" + trailerTypes[i] + "%"); } // Remove last " OR " - clause.Length -= Or.Length; - clause.Append(')'); + clauseBuilder.Length -= Or.Length; + clauseBuilder.Append(')'); + + whereClauses.Add(clauseBuilder.ToString()); - whereClauses.Add(clause.ToString()); + clauseBuilder.Length = 0; } if (query.IsAiring.HasValue) @@ -3757,23 +3762,35 @@ namespace Emby.Server.Implementations.Data } } - if (query.PersonIds.Length > 0) + int personIdsLen = query.PersonIds.Length; + if (personIdsLen > 0) { // TODO: Should this query with CleanName ? - var clauses = new List<string>(); - var index = 0; - foreach (var personId in query.PersonIds) + clauseBuilder.Append('('); + + Span<byte> idBytes = stackalloc byte[16]; + for (int i = 0; i < personIdsLen; i++) { - var paramName = "@PersonId" + index; + string paramName = "@PersonId" + i; + clauseBuilder.Append("(guid in (select itemid from People where Name = (select Name from TypedBaseItems where guid=") + .Append(paramName) + .Append("))) OR "); - clauses.Add("(guid in (select itemid from People where Name = (select Name from TypedBaseItems where guid=" + paramName + ")))"); - statement?.TryBind(paramName, personId.ToByteArray()); - index++; + if (statement != null) + { + query.PersonIds[i].TryWriteBytes(idBytes); + statement.TryBind(paramName, idBytes); + } } - var clause = "(" + string.Join(" OR ", clauses) + ")"; - whereClauses.Add(clause); + // Remove last " OR " + clauseBuilder.Length -= Or.Length; + clauseBuilder.Append(')'); + + whereClauses.Add(clauseBuilder.ToString()); + + clauseBuilder.Length = 0; } if (!string.IsNullOrWhiteSpace(query.Person)) @@ -5149,7 +5166,8 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type CheckDisposed(); - var itemIdBlob = itemId.ToByteArray(); + Span<byte> itemIdBlob = stackalloc byte[16] + itemId.TryWriteBytes(itemIdBlob); // First delete deleteAncestorsStatement.Reset(); @@ -5165,17 +5183,15 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type for (var i = 0; i < ancestorIds.Count; i++) { - if (i > 0) - { - insertText.Append(','); - } - insertText.AppendFormat( CultureInfo.InvariantCulture, - "(@ItemId, @AncestorId{0}, @AncestorIdText{0})", + "(@ItemId, @AncestorId{0}, @AncestorIdText{0}),", i.ToString(CultureInfo.InvariantCulture)); } + // Remove last , + insertText.Length--; + using (var statement = PrepareStatement(db, insertText.ToString())) { statement.TryBind("@ItemId", itemIdBlob); @@ -5185,8 +5201,9 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type var index = i.ToString(CultureInfo.InvariantCulture); var ancestorId = ancestorIds[i]; + ancestorId.TryWriteBytes(itemIdBlob); - statement.TryBind("@AncestorId" + index, ancestorId.ToByteArray()); + statement.TryBind("@AncestorId" + index, itemIdBlob); statement.TryBind("@AncestorIdText" + index, ancestorId.ToString("N", CultureInfo.InvariantCulture)); } @@ -5466,7 +5483,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type connection.RunInTransaction( db => { - var statements = PrepareAll(db, statementTexts).ToList(); + var statements = PrepareAll(db, statementTexts); if (!isReturningZeroItems) { diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index 375f09f5b..6e7970e01 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -513,10 +513,11 @@ namespace Emby.Server.Implementations.Library throw new ArgumentNullException(nameof(type)); } - if (key.StartsWith(_configurationManager.ApplicationPaths.ProgramDataPath, StringComparison.Ordinal)) + string programDataPath = _configurationManager.ApplicationPaths.ProgramDataPath; + if (key.StartsWith(programDataPath, StringComparison.Ordinal)) { // Try to normalize paths located underneath program-data in an attempt to make them more portable - key = key.Substring(_configurationManager.ApplicationPaths.ProgramDataPath.Length) + key = key.Substring(programDataPath.Length) .TrimStart('/', '\\') .Replace('/', '\\'); } @@ -871,17 +872,17 @@ namespace Emby.Server.Implementations.Library public Guid GetStudioId(string name) { - return GetItemByNameId<Studio>(Studio.GetPath, name); + return GetItemByNameId<Studio>(Studio.GetPath(name)); } public Guid GetGenreId(string name) { - return GetItemByNameId<Genre>(Genre.GetPath, name); + return GetItemByNameId<Genre>(Genre.GetPath(name)); } public Guid GetMusicGenreId(string name) { - return GetItemByNameId<MusicGenre>(MusicGenre.GetPath, name); + return GetItemByNameId<MusicGenre>(MusicGenre.GetPath(name)); } /// <summary> @@ -943,7 +944,7 @@ namespace Emby.Server.Implementations.Library { var existing = GetItemList(new InternalItemsQuery { - IncludeItemTypes = new[] { typeof(T).Name }, + IncludeItemTypes = new[] { nameof(MusicArtist) }, Name = name, DtoOptions = options }).Cast<MusicArtist>() @@ -957,13 +958,11 @@ namespace Emby.Server.Implementations.Library } } - var id = GetItemByNameId<T>(getPathFn, name); - - var item = GetItemById(id) as T; + var path = getPathFn(name); + var id = GetItemByNameId<T>(path); - if (item == null) + if (GetItemById(id) is T item) { - var path = getPathFn(name); item = new T { Name = name, @@ -974,15 +973,16 @@ namespace Emby.Server.Implementations.Library }; CreateItem(item, null); + + return item; } - return item; + return null; } - private Guid GetItemByNameId<T>(Func<string, string> getPathFn, string name) + private Guid GetItemByNameId<T>(string path) where T : BaseItem, new() { - var path = getPathFn(name); var forceCaseInsensitiveId = _configurationManager.Configuration.EnableNormalizedItemByNameIds; return GetNewItemIdInternal(path, typeof(T), forceCaseInsensitiveId); } @@ -1805,21 +1805,18 @@ namespace Emby.Server.Implementations.Library /// <param name="items">The items.</param> /// <param name="parent">The parent item.</param> /// <param name="cancellationToken">The cancellation token.</param> - public void CreateItems(IEnumerable<BaseItem> items, BaseItem parent, CancellationToken cancellationToken) + public void CreateItems(IReadOnlyList<BaseItem> items, BaseItem parent, CancellationToken cancellationToken) { - // Don't iterate multiple times - var itemsList = items.ToList(); - - _itemRepository.SaveItems(itemsList, cancellationToken); + _itemRepository.SaveItems(items, cancellationToken); - foreach (var item in itemsList) + foreach (var item in items) { RegisterItem(item); } if (ItemAdded != null) { - foreach (var item in itemsList) + foreach (var item in items) { // With the live tv guide this just creates too much noise if (item.SourceType != SourceType.Library) diff --git a/Emby.Server.Implementations/Security/AuthenticationRepository.cs b/Emby.Server.Implementations/Security/AuthenticationRepository.cs index 4dfadc703..29393ae07 100644 --- a/Emby.Server.Implementations/Security/AuthenticationRepository.cs +++ b/Emby.Server.Implementations/Security/AuthenticationRepository.cs @@ -257,8 +257,7 @@ namespace Emby.Server.Implementations.Security connection.RunInTransaction( db => { - var statements = PrepareAll(db, statementTexts) - .ToList(); + var statements = PrepareAll(db, statementTexts); using (var statement = statements[0]) { @@ -282,7 +281,7 @@ namespace Emby.Server.Implementations.Security ReadTransactionMode); } - result.Items = list.ToArray(); + result.Items = list; return result; } diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs index d2f937d4f..804170d5c 100644 --- a/MediaBrowser.Controller/Library/ILibraryManager.cs +++ b/MediaBrowser.Controller/Library/ILibraryManager.cs @@ -200,7 +200,7 @@ namespace MediaBrowser.Controller.Library /// <summary> /// Creates the items. /// </summary> - void CreateItems(IEnumerable<BaseItem> items, BaseItem parent, CancellationToken cancellationToken); + void CreateItems(IReadOnlyList<BaseItem> items, BaseItem parent, CancellationToken cancellationToken); /// <summary> /// Updates the item. -- cgit v1.2.3