|
@@ -30,17 +30,17 @@ using Microsoft.Extensions.Logging;
|
|
namespace Emby.Server.Implementations.Session
|
|
namespace Emby.Server.Implementations.Session
|
|
{
|
|
{
|
|
/// <summary>
|
|
/// <summary>
|
|
- /// Class SessionManager
|
|
|
|
|
|
+ /// Class SessionManager.
|
|
/// </summary>
|
|
/// </summary>
|
|
public class SessionManager : ISessionManager, IDisposable
|
|
public class SessionManager : ISessionManager, IDisposable
|
|
{
|
|
{
|
|
/// <summary>
|
|
/// <summary>
|
|
- /// The _user data repository
|
|
|
|
|
|
+ /// The _user data repository.
|
|
/// </summary>
|
|
/// </summary>
|
|
private readonly IUserDataManager _userDataManager;
|
|
private readonly IUserDataManager _userDataManager;
|
|
|
|
|
|
/// <summary>
|
|
/// <summary>
|
|
- /// The _logger
|
|
|
|
|
|
+ /// The _logger.
|
|
/// </summary>
|
|
/// </summary>
|
|
private readonly ILogger _logger;
|
|
private readonly ILogger _logger;
|
|
|
|
|
|
@@ -57,36 +57,19 @@ namespace Emby.Server.Implementations.Session
|
|
private readonly IDeviceManager _deviceManager;
|
|
private readonly IDeviceManager _deviceManager;
|
|
|
|
|
|
/// <summary>
|
|
/// <summary>
|
|
- /// The _active connections
|
|
|
|
|
|
+ /// The _active connections.
|
|
/// </summary>
|
|
/// </summary>
|
|
private readonly ConcurrentDictionary<string, SessionInfo> _activeConnections =
|
|
private readonly ConcurrentDictionary<string, SessionInfo> _activeConnections =
|
|
new ConcurrentDictionary<string, SessionInfo>(StringComparer.OrdinalIgnoreCase);
|
|
new ConcurrentDictionary<string, SessionInfo>(StringComparer.OrdinalIgnoreCase);
|
|
|
|
|
|
- public event EventHandler<GenericEventArgs<AuthenticationRequest>> AuthenticationFailed;
|
|
|
|
-
|
|
|
|
- public event EventHandler<GenericEventArgs<AuthenticationResult>> AuthenticationSucceeded;
|
|
|
|
-
|
|
|
|
- /// <summary>
|
|
|
|
- /// Occurs when [playback start].
|
|
|
|
- /// </summary>
|
|
|
|
- public event EventHandler<PlaybackProgressEventArgs> PlaybackStart;
|
|
|
|
- /// <summary>
|
|
|
|
- /// Occurs when [playback progress].
|
|
|
|
- /// </summary>
|
|
|
|
- public event EventHandler<PlaybackProgressEventArgs> PlaybackProgress;
|
|
|
|
- /// <summary>
|
|
|
|
- /// Occurs when [playback stopped].
|
|
|
|
- /// </summary>
|
|
|
|
- public event EventHandler<PlaybackStopEventArgs> PlaybackStopped;
|
|
|
|
|
|
+ private Timer _idleTimer;
|
|
|
|
|
|
- public event EventHandler<SessionEventArgs> SessionStarted;
|
|
|
|
- public event EventHandler<SessionEventArgs> CapabilitiesChanged;
|
|
|
|
- public event EventHandler<SessionEventArgs> SessionEnded;
|
|
|
|
- public event EventHandler<SessionEventArgs> SessionActivity;
|
|
|
|
|
|
+ private DtoOptions _itemInfoDtoOptions;
|
|
|
|
+ private bool _disposed = false;
|
|
|
|
|
|
public SessionManager(
|
|
public SessionManager(
|
|
|
|
+ ILogger<SessionManager> logger,
|
|
IUserDataManager userDataManager,
|
|
IUserDataManager userDataManager,
|
|
- ILoggerFactory loggerFactory,
|
|
|
|
ILibraryManager libraryManager,
|
|
ILibraryManager libraryManager,
|
|
IUserManager userManager,
|
|
IUserManager userManager,
|
|
IMusicManager musicManager,
|
|
IMusicManager musicManager,
|
|
@@ -97,8 +80,8 @@ namespace Emby.Server.Implementations.Session
|
|
IDeviceManager deviceManager,
|
|
IDeviceManager deviceManager,
|
|
IMediaSourceManager mediaSourceManager)
|
|
IMediaSourceManager mediaSourceManager)
|
|
{
|
|
{
|
|
|
|
+ _logger = logger;
|
|
_userDataManager = userDataManager;
|
|
_userDataManager = userDataManager;
|
|
- _logger = loggerFactory.CreateLogger(nameof(SessionManager));
|
|
|
|
_libraryManager = libraryManager;
|
|
_libraryManager = libraryManager;
|
|
_userManager = userManager;
|
|
_userManager = userManager;
|
|
_musicManager = musicManager;
|
|
_musicManager = musicManager;
|
|
@@ -108,9 +91,49 @@ namespace Emby.Server.Implementations.Session
|
|
_authRepo = authRepo;
|
|
_authRepo = authRepo;
|
|
_deviceManager = deviceManager;
|
|
_deviceManager = deviceManager;
|
|
_mediaSourceManager = mediaSourceManager;
|
|
_mediaSourceManager = mediaSourceManager;
|
|
|
|
+
|
|
_deviceManager.DeviceOptionsUpdated += OnDeviceManagerDeviceOptionsUpdated;
|
|
_deviceManager.DeviceOptionsUpdated += OnDeviceManagerDeviceOptionsUpdated;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /// <inheritdoc />
|
|
|
|
+ public event EventHandler<GenericEventArgs<AuthenticationRequest>> AuthenticationFailed;
|
|
|
|
+
|
|
|
|
+ /// <inheritdoc />
|
|
|
|
+ public event EventHandler<GenericEventArgs<AuthenticationResult>> AuthenticationSucceeded;
|
|
|
|
+
|
|
|
|
+ /// <summary>
|
|
|
|
+ /// Occurs when [playback start].
|
|
|
|
+ /// </summary>
|
|
|
|
+ public event EventHandler<PlaybackProgressEventArgs> PlaybackStart;
|
|
|
|
+
|
|
|
|
+ /// <summary>
|
|
|
|
+ /// Occurs when [playback progress].
|
|
|
|
+ /// </summary>
|
|
|
|
+ public event EventHandler<PlaybackProgressEventArgs> PlaybackProgress;
|
|
|
|
+
|
|
|
|
+ /// <summary>
|
|
|
|
+ /// Occurs when [playback stopped].
|
|
|
|
+ /// </summary>
|
|
|
|
+ public event EventHandler<PlaybackStopEventArgs> PlaybackStopped;
|
|
|
|
+
|
|
|
|
+ /// <inheritdoc />
|
|
|
|
+ public event EventHandler<SessionEventArgs> SessionStarted;
|
|
|
|
+
|
|
|
|
+ /// <inheritdoc />
|
|
|
|
+ public event EventHandler<SessionEventArgs> CapabilitiesChanged;
|
|
|
|
+
|
|
|
|
+ /// <inheritdoc />
|
|
|
|
+ public event EventHandler<SessionEventArgs> SessionEnded;
|
|
|
|
+
|
|
|
|
+ /// <inheritdoc />
|
|
|
|
+ public event EventHandler<SessionEventArgs> SessionActivity;
|
|
|
|
+
|
|
|
|
+ /// <summary>
|
|
|
|
+ /// Gets all connections.
|
|
|
|
+ /// </summary>
|
|
|
|
+ /// <value>All connections.</value>
|
|
|
|
+ public IEnumerable<SessionInfo> Sessions => _activeConnections.Values.OrderByDescending(c => c.LastActivityDate);
|
|
|
|
+
|
|
private void OnDeviceManagerDeviceOptionsUpdated(object sender, GenericEventArgs<Tuple<string, DeviceOptions>> e)
|
|
private void OnDeviceManagerDeviceOptionsUpdated(object sender, GenericEventArgs<Tuple<string, DeviceOptions>> e)
|
|
{
|
|
{
|
|
foreach (var session in Sessions)
|
|
foreach (var session in Sessions)
|
|
@@ -130,14 +153,17 @@ namespace Emby.Server.Implementations.Session
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- private bool _disposed = false;
|
|
|
|
-
|
|
|
|
|
|
+ /// <inheritdoc />
|
|
public void Dispose()
|
|
public void Dispose()
|
|
{
|
|
{
|
|
Dispose(true);
|
|
Dispose(true);
|
|
GC.SuppressFinalize(this);
|
|
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)
|
|
protected virtual void Dispose(bool disposing)
|
|
{
|
|
{
|
|
if (_disposed)
|
|
if (_disposed)
|
|
@@ -147,15 +173,17 @@ namespace Emby.Server.Implementations.Session
|
|
|
|
|
|
if (disposing)
|
|
if (disposing)
|
|
{
|
|
{
|
|
- // TODO: dispose stuff
|
|
|
|
|
|
+ _idleTimer?.Dispose();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ _idleTimer = null;
|
|
|
|
+
|
|
_deviceManager.DeviceOptionsUpdated -= OnDeviceManagerDeviceOptionsUpdated;
|
|
_deviceManager.DeviceOptionsUpdated -= OnDeviceManagerDeviceOptionsUpdated;
|
|
|
|
|
|
_disposed = true;
|
|
_disposed = true;
|
|
}
|
|
}
|
|
|
|
|
|
- public void CheckDisposed()
|
|
|
|
|
|
+ private void CheckDisposed()
|
|
{
|
|
{
|
|
if (_disposed)
|
|
if (_disposed)
|
|
{
|
|
{
|
|
@@ -163,12 +191,6 @@ namespace Emby.Server.Implementations.Session
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- /// <summary>
|
|
|
|
- /// Gets all connections.
|
|
|
|
- /// </summary>
|
|
|
|
- /// <value>All connections.</value>
|
|
|
|
- public IEnumerable<SessionInfo> Sessions => _activeConnections.Values.OrderByDescending(c => c.LastActivityDate);
|
|
|
|
-
|
|
|
|
private void OnSessionStarted(SessionInfo info)
|
|
private void OnSessionStarted(SessionInfo info)
|
|
{
|
|
{
|
|
if (!string.IsNullOrEmpty(info.DeviceId))
|
|
if (!string.IsNullOrEmpty(info.DeviceId))
|
|
@@ -199,13 +221,13 @@ namespace Emby.Server.Implementations.Session
|
|
new SessionEventArgs
|
|
new SessionEventArgs
|
|
{
|
|
{
|
|
SessionInfo = info
|
|
SessionInfo = info
|
|
-
|
|
|
|
},
|
|
},
|
|
_logger);
|
|
_logger);
|
|
|
|
|
|
info.Dispose();
|
|
info.Dispose();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /// <inheritdoc />
|
|
public void UpdateDeviceName(string sessionId, string deviceName)
|
|
public void UpdateDeviceName(string sessionId, string deviceName)
|
|
{
|
|
{
|
|
var session = GetSession(sessionId);
|
|
var session = GetSession(sessionId);
|
|
@@ -225,7 +247,6 @@ namespace Emby.Server.Implementations.Session
|
|
/// <param name="remoteEndPoint">The remote end point.</param>
|
|
/// <param name="remoteEndPoint">The remote end point.</param>
|
|
/// <param name="user">The user.</param>
|
|
/// <param name="user">The user.</param>
|
|
/// <returns>SessionInfo.</returns>
|
|
/// <returns>SessionInfo.</returns>
|
|
- /// <exception cref="ArgumentNullException">user</exception>
|
|
|
|
public SessionInfo LogSessionActivity(
|
|
public SessionInfo LogSessionActivity(
|
|
string appName,
|
|
string appName,
|
|
string appVersion,
|
|
string appVersion,
|
|
@@ -263,14 +284,7 @@ namespace Emby.Server.Implementations.Session
|
|
|
|
|
|
if ((activityDate - userLastActivityDate).TotalSeconds > 60)
|
|
if ((activityDate - userLastActivityDate).TotalSeconds > 60)
|
|
{
|
|
{
|
|
- try
|
|
|
|
- {
|
|
|
|
- _userManager.UpdateUser(user);
|
|
|
|
- }
|
|
|
|
- catch (Exception ex)
|
|
|
|
- {
|
|
|
|
- _logger.LogError("Error updating user", ex);
|
|
|
|
- }
|
|
|
|
|
|
+ _userManager.UpdateUser(user);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -287,18 +301,20 @@ namespace Emby.Server.Implementations.Session
|
|
return session;
|
|
return session;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /// <inheritdoc />
|
|
public void CloseIfNeeded(SessionInfo session)
|
|
public void CloseIfNeeded(SessionInfo session)
|
|
{
|
|
{
|
|
if (!session.SessionControllers.Any(i => i.IsSessionActive))
|
|
if (!session.SessionControllers.Any(i => i.IsSessionActive))
|
|
{
|
|
{
|
|
var key = GetSessionKey(session.Client, session.DeviceId);
|
|
var key = GetSessionKey(session.Client, session.DeviceId);
|
|
|
|
|
|
- _activeConnections.TryRemove(key, out var removed);
|
|
|
|
|
|
+ _activeConnections.TryRemove(key, out _);
|
|
|
|
|
|
OnSessionEnded(session);
|
|
OnSessionEnded(session);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /// <inheritdoc />
|
|
public void ReportSessionEnded(string sessionId)
|
|
public void ReportSessionEnded(string sessionId)
|
|
{
|
|
{
|
|
CheckDisposed();
|
|
CheckDisposed();
|
|
@@ -308,7 +324,7 @@ namespace Emby.Server.Implementations.Session
|
|
{
|
|
{
|
|
var key = GetSessionKey(session.Client, session.DeviceId);
|
|
var key = GetSessionKey(session.Client, session.DeviceId);
|
|
|
|
|
|
- _activeConnections.TryRemove(key, out var removed);
|
|
|
|
|
|
+ _activeConnections.TryRemove(key, out _);
|
|
|
|
|
|
OnSessionEnded(session);
|
|
OnSessionEnded(session);
|
|
}
|
|
}
|
|
@@ -339,7 +355,7 @@ namespace Emby.Server.Implementations.Session
|
|
var runtimeTicks = libraryItem.RunTimeTicks;
|
|
var runtimeTicks = libraryItem.RunTimeTicks;
|
|
|
|
|
|
MediaSourceInfo mediaSource = null;
|
|
MediaSourceInfo mediaSource = null;
|
|
- if (libraryItem is IHasMediaSources hasMediaSources)
|
|
|
|
|
|
+ if (libraryItem is IHasMediaSources)
|
|
{
|
|
{
|
|
mediaSource = await GetMediaSource(libraryItem, info.MediaSourceId, info.LiveStreamId).ConfigureAwait(false);
|
|
mediaSource = await GetMediaSource(libraryItem, info.MediaSourceId, info.LiveStreamId).ConfigureAwait(false);
|
|
|
|
|
|
@@ -391,7 +407,6 @@ namespace Emby.Server.Implementations.Session
|
|
/// Removes the now playing item id.
|
|
/// Removes the now playing item id.
|
|
/// </summary>
|
|
/// </summary>
|
|
/// <param name="session">The session.</param>
|
|
/// <param name="session">The session.</param>
|
|
- /// <exception cref="ArgumentNullException">item</exception>
|
|
|
|
private void RemoveNowPlayingItem(SessionInfo session)
|
|
private void RemoveNowPlayingItem(SessionInfo session)
|
|
{
|
|
{
|
|
session.NowPlayingItem = null;
|
|
session.NowPlayingItem = null;
|
|
@@ -404,9 +419,7 @@ namespace Emby.Server.Implementations.Session
|
|
}
|
|
}
|
|
|
|
|
|
private static string GetSessionKey(string appName, string deviceId)
|
|
private static string GetSessionKey(string appName, string deviceId)
|
|
- {
|
|
|
|
- return appName + deviceId;
|
|
|
|
- }
|
|
|
|
|
|
+ => appName + deviceId;
|
|
|
|
|
|
/// <summary>
|
|
/// <summary>
|
|
/// Gets the connection.
|
|
/// Gets the connection.
|
|
@@ -426,6 +439,7 @@ namespace Emby.Server.Implementations.Session
|
|
{
|
|
{
|
|
throw new ArgumentNullException(nameof(deviceId));
|
|
throw new ArgumentNullException(nameof(deviceId));
|
|
}
|
|
}
|
|
|
|
+
|
|
var key = GetSessionKey(appName, deviceId);
|
|
var key = GetSessionKey(appName, deviceId);
|
|
|
|
|
|
CheckDisposed();
|
|
CheckDisposed();
|
|
@@ -498,7 +512,7 @@ namespace Emby.Server.Implementations.Session
|
|
{
|
|
{
|
|
var users = new List<User>();
|
|
var users = new List<User>();
|
|
|
|
|
|
- if (!session.UserId.Equals(Guid.Empty))
|
|
|
|
|
|
+ if (session.UserId != Guid.Empty)
|
|
{
|
|
{
|
|
var user = _userManager.GetUserById(session.UserId);
|
|
var user = _userManager.GetUserById(session.UserId);
|
|
|
|
|
|
@@ -517,8 +531,6 @@ namespace Emby.Server.Implementations.Session
|
|
return users;
|
|
return users;
|
|
}
|
|
}
|
|
|
|
|
|
- private Timer _idleTimer;
|
|
|
|
-
|
|
|
|
private void StartIdleCheckTimer()
|
|
private void StartIdleCheckTimer()
|
|
{
|
|
{
|
|
if (_idleTimer == null)
|
|
if (_idleTimer == null)
|
|
@@ -594,11 +606,11 @@ namespace Emby.Server.Implementations.Session
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// <summary>
|
|
- /// Used to report that playback has started for an item
|
|
|
|
|
|
+ /// Used to report that playback has started for an item.
|
|
/// </summary>
|
|
/// </summary>
|
|
/// <param name="info">The info.</param>
|
|
/// <param name="info">The info.</param>
|
|
/// <returns>Task.</returns>
|
|
/// <returns>Task.</returns>
|
|
- /// <exception cref="ArgumentNullException">info</exception>
|
|
|
|
|
|
+ /// <exception cref="ArgumentNullException"><c>info</c> is <c>null</c>.</exception>
|
|
public async Task OnPlaybackStart(PlaybackStartInfo info)
|
|
public async Task OnPlaybackStart(PlaybackStartInfo info)
|
|
{
|
|
{
|
|
CheckDisposed();
|
|
CheckDisposed();
|
|
@@ -610,7 +622,7 @@ namespace Emby.Server.Implementations.Session
|
|
|
|
|
|
var session = GetSession(info.SessionId);
|
|
var session = GetSession(info.SessionId);
|
|
|
|
|
|
- var libraryItem = info.ItemId.Equals(Guid.Empty)
|
|
|
|
|
|
+ var libraryItem = info.ItemId == Guid.Empty
|
|
? null
|
|
? null
|
|
: GetNowPlayingItem(session, info.ItemId);
|
|
: GetNowPlayingItem(session, info.ItemId);
|
|
|
|
|
|
@@ -648,7 +660,6 @@ namespace Emby.Server.Implementations.Session
|
|
ClientName = session.Client,
|
|
ClientName = session.Client,
|
|
DeviceId = session.DeviceId,
|
|
DeviceId = session.DeviceId,
|
|
Session = session
|
|
Session = session
|
|
-
|
|
|
|
},
|
|
},
|
|
_logger);
|
|
_logger);
|
|
|
|
|
|
@@ -679,13 +690,14 @@ namespace Emby.Server.Implementations.Session
|
|
_userDataManager.SaveUserData(user, item, data, UserDataSaveReason.PlaybackStart, CancellationToken.None);
|
|
_userDataManager.SaveUserData(user, item, data, UserDataSaveReason.PlaybackStart, CancellationToken.None);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /// <inheritdoc />
|
|
public Task OnPlaybackProgress(PlaybackProgressInfo info)
|
|
public Task OnPlaybackProgress(PlaybackProgressInfo info)
|
|
{
|
|
{
|
|
return OnPlaybackProgress(info, false);
|
|
return OnPlaybackProgress(info, false);
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// <summary>
|
|
- /// Used to report playback progress for an item
|
|
|
|
|
|
+ /// Used to report playback progress for an item.
|
|
/// </summary>
|
|
/// </summary>
|
|
/// <returns>Task.</returns>
|
|
/// <returns>Task.</returns>
|
|
public async Task OnPlaybackProgress(PlaybackProgressInfo info, bool isAutomated)
|
|
public async Task OnPlaybackProgress(PlaybackProgressInfo info, bool isAutomated)
|
|
@@ -852,7 +864,7 @@ namespace Emby.Server.Implementations.Session
|
|
{
|
|
{
|
|
MediaSourceInfo mediaSource = null;
|
|
MediaSourceInfo mediaSource = null;
|
|
|
|
|
|
- if (libraryItem is IHasMediaSources hasMediaSources)
|
|
|
|
|
|
+ if (libraryItem is IHasMediaSources)
|
|
{
|
|
{
|
|
mediaSource = await GetMediaSource(libraryItem, info.MediaSourceId, info.LiveStreamId).ConfigureAwait(false);
|
|
mediaSource = await GetMediaSource(libraryItem, info.MediaSourceId, info.LiveStreamId).ConfigureAwait(false);
|
|
}
|
|
}
|
|
@@ -924,7 +936,6 @@ namespace Emby.Server.Implementations.Session
|
|
ClientName = session.Client,
|
|
ClientName = session.Client,
|
|
DeviceId = session.DeviceId,
|
|
DeviceId = session.DeviceId,
|
|
Session = session
|
|
Session = session
|
|
-
|
|
|
|
},
|
|
},
|
|
_logger);
|
|
_logger);
|
|
}
|
|
}
|
|
@@ -962,13 +973,17 @@ namespace Emby.Server.Implementations.Session
|
|
/// <param name="sessionId">The session identifier.</param>
|
|
/// <param name="sessionId">The session identifier.</param>
|
|
/// <param name="throwOnMissing">if set to <c>true</c> [throw on missing].</param>
|
|
/// <param name="throwOnMissing">if set to <c>true</c> [throw on missing].</param>
|
|
/// <returns>SessionInfo.</returns>
|
|
/// <returns>SessionInfo.</returns>
|
|
- /// <exception cref="ResourceNotFoundException">sessionId</exception>
|
|
|
|
|
|
+ /// <exception cref="ResourceNotFoundException">
|
|
|
|
+ /// No session with an Id equal to <c>sessionId</c> was found
|
|
|
|
+ /// and <c>throwOnMissing</c> is <c>true</c>.
|
|
|
|
+ /// </exception>
|
|
private SessionInfo GetSession(string sessionId, bool throwOnMissing = true)
|
|
private SessionInfo GetSession(string sessionId, bool throwOnMissing = true)
|
|
{
|
|
{
|
|
var session = Sessions.FirstOrDefault(i => string.Equals(i.Id, sessionId, StringComparison.Ordinal));
|
|
var session = Sessions.FirstOrDefault(i => string.Equals(i.Id, sessionId, StringComparison.Ordinal));
|
|
if (session == null && throwOnMissing)
|
|
if (session == null && throwOnMissing)
|
|
{
|
|
{
|
|
- throw new ResourceNotFoundException(string.Format("Session {0} not found.", sessionId));
|
|
|
|
|
|
+ throw new ResourceNotFoundException(
|
|
|
|
+ string.Format(CultureInfo.InvariantCulture, "Session {0} not found.", sessionId));
|
|
}
|
|
}
|
|
|
|
|
|
return session;
|
|
return session;
|
|
@@ -981,12 +996,14 @@ namespace Emby.Server.Implementations.Session
|
|
|
|
|
|
if (session == null)
|
|
if (session == null)
|
|
{
|
|
{
|
|
- throw new ResourceNotFoundException(string.Format("Session {0} not found.", sessionId));
|
|
|
|
|
|
+ throw new ResourceNotFoundException(
|
|
|
|
+ string.Format(CultureInfo.InvariantCulture, "Session {0} not found.", sessionId));
|
|
}
|
|
}
|
|
|
|
|
|
return session;
|
|
return session;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /// <inheritdoc />
|
|
public Task SendMessageCommand(string controllingSessionId, string sessionId, MessageCommand command, CancellationToken cancellationToken)
|
|
public Task SendMessageCommand(string controllingSessionId, string sessionId, MessageCommand command, CancellationToken cancellationToken)
|
|
{
|
|
{
|
|
CheckDisposed();
|
|
CheckDisposed();
|
|
@@ -1007,6 +1024,7 @@ namespace Emby.Server.Implementations.Session
|
|
return SendGeneralCommand(controllingSessionId, sessionId, generalCommand, cancellationToken);
|
|
return SendGeneralCommand(controllingSessionId, sessionId, generalCommand, cancellationToken);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /// <inheritdoc />
|
|
public Task SendGeneralCommand(string controllingSessionId, string sessionId, GeneralCommand command, CancellationToken cancellationToken)
|
|
public Task SendGeneralCommand(string controllingSessionId, string sessionId, GeneralCommand command, CancellationToken cancellationToken)
|
|
{
|
|
{
|
|
CheckDisposed();
|
|
CheckDisposed();
|
|
@@ -1051,6 +1069,7 @@ namespace Emby.Server.Implementations.Session
|
|
return Task.WhenAll(GetTasks());
|
|
return Task.WhenAll(GetTasks());
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /// <inheritdoc />
|
|
public async Task SendPlayCommand(string controllingSessionId, string sessionId, PlayRequest command, CancellationToken cancellationToken)
|
|
public async Task SendPlayCommand(string controllingSessionId, string sessionId, PlayRequest command, CancellationToken cancellationToken)
|
|
{
|
|
{
|
|
CheckDisposed();
|
|
CheckDisposed();
|
|
@@ -1092,7 +1111,8 @@ namespace Emby.Server.Implementations.Session
|
|
{
|
|
{
|
|
if (items.Any(i => i.GetPlayAccess(user) != PlayAccess.Full))
|
|
if (items.Any(i => i.GetPlayAccess(user) != PlayAccess.Full))
|
|
{
|
|
{
|
|
- throw new ArgumentException(string.Format("{0} is not allowed to play media.", user.Name));
|
|
|
|
|
|
+ throw new ArgumentException(
|
|
|
|
+ string.Format(CultureInfo.InvariantCulture, "{0} is not allowed to play media.", user.Name));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1200,6 +1220,7 @@ namespace Emby.Server.Implementations.Session
|
|
return _musicManager.GetInstantMixFromItem(item, user, new DtoOptions(false) { EnableImages = false });
|
|
return _musicManager.GetInstantMixFromItem(item, user, new DtoOptions(false) { EnableImages = false });
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /// <inheritdoc />
|
|
public Task SendBrowseCommand(string controllingSessionId, string sessionId, BrowseRequest command, CancellationToken cancellationToken)
|
|
public Task SendBrowseCommand(string controllingSessionId, string sessionId, BrowseRequest command, CancellationToken cancellationToken)
|
|
{
|
|
{
|
|
var generalCommand = new GeneralCommand
|
|
var generalCommand = new GeneralCommand
|
|
@@ -1216,6 +1237,7 @@ namespace Emby.Server.Implementations.Session
|
|
return SendGeneralCommand(controllingSessionId, sessionId, generalCommand, cancellationToken);
|
|
return SendGeneralCommand(controllingSessionId, sessionId, generalCommand, cancellationToken);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /// <inheritdoc />
|
|
public Task SendPlaystateCommand(string controllingSessionId, string sessionId, PlaystateRequest command, CancellationToken cancellationToken)
|
|
public Task SendPlaystateCommand(string controllingSessionId, string sessionId, PlaystateRequest command, CancellationToken cancellationToken)
|
|
{
|
|
{
|
|
CheckDisposed();
|
|
CheckDisposed();
|
|
@@ -1299,12 +1321,12 @@ namespace Emby.Server.Implementations.Session
|
|
|
|
|
|
var session = GetSession(sessionId);
|
|
var session = GetSession(sessionId);
|
|
|
|
|
|
- if (session.UserId.Equals(userId))
|
|
|
|
|
|
+ if (session.UserId == userId)
|
|
{
|
|
{
|
|
throw new ArgumentException("The requested user is already the primary user of the session.");
|
|
throw new ArgumentException("The requested user is already the primary user of the session.");
|
|
}
|
|
}
|
|
|
|
|
|
- if (session.AdditionalUsers.All(i => !i.UserId.Equals(userId)))
|
|
|
|
|
|
+ if (session.AdditionalUsers.All(i => i.UserId != userId))
|
|
{
|
|
{
|
|
var user = _userManager.GetUserById(userId);
|
|
var user = _userManager.GetUserById(userId);
|
|
|
|
|
|
@@ -1430,19 +1452,19 @@ namespace Emby.Server.Implementations.Session
|
|
|
|
|
|
private string GetAuthorizationToken(User user, string deviceId, string app, string appVersion, string deviceName)
|
|
private string GetAuthorizationToken(User user, string deviceId, string app, string appVersion, string deviceName)
|
|
{
|
|
{
|
|
- var existing = _authRepo.Get(new AuthenticationInfoQuery
|
|
|
|
- {
|
|
|
|
- DeviceId = deviceId,
|
|
|
|
- UserId = user.Id,
|
|
|
|
- Limit = 1
|
|
|
|
-
|
|
|
|
- }).Items.FirstOrDefault();
|
|
|
|
-
|
|
|
|
- var allExistingForDevice = _authRepo.Get(new AuthenticationInfoQuery
|
|
|
|
- {
|
|
|
|
- DeviceId = deviceId
|
|
|
|
|
|
+ var existing = _authRepo.Get(
|
|
|
|
+ new AuthenticationInfoQuery
|
|
|
|
+ {
|
|
|
|
+ DeviceId = deviceId,
|
|
|
|
+ UserId = user.Id,
|
|
|
|
+ Limit = 1
|
|
|
|
+ }).Items.FirstOrDefault();
|
|
|
|
|
|
- }).Items;
|
|
|
|
|
|
+ var allExistingForDevice = _authRepo.Get(
|
|
|
|
+ new AuthenticationInfoQuery
|
|
|
|
+ {
|
|
|
|
+ DeviceId = deviceId
|
|
|
|
+ }).Items;
|
|
|
|
|
|
foreach (var auth in allExistingForDevice)
|
|
foreach (var auth in allExistingForDevice)
|
|
{
|
|
{
|
|
@@ -1461,7 +1483,7 @@ namespace Emby.Server.Implementations.Session
|
|
|
|
|
|
if (existing != null)
|
|
if (existing != null)
|
|
{
|
|
{
|
|
- _logger.LogInformation("Reissuing access token: " + existing.AccessToken);
|
|
|
|
|
|
+ _logger.LogInformation("Reissuing access token: {Token}", existing.AccessToken);
|
|
return existing.AccessToken;
|
|
return existing.AccessToken;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1486,6 +1508,7 @@ namespace Emby.Server.Implementations.Session
|
|
return newToken.AccessToken;
|
|
return newToken.AccessToken;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /// <inheritdoc />
|
|
public void Logout(string accessToken)
|
|
public void Logout(string accessToken)
|
|
{
|
|
{
|
|
CheckDisposed();
|
|
CheckDisposed();
|
|
@@ -1495,19 +1518,20 @@ namespace Emby.Server.Implementations.Session
|
|
throw new ArgumentNullException(nameof(accessToken));
|
|
throw new ArgumentNullException(nameof(accessToken));
|
|
}
|
|
}
|
|
|
|
|
|
- var existing = _authRepo.Get(new AuthenticationInfoQuery
|
|
|
|
- {
|
|
|
|
- Limit = 1,
|
|
|
|
- AccessToken = accessToken
|
|
|
|
-
|
|
|
|
- }).Items.FirstOrDefault();
|
|
|
|
|
|
+ var existing = _authRepo.Get(
|
|
|
|
+ new AuthenticationInfoQuery
|
|
|
|
+ {
|
|
|
|
+ Limit = 1,
|
|
|
|
+ AccessToken = accessToken
|
|
|
|
+ }).Items;
|
|
|
|
|
|
- if (existing != null)
|
|
|
|
|
|
+ if (existing.Count > 0)
|
|
{
|
|
{
|
|
- Logout(existing);
|
|
|
|
|
|
+ Logout(existing[0]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /// <inheritdoc />
|
|
public void Logout(AuthenticationInfo existing)
|
|
public void Logout(AuthenticationInfo existing)
|
|
{
|
|
{
|
|
CheckDisposed();
|
|
CheckDisposed();
|
|
@@ -1533,6 +1557,7 @@ namespace Emby.Server.Implementations.Session
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /// <inheritdoc />
|
|
public void RevokeUserTokens(Guid userId, string currentAccessToken)
|
|
public void RevokeUserTokens(Guid userId, string currentAccessToken)
|
|
{
|
|
{
|
|
CheckDisposed();
|
|
CheckDisposed();
|
|
@@ -1551,6 +1576,7 @@ namespace Emby.Server.Implementations.Session
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /// <inheritdoc />
|
|
public void RevokeToken(string token)
|
|
public void RevokeToken(string token)
|
|
{
|
|
{
|
|
Logout(token);
|
|
Logout(token);
|
|
@@ -1607,10 +1633,8 @@ namespace Emby.Server.Implementations.Session
|
|
_deviceManager.SaveCapabilities(deviceId, capabilities);
|
|
_deviceManager.SaveCapabilities(deviceId, capabilities);
|
|
}
|
|
}
|
|
|
|
|
|
- private DtoOptions _itemInfoDtoOptions;
|
|
|
|
-
|
|
|
|
/// <summary>
|
|
/// <summary>
|
|
- /// Converts a BaseItem to a BaseItemInfo
|
|
|
|
|
|
+ /// Converts a BaseItem to a BaseItemInfo.
|
|
/// </summary>
|
|
/// </summary>
|
|
private BaseItemDto GetItemInfo(BaseItem item, MediaSourceInfo mediaSource)
|
|
private BaseItemDto GetItemInfo(BaseItem item, MediaSourceInfo mediaSource)
|
|
{
|
|
{
|
|
@@ -1685,6 +1709,7 @@ namespace Emby.Server.Implementations.Session
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /// <inheritdoc />
|
|
public void ReportNowViewingItem(string sessionId, string itemId)
|
|
public void ReportNowViewingItem(string sessionId, string itemId)
|
|
{
|
|
{
|
|
if (string.IsNullOrEmpty(itemId))
|
|
if (string.IsNullOrEmpty(itemId))
|
|
@@ -1692,23 +1717,26 @@ namespace Emby.Server.Implementations.Session
|
|
throw new ArgumentNullException(nameof(itemId));
|
|
throw new ArgumentNullException(nameof(itemId));
|
|
}
|
|
}
|
|
|
|
|
|
- //var item = _libraryManager.GetItemById(new Guid(itemId));
|
|
|
|
|
|
+ var item = _libraryManager.GetItemById(new Guid(itemId));
|
|
|
|
|
|
- //var info = GetItemInfo(item, null, null);
|
|
|
|
|
|
+ var info = GetItemInfo(item, null);
|
|
|
|
|
|
- //ReportNowViewingItem(sessionId, info);
|
|
|
|
|
|
+ ReportNowViewingItem(sessionId, info);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /// <inheritdoc />
|
|
public void ReportNowViewingItem(string sessionId, BaseItemDto item)
|
|
public void ReportNowViewingItem(string sessionId, BaseItemDto item)
|
|
{
|
|
{
|
|
- //var session = GetSession(sessionId);
|
|
|
|
|
|
+ throw new NotImplementedException();
|
|
|
|
|
|
- //session.NowViewingItem = item;
|
|
|
|
|
|
+ // var session = GetSession(sessionId);
|
|
|
|
+ // session.NowViewingItem = item;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /// <inheritdoc />
|
|
public void ReportTranscodingInfo(string deviceId, TranscodingInfo info)
|
|
public void ReportTranscodingInfo(string deviceId, TranscodingInfo info)
|
|
{
|
|
{
|
|
- var session = Sessions.FirstOrDefault(i => string.Equals(i.DeviceId, deviceId));
|
|
|
|
|
|
+ var session = Sessions.FirstOrDefault(i => string.Equals(i.DeviceId, deviceId, StringComparison.Ordinal));
|
|
|
|
|
|
if (session != null)
|
|
if (session != null)
|
|
{
|
|
{
|
|
@@ -1716,17 +1744,18 @@ namespace Emby.Server.Implementations.Session
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /// <inheritdoc />
|
|
public void ClearTranscodingInfo(string deviceId)
|
|
public void ClearTranscodingInfo(string deviceId)
|
|
{
|
|
{
|
|
ReportTranscodingInfo(deviceId, null);
|
|
ReportTranscodingInfo(deviceId, null);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /// <inheritdoc />
|
|
public SessionInfo GetSession(string deviceId, string client, string version)
|
|
public SessionInfo GetSession(string deviceId, string client, string version)
|
|
- {
|
|
|
|
- return Sessions.FirstOrDefault(i => string.Equals(i.DeviceId, deviceId) &&
|
|
|
|
- string.Equals(i.Client, client));
|
|
|
|
- }
|
|
|
|
|
|
+ => Sessions.FirstOrDefault(
|
|
|
|
+ i => string.Equals(i.DeviceId, deviceId, StringComparison.Ordinal) && string.Equals(i.Client, client, StringComparison.Ordinal));
|
|
|
|
|
|
|
|
+ /// <inheritdoc />
|
|
public SessionInfo GetSessionByAuthenticationToken(AuthenticationInfo info, string deviceId, string remoteEndpoint, string appVersion)
|
|
public SessionInfo GetSessionByAuthenticationToken(AuthenticationInfo info, string deviceId, string remoteEndpoint, string appVersion)
|
|
{
|
|
{
|
|
if (info == null)
|
|
if (info == null)
|
|
@@ -1759,23 +1788,24 @@ namespace Emby.Server.Implementations.Session
|
|
return LogSessionActivity(appName, appVersion, deviceId, deviceName, remoteEndpoint, user);
|
|
return LogSessionActivity(appName, appVersion, deviceId, deviceName, remoteEndpoint, user);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /// <inheritdoc />
|
|
public SessionInfo GetSessionByAuthenticationToken(string token, string deviceId, string remoteEndpoint)
|
|
public SessionInfo GetSessionByAuthenticationToken(string token, string deviceId, string remoteEndpoint)
|
|
{
|
|
{
|
|
- var result = _authRepo.Get(new AuthenticationInfoQuery
|
|
|
|
|
|
+ var items = _authRepo.Get(new AuthenticationInfoQuery
|
|
{
|
|
{
|
|
- AccessToken = token
|
|
|
|
- });
|
|
|
|
-
|
|
|
|
- var info = result.Items.FirstOrDefault();
|
|
|
|
|
|
+ AccessToken = token,
|
|
|
|
+ Limit = 1
|
|
|
|
+ }).Items;
|
|
|
|
|
|
- if (info == null)
|
|
|
|
|
|
+ if (items.Count == 0)
|
|
{
|
|
{
|
|
return null;
|
|
return null;
|
|
}
|
|
}
|
|
|
|
|
|
- return GetSessionByAuthenticationToken(info, deviceId, remoteEndpoint, null);
|
|
|
|
|
|
+ return GetSessionByAuthenticationToken(items[0], deviceId, remoteEndpoint, null);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /// <inheritdoc />
|
|
public Task SendMessageToAdminSessions<T>(string name, T data, CancellationToken cancellationToken)
|
|
public Task SendMessageToAdminSessions<T>(string name, T data, CancellationToken cancellationToken)
|
|
{
|
|
{
|
|
CheckDisposed();
|
|
CheckDisposed();
|
|
@@ -1785,6 +1815,7 @@ namespace Emby.Server.Implementations.Session
|
|
return SendMessageToUserSessions(adminUserIds, name, data, cancellationToken);
|
|
return SendMessageToUserSessions(adminUserIds, name, data, cancellationToken);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /// <inheritdoc />
|
|
public Task SendMessageToUserSessions<T>(List<Guid> userIds, string name, Func<T> dataFn, CancellationToken cancellationToken)
|
|
public Task SendMessageToUserSessions<T>(List<Guid> userIds, string name, Func<T> dataFn, CancellationToken cancellationToken)
|
|
{
|
|
{
|
|
CheckDisposed();
|
|
CheckDisposed();
|
|
@@ -1796,11 +1827,10 @@ namespace Emby.Server.Implementations.Session
|
|
return Task.CompletedTask;
|
|
return Task.CompletedTask;
|
|
}
|
|
}
|
|
|
|
|
|
- var data = dataFn();
|
|
|
|
-
|
|
|
|
- return SendMessageToSessions(sessions, name, data, cancellationToken);
|
|
|
|
|
|
+ return SendMessageToSessions(sessions, name, dataFn(), cancellationToken);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /// <inheritdoc />
|
|
public Task SendMessageToUserSessions<T>(List<Guid> userIds, string name, T data, CancellationToken cancellationToken)
|
|
public Task SendMessageToUserSessions<T>(List<Guid> userIds, string name, T data, CancellationToken cancellationToken)
|
|
{
|
|
{
|
|
CheckDisposed();
|
|
CheckDisposed();
|
|
@@ -1809,6 +1839,7 @@ namespace Emby.Server.Implementations.Session
|
|
return SendMessageToSessions(sessions, name, data, cancellationToken);
|
|
return SendMessageToSessions(sessions, name, data, cancellationToken);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /// <inheritdoc />
|
|
public Task SendMessageToUserDeviceSessions<T>(string deviceId, string name, T data, CancellationToken cancellationToken)
|
|
public Task SendMessageToUserDeviceSessions<T>(string deviceId, string name, T data, CancellationToken cancellationToken)
|
|
{
|
|
{
|
|
CheckDisposed();
|
|
CheckDisposed();
|
|
@@ -1817,22 +1848,5 @@ namespace Emby.Server.Implementations.Session
|
|
|
|
|
|
return SendMessageToSessions(sessions, name, data, cancellationToken);
|
|
return SendMessageToSessions(sessions, name, data, cancellationToken);
|
|
}
|
|
}
|
|
-
|
|
|
|
- public Task SendMessageToUserDeviceAndAdminSessions<T>(string deviceId, string name, T data, CancellationToken cancellationToken)
|
|
|
|
- {
|
|
|
|
- CheckDisposed();
|
|
|
|
-
|
|
|
|
- var sessions = Sessions
|
|
|
|
- .Where(i => string.Equals(i.DeviceId, deviceId, StringComparison.OrdinalIgnoreCase) || IsAdminSession(i));
|
|
|
|
-
|
|
|
|
- return SendMessageToSessions(sessions, name, data, cancellationToken);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private bool IsAdminSession(SessionInfo s)
|
|
|
|
- {
|
|
|
|
- var user = _userManager.GetUserById(s.UserId);
|
|
|
|
-
|
|
|
|
- return user != null && user.Policy.IsAdministrator;
|
|
|
|
- }
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|