0.2.63 update

This commit is contained in:
ponzischeme89
2026-08-14 11:47:32 +12:00
parent 9a8ecbdceb
commit 06b6490ac9
41 changed files with 921 additions and 179 deletions
+44 -2
View File
@@ -8,8 +8,10 @@ import (
"net/url"
"strconv"
"strings"
"time"
"github.com/ponzischeme89/memby/server/internal/emby"
serverlogging "github.com/ponzischeme89/memby/server/internal/logging"
"github.com/ponzischeme89/memby/server/internal/store"
)
@@ -161,9 +163,11 @@ func (s *Server) handlePlayback(w http.ResponseWriter, r *http.Request, sess sto
subtitleIndex = &parsed
}
}
negotiationStarted := time.Now()
forceTranscode := queryBool(r, "forceTranscode")
subtitles, mediaSourceID, playSessionID, negotiatedURL, playMethod := s.playbackSubtitles(
ctx, cred, target.ID, target.UserData.PlaybackPositionTicks, subtitleIndex, "",
queryBool(r, "forceTranscode"), s.effectivePlaybackCapabilities(ctx, sess),
forceTranscode, s.effectivePlaybackCapabilities(ctx, sess),
)
streamURL := s.emby.StreamURL(cred, target.ID)
if negotiatedURL != "" {
@@ -198,6 +202,10 @@ func (s *Server) handlePlayback(w http.ResponseWriter, r *http.Request, sess sto
"subtitles", len(subtitles),
"subtitle_track", clientLogValue(selectedSubtitleID),
"subtitle_language", clientLogValue(subtitleLanguage),
"media_source_id", mediaSourceID,
"play_session_id", clientLogValue(playSessionID),
"force_transcode", forceTranscode,
"negotiation_duration", time.Since(negotiationStarted).Round(time.Millisecond),
)
writeJSON(w, http.StatusOK, playbackResponse{
@@ -392,15 +400,20 @@ func (s *Server) playbackSubtitles(
subtitleIndex *int, currentPlaySessionID string, forceTranscode bool,
capabilities emby.PlaybackCapabilities,
) ([]playableSubtitle, string, string, string, string) {
started := time.Now()
log := s.loggerFor(ctx).With("item", itemID, "force_transcode", forceTranscode,
"subtitle_index", subtitleIndex != nil, "resume", millisecondDuration(startTicks/ticksPerMillisecond))
log.Log(ctx, serverlogging.LevelTrace, "Emby playback negotiation started")
info, err := s.emby.PlaybackInfo(
ctx, cred, itemID, startTicks, subtitleIndex, currentPlaySessionID, forceTranscode,
capabilities,
)
if err != nil {
s.loggerFor(ctx).Warn("could not load subtitle metadata", "item_id", itemID, "error", err)
log.Warn("Emby playback negotiation failed", "duration", time.Since(started).Round(time.Millisecond), "error", err)
return []playableSubtitle{}, itemID, "", "", "DirectPlay"
}
if len(info.MediaSources) == 0 {
log.Warn("Emby playback negotiation returned no media sources", "duration", time.Since(started).Round(time.Millisecond), "play_session_id", info.PlaySessionID)
return []playableSubtitle{}, itemID, info.PlaySessionID, "", "DirectPlay"
}
out := make([]playableSubtitle, 0)
@@ -457,12 +470,37 @@ func (s *Server) playbackSubtitles(
// download that produced it.
out = mergeSubtitleTracks(out, s.storedSubtitlesFor(ctx, itemID))
delivery, playMethod := selectPlaybackDelivery(source, forceTranscode || subtitleIndex != nil)
log.Debug("Emby playback source selected",
"duration", time.Since(started).Round(time.Millisecond), "play_session_id", info.PlaySessionID,
"media_source_id", source.ID, "media_sources", len(info.MediaSources), "subtitles", len(out),
"play_method", playMethod, "selection_reason", playbackSelectionReason(source, forceTranscode || subtitleIndex != nil),
"supports_direct_play", source.SupportsDirectPlay, "supports_direct_stream", source.SupportsDirectStream,
"supports_transcoding", source.SupportsTranscoding)
if delivery != "" {
delivery = s.emby.DeliveryURL(cred, delivery)
}
return out, source.ID, info.PlaySessionID, delivery, playMethod
}
func playbackSelectionReason(source emby.MediaSourceInfo, forceTranscode bool) string {
switch {
case forceTranscode && source.TranscodingURL != "":
return "forced by viewer or burned-in subtitle"
case source.SupportsDirectPlay:
return "source supports direct play"
case source.SupportsDirectStream && source.DirectStreamURL != "":
return "direct play unavailable; source supports direct stream"
case source.SupportsTranscoding && source.TranscodingURL != "":
return "source requires transcoding"
case source.DirectStreamURL != "":
return "fallback direct-stream URL available"
case source.TranscodingURL != "":
return "fallback transcode URL available"
default:
return "Emby supplied no alternate delivery URL"
}
}
func sessionPlaybackCapabilities(sess store.Session) emby.PlaybackCapabilities {
capabilities := emby.PlaybackCapabilities{}
for _, value := range sess.ClientCapabilities {
@@ -729,6 +767,8 @@ func (s *Server) handlePlaybackReport(w http.ResponseWriter, r *http.Request, se
log := s.loggerFor(r.Context()).With(
"title", s.playbackTitles.name(report.ItemID),
"item", report.ItemID,
"media_source_id", clientLogValue(report.MediaSourceID),
"play_session_id", clientLogValue(report.PlaySessionID),
)
err := s.emby.ReportPlayback(
@@ -756,6 +796,7 @@ func (s *Server) handlePlaybackReport(w http.ResponseWriter, r *http.Request, se
log.Info("playback started",
"position", millisecondDuration(report.PositionMs),
"play_method", clientLogValue(report.PlayMethod),
"event_name", clientLogValue(report.EventName),
)
case "stopped":
log.Info("playback stopped",
@@ -767,6 +808,7 @@ func (s *Server) handlePlaybackReport(w http.ResponseWriter, r *http.Request, se
log.Debug("playback progress",
"position", millisecondDuration(report.PositionMs),
"paused", report.IsPaused,
"event_name", clientLogValue(report.EventName),
)
}