mirror of
https://github.com/SoPat712/allstarr.git
synced 2026-02-09 23:55:10 -05:00
Fix scrobbling: track playing item in session and send proper PlaybackStopped data on cleanup
This commit is contained in:
@@ -2006,6 +2006,7 @@ public class JellyfinController : ControllerBase
|
|||||||
var doc = JsonDocument.Parse(body);
|
var doc = JsonDocument.Parse(body);
|
||||||
string? itemId = null;
|
string? itemId = null;
|
||||||
string? itemName = null;
|
string? itemName = null;
|
||||||
|
long? positionTicks = null;
|
||||||
|
|
||||||
if (doc.RootElement.TryGetProperty("ItemId", out var itemIdProp))
|
if (doc.RootElement.TryGetProperty("ItemId", out var itemIdProp))
|
||||||
{
|
{
|
||||||
@@ -2016,6 +2017,18 @@ public class JellyfinController : ControllerBase
|
|||||||
{
|
{
|
||||||
itemName = itemNameProp.GetString();
|
itemName = itemNameProp.GetString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (doc.RootElement.TryGetProperty("PositionTicks", out var posProp))
|
||||||
|
{
|
||||||
|
positionTicks = posProp.GetInt64();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Track the playing item for scrobbling on session cleanup
|
||||||
|
var (deviceId, client, device, version) = ExtractDeviceInfo(Request.Headers);
|
||||||
|
if (!string.IsNullOrEmpty(deviceId) && !string.IsNullOrEmpty(itemId))
|
||||||
|
{
|
||||||
|
_sessionManager.UpdatePlayingItem(deviceId, itemId, positionTicks);
|
||||||
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(itemId))
|
if (!string.IsNullOrEmpty(itemId))
|
||||||
{
|
{
|
||||||
@@ -2050,7 +2063,7 @@ public class JellyfinController : ControllerBase
|
|||||||
var playbackStart = new
|
var playbackStart = new
|
||||||
{
|
{
|
||||||
ItemId = itemId,
|
ItemId = itemId,
|
||||||
PositionTicks = doc.RootElement.TryGetProperty("PositionTicks", out var posProp) ? posProp.GetInt64() : 0,
|
PositionTicks = positionTicks ?? 0,
|
||||||
// Let Jellyfin fetch the item details - don't include NowPlayingItem
|
// Let Jellyfin fetch the item details - don't include NowPlayingItem
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -2064,7 +2077,6 @@ public class JellyfinController : ControllerBase
|
|||||||
_logger.LogInformation("✓ Playback start forwarded to Jellyfin ({StatusCode})", statusCode);
|
_logger.LogInformation("✓ Playback start forwarded to Jellyfin ({StatusCode})", statusCode);
|
||||||
|
|
||||||
// NOW ensure session exists with capabilities (after playback is reported)
|
// NOW ensure session exists with capabilities (after playback is reported)
|
||||||
var (deviceId, client, device, version) = ExtractDeviceInfo(Request.Headers);
|
|
||||||
if (!string.IsNullOrEmpty(deviceId))
|
if (!string.IsNullOrEmpty(deviceId))
|
||||||
{
|
{
|
||||||
var sessionCreated = await _sessionManager.EnsureSessionAsync(deviceId, client ?? "Unknown", device ?? "Unknown", version ?? "1.0", Request.Headers);
|
var sessionCreated = await _sessionManager.EnsureSessionAsync(deviceId, client ?? "Unknown", device ?? "Unknown", version ?? "1.0", Request.Headers);
|
||||||
@@ -2155,6 +2167,12 @@ public class JellyfinController : ControllerBase
|
|||||||
positionTicks = posProp.GetInt64();
|
positionTicks = posProp.GetInt64();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Track the playing item for scrobbling on session cleanup
|
||||||
|
if (!string.IsNullOrEmpty(deviceId) && !string.IsNullOrEmpty(itemId))
|
||||||
|
{
|
||||||
|
_sessionManager.UpdatePlayingItem(deviceId, itemId, positionTicks);
|
||||||
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(itemId))
|
if (!string.IsNullOrEmpty(itemId))
|
||||||
{
|
{
|
||||||
var (isExternal, provider, externalId) = _localLibraryService.ParseSongId(itemId);
|
var (isExternal, provider, externalId) = _localLibraryService.ParseSongId(itemId);
|
||||||
|
|||||||
@@ -142,6 +142,21 @@ public class JellyfinSessionManager : IDisposable
|
|||||||
_logger.LogDebug("⚠️ SESSION: Cannot update activity - device {DeviceId} not found", deviceId);
|
_logger.LogDebug("⚠️ SESSION: Cannot update activity - device {DeviceId} not found", deviceId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Updates the currently playing item for a session (for scrobbling on cleanup).
|
||||||
|
/// </summary>
|
||||||
|
public void UpdatePlayingItem(string deviceId, string? itemId, long? positionTicks)
|
||||||
|
{
|
||||||
|
if (_sessions.TryGetValue(deviceId, out var session))
|
||||||
|
{
|
||||||
|
session.LastPlayingItemId = itemId;
|
||||||
|
session.LastPlayingPositionTicks = positionTicks;
|
||||||
|
session.LastActivity = DateTime.UtcNow;
|
||||||
|
_logger.LogDebug("🎵 SESSION: Updated playing item for {DeviceId}: {ItemId} at {Position}",
|
||||||
|
deviceId, itemId, positionTicks);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Marks a session as potentially ended (e.g., after playback stops).
|
/// Marks a session as potentially ended (e.g., after playback stops).
|
||||||
@@ -230,10 +245,19 @@ public class JellyfinSessionManager : IDisposable
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Report playback stopped to Jellyfin
|
// Report playback stopped to Jellyfin if we have a playing item (for scrobbling)
|
||||||
var stopPayload = JsonSerializer.Serialize(new { });
|
if (!string.IsNullOrEmpty(session.LastPlayingItemId))
|
||||||
await _proxyService.PostJsonAsync("Sessions/Playing/Stopped", stopPayload, session.Headers);
|
{
|
||||||
_logger.LogDebug("🛑 SESSION: Reported playback stopped for {DeviceId}", deviceId);
|
var stopPayload = new
|
||||||
|
{
|
||||||
|
ItemId = session.LastPlayingItemId,
|
||||||
|
PositionTicks = session.LastPlayingPositionTicks ?? 0
|
||||||
|
};
|
||||||
|
var stopJson = JsonSerializer.Serialize(stopPayload);
|
||||||
|
await _proxyService.PostJsonAsync("Sessions/Playing/Stopped", stopJson, session.Headers);
|
||||||
|
_logger.LogInformation("🛑 SESSION: Reported playback stopped for {DeviceId} (ItemId: {ItemId}, Position: {Position})",
|
||||||
|
deviceId, session.LastPlayingItemId, session.LastPlayingPositionTicks);
|
||||||
|
}
|
||||||
|
|
||||||
// Notify Jellyfin that the session is ending
|
// Notify Jellyfin that the session is ending
|
||||||
await _proxyService.PostJsonAsync("Sessions/Logout", "{}", session.Headers);
|
await _proxyService.PostJsonAsync("Sessions/Logout", "{}", session.Headers);
|
||||||
@@ -500,6 +524,8 @@ public class JellyfinSessionManager : IDisposable
|
|||||||
public DateTime LastActivity { get; set; }
|
public DateTime LastActivity { get; set; }
|
||||||
public required IHeaderDictionary Headers { get; init; }
|
public required IHeaderDictionary Headers { get; init; }
|
||||||
public ClientWebSocket? WebSocket { get; set; }
|
public ClientWebSocket? WebSocket { get; set; }
|
||||||
|
public string? LastPlayingItemId { get; set; }
|
||||||
|
public long? LastPlayingPositionTicks { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
|
|||||||
Reference in New Issue
Block a user