diff --git a/docs/DEVELOPMENT.md b/docs/DEVELOPMENT.md index 687cba066..6ed1f25b2 100644 --- a/docs/DEVELOPMENT.md +++ b/docs/DEVELOPMENT.md @@ -3,6 +3,7 @@ ## Pre-requisites * [Go](https://golang.org/dl/) + * Version 1.24.* (v1.26.x is unable to run the linter) * [GolangCI](https://golangci-lint.run/) - A meta-linter which runs several linters in parallel * To install, follow the [local installation instructions](https://golangci-lint.run/welcome/install/#local-installation) * Install v1, NOT v2 diff --git a/internal/manager/task_scan.go b/internal/manager/task_scan.go index 6dbb466ae..48058e9f3 100644 --- a/internal/manager/task_scan.go +++ b/internal/manager/task_scan.go @@ -636,13 +636,14 @@ func (f *scanFilter) Accept(ctx context.Context, path string, info fs.FileInfo, return false } - if isVideoFile && (s.ExcludeVideo || matchFileRegex(path, f.videoExcludeRegex)) { + switch { + case isVideoFile && (s.ExcludeVideo || matchFileRegex(path, f.videoExcludeRegex)): logger.Debugf("Skipping %s as it matches video exclusion patterns", path) return false - } else if isAudioFile && (s.ExcludeAudio || matchFileRegex(path, f.audioExcludeRegex)) { + case isAudioFile && (s.ExcludeAudio || matchFileRegex(path, f.audioExcludeRegex)): logger.Debugf("Skipping %s as it matches audio exclusion patterns", path) return false - } else if (isImageFile || isZipFile) && (s.ExcludeImage || matchFileRegex(path, f.imageExcludeRegex)) { + case (isImageFile || isZipFile) && (s.ExcludeImage || matchFileRegex(path, f.imageExcludeRegex)): logger.Debugf("Skipping %s as it matches image exclusion patterns", path) return false } diff --git a/pkg/audio/export.go b/pkg/audio/export.go index 71f0d6ead..9601766bd 100644 --- a/pkg/audio/export.go +++ b/pkg/audio/export.go @@ -5,7 +5,6 @@ package audio import ( "context" "fmt" - "math" "github.com/stashapp/stash/pkg/models" "github.com/stashapp/stash/pkg/models/json" @@ -169,17 +168,3 @@ func GetDependentGroupIDs(ctx context.Context, audio *models.Audio) ([]int, erro return ret, nil } - -func getPrecision(num float64) int { - if num == 0 { - return 0 - } - - e := 1.0 - p := 0 - for (math.Round(num*e) / e) != num { - e *= 10 - p++ - } - return p -} diff --git a/pkg/audio/generate/generator.go b/pkg/audio/generate/generator.go deleted file mode 100644 index cb8ef48c0..000000000 --- a/pkg/audio/generate/generator.go +++ /dev/null @@ -1,169 +0,0 @@ -// TODO(audio): this file is currently not used, DELETE when you know it isn't needed - -// Package generate provides functions to generate media assets from audios. -package generate - -import ( - "bytes" - "errors" - "fmt" - "os" - "os/exec" - "strings" - - "github.com/stashapp/stash/pkg/ffmpeg" - "github.com/stashapp/stash/pkg/fsutil" -) - -const ( - mp3Pattern = "*.mp3" - jpgPattern = "*.jpg" - txtPattern = "*.txt" -) - -type Paths interface { - TempFile(pattern string) (*os.File, error) -} - -type AudioPaths interface { - Paths - - GetTranscodePath(checksum string) string -} - -type FFMpegConfig interface { - GetTranscodeInputArgs() []string - GetTranscodeOutputArgs() []string -} - -type Generator struct { - Encoder *ffmpeg.FFMpeg - FFMpegConfig FFMpegConfig - LockManager *fsutil.ReadLockManager - AudioPaths AudioPaths - Overwrite bool -} - -type generateFn func(lockCtx *fsutil.LockContext, tmpFn string) error - -func (g Generator) tempFile(p Paths, pattern string) (*os.File, error) { - tmpFile, err := p.TempFile(pattern) // tmp output in case the process ends abruptly - if err != nil { - return nil, fmt.Errorf("creating temporary file: %w", err) - } - _ = tmpFile.Close() - return tmpFile, err -} - -// generateFile performs a generate operation by generating a temporary file using p and pattern, then -// moving it to output on success. -func (g Generator) generateFile(lockCtx *fsutil.LockContext, p Paths, pattern string, output string, generateFn generateFn) error { - tmpFile, err := g.tempFile(p, pattern) // tmp output in case the process ends abruptly - if err != nil { - return err - } - - tmpFn := tmpFile.Name() - defer func() { - _ = os.Remove(tmpFn) - }() - - if err := generateFn(lockCtx, tmpFn); err != nil { - return err - } - - // check if generated empty file - stat, err := os.Stat(tmpFn) - if err != nil { - return fmt.Errorf("error getting file stat: %w", err) - } - - if stat.Size() == 0 { - return fmt.Errorf("ffmpeg command produced no output") - } - - if err := fsutil.SafeMove(tmpFn, output); err != nil { - return fmt.Errorf("moving %s to %s failed: %w", tmpFn, output, err) - } - - return nil -} - -// generateBytes performs a generate operation by generating a temporary file using p and pattern, returns the contents, then deletes it. -func (g Generator) generateBytes(lockCtx *fsutil.LockContext, p Paths, pattern string, generateFn generateFn) ([]byte, error) { - tmpFile, err := g.tempFile(p, pattern) // tmp output in case the process ends abruptly - if err != nil { - return nil, err - } - - tmpFn := tmpFile.Name() - defer func() { - _ = os.Remove(tmpFn) - }() - - if err := generateFn(lockCtx, tmpFn); err != nil { - return nil, err - } - - defer os.Remove(tmpFn) - return os.ReadFile(tmpFn) -} - -// generate runs ffmpeg with the given args and waits for it to finish. -// Returns an error if the command fails. If the command fails, the return -// value will be of type *exec.ExitError. -func (g Generator) generate(ctx *fsutil.LockContext, args []string) error { - cmd := g.Encoder.Command(ctx, args) - - var stderr bytes.Buffer - cmd.Stderr = &stderr - - if err := cmd.Start(); err != nil { - return fmt.Errorf("error starting command: %w", err) - } - - ctx.AttachCommand(cmd) - - if err := cmd.Wait(); err != nil { - var exitErr *exec.ExitError - if errors.As(err, &exitErr) { - exitErr.Stderr = stderr.Bytes() - err = exitErr - } - return fmt.Errorf("error running ffmpeg command <%s>: %w", strings.Join(args, " "), err) - } - - return nil -} - -// GenerateOutput runs ffmpeg with the given args and returns it standard output. -func (g Generator) generateOutput(lockCtx *fsutil.LockContext, args []string) ([]byte, error) { - cmd := g.Encoder.Command(lockCtx, args) - - var stdout bytes.Buffer - cmd.Stdout = &stdout - - var stderr bytes.Buffer - cmd.Stderr = &stderr - - if err := cmd.Start(); err != nil { - return nil, fmt.Errorf("error starting command: %w", err) - } - - lockCtx.AttachCommand(cmd) - - if err := cmd.Wait(); err != nil { - var exitErr *exec.ExitError - if errors.As(err, &exitErr) { - exitErr.Stderr = stderr.Bytes() - err = exitErr - } - return nil, fmt.Errorf("error running ffmpeg command <%s>: %w", strings.Join(args, " "), err) - } - - if stdout.Len() == 0 { - return nil, fmt.Errorf("ffmpeg command produced no output: <%s>", strings.Join(args, " ")) - } - - return stdout.Bytes(), nil -} diff --git a/pkg/audio/migrate_hash.go b/pkg/audio/migrate_hash.go index f6c488205..702824127 100644 --- a/pkg/audio/migrate_hash.go +++ b/pkg/audio/migrate_hash.go @@ -37,18 +37,3 @@ func migrateAudioFiles(oldName, newName string) { } } } - -func migrateAudioFolder(oldName, newName string) { - oldExists, err := fsutil.DirExists(oldName) - if err != nil && !os.IsNotExist(err) { - logger.Errorf("Error checking existence of %s: %s", oldName, err.Error()) - return - } - - if oldExists { - logger.Infof("renaming %s to %s", oldName, newName) - if err := os.Rename(oldName, newName); err != nil { - logger.Errorf("error renaming %s to %s: %s", oldName, newName, err.Error()) - } - } -} diff --git a/pkg/audio/scan.go b/pkg/audio/scan.go index 302e87bdd..17e473b0e 100644 --- a/pkg/audio/scan.go +++ b/pkg/audio/scan.go @@ -119,7 +119,7 @@ func (h *ScanHandler) Handle(ctx context.Context, f models.File, oldFile models. h.PluginCache.RegisterPostHooks(ctx, newAudio.ID, hook.AudioCreatePost, nil, nil) - existing = []*models.Audio{&newAudio} + // existing = []*models.Audio{&newAudio} } if oldFile != nil { diff --git a/pkg/ffmpeg/browser.go b/pkg/ffmpeg/browser.go index 796331ca9..e0b34930b 100644 --- a/pkg/ffmpeg/browser.go +++ b/pkg/ffmpeg/browser.go @@ -58,26 +58,25 @@ func isValidCodec(codecName string, supportedCodecs []string) bool { return false } -func isValidAudio(audio ProbeAudioCodec, validCodecs []ProbeAudioCodec) bool { - // if audio codec is missing or unsupported by ffmpeg we can't do anything about it - // report it as valid so that the file can at least be streamed directly if the video codec is supported - if audio == MissingUnsupported { - return true - } +// func isValidAudio(audio ProbeAudioCodec, validCodecs []ProbeAudioCodec) bool { +// // if audio codec is missing or unsupported by ffmpeg we can't do anything about it +// // report it as valid so that the file can at least be streamed directly if the video codec is supported +// if audio == MissingUnsupported { +// return true +// } - for _, c := range validCodecs { - if c == audio { - return true - } - } +// for _, c := range validCodecs { +// if c == audio { +// return true +// } +// } - return false -} +// return false +// } // IsValidAudioForContainer returns true if the audio codec is valid for the container. func IsValidAudioForContainer(audio ProbeAudioCodec, format Container) bool { - switch format { - case Mp3Container: + if format == Mp3Container { return true // TODO(audio): do we need to check ProbeAudioCodec for audio containers? // return isValidAudio(audio, validAudioForMp3) diff --git a/pkg/sqlite/tables.go b/pkg/sqlite/tables.go index 770f6fee4..8c6ebe200 100644 --- a/pkg/sqlite/tables.go +++ b/pkg/sqlite/tables.go @@ -284,8 +284,6 @@ var ( fkColumn: audiosPerformersJoinTable.Col(performerIDColumn), } - audiosGalleriesTableMgr = galleriesScenesTableMgr.invert() - audiosGroupsTableMgr = &audiosGroupsTable{ table: table{ table: audiosGroupsJoinTable,