Files
silo-server/internal/playback/chapter_thumbnail_notifier.go
T

122 lines
2.6 KiB
Go

package playback
import (
"context"
"errors"
"log/slog"
"strings"
"time"
)
const defaultChapterThumbnailEventTTL = 15 * time.Minute
type chapterThumbnailSessionLookup interface {
GetSessionsByMediaFileID(fileID int) []*Session
}
type chapterThumbnailURLPresigner interface {
PresignGetURL(ctx context.Context, bucket, key string, expiry time.Duration) (string, error)
Bucket() string
}
// ChapterThumbnailNotifier publishes live chapter thumbnail updates to active playback sessions.
type ChapterThumbnailNotifier struct {
sessions chapterThumbnailSessionLookup
hub *RealtimeHub
presign chapterThumbnailURLPresigner
ttl time.Duration
}
// NewChapterThumbnailNotifier creates a notifier that targets active sessions for a file.
func NewChapterThumbnailNotifier(
sessions chapterThumbnailSessionLookup,
hub *RealtimeHub,
presign chapterThumbnailURLPresigner,
ttl time.Duration,
) *ChapterThumbnailNotifier {
if sessions == nil || hub == nil || presign == nil {
return nil
}
if ttl <= 0 {
ttl = defaultChapterThumbnailEventTTL
}
return &ChapterThumbnailNotifier{
sessions: sessions,
hub: hub,
presign: presign,
ttl: ttl,
}
}
// ChapterThumbnailReady notifies active sessions that a chapter thumbnail is now available.
func (n *ChapterThumbnailNotifier) ChapterThumbnailReady(
ctx context.Context,
fileID int,
chapterIndex int,
thumbnailPath string,
thumbnailThumbhash string,
) {
if n == nil || fileID <= 0 || chapterIndex < 0 || thumbnailPath == "" {
return
}
thumbnailURL, err := n.presign.PresignGetURL(
ctx,
n.presign.Bucket(),
strings.Replace(thumbnailPath, "/original.", "/w300.", 1),
n.ttl,
)
if err != nil {
slog.Warn(
"failed to presign chapter thumbnail for realtime event",
"file_id",
fileID,
"chapter_index",
chapterIndex,
"error",
err,
)
return
}
for _, session := range n.sessions.GetSessionsByMediaFileID(fileID) {
if session == nil || session.ID == "" || !session.HasRealtimeConnection {
continue
}
event, err := NewChapterThumbnailReadyEvent(
session.ID,
fileID,
chapterIndex,
thumbnailURL,
thumbnailThumbhash,
)
if err != nil {
slog.Warn(
"failed to encode chapter thumbnail realtime event",
"session_id",
session.ID,
"file_id",
fileID,
"chapter_index",
chapterIndex,
"error",
err,
)
continue
}
if err := n.hub.Send(session.ID, event); err != nil && !errors.Is(err, ErrRealtimeConnectionNotFound) {
slog.Warn(
"failed to deliver chapter thumbnail realtime event",
"session_id",
session.ID,
"file_id",
fileID,
"chapter_index",
chapterIndex,
"error",
err,
)
}
}
}