mirror of
https://github.com/stashapp/stash.git
synced 2025-12-18 04:44:37 +03:00
Phash distance filter (#3596)
* Add phash_distance filter criterion * Add distance to phash filter in UI
This commit is contained in:
@@ -29,6 +29,7 @@ func (d *CustomSQLiteDriver) Open(dsn string) (driver.Conn, error) {
|
||||
"regexp": regexFn,
|
||||
"durationToTinyInt": durationToTinyIntFn,
|
||||
"basename": basenameFn,
|
||||
"phash_distance": phashDistanceFn,
|
||||
}
|
||||
|
||||
for name, fn := range funcs {
|
||||
|
||||
10
pkg/sqlite/phash.go
Normal file
10
pkg/sqlite/phash.go
Normal file
@@ -0,0 +1,10 @@
|
||||
package sqlite
|
||||
|
||||
import "github.com/corona10/goimagehash"
|
||||
|
||||
func phashDistanceFn(phash1 int64, phash2 int64) (int64, error) {
|
||||
hash1 := goimagehash.NewImageHash(uint64(phash1), goimagehash.PHash)
|
||||
hash2 := goimagehash.NewImageHash(uint64(phash2), goimagehash.PHash)
|
||||
distance, _ := hash1.Distance(hash2)
|
||||
return int64(distance), nil
|
||||
}
|
||||
@@ -882,17 +882,16 @@ func (qb *SceneStore) makeFilter(ctx context.Context, sceneFilter *models.SceneF
|
||||
|
||||
query.handleCriterion(ctx, criterionHandlerFunc(func(ctx context.Context, f *filterBuilder) {
|
||||
if sceneFilter.Phash != nil {
|
||||
qb.addSceneFilesTable(f)
|
||||
f.addLeftJoin(fingerprintTable, "fingerprints_phash", "scenes_files.file_id = fingerprints_phash.file_id AND fingerprints_phash.type = 'phash'")
|
||||
|
||||
value, _ := utils.StringToPhash(sceneFilter.Phash.Value)
|
||||
intCriterionHandler(&models.IntCriterionInput{
|
||||
Value: int(value),
|
||||
// backwards compatibility
|
||||
scenePhashDistanceCriterionHandler(qb, &models.PhashDistanceCriterionInput{
|
||||
Value: sceneFilter.Phash.Value,
|
||||
Modifier: sceneFilter.Phash.Modifier,
|
||||
}, "fingerprints_phash.fingerprint", nil)(ctx, f)
|
||||
})(ctx, f)
|
||||
}
|
||||
}))
|
||||
|
||||
query.handleCriterion(ctx, scenePhashDistanceCriterionHandler(qb, sceneFilter.PhashDistance))
|
||||
|
||||
query.handleCriterion(ctx, intCriterionHandler(sceneFilter.Rating100, "scenes.rating", nil))
|
||||
// legacy rating handler
|
||||
query.handleCriterion(ctx, rating5CriterionHandler(sceneFilter.Rating, "scenes.rating", nil))
|
||||
@@ -1382,6 +1381,45 @@ INNER JOIN (` + valuesClause + `) t ON t.column2 = pt.tag_id
|
||||
}
|
||||
}
|
||||
|
||||
func scenePhashDistanceCriterionHandler(qb *SceneStore, phashDistance *models.PhashDistanceCriterionInput) criterionHandlerFunc {
|
||||
return func(ctx context.Context, f *filterBuilder) {
|
||||
if phashDistance != nil {
|
||||
qb.addSceneFilesTable(f)
|
||||
f.addLeftJoin(fingerprintTable, "fingerprints_phash", "scenes_files.file_id = fingerprints_phash.file_id AND fingerprints_phash.type = 'phash'")
|
||||
|
||||
value, _ := utils.StringToPhash(phashDistance.Value)
|
||||
distance := 0
|
||||
if phashDistance.Distance != nil {
|
||||
distance = *phashDistance.Distance
|
||||
}
|
||||
|
||||
if distance == 0 {
|
||||
// use the default handler
|
||||
intCriterionHandler(&models.IntCriterionInput{
|
||||
Value: int(value),
|
||||
Modifier: phashDistance.Modifier,
|
||||
}, "fingerprints_phash.fingerprint", nil)(ctx, f)
|
||||
}
|
||||
|
||||
switch {
|
||||
case phashDistance.Modifier == models.CriterionModifierEquals && distance > 0:
|
||||
// needed to avoid a type mismatch
|
||||
f.addWhere("typeof(fingerprints_phash.fingerprint) = 'integer'")
|
||||
f.addWhere("phash_distance(fingerprints_phash.fingerprint, ?) < ?", value, distance)
|
||||
case phashDistance.Modifier == models.CriterionModifierNotEquals && distance > 0:
|
||||
// needed to avoid a type mismatch
|
||||
f.addWhere("typeof(fingerprints_phash.fingerprint) = 'integer'")
|
||||
f.addWhere("phash_distance(fingerprints_phash.fingerprint, ?) > ?", value, distance)
|
||||
default:
|
||||
intCriterionHandler(&models.IntCriterionInput{
|
||||
Value: int(value),
|
||||
Modifier: phashDistance.Modifier,
|
||||
}, "fingerprints_phash.fingerprint", nil)(ctx, f)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (qb *SceneStore) setSceneSort(query *queryBuilder, findFilter *models.FindFilterType) {
|
||||
if findFilter == nil || findFilter.Sort == nil || *findFilter.Sort == "" {
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user