mirror of
https://github.com/stashapp/stash.git
synced 2026-02-07 16:05:47 +01:00
handlers
This commit is contained in:
parent
cd3c25ccc5
commit
6df099a4bd
3 changed files with 86 additions and 61 deletions
|
|
@ -82,7 +82,7 @@ func (qb *fileFilterHandler) criterionHandler() criterionHandler {
|
|||
|
||||
qb.hashesCriterionHandler(fileFilter.Hashes),
|
||||
|
||||
qb.phashDuplicatedCriterionHandler(fileFilter.Duplicated),
|
||||
qb.duplicatedCriterionHandler(fileFilter.Duplicated),
|
||||
×tampCriterionHandler{fileFilter.CreatedAt, "files.created_at", nil},
|
||||
×tampCriterionHandler{fileFilter.UpdatedAt, "files.updated_at", nil},
|
||||
|
||||
|
|
@ -205,12 +205,26 @@ func (qb *fileFilterHandler) galleryCountCriterionHandler(c *models.IntCriterion
|
|||
return h.handler(c)
|
||||
}
|
||||
|
||||
func (qb *fileFilterHandler) phashDuplicatedCriterionHandler(duplicatedFilter *models.PHashDuplicationCriterionInput) criterionHandlerFunc {
|
||||
func (qb *fileFilterHandler) duplicatedCriterionHandler(duplicatedFilter *models.DuplicationCriterionInput) criterionHandlerFunc {
|
||||
return func(ctx context.Context, f *filterBuilder) {
|
||||
// TODO: Wishlist item: Implement Distance matching
|
||||
if duplicatedFilter != nil {
|
||||
// For files, only phash duplication applies
|
||||
if duplicatedFilter == nil {
|
||||
return
|
||||
}
|
||||
|
||||
var phashValue *bool
|
||||
|
||||
// Handle legacy 'duplicated' field for backwards compatibility
|
||||
if duplicatedFilter.Duplicated != nil && duplicatedFilter.Phash == nil {
|
||||
phashValue = duplicatedFilter.Duplicated
|
||||
} else if duplicatedFilter.Phash != nil {
|
||||
phashValue = duplicatedFilter.Phash
|
||||
}
|
||||
|
||||
if phashValue != nil {
|
||||
var v string
|
||||
if *duplicatedFilter.Duplicated {
|
||||
if *phashValue {
|
||||
v = ">"
|
||||
} else {
|
||||
v = "="
|
||||
|
|
|
|||
|
|
@ -155,10 +155,7 @@ func (qb *sceneFilterHandler) criterionHandler() criterionHandler {
|
|||
qb.performerTagsCriterionHandler(sceneFilter.PerformerTags),
|
||||
qb.performerFavoriteCriterionHandler(sceneFilter.PerformerFavorite),
|
||||
qb.performerAgeCriterionHandler(sceneFilter.PerformerAge),
|
||||
qb.phashDuplicatedCriterionHandler(sceneFilter.Duplicated, qb.addSceneFilesTable),
|
||||
qb.stashIDDuplicatedCriterionHandler(sceneFilter.DuplicatedStashID),
|
||||
qb.titleDuplicatedCriterionHandler(sceneFilter.DuplicatedTitle),
|
||||
qb.urlDuplicatedCriterionHandler(sceneFilter.DuplicatedURL),
|
||||
qb.duplicatedCriterionHandler(sceneFilter.Duplicated),
|
||||
&dateCriterionHandler{sceneFilter.Date, "scenes.date", nil},
|
||||
×tampCriterionHandler{sceneFilter.CreatedAt, "scenes.created_at", nil},
|
||||
×tampCriterionHandler{sceneFilter.UpdatedAt, "scenes.updated_at", nil},
|
||||
|
|
@ -280,72 +277,86 @@ func (qb *sceneFilterHandler) fileCountCriterionHandler(fileCount *models.IntCri
|
|||
return h.handler(fileCount)
|
||||
}
|
||||
|
||||
func (qb *sceneFilterHandler) phashDuplicatedCriterionHandler(duplicatedFilter *models.PHashDuplicationCriterionInput, addJoinFn func(f *filterBuilder)) criterionHandlerFunc {
|
||||
func (qb *sceneFilterHandler) duplicatedCriterionHandler(duplicatedFilter *models.DuplicationCriterionInput) criterionHandlerFunc {
|
||||
return func(ctx context.Context, f *filterBuilder) {
|
||||
// TODO: Wishlist item: Implement Distance matching
|
||||
if duplicatedFilter != nil {
|
||||
if addJoinFn != nil {
|
||||
addJoinFn(f)
|
||||
}
|
||||
if duplicatedFilter == nil {
|
||||
return
|
||||
}
|
||||
|
||||
var v string
|
||||
if *duplicatedFilter.Duplicated {
|
||||
v = ">"
|
||||
} else {
|
||||
v = "="
|
||||
}
|
||||
// Handle legacy 'duplicated' field for backwards compatibility
|
||||
// Only use it if set AND none of the new fields are set
|
||||
if duplicatedFilter.Duplicated != nil &&
|
||||
duplicatedFilter.Phash == nil &&
|
||||
duplicatedFilter.URL == nil &&
|
||||
duplicatedFilter.StashID == nil &&
|
||||
duplicatedFilter.Title == nil {
|
||||
qb.addSceneFilesTable(f)
|
||||
qb.applyPhashDuplication(f, *duplicatedFilter.Duplicated)
|
||||
return
|
||||
}
|
||||
|
||||
f.addInnerJoin("(SELECT file_id FROM files_fingerprints INNER JOIN (SELECT fingerprint FROM files_fingerprints WHERE type = 'phash' GROUP BY fingerprint HAVING COUNT (fingerprint) "+v+" 1) dupes on files_fingerprints.fingerprint = dupes.fingerprint)", "scph", "scenes_files.file_id = scph.file_id")
|
||||
// Handle new explicit fields
|
||||
if duplicatedFilter.Phash != nil {
|
||||
qb.addSceneFilesTable(f)
|
||||
qb.applyPhashDuplication(f, *duplicatedFilter.Phash)
|
||||
}
|
||||
|
||||
if duplicatedFilter.StashID != nil {
|
||||
qb.applyStashIDDuplication(f, *duplicatedFilter.StashID)
|
||||
}
|
||||
|
||||
if duplicatedFilter.Title != nil {
|
||||
qb.applyTitleDuplication(f, *duplicatedFilter.Title)
|
||||
}
|
||||
|
||||
if duplicatedFilter.URL != nil {
|
||||
qb.applyURLDuplication(f, *duplicatedFilter.URL)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (qb *sceneFilterHandler) stashIDDuplicatedCriterionHandler(duplicatedFilter *models.StashIDDuplicationCriterionInput) criterionHandlerFunc {
|
||||
return func(ctx context.Context, f *filterBuilder) {
|
||||
if duplicatedFilter != nil && duplicatedFilter.Duplicated != nil {
|
||||
var v string
|
||||
if *duplicatedFilter.Duplicated {
|
||||
v = ">"
|
||||
} else {
|
||||
v = "="
|
||||
}
|
||||
|
||||
// Find stash_ids that appear on more than one scene
|
||||
f.addInnerJoin("(SELECT scene_id FROM scene_stash_ids INNER JOIN (SELECT stash_id FROM scene_stash_ids GROUP BY stash_id HAVING COUNT(DISTINCT scene_id) "+v+" 1) dupes ON scene_stash_ids.stash_id = dupes.stash_id)", "scsi", "scenes.id = scsi.scene_id")
|
||||
}
|
||||
func (qb *sceneFilterHandler) applyPhashDuplication(f *filterBuilder, duplicated bool) {
|
||||
// TODO: Wishlist item: Implement Distance matching
|
||||
var v string
|
||||
if duplicated {
|
||||
v = ">"
|
||||
} else {
|
||||
v = "="
|
||||
}
|
||||
f.addInnerJoin("(SELECT file_id FROM files_fingerprints INNER JOIN (SELECT fingerprint FROM files_fingerprints WHERE type = 'phash' GROUP BY fingerprint HAVING COUNT (fingerprint) "+v+" 1) dupes on files_fingerprints.fingerprint = dupes.fingerprint)", "scph", "scenes_files.file_id = scph.file_id")
|
||||
}
|
||||
|
||||
func (qb *sceneFilterHandler) titleDuplicatedCriterionHandler(duplicatedFilter *models.TitleDuplicationCriterionInput) criterionHandlerFunc {
|
||||
return func(ctx context.Context, f *filterBuilder) {
|
||||
if duplicatedFilter != nil && duplicatedFilter.Duplicated != nil {
|
||||
var v string
|
||||
if *duplicatedFilter.Duplicated {
|
||||
v = ">"
|
||||
} else {
|
||||
v = "="
|
||||
}
|
||||
|
||||
// Find titles that appear on more than one scene (excluding empty titles)
|
||||
f.addInnerJoin("(SELECT id FROM scenes WHERE title != '' AND title IS NOT NULL AND title IN (SELECT title FROM scenes WHERE title != '' AND title IS NOT NULL GROUP BY title HAVING COUNT(*) "+v+" 1))", "sctitle", "scenes.id = sctitle.id")
|
||||
}
|
||||
func (qb *sceneFilterHandler) applyStashIDDuplication(f *filterBuilder, duplicated bool) {
|
||||
var v string
|
||||
if duplicated {
|
||||
v = ">"
|
||||
} else {
|
||||
v = "="
|
||||
}
|
||||
// Find stash_ids that appear on more than one scene
|
||||
f.addInnerJoin("(SELECT scene_id FROM scene_stash_ids INNER JOIN (SELECT stash_id FROM scene_stash_ids GROUP BY stash_id HAVING COUNT(DISTINCT scene_id) "+v+" 1) dupes ON scene_stash_ids.stash_id = dupes.stash_id)", "scsi", "scenes.id = scsi.scene_id")
|
||||
}
|
||||
|
||||
func (qb *sceneFilterHandler) urlDuplicatedCriterionHandler(duplicatedFilter *models.URLDuplicationCriterionInput) criterionHandlerFunc {
|
||||
return func(ctx context.Context, f *filterBuilder) {
|
||||
if duplicatedFilter != nil && duplicatedFilter.Duplicated != nil {
|
||||
var v string
|
||||
if *duplicatedFilter.Duplicated {
|
||||
v = ">"
|
||||
} else {
|
||||
v = "="
|
||||
}
|
||||
|
||||
// Find URLs that appear on more than one scene
|
||||
f.addInnerJoin("(SELECT scene_id FROM scene_urls INNER JOIN (SELECT url FROM scene_urls GROUP BY url HAVING COUNT(DISTINCT scene_id) "+v+" 1) dupes ON scene_urls.url = dupes.url)", "scurl", "scenes.id = scurl.scene_id")
|
||||
}
|
||||
func (qb *sceneFilterHandler) applyTitleDuplication(f *filterBuilder, duplicated bool) {
|
||||
var v string
|
||||
if duplicated {
|
||||
v = ">"
|
||||
} else {
|
||||
v = "="
|
||||
}
|
||||
// Find titles that appear on more than one scene (excluding empty titles)
|
||||
f.addInnerJoin("(SELECT id FROM scenes WHERE title != '' AND title IS NOT NULL AND title IN (SELECT title FROM scenes WHERE title != '' AND title IS NOT NULL GROUP BY title HAVING COUNT(*) "+v+" 1))", "sctitle", "scenes.id = sctitle.id")
|
||||
}
|
||||
|
||||
func (qb *sceneFilterHandler) applyURLDuplication(f *filterBuilder, duplicated bool) {
|
||||
var v string
|
||||
if duplicated {
|
||||
v = ">"
|
||||
} else {
|
||||
v = "="
|
||||
}
|
||||
// Find URLs that appear on more than one scene
|
||||
f.addInnerJoin("(SELECT scene_id FROM scene_urls INNER JOIN (SELECT url FROM scene_urls GROUP BY url HAVING COUNT(DISTINCT scene_id) "+v+" 1) dupes ON scene_urls.url = dupes.url)", "scurl", "scenes.id = scurl.scene_id")
|
||||
}
|
||||
|
||||
func (qb *sceneFilterHandler) codecCriterionHandler(codec *models.StringCriterionInput, codecColumn string, addJoinFn func(f *filterBuilder)) criterionHandlerFunc {
|
||||
|
|
|
|||
|
|
@ -4039,7 +4039,7 @@ func TestSceneQueryPhashDuplicated(t *testing.T) {
|
|||
withTxn(func(ctx context.Context) error {
|
||||
sqb := db.Scene
|
||||
duplicated := true
|
||||
phashCriterion := models.PHashDuplicationCriterionInput{
|
||||
phashCriterion := models.DuplicationCriterionInput{
|
||||
Duplicated: &duplicated,
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue