refactor(playback): consolidate clone functions and choosePlaybackSource

This commit is contained in:
2026-04-20 01:24:07 +02:00
parent 714ea42555
commit 82820f04d3
2 changed files with 17 additions and 50 deletions

View File

@@ -180,7 +180,7 @@ func (s *Service) BuildWatchPageData(ctx context.Context, malID int, titleCandid
StartTimeSeconds: userState.StartTimeSeconds, StartTimeSeconds: userState.StartTimeSeconds,
CurrentStatus: userState.CurrentStatus, CurrentStatus: userState.CurrentStatus,
InitialMode: initialMode, InitialMode: initialMode,
AvailableModes: cloneStringSlice(baseData.AvailableModes), AvailableModes: cloneSlice(baseData.AvailableModes),
ModeSources: clientModeSources, ModeSources: clientModeSources,
Segments: cloneSegments(baseData.Segments), Segments: cloneSegments(baseData.Segments),
}, nil }, nil
@@ -336,17 +336,17 @@ func (s *Service) fetchPlaybackSourcesAndSegments(ctx context.Context, showID st
func clonePlaybackBaseData(data playbackBaseData) playbackBaseData { func clonePlaybackBaseData(data playbackBaseData) playbackBaseData {
return playbackBaseData{ return playbackBaseData{
Title: data.Title, Title: data.Title,
AvailableModes: cloneStringSlice(data.AvailableModes), AvailableModes: cloneSlice(data.AvailableModes),
ModeSources: cloneModeSources(data.ModeSources), ModeSources: cloneModeSources(data.ModeSources),
Segments: cloneSegments(data.Segments), Segments: cloneSlice(data.Segments),
} }
} }
func cloneStringSlice(items []string) []string { func cloneSlice[T any](items []T) []T {
if len(items) == 0 { if len(items) == 0 {
return nil return nil
} }
cloned := make([]string, len(items)) cloned := make([]T, len(items))
copy(cloned, items) copy(cloned, items)
return cloned return cloned
} }
@@ -367,19 +367,9 @@ func cloneModeSources(modeSources map[string]ModeSource) map[string]ModeSource {
} }
func cloneSubtitleItems(items []SubtitleItem) []SubtitleItem { func cloneSubtitleItems(items []SubtitleItem) []SubtitleItem {
if len(items) == 0 { return cloneSlice(items)
return nil
}
cloned := make([]SubtitleItem, len(items))
copy(cloned, items)
return cloned
} }
func cloneSegments(segments []SkipSegment) []SkipSegment { func cloneSegments(segments []SkipSegment) []SkipSegment {
if len(segments) == 0 { return cloneSlice(segments)
return nil
}
cloned := make([]SkipSegment, len(segments))
copy(cloned, segments)
return cloned
} }

View File

@@ -20,7 +20,7 @@ func (s *Service) resolveModeSource(ctx context.Context, showID string, episode
return StreamSource{}, err return StreamSource{}, err
} }
selected, _, err := s.choosePlaybackSource(ctx, ranked) selected, _, err := s.choosePlaybackSource(ctx, ranked, s.probeDirectMedia)
if err != nil { if err != nil {
return StreamSource{}, err return StreamSource{}, err
} }
@@ -55,7 +55,11 @@ func (s *Service) resolveModeSourceWithCache(
return selected, nil return selected, nil
} }
func (s *Service) choosePlaybackSource(ctx context.Context, ranked []sourceScore) (StreamSource, string, error) { func (s *Service) choosePlaybackSource(
ctx context.Context,
ranked []sourceScore,
probeFn func(context.Context, StreamSource) (bool, string),
) (StreamSource, string, error) {
if len(ranked) == 0 { if len(ranked) == 0 {
return StreamSource{}, "", errors.New("no ranked sources available") return StreamSource{}, "", errors.New("no ranked sources available")
} }
@@ -69,7 +73,7 @@ func (s *Service) choosePlaybackSource(ctx context.Context, ranked []sourceScore
case "embed": case "embed":
embedCandidates = append(embedCandidates, source) embedCandidates = append(embedCandidates, source)
default: default:
if playable, contentType := s.probeDirectMedia(ctx, source); playable { if playable, contentType := probeFn(ctx, source); playable {
return normalizeSourceTypeFromProbe(source, contentType), "probed-media", nil return normalizeSourceTypeFromProbe(source, contentType), "probed-media", nil
} }
} }
@@ -94,36 +98,9 @@ func (s *Service) choosePlaybackSourceWithCache(
probeCache map[string]directProbeResult, probeCache map[string]directProbeResult,
probeCacheMu *sync.Mutex, probeCacheMu *sync.Mutex,
) (StreamSource, string, error) { ) (StreamSource, string, error) {
if len(ranked) == 0 { return s.choosePlaybackSource(ctx, ranked, func(ctx context.Context, source StreamSource) (bool, string) {
return StreamSource{}, "", errors.New("no ranked sources available") return s.probeDirectMediaCached(ctx, source, probeCache, probeCacheMu)
} })
embedCandidates := make([]StreamSource, 0, len(ranked))
for _, candidate := range ranked {
source := candidate.source
switch strings.ToLower(source.Type) {
case "mp4", "m3u8":
return source, "direct-media", nil
case "embed":
embedCandidates = append(embedCandidates, source)
default:
if playable, contentType := s.probeDirectMediaCached(ctx, source, probeCache, probeCacheMu); playable {
return normalizeSourceTypeFromProbe(source, contentType), "probed-media", nil
}
}
}
for _, embed := range embedCandidates {
if s.probeEmbedSource(ctx, embed) {
return embed, "embed-probed", nil
}
}
if len(embedCandidates) > 0 {
return embedCandidates[0], "embed-fallback", nil
}
return ranked[0].source, "ranked-fallback", nil
} }
func (s *Service) probeDirectMediaCached( func (s *Service) probeDirectMediaCached(