refactor(playback): simplify service files

This commit is contained in:
2026-04-20 01:20:07 +02:00
parent 158ead08f3
commit 3c438951a8
5 changed files with 30 additions and 46 deletions

View File

@@ -259,12 +259,11 @@ func (s *Service) setPlaybackBaseDataCache(key string, data playbackBaseData) {
} }
func (s *Service) resolveShowCached(ctx context.Context, malID int, titleCandidates []string) (string, string, error) { func (s *Service) resolveShowCached(ctx context.Context, malID int, titleCandidates []string) (string, string, error) {
now := time.Now()
s.cacheMu.RLock() s.cacheMu.RLock()
item, ok := s.showResolution[malID] item, ok := s.showResolution[malID]
s.cacheMu.RUnlock() s.cacheMu.RUnlock()
now := time.Now()
if ok && now.Before(item.ExpiresAt) && strings.TrimSpace(item.ShowID) != "" { if ok && now.Before(item.ExpiresAt) && strings.TrimSpace(item.ShowID) != "" {
return item.ShowID, item.Title, nil return item.ShowID, item.Title, nil
} }
@@ -278,7 +277,7 @@ func (s *Service) resolveShowCached(ctx context.Context, malID int, titleCandida
s.showResolution[malID] = showResolutionCacheItem{ s.showResolution[malID] = showResolutionCacheItem{
ShowID: showID, ShowID: showID,
Title: resolvedTitle, Title: resolvedTitle,
ExpiresAt: time.Now().Add(showResolutionCacheTTL), ExpiresAt: now.Add(showResolutionCacheTTL),
} }
s.cacheMu.Unlock() s.cacheMu.Unlock()
@@ -347,7 +346,6 @@ func cloneStringSlice(items []string) []string {
if len(items) == 0 { if len(items) == 0 {
return nil return nil
} }
cloned := make([]string, len(items)) cloned := make([]string, len(items))
copy(cloned, items) copy(cloned, items)
return cloned return cloned
@@ -357,7 +355,6 @@ func cloneModeSources(modeSources map[string]ModeSource) map[string]ModeSource {
if len(modeSources) == 0 { if len(modeSources) == 0 {
return nil return nil
} }
cloned := make(map[string]ModeSource, len(modeSources)) cloned := make(map[string]ModeSource, len(modeSources))
for mode, source := range modeSources { for mode, source := range modeSources {
cloned[mode] = ModeSource{ cloned[mode] = ModeSource{
@@ -366,7 +363,6 @@ func cloneModeSources(modeSources map[string]ModeSource) map[string]ModeSource {
Subtitles: cloneSubtitleItems(source.Subtitles), Subtitles: cloneSubtitleItems(source.Subtitles),
} }
} }
return cloned return cloned
} }
@@ -374,7 +370,6 @@ func cloneSubtitleItems(items []SubtitleItem) []SubtitleItem {
if len(items) == 0 { if len(items) == 0 {
return nil return nil
} }
cloned := make([]SubtitleItem, len(items)) cloned := make([]SubtitleItem, len(items))
copy(cloned, items) copy(cloned, items)
return cloned return cloned
@@ -384,7 +379,6 @@ func cloneSegments(segments []SkipSegment) []SkipSegment {
if len(segments) == 0 { if len(segments) == 0 {
return nil return nil
} }
cloned := make([]SkipSegment, len(segments)) cloned := make([]SkipSegment, len(segments))
copy(cloned, segments) copy(cloned, segments)
return cloned return cloned

View File

@@ -49,27 +49,33 @@ func (s *Service) ProxyStream(ctx context.Context, targetURL string, referer str
} }
func isM3U8(targetURL string, contentType string) bool { func isM3U8(targetURL string, contentType string) bool {
lowerURL := strings.ToLower(targetURL) if strings.Contains(strings.ToLower(targetURL), ".m3u8") {
lowerType := strings.ToLower(contentType)
if strings.Contains(lowerURL, ".m3u8") {
return true return true
} }
lowerType := strings.ToLower(contentType)
return strings.Contains(lowerType, "application/vnd.apple.mpegurl") || strings.Contains(lowerType, "application/x-mpegurl") return strings.Contains(lowerType, "application/vnd.apple.mpegurl") || strings.Contains(lowerType, "application/x-mpegurl")
} }
var hopHeaders = map[string]struct{}{
"connection": {},
"transfer-encoding": {},
"keep-alive": {},
"proxy-authenticate": {},
"proxy-authorization": {},
"te": {},
"trailers": {},
"upgrade": {},
}
func cloneHeaders(src http.Header) http.Header { func cloneHeaders(src http.Header) http.Header {
dst := make(http.Header) dst := make(http.Header)
for key, values := range src { for key, values := range src {
lower := strings.ToLower(key) if _, ok := hopHeaders[strings.ToLower(key)]; ok {
if lower == "connection" || lower == "transfer-encoding" || lower == "keep-alive" || lower == "proxy-authenticate" || lower == "proxy-authorization" || lower == "te" || lower == "trailers" || lower == "upgrade" {
continue continue
} }
for _, value := range values { for _, value := range values {
dst.Add(key, value) dst.Add(key, value)
} }
} }
return dst return dst
} }

View File

@@ -189,16 +189,12 @@ func extractDigits(value string) string {
func normalizeSourceTypeFromProbe(source StreamSource, contentType string) StreamSource { func normalizeSourceTypeFromProbe(source StreamSource, contentType string) StreamSource {
lower := strings.ToLower(contentType) lower := strings.ToLower(contentType)
if strings.Contains(lower, "video/mp4") { switch {
case strings.Contains(lower, "video/mp4"):
source.Type = "mp4" source.Type = "mp4"
return source case strings.Contains(lower, "mpegurl"):
}
if strings.Contains(lower, "mpegurl") {
source.Type = "m3u8" source.Type = "m3u8"
return source
} }
return source return source
} }

View File

@@ -122,12 +122,7 @@ func firstNonEmptyTitle(values []string) string {
} }
func normalizeMode(raw string) string { func normalizeMode(raw string) string {
lower := strings.ToLower(strings.TrimSpace(raw)) return strings.ToLower(strings.TrimSpace(raw))
if lower == "sub" || lower == "dub" {
return lower
}
return lower
} }
func availableModes(modeSources map[string]ModeSource) []string { func availableModes(modeSources map[string]ModeSource) []string {

View File

@@ -60,19 +60,16 @@ func (s *Service) choosePlaybackSource(ctx context.Context, ranked []sourceScore
return StreamSource{}, "", errors.New("no ranked sources available") return StreamSource{}, "", errors.New("no ranked sources available")
} }
embedCandidates := make([]StreamSource, 0) embedCandidates := make([]StreamSource, 0, len(ranked))
for _, candidate := range ranked { for _, candidate := range ranked {
source := candidate.source source := candidate.source
sourceType := strings.ToLower(source.Type) switch strings.ToLower(source.Type) {
switch sourceType {
case "mp4", "m3u8": case "mp4", "m3u8":
return source, "direct-media", nil return source, "direct-media", nil
case "embed": case "embed":
embedCandidates = append(embedCandidates, source) embedCandidates = append(embedCandidates, source)
default: default:
playable, contentType := s.probeDirectMedia(ctx, source) if playable, contentType := s.probeDirectMedia(ctx, source); playable {
if playable {
return normalizeSourceTypeFromProbe(source, contentType), "probed-media", nil return normalizeSourceTypeFromProbe(source, contentType), "probed-media", nil
} }
} }
@@ -101,19 +98,16 @@ func (s *Service) choosePlaybackSourceWithCache(
return StreamSource{}, "", errors.New("no ranked sources available") return StreamSource{}, "", errors.New("no ranked sources available")
} }
embedCandidates := make([]StreamSource, 0) embedCandidates := make([]StreamSource, 0, len(ranked))
for _, candidate := range ranked { for _, candidate := range ranked {
source := candidate.source source := candidate.source
sourceType := strings.ToLower(source.Type) switch strings.ToLower(source.Type) {
switch sourceType {
case "mp4", "m3u8": case "mp4", "m3u8":
return source, "direct-media", nil return source, "direct-media", nil
case "embed": case "embed":
embedCandidates = append(embedCandidates, source) embedCandidates = append(embedCandidates, source)
default: default:
playable, contentType := s.probeDirectMediaCached(ctx, source, probeCache, probeCacheMu) if playable, contentType := s.probeDirectMediaCached(ctx, source, probeCache, probeCacheMu); playable {
if playable {
return normalizeSourceTypeFromProbe(source, contentType), "probed-media", nil return normalizeSourceTypeFromProbe(source, contentType), "probed-media", nil
} }
} }
@@ -208,10 +202,10 @@ func (s *Service) probeDirectMedia(ctx context.Context, source StreamSource) (bo
} }
func (s *Service) probeEmbedSource(ctx context.Context, source StreamSource) bool { func (s *Service) probeEmbedSource(ctx context.Context, source StreamSource) bool {
probeCtx, cancel := context.WithTimeout(ctx, providerProbeTimeout) ctx, cancel := context.WithTimeout(ctx, providerProbeTimeout)
defer cancel() defer cancel()
req, err := http.NewRequestWithContext(probeCtx, http.MethodGet, source.URL, nil) req, err := http.NewRequestWithContext(ctx, http.MethodGet, source.URL, nil)
if err != nil { if err != nil {
return false return false
} }
@@ -237,7 +231,7 @@ func (s *Service) probeEmbedSource(ctx context.Context, source StreamSource) boo
} }
content := strings.ToLower(string(body)) content := strings.ToLower(string(body))
markers := []string{ for _, marker := range []string{
"file was deleted", "file was deleted",
"file has been deleted", "file has been deleted",
"video was deleted", "video was deleted",
@@ -246,8 +240,7 @@ func (s *Service) probeEmbedSource(ctx context.Context, source StreamSource) boo
"file not found", "file not found",
"this file does not exist", "this file does not exist",
"resource unavailable", "resource unavailable",
} } {
for _, marker := range markers {
if strings.Contains(content, marker) { if strings.Contains(content, marker) {
return false return false
} }