App v0.2.26 and gateway 0.1.20
Client: seek controls, Bazarr subtitle download and cast panel in the player; MDBList ratings strip; episode and schedule detail pages; series pace estimate; what's new panel; install-permission onboarding step; synced per-profile preferences; Emby outage banner. Gateway: rebuilt admin console (one fragment per page), preference history and restore, merged Continue Watching, Emby health probe, subtitle selection and Bazarr download, structured request logging with per-request identity, and embedded build version. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
2675e6d82b
commit
4a4df7a73c
@@ -64,7 +64,7 @@ func (s *Server) buildRecommendations(ctx context.Context, sess store.Session) (
|
||||
// rebuild on every single home load.
|
||||
if raw, err := json.Marshal(rows); err == nil {
|
||||
if err := s.cache.Set(ctx, cache.RecommendationsKey(sess.EmbyUserID), raw, s.cfg.RecommendTTL); err != nil {
|
||||
s.log.Warn("recommendation cache write failed", "error", err)
|
||||
s.loggerFor(ctx).Warn("recommendation cache write failed", "error", err)
|
||||
}
|
||||
}
|
||||
return rows, nil
|
||||
@@ -89,10 +89,10 @@ func (s *Server) refreshRecommendationsInBackground(sess store.Session) {
|
||||
started := time.Now()
|
||||
rows, err := s.buildRecommendations(ctx, sess)
|
||||
if err != nil {
|
||||
s.log.Warn("recommendation build failed", "user", sess.EmbyUserID, "error", err)
|
||||
s.loggerFor(ctx).Warn("recommendation build failed", "user", sess.EmbyUserID, "error", err)
|
||||
return
|
||||
}
|
||||
s.log.Info("recommendations rebuilt",
|
||||
s.loggerFor(ctx).Info("recommendations rebuilt",
|
||||
"user", sess.EmbyUserID, "rows", len(rows), "ms", time.Since(started).Milliseconds())
|
||||
}()
|
||||
}
|
||||
@@ -107,6 +107,7 @@ func (s *Server) handleRecommendations(w http.ResponseWriter, r *http.Request, s
|
||||
if !forceRefresh {
|
||||
if rows := s.cachedRecommendations(ctx, sess.EmbyUserID); rows != nil {
|
||||
w.Header().Set("X-Memby-Cache", "hit")
|
||||
s.decorateRowRatings(ctx, rows)
|
||||
writeJSON(w, http.StatusOK, map[string]any{"rows": rows})
|
||||
return
|
||||
}
|
||||
@@ -117,10 +118,11 @@ func (s *Server) handleRecommendations(w http.ResponseWriter, r *http.Request, s
|
||||
|
||||
rows, err := s.buildRecommendations(buildCtx, sess)
|
||||
if err != nil {
|
||||
s.writeUpstreamError(w, err, "could not build recommendations")
|
||||
s.writeUpstreamError(ctx, w, err, "could not build recommendations")
|
||||
return
|
||||
}
|
||||
w.Header().Set("X-Memby-Cache", "miss")
|
||||
s.decorateRowRatings(ctx, rows)
|
||||
writeJSON(w, http.StatusOK, map[string]any{"rows": nonNilRows(rows)})
|
||||
}
|
||||
|
||||
@@ -132,13 +134,14 @@ func (s *Server) handleForYou(w http.ResponseWriter, r *http.Request, sess store
|
||||
if s.forYou != nil && r.URL.Query().Get("refresh") != "1" {
|
||||
rows, hit, stale, err := s.forYou.PreparedRows(r.Context(), sess, minutes)
|
||||
if err != nil {
|
||||
s.log.Warn("prepared For You read failed; using live fallback",
|
||||
s.loggerFor(r.Context()).Warn("prepared For You read failed; using live fallback",
|
||||
"user", sess.EmbyUserID, "error", err)
|
||||
} else if hit {
|
||||
rows = s.filterRecommendationPermissions(r.Context(), sess, rows)
|
||||
rows = s.personalizeTitles(r.Context(), sess, rows)
|
||||
rows = deduplicateRows(personalizeRowsByTitleScores(selectPersonalizedRows(rows)))
|
||||
w.Header().Set("X-Memby-For-You", "prepared")
|
||||
s.decorateRowRatings(r.Context(), rows)
|
||||
if stale {
|
||||
s.forYou.MarkDirty(r.Context(), sess)
|
||||
s.forYou.RefreshAsync(sess, false)
|
||||
@@ -160,13 +163,14 @@ func (s *Server) handleForYou(w http.ResponseWriter, r *http.Request, sess store
|
||||
recommend.ForYouOptions{AvailableMinutes: minutes},
|
||||
)
|
||||
if err != nil {
|
||||
s.writeUpstreamError(w, err, "could not build For You recommendations")
|
||||
s.writeUpstreamError(r.Context(), w, err, "could not build For You recommendations")
|
||||
return
|
||||
}
|
||||
rows = s.filterRecommendationPermissions(r.Context(), sess, rows)
|
||||
rows = s.personalizeTitles(r.Context(), sess, rows)
|
||||
rows = deduplicateRows(personalizeRowsByTitleScores(selectPersonalizedRows(rows)))
|
||||
w.Header().Set("X-Memby-For-You", "live-fallback")
|
||||
s.decorateRowRatings(r.Context(), rows)
|
||||
writeJSON(w, http.StatusOK, map[string]any{"rows": nonNilRows(rows)})
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user