Merge pull request #10357 from herby2212/kill-inactive-streams-v2
Add auto close of an inactive session after X minutes
This commit is contained in:
commit
0973f1e0ba
|
@ -19,6 +19,7 @@ using MediaBrowser.Common.Events;
|
||||||
using MediaBrowser.Common.Extensions;
|
using MediaBrowser.Common.Extensions;
|
||||||
using MediaBrowser.Controller;
|
using MediaBrowser.Controller;
|
||||||
using MediaBrowser.Controller.Authentication;
|
using MediaBrowser.Controller.Authentication;
|
||||||
|
using MediaBrowser.Controller.Configuration;
|
||||||
using MediaBrowser.Controller.Devices;
|
using MediaBrowser.Controller.Devices;
|
||||||
using MediaBrowser.Controller.Drawing;
|
using MediaBrowser.Controller.Drawing;
|
||||||
using MediaBrowser.Controller.Dto;
|
using MediaBrowser.Controller.Dto;
|
||||||
|
@ -48,6 +49,7 @@ namespace Emby.Server.Implementations.Session
|
||||||
public sealed class SessionManager : ISessionManager, IAsyncDisposable
|
public sealed class SessionManager : ISessionManager, IAsyncDisposable
|
||||||
{
|
{
|
||||||
private readonly IUserDataManager _userDataManager;
|
private readonly IUserDataManager _userDataManager;
|
||||||
|
private readonly IServerConfigurationManager _config;
|
||||||
private readonly ILogger<SessionManager> _logger;
|
private readonly ILogger<SessionManager> _logger;
|
||||||
private readonly IEventManager _eventManager;
|
private readonly IEventManager _eventManager;
|
||||||
private readonly ILibraryManager _libraryManager;
|
private readonly ILibraryManager _libraryManager;
|
||||||
|
@ -63,6 +65,7 @@ namespace Emby.Server.Implementations.Session
|
||||||
= new(StringComparer.OrdinalIgnoreCase);
|
= new(StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
private Timer _idleTimer;
|
private Timer _idleTimer;
|
||||||
|
private Timer _inactiveTimer;
|
||||||
|
|
||||||
private DtoOptions _itemInfoDtoOptions;
|
private DtoOptions _itemInfoDtoOptions;
|
||||||
private bool _disposed = false;
|
private bool _disposed = false;
|
||||||
|
@ -71,6 +74,7 @@ namespace Emby.Server.Implementations.Session
|
||||||
ILogger<SessionManager> logger,
|
ILogger<SessionManager> logger,
|
||||||
IEventManager eventManager,
|
IEventManager eventManager,
|
||||||
IUserDataManager userDataManager,
|
IUserDataManager userDataManager,
|
||||||
|
IServerConfigurationManager config,
|
||||||
ILibraryManager libraryManager,
|
ILibraryManager libraryManager,
|
||||||
IUserManager userManager,
|
IUserManager userManager,
|
||||||
IMusicManager musicManager,
|
IMusicManager musicManager,
|
||||||
|
@ -84,6 +88,7 @@ namespace Emby.Server.Implementations.Session
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_eventManager = eventManager;
|
_eventManager = eventManager;
|
||||||
_userDataManager = userDataManager;
|
_userDataManager = userDataManager;
|
||||||
|
_config = config;
|
||||||
_libraryManager = libraryManager;
|
_libraryManager = libraryManager;
|
||||||
_userManager = userManager;
|
_userManager = userManager;
|
||||||
_musicManager = musicManager;
|
_musicManager = musicManager;
|
||||||
|
@ -369,6 +374,15 @@ namespace Emby.Server.Implementations.Session
|
||||||
session.LastPlaybackCheckIn = DateTime.UtcNow;
|
session.LastPlaybackCheckIn = DateTime.UtcNow;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (info.IsPaused && session.LastPausedDate is null)
|
||||||
|
{
|
||||||
|
session.LastPausedDate = DateTime.UtcNow;
|
||||||
|
}
|
||||||
|
else if (!info.IsPaused)
|
||||||
|
{
|
||||||
|
session.LastPausedDate = null;
|
||||||
|
}
|
||||||
|
|
||||||
session.PlayState.IsPaused = info.IsPaused;
|
session.PlayState.IsPaused = info.IsPaused;
|
||||||
session.PlayState.PositionTicks = info.PositionTicks;
|
session.PlayState.PositionTicks = info.PositionTicks;
|
||||||
session.PlayState.MediaSourceId = info.MediaSourceId;
|
session.PlayState.MediaSourceId = info.MediaSourceId;
|
||||||
|
@ -536,9 +550,18 @@ namespace Emby.Server.Implementations.Session
|
||||||
return users;
|
return users;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void StartIdleCheckTimer()
|
private void StartCheckTimers()
|
||||||
{
|
{
|
||||||
_idleTimer ??= new Timer(CheckForIdlePlayback, null, TimeSpan.FromMinutes(5), TimeSpan.FromMinutes(5));
|
_idleTimer ??= new Timer(CheckForIdlePlayback, null, TimeSpan.FromMinutes(5), TimeSpan.FromMinutes(5));
|
||||||
|
|
||||||
|
if (_config.Configuration.InactiveSessionThreshold > 0)
|
||||||
|
{
|
||||||
|
_inactiveTimer ??= new Timer(CheckForInactiveSteams, null, TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(1));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
StopInactiveCheckTimer();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void StopIdleCheckTimer()
|
private void StopIdleCheckTimer()
|
||||||
|
@ -550,6 +573,15 @@ namespace Emby.Server.Implementations.Session
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void StopInactiveCheckTimer()
|
||||||
|
{
|
||||||
|
if (_inactiveTimer is not null)
|
||||||
|
{
|
||||||
|
_inactiveTimer.Dispose();
|
||||||
|
_inactiveTimer = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async void CheckForIdlePlayback(object state)
|
private async void CheckForIdlePlayback(object state)
|
||||||
{
|
{
|
||||||
var playingSessions = Sessions.Where(i => i.NowPlayingItem is not null)
|
var playingSessions = Sessions.Where(i => i.NowPlayingItem is not null)
|
||||||
|
@ -585,13 +617,50 @@ namespace Emby.Server.Implementations.Session
|
||||||
playingSessions = Sessions.Where(i => i.NowPlayingItem is not null)
|
playingSessions = Sessions.Where(i => i.NowPlayingItem is not null)
|
||||||
.ToList();
|
.ToList();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
if (playingSessions.Count == 0)
|
|
||||||
{
|
{
|
||||||
StopIdleCheckTimer();
|
StopIdleCheckTimer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async void CheckForInactiveSteams(object state)
|
||||||
|
{
|
||||||
|
var inactiveSessions = Sessions.Where(i =>
|
||||||
|
i.NowPlayingItem is not null
|
||||||
|
&& i.PlayState.IsPaused
|
||||||
|
&& (DateTime.UtcNow - i.LastPausedDate).Value.TotalMinutes > _config.Configuration.InactiveSessionThreshold);
|
||||||
|
|
||||||
|
foreach (var session in inactiveSessions)
|
||||||
|
{
|
||||||
|
_logger.LogDebug("Session {Session} has been inactive for {InactiveTime} minutes. Stopping it.", session.Id, _config.Configuration.InactiveSessionThreshold);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await SendPlaystateCommand(
|
||||||
|
session.Id,
|
||||||
|
session.Id,
|
||||||
|
new PlaystateRequest()
|
||||||
|
{
|
||||||
|
Command = PlaystateCommand.Stop,
|
||||||
|
ControllingUserId = session.UserId.ToString(),
|
||||||
|
SeekPositionTicks = session.PlayState?.PositionTicks
|
||||||
|
},
|
||||||
|
CancellationToken.None).ConfigureAwait(true);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogDebug(ex, "Error calling SendPlaystateCommand for stopping inactive session {Session}.", session.Id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool playingSessions = Sessions.Any(i => i.NowPlayingItem is not null);
|
||||||
|
|
||||||
|
if (!playingSessions)
|
||||||
|
{
|
||||||
|
StopInactiveCheckTimer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private BaseItem GetNowPlayingItem(SessionInfo session, Guid itemId)
|
private BaseItem GetNowPlayingItem(SessionInfo session, Guid itemId)
|
||||||
{
|
{
|
||||||
var item = session.FullNowPlayingItem;
|
var item = session.FullNowPlayingItem;
|
||||||
|
@ -668,7 +737,7 @@ namespace Emby.Server.Implementations.Session
|
||||||
eventArgs,
|
eventArgs,
|
||||||
_logger);
|
_logger);
|
||||||
|
|
||||||
StartIdleCheckTimer();
|
StartCheckTimers();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -762,7 +831,7 @@ namespace Emby.Server.Implementations.Session
|
||||||
session.StartAutomaticProgress(info);
|
session.StartAutomaticProgress(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
StartIdleCheckTimer();
|
StartCheckTimers();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnPlaybackProgress(User user, BaseItem item, PlaybackProgressInfo info)
|
private void OnPlaybackProgress(User user, BaseItem item, PlaybackProgressInfo info)
|
||||||
|
@ -1798,6 +1867,12 @@ namespace Emby.Server.Implementations.Session
|
||||||
_idleTimer = null;
|
_idleTimer = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_inactiveTimer is not null)
|
||||||
|
{
|
||||||
|
await _inactiveTimer.DisposeAsync().ConfigureAwait(false);
|
||||||
|
_inactiveTimer = null;
|
||||||
|
}
|
||||||
|
|
||||||
await _shutdownCallback.DisposeAsync().ConfigureAwait(false);
|
await _shutdownCallback.DisposeAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
_deviceManager.DeviceOptionsUpdated -= OnDeviceManagerDeviceOptionsUpdated;
|
_deviceManager.DeviceOptionsUpdated -= OnDeviceManagerDeviceOptionsUpdated;
|
||||||
|
|
|
@ -109,6 +109,12 @@ namespace MediaBrowser.Controller.Session
|
||||||
/// <value>The last playback check in.</value>
|
/// <value>The last playback check in.</value>
|
||||||
public DateTime LastPlaybackCheckIn { get; set; }
|
public DateTime LastPlaybackCheckIn { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the last paused date.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The last paused date.</value>
|
||||||
|
public DateTime? LastPausedDate { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the name of the device.
|
/// Gets or sets the name of the device.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -158,6 +158,13 @@ public class ServerConfiguration : BaseApplicationConfiguration
|
||||||
/// <value>The remaining time in minutes.</value>
|
/// <value>The remaining time in minutes.</value>
|
||||||
public int MaxAudiobookResume { get; set; } = 5;
|
public int MaxAudiobookResume { get; set; } = 5;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the threshold in minutes after a inactive session gets closed automatically.
|
||||||
|
/// If set to 0 the check for inactive sessions gets disabled.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The close inactive session threshold in minutes. 0 to disable.</value>
|
||||||
|
public int InactiveSessionThreshold { get; set; } = 10;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the delay in seconds that we will wait after a file system change to try and discover what has been added/removed
|
/// Gets or sets the delay in seconds that we will wait after a file system change to try and discover what has been added/removed
|
||||||
/// Some delay is necessary with some items because their creation is not atomic. It involves the creation of several
|
/// Some delay is necessary with some items because their creation is not atomic. It involves the creation of several
|
||||||
|
|
Loading…
Reference in New Issue
Block a user