Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add phasher #3864

Merged
merged 9 commits into from
Jul 11, 2023
Merged
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ node_modules
*.db

/stash
/phasher
dist
.DS_Store
/.local
/.local
6 changes: 6 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,12 @@ build: build-flags
build:
go build $(OUTPUT) $(BUILD_FLAGS) ./cmd/stash

# TODO: Integrate the phasher target with the rest of the Makefile,
# TODO: so it can be built as part of normal releases.
.PHONY: phasher
phasher:
go build -o $@ -trimpath -buildmode=pie -ldflags '-s -w' ./cmd/phasher

# builds a dynamically-linked release binary
.PHONY: build-release
build-release: LDFLAGS += -s -w
Expand Down
83 changes: 83 additions & 0 deletions cmd/phasher/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
// TODO: document in README.md
package main

import (
"context"
"fmt"
"os"

flag "github.com/spf13/pflag"
"github.com/stashapp/stash/pkg/ffmpeg"
"github.com/stashapp/stash/pkg/file"
"github.com/stashapp/stash/pkg/hash/videophash"
)

func customUsage() {
fmt.Fprintf(os.Stderr, "Usage:\n")
fmt.Fprintf(os.Stderr, "%s [OPTIONS] VIDEOFILE...\n\nOptions:\n", os.Args[0])
flag.PrintDefaults()
}

func printPhash(ff *ffmpeg.FFMpeg, ffp ffmpeg.FFProbe, inputfile string, quiet *bool) error {
ffvideoFile, err := ffp.NewVideoFile(inputfile)
if err != nil {
return err
}

// All we need for videophash.Generate() is
// videoFile.Path (from BaseFile)
// videoFile.Duration
// The rest of the struct isn't needed.
vf := &file.VideoFile{
BaseFile: &file.BaseFile{Path: inputfile},
Duration: ffvideoFile.FileDuration,
}

phash, err := videophash.Generate(ff, vf)
if err != nil {
return err
}

if *quiet {
fmt.Printf("%x\n", *phash)
} else {
fmt.Printf("%x %v\n", *phash, vf.Path)
}
return nil
}

func main() {
flag.Usage = customUsage
quiet := flag.BoolP("quiet", "q", false, "print only the phash")
help := flag.BoolP("help", "h", false, "print this help output")
flag.Parse()

if *help {
flag.Usage()
os.Exit(2)
}

args := flag.Args()

if len(args) < 1 {
fmt.Fprintf(os.Stderr, "Missing VIDEOFILE argument.\n")
flag.Usage()
os.Exit(2)
}

if len(args) > 1 {
fmt.Fprintln(os.Stderr, "Files will be processed sequentially! Consier using GNU Parallel.")
fmt.Fprintf(os.Stderr, "Example: parallel %v ::: *.mp4\n", os.Args[0])
}

ffmpegPath, ffprobePath := ffmpeg.GetPaths(nil)
encoder := ffmpeg.NewEncoder(ffmpegPath)
encoder.InitHWSupport(context.TODO())
ffprobe := ffmpeg.FFProbe(ffprobePath)

for _, item := range args {
if err := printPhash(encoder, ffprobe, item, quiet); err != nil {
fmt.Fprintln(os.Stderr, err)
}
}
}