diff --git a/internal/api/resolver_query_configuration.go b/internal/api/resolver_query_configuration.go index cf2c0e3cc..0098c5769 100644 --- a/internal/api/resolver_query_configuration.go +++ b/internal/api/resolver_query_configuration.go @@ -104,6 +104,7 @@ func makeConfigGeneralResult() *ConfigGeneralResult { PreviewAudio: config.GetPreviewAudio(), PreviewSegments: config.GetPreviewSegments(), PreviewSegmentDuration: config.GetPreviewSegmentDuration(), + MaxMarkerPreviewDuration: config.GetMaxMarkerPreviewDuration(), PreviewExcludeStart: config.GetPreviewExcludeStart(), PreviewExcludeEnd: config.GetPreviewExcludeEnd(), PreviewPreset: config.GetPreviewPreset(), diff --git a/internal/manager/config/config.go b/internal/manager/config/config.go index 05dcf97a4..1c75f4719 100644 --- a/internal/manager/config/config.go +++ b/internal/manager/config/config.go @@ -120,7 +120,7 @@ const ( previewExcludeEndDefault = "0" MaxMarkerPreviewDuration = "max_marker_preview_duration" - maxMarkerPreviewDurationDefault = 20 + maxMarkerPreviewDurationDefault = 0 WriteImageThumbnails = "write_image_thumbnails" writeImageThumbnailsDefault = true diff --git a/pkg/scene/generate/marker_preview.go b/pkg/scene/generate/marker_preview.go index 83faec2fa..0f7e612a6 100644 --- a/pkg/scene/generate/marker_preview.go +++ b/pkg/scene/generate/marker_preview.go @@ -39,16 +39,19 @@ func (g Generator) MarkerPreviewVideo(ctx context.Context, input string, hash st // Honor the marker's explicit interval when present and positive, capped // by the configured safety ceiling. maxDuration <= 0 disables the ceiling. + // Non-positive intervals are treated as "no video wanted" and skipped — + // if the user intentionally set end = start they didn't want a preview, + // and if it's a data mistake we'd rather surface it than silently default. if endSeconds != nil { interval := *endSeconds - seconds - if interval > 0 { - if maxDuration <= 0 || interval <= float64(maxDuration) { - duration = interval - } else { - duration = float64(maxDuration) - } + if interval <= 0 { + logger.Warnf("[generator] marker at %.2fs has non-positive interval (end=%.2f); skipping video preview generation", seconds, *endSeconds) + return nil + } + if maxDuration <= 0 || interval <= float64(maxDuration) { + duration = interval } else { - logger.Warnf("[generator] marker at %.2fs has non-positive interval (end=%.2f); falling back to %ds default", seconds, *endSeconds, markerPreviewDefaultDuration) + duration = float64(maxDuration) } } diff --git a/ui/v2.5/src/locales/en-GB.json b/ui/v2.5/src/locales/en-GB.json index 3cc754928..d0e044dcc 100644 --- a/ui/v2.5/src/locales/en-GB.json +++ b/ui/v2.5/src/locales/en-GB.json @@ -418,7 +418,7 @@ "include_audio_desc": "Includes audio stream when generating previews.", "include_audio_head": "Include audio", "logging": "Logging", - "max_marker_preview_duration_desc": "Ceiling (in seconds) applied to generated marker preview videos when the marker has an explicit end time. Protects against unexpectedly long previews from imports or data entry mistakes. Set to 0 to disable the ceiling and honor the marker's end time verbatim.", + "max_marker_preview_duration_desc": "Optional ceiling (in seconds) for marker preview videos with explicit end times. Default is 0 (no ceiling, the marker's end time is honored verbatim). Set a positive value to cap preview duration as a safety against imports or data entry mistakes. Markers without an end time use a fixed 20-second default, unaffected by this setting.", "max_marker_preview_duration_head": "Max marker preview duration", "maximum_streaming_transcode_size_desc": "Maximum size for transcoded streams.", "maximum_streaming_transcode_size_head": "Maximum streaming transcode size",