using System;
using System.Threading;
using System.Threading.Tasks;
using Jellyfin.Plugin.SRFPlay.Services.Interfaces;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Session;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
namespace Jellyfin.Plugin.SRFPlay.Services;
///
/// Watches for livestream playback ending and immediately drops the resume point Jellyfin
/// just saved for it. Without this, every livestream a user stops watching sticks in
/// "Continue Watching" until the nightly cleanup task runs.
///
public class PlaybackResumeGuard : IHostedService
{
private readonly ILogger _logger;
private readonly ISessionManager _sessionManager;
private readonly IResumeCleanupService _resumeCleanupService;
///
/// Initializes a new instance of the class.
///
/// The logger.
/// The session manager raising playback events.
/// The resume cleanup service.
public PlaybackResumeGuard(
ILogger logger,
ISessionManager sessionManager,
IResumeCleanupService resumeCleanupService)
{
_logger = logger;
_sessionManager = sessionManager;
_resumeCleanupService = resumeCleanupService;
}
///
public Task StartAsync(CancellationToken cancellationToken)
{
_sessionManager.PlaybackStopped += OnPlaybackStopped;
_logger.LogDebug("PlaybackResumeGuard attached to session manager");
return Task.CompletedTask;
}
///
public Task StopAsync(CancellationToken cancellationToken)
{
_sessionManager.PlaybackStopped -= OnPlaybackStopped;
return Task.CompletedTask;
}
private void OnPlaybackStopped(object? sender, PlaybackStopEventArgs e)
{
// Jellyfin saves the resume point before raising this event, so clearing it here wins.
if (e?.Item == null || e.Users == null || e.Users.Count == 0)
{
return;
}
try
{
var cleared = _resumeCleanupService.ClearLiveStreamResumePoint(e.Item, e.Users);
if (cleared > 0)
{
_logger.LogDebug(
"Dropped {Count} resume point(s) for finished livestream '{Name}'",
cleared,
e.Item.Name);
}
}
catch (Exception ex)
{
// Never let a cleanup failure escape into Jellyfin's playback event pipeline.
_logger.LogError(ex, "Error clearing livestream resume point for '{Name}'", e.Item.Name);
}
}
}