Use Marker endSeconds value when generating previews (#5542)

* generate marker previews using endSeconds value
* Limit marker preview duration to 20 seconds max
---------
Co-authored-by: WithoutPants <53250216+WithoutPants@users.noreply.github.com>
This commit is contained in:
stg-annon 2025-01-29 21:40:08 -05:00 committed by GitHub
parent 4d43763a39
commit 8bacaa17f4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 26 additions and 17 deletions

View file

@ -105,11 +105,11 @@ func (t *GenerateMarkersTask) generateSceneMarkers(ctx context.Context) {
func (t *GenerateMarkersTask) generateMarker(videoFile *models.VideoFile, scene *models.Scene, sceneMarker *models.SceneMarker) { func (t *GenerateMarkersTask) generateMarker(videoFile *models.VideoFile, scene *models.Scene, sceneMarker *models.SceneMarker) {
sceneHash := scene.GetHash(t.fileNamingAlgorithm) sceneHash := scene.GetHash(t.fileNamingAlgorithm)
seconds := int(sceneMarker.Seconds) seconds := float64(sceneMarker.Seconds)
g := t.generator g := t.generator
if err := g.MarkerPreviewVideo(context.TODO(), videoFile.Path, sceneHash, seconds, instance.Config.GetPreviewAudio()); err != nil { if err := g.MarkerPreviewVideo(context.TODO(), videoFile.Path, sceneHash, seconds, sceneMarker.EndSeconds, instance.Config.GetPreviewAudio()); err != nil {
logger.Errorf("[generator] failed to generate marker video: %v", err) logger.Errorf("[generator] failed to generate marker video: %v", err)
logErrorOutput(err) logErrorOutput(err)
} }

View file

@ -11,7 +11,7 @@ import (
const ( const (
markerPreviewWidth = 640 markerPreviewWidth = 640
markerPreviewDuration = 20 maxMarkerPreviewDuration = 20
markerPreviewAudioBitrate = "64k" markerPreviewAudioBitrate = "64k"
markerImageDuration = 5 markerImageDuration = 5
@ -20,20 +20,28 @@ const (
markerScreenshotQuality = 2 markerScreenshotQuality = 2
) )
func (g Generator) MarkerPreviewVideo(ctx context.Context, input string, hash string, seconds int, includeAudio bool) error { func (g Generator) MarkerPreviewVideo(ctx context.Context, input string, hash string, seconds float64, endSeconds *float64, includeAudio bool) error {
lockCtx := g.LockManager.ReadLock(ctx, input) lockCtx := g.LockManager.ReadLock(ctx, input)
defer lockCtx.Cancel() defer lockCtx.Cancel()
output := g.MarkerPaths.GetVideoPreviewPath(hash, seconds) output := g.MarkerPaths.GetVideoPreviewPath(hash, int(seconds))
if !g.Overwrite { if !g.Overwrite {
if exists, _ := fsutil.FileExists(output); exists { if exists, _ := fsutil.FileExists(output); exists {
return nil return nil
} }
} }
duration := float64(maxMarkerPreviewDuration)
// don't allow preview to exceed max duration
if endSeconds != nil && *endSeconds-seconds < maxMarkerPreviewDuration {
duration = float64(*endSeconds) - seconds
}
if err := g.generateFile(lockCtx, g.MarkerPaths, mp4Pattern, output, g.markerPreviewVideo(input, sceneMarkerOptions{ if err := g.generateFile(lockCtx, g.MarkerPaths, mp4Pattern, output, g.markerPreviewVideo(input, sceneMarkerOptions{
Seconds: seconds, Seconds: seconds,
Audio: includeAudio, Duration: duration,
Audio: includeAudio,
})); err != nil { })); err != nil {
return err return err
} }
@ -44,8 +52,9 @@ func (g Generator) MarkerPreviewVideo(ctx context.Context, input string, hash st
} }
type sceneMarkerOptions struct { type sceneMarkerOptions struct {
Seconds int Seconds float64
Audio bool Duration float64
Audio bool
} }
func (g Generator) markerPreviewVideo(input string, options sceneMarkerOptions) generateFn { func (g Generator) markerPreviewVideo(input string, options sceneMarkerOptions) generateFn {
@ -69,8 +78,8 @@ func (g Generator) markerPreviewVideo(input string, options sceneMarkerOptions)
) )
trimOptions := transcoder.TranscodeOptions{ trimOptions := transcoder.TranscodeOptions{
Duration: markerPreviewDuration, Duration: options.Duration,
StartTime: float64(options.Seconds), StartTime: options.Seconds,
OutputPath: tmpFn, OutputPath: tmpFn,
VideoCodec: ffmpeg.VideoCodecLibX264, VideoCodec: ffmpeg.VideoCodecLibX264,
VideoArgs: videoArgs, VideoArgs: videoArgs,
@ -90,11 +99,11 @@ func (g Generator) markerPreviewVideo(input string, options sceneMarkerOptions)
} }
} }
func (g Generator) SceneMarkerWebp(ctx context.Context, input string, hash string, seconds int) error { func (g Generator) SceneMarkerWebp(ctx context.Context, input string, hash string, seconds float64) error {
lockCtx := g.LockManager.ReadLock(ctx, input) lockCtx := g.LockManager.ReadLock(ctx, input)
defer lockCtx.Cancel() defer lockCtx.Cancel()
output := g.MarkerPaths.GetWebpPreviewPath(hash, seconds) output := g.MarkerPaths.GetWebpPreviewPath(hash, int(seconds))
if !g.Overwrite { if !g.Overwrite {
if exists, _ := fsutil.FileExists(output); exists { if exists, _ := fsutil.FileExists(output); exists {
return nil return nil
@ -143,11 +152,11 @@ func (g Generator) sceneMarkerWebp(input string, options sceneMarkerOptions) gen
} }
} }
func (g Generator) SceneMarkerScreenshot(ctx context.Context, input string, hash string, seconds int, width int) error { func (g Generator) SceneMarkerScreenshot(ctx context.Context, input string, hash string, seconds float64, width int) error {
lockCtx := g.LockManager.ReadLock(ctx, input) lockCtx := g.LockManager.ReadLock(ctx, input)
defer lockCtx.Cancel() defer lockCtx.Cancel()
output := g.MarkerPaths.GetScreenshotPath(hash, seconds) output := g.MarkerPaths.GetScreenshotPath(hash, int(seconds))
if !g.Overwrite { if !g.Overwrite {
if exists, _ := fsutil.FileExists(output); exists { if exists, _ := fsutil.FileExists(output); exists {
return nil return nil
@ -167,7 +176,7 @@ func (g Generator) SceneMarkerScreenshot(ctx context.Context, input string, hash
} }
type SceneMarkerScreenshotOptions struct { type SceneMarkerScreenshotOptions struct {
Seconds int Seconds float64
Width int Width int
} }
@ -180,7 +189,7 @@ func (g Generator) sceneMarkerScreenshot(input string, options SceneMarkerScreen
Width: options.Width, Width: options.Width,
} }
args := transcoder.ScreenshotTime(input, float64(options.Seconds), ssOptions) args := transcoder.ScreenshotTime(input, options.Seconds, ssOptions)
return g.generate(lockCtx, args) return g.generate(lockCtx, args)
} }