package jellyfin
import (
"context"
"encoding/json"
"net/http"
"github.com/navidrome/navidrome/core/scrobbler"
"github.com/navidrome/navidrome/log"
"github.com/navidrome/navidrome/model/request"
"github.com/navidrome/navidrome/server/jellyfin/dto"
)
type playbackReport struct {
ItemId string `json:"ItemId"`
PositionTicks int64 `json:"PositionTicks"`
IsPaused bool `json:"IsPaused"`
}
func (api *Router) decodeReport(r *http.Request) playbackReport {
var body playbackReport
_ = json.NewDecoder(r.Body).Decode(&body)
if body.ItemId == "" {
body.ItemId = r.URL.Query().Get("itemid")
}
if id, ok := dto.DecodeID(body.ItemId); ok {
body.ItemId = id
} else {
body.ItemId = ""
}
return body
}
func clientIdentity(ctx context.Context) (id, name string) {
player, _ := request.PlayerFrom(ctx)
return player.ID, player.Client
}
func (api *Router) reportPlaybackStart(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
body := api.decodeReport(r)
clientId, clientName := clientIdentity(ctx)
err := api.scrobbler.ReportPlayback(ctx, scrobbler.ReportPlaybackParams{
MediaId: body.ItemId,
PositionMs: dto.MillisFromTicks(body.PositionTicks),
State: scrobbler.StatePlaying,
PlaybackRate: 1.0,
ClientId: clientId,
ClientName: clientName,
})
if err != nil {
log.Warn(ctx, "Jellyfin API: report playback start failed", "id", body.ItemId, err)
}
w.WriteHeader(http.StatusNoContent)
}
func (api *Router) reportPlaybackProgress(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
body := api.decodeReport(r)
state := scrobbler.StatePlaying
if body.IsPaused {
state = scrobbler.StatePaused
}
clientId, clientName := clientIdentity(ctx)
err := api.scrobbler.ReportPlayback(ctx, scrobbler.ReportPlaybackParams{
MediaId: body.ItemId,
PositionMs: dto.MillisFromTicks(body.PositionTicks),
State: state,
PlaybackRate: 1.0,
ClientId: clientId,
ClientName: clientName,
})
if err != nil {
log.Warn(ctx, "Jellyfin API: report playback progress failed", "id", body.ItemId, err)
}
w.WriteHeader(http.StatusNoContent)
}
func (api *Router) reportPlaybackStopped(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
body := api.decodeReport(r)
clientId, clientName := clientIdentity(ctx)
err := api.scrobbler.ReportPlayback(ctx, scrobbler.ReportPlaybackParams{
MediaId: body.ItemId,
PositionMs: dto.MillisFromTicks(body.PositionTicks),
State: scrobbler.StateStopped,
ClientId: clientId,
ClientName: clientName,
})
if err != nil {
log.Warn(ctx, "Jellyfin API: report playback stopped failed", "id", body.ItemId, err)
}
w.WriteHeader(http.StatusNoContent)
}
func (api *Router) acknowledge(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusNoContent)
}