Commit graph

90 commits

Author SHA1 Message Date
notsafeforgit
f2f299307a perf: eliminate O(N^2) bottlenecks in image and scene duplicate detection
This update resolves major performance regressions when processing large libraries:

1. Optimized FindMany in both Image and Scene stores to use map-based ID lookups. Previously, this function used slices.Index in a loop, resulting in O(N^2) complexity. On a library with 300k items, this was causing the server to hang indefinitely.

2. Refined the exact image duplicate SQL query to match the scene checker's level of optimization. It now joins the files table and orders results by total duplicate file size, ensuring that the most impactful duplicates are shown first.

3. Removed the temporary LIMIT 1000 from the image duplicate query now that the algorithmic bottlenecks have been resolved.
2026-03-20 15:29:04 -07:00
notsafeforgit
6de7195ed6 perf: further optimize image duplicate detection
This update provides additional performance improvements specifically targeted at large image libraries (e.g. 300k+ images):

1. Optimized the exact match SQL query for images:
   - Added filtering for zero/empty fingerprints to avoid massive false-positive groups.
   - Added a LIMIT of 1000 duplicate groups to prevent excessive memory consumption and serialization overhead.
   - Simplified the join structure to ensure better use of the database index.

2. Parallelized the Go comparison loop in pkg/utils/phash.go:
   - Utilizes all available CPU cores to perform Hamming distance calculations.
   - Uses a lock-free design to minimize synchronization overhead.
   - This makes non-zero distance searches significantly faster on multi-core systems.
2026-03-20 15:26:18 -07:00
notsafeforgit
acc5438af2 perf: massive optimization for image and scene duplicate detection
This update provides significant performance improvements for both image and scene duplicate searching:

1. Optimized the core Hamming distance algorithm in pkg/utils/phash.go:
   - Uses native CPU popcount instructions (math/bits) for bit counting.
   - Pre-calculates hash values to eliminate object allocations in the hot loop.
   - Halves the number of comparisons by leveraging the symmetry of the Hamming distance.
   - The loop is now several orders of magnitude faster and allocation-free.

2. Solved the N+1 database query bottleneck:
   - Replaced individual database lookups for each duplicate group with a single batched query for all duplicate IDs.
   - This optimization was applied to both Image and Scene repositories.

3. Simplified the SQL fast path for exact image matches to remove redundant table joins.
2026-03-20 15:06:05 -07:00
notsafeforgit
3924acdb0f perf(sqlite): implement SQL-based fast path for exact image duplicate detection
This change adds a specialized SQL query to find exact image duplicate matches (distance 0) directly in the database.

Previously, the image duplicate checker always used an O(N^2) Go-based comparison loop, which caused indefinite loading and timeouts on libraries with a large number of images. The new SQL fast path reduces the time to find exact duplicates from minutes/hours to milliseconds.
2026-03-20 14:35:19 -07:00
notsafeforgit
fa5725e709 fix(sqlite): fix image duplicate detection by scanning phash as integer
This fixes a bug where identical image duplicates were not being detected.

The implementation was incorrectly scanning the phash BLOB into a string and then attempting to parse it as a hex string. Since phashes are stored as 64-bit integers, they were being converted to decimal strings. For phashes with the MSB set (negative when treated as int64), the resulting decimal string started with a '-', which caused the hex parser to fail and skip the image entirely.

Additionally, even for non-negative phashes, parsing a decimal string as hex yielded incorrect hash values.

Scanning directly into the utils.Phash struct (which uses int64) matches how Scene phashes are handled and ensures the hash values are correct.
2026-03-20 04:53:39 -07:00
notsafeforgit
27ab865d70 fix: update image duplicate checker UI and API handling
- Fixes 400 error in ImageDuplicateChecker

- Updates UI and frontend types

- Fixes tools casing
2026-03-16 04:15:28 -07:00
notsafeforgit
9295655d19 fix: resolve image duplicate finder issues
- Wrap FindDuplicateImages query in r.withReadTxn() to ensure a database transaction in context.
- Use queryFunc instead of queryStruct for fetching multiple hashes, preventing runtime errors.
- Fix N+1 query issue in duplicate grouping by using qb.FindMany() instead of qb.Find() for each duplicate image.
- Revert searchColumns array to exclude "images.details" which was from another PR and remove related failing test.
2026-03-13 18:39:34 -07:00
notsafeforgit
8358c794ba fix: resolve unused import and undefined reference in sqlite image repository
- Removed unused `strconv` import from `pkg/sqlite/image.go`.
- Added missing `github.com/stashapp/stash/pkg/utils` import to resolve the undefined `utils` reference.
- Fixed pagination prop in ImageDuplicateChecker component.
- Formatted modified go files using gofmt.
- Ran prettier over the UI codebase to resolve the formatting check CI failure.
2026-03-13 18:11:05 -07:00
notsafeforgit
af75c8c1b4 feat: improve Image Duplicate Checker implementation
This change unifies the duplicate detection logic by leveraging the shared phash utility. It also enhances the UI with:
- Pagination for large result sets.
- Sorting duplicate groups by total file size.
- A more detailed table view with image thumbnails, paths, and dimensions.
- Consistency with the existing Scene Duplicate Checker tool.
2026-03-13 15:35:29 -07:00
notsafeforgit
3b1fccb010 feat: Implement Image Duplicate Checker
This change introduces a new tool to identify duplicate images based on their perceptual hash (phash). It includes:
- Backend implementation for phash distance comparison and grouping.
- GraphQL schema updates and API resolvers.
- Frontend UI for the Image Duplicate Checker tool.
- Unit tests for the image search and duplicate detection logic.
2026-03-13 15:23:02 -07:00
Gykes
c874bd560e
Fix: Custom Field Filtering (#6614)
* add tests
* Refactor queryBuilder: split args into per-clause fields
2026-02-28 11:05:13 +11:00
WithoutPants
86abe7b24c
Backend support for image custom fields (#6598)
* Initialise maps in bulk get custom fields to fix graphql validation error
2026-02-24 07:41:40 +11:00
Gykes
956af44a29
FR: Sort Scenes and Images by Resolution (#6441) 2026-01-05 16:36:21 +11:00
WithoutPants
7db394bbea
Date precision (#6359)
* Remove month/year only formats from ParseDateStringAsTime
* Add precision field to Date and handle parsing year/month-only dates
* Add date precision columns for date columns
* Adjust UI to account for fuzzy dates
2025-12-08 09:11:40 +11:00
WithoutPants
0fd7a2ac20
SQL performance improvements (#6378)
* Change queryStruct to use tx.Get instead of queryFunc

Using queryFunc meant that the performance logging was inaccurate due to the query actually being executed during the call to Scan.

* Only add join args if join was added

* Omit joins that are only used for sorting when skipping sorting

Should provide some marginal improvement on systems with a lot of items.

* Make all calls to the database pass context.

This means that long queries can be cancelled by navigating to another page. Previously the query would continue to run, impacting on future queries.
2025-12-08 08:08:31 +11:00
Slick Daddy
ecd9c6ec5b
Show O Counter in Studio card (#5982)
Co-authored-by: WithoutPants <53250216+WithoutPants@users.noreply.github.com>
2025-11-25 10:06:36 +11:00
WithoutPants
ce4b86daf5
Fix tag order on details pages (#6143)
* Fix related tag order
* Fix unit tests
2025-10-16 13:15:09 +11:00
stg-annon
d2daf6c69f
Add Sort Name to Tags (#5531)
* override "name" sort with COALESCE
* tag sort_name frontend

adds `data-sort-name` attribute to tag links prioritizes sort_name value but will default to tag name if not present in the same way that COALESCE will prioritize the same values in the same way
* add sort_name filter, update locale per request

* Include sort name in anonymiser
* Add import/export support
---------
Co-authored-by: WithoutPants <53250216+WithoutPants@users.noreply.github.com>
2025-02-11 08:17:21 +11:00
its-josh4
c6bcdd89be
Use slices package from the stdlib when possible (#5360)
* Use slices from the stdlib when possible

* Add some unit tests

* More small tweaks + add benchmark func
2024-10-29 11:26:23 +11:00
WithoutPants
c6c3754f02
Fix panic when deleting image with no files (#5328) 2024-10-02 12:19:13 +10:00
WithoutPants
8c2a25b833
Fix gallery scrubber image order (#5222) 2024-09-05 12:59:20 +10:00
WithoutPants
ad17e7defe
Fix handling of files to delete during delete Gallery operation (#5213)
* Only remove file in zip from image if deleting from zip file
* Only remove file in folder from image if deleting from folder
2024-09-05 11:27:31 +10:00
sezzim
68738bd227
Support for assigning any image from a gallery as the cover (#5053)
Co-authored-by: WithoutPants <53250216+WithoutPants@users.noreply.github.com>
2024-08-29 11:24:52 +10:00
WithoutPants
996dfb1c2f
Gallery scrubber (#5133) 2024-08-28 08:59:41 +10:00
WithoutPants
e843c890fb
Add related object filter criteria to various filter types in graphql schema (#4861)
* Move filter criterion handlers into separate file
* Add related filters for image filter
* Add related filters for scene filter
* Add related filters to gallery filter
* Add related filters to movie filter
* Add related filters to performer filter
* Add related filters to studio filter
* Add related filters to tag filter
* Add scene filter to scene marker filter
2024-06-11 11:34:38 +10:00
WithoutPants
89553864f5
Enforce whitelist for sort values (#4865) 2024-05-22 14:59:08 +10:00
WithoutPants
a303446bb7
Scene play and o-counter history view and editing (#4532)
Co-authored-by: randemgame <61895715+randemgame@users.noreply.github.com>
2024-02-22 11:28:18 +11:00
dogwithakeyboard
37acd6b79b
restore image performer age filter (#4601) 2024-02-21 11:22:04 +11:00
keenbed
14bde44597
added support for image orientation filter (#4404)
* added support for image orientation filter
* Add orientation filtering to scenes
---------
Co-authored-by: WithoutPants <53250216+WithoutPants@users.noreply.github.com>
2024-01-16 13:50:17 +11:00
DingDongSoLong4
0cdea209bb
Fix stats page SUM error (#4390) 2023-12-22 12:40:05 +02:00
DingDongSoLong4
d0d0d1e11f
Include image total O-Count on stats page (#4386) 2023-12-21 16:19:41 +11:00
bob123491234
413311711f
Add Details, Studio Code, and Photographer to Images (#4217)
* Add Details, Code, and Photographer to Images
* Add date and details to image card
---------
Co-authored-by: WithoutPants <53250216+WithoutPants@users.noreply.github.com>
2023-11-28 15:45:07 +11:00
DingDongSoLong4
9621213424
Genericise sliceutil functions (#4253)
* Genericise sliceutil.SliceSame
* Genericise intslice functions
* Genericise stringutil functions
2023-11-02 08:58:32 +11:00
WithoutPants
b6714fafba
Remove deprecated graphql fields (#4064)
* Remove deprecated list*Scrapers queries
* Remove other deprecated query resolvers
* Remove deprecated config fields
* Remove deprecated gallery fields
* Remove deprecated image fields
* Remove deprecated movie fields
* Remove deprecated performer fields
* Document scrape function issue
* Remove deprecated studio fields
* Remove deprecated scan input fields
* Remove deprecated scene fields
* Remove deprecated fields from filters
* Remove scene.file_mod_time
2023-10-17 11:59:35 +11:00
bob123491234
bdf705fe7c
Fix images total megapixels and filesize queries (#4203) 2023-10-16 17:16:40 +11:00
WithoutPants
a25286bdcb
Multiple image URLs (#4000)
* Backend changes - ported from scene impl
* Front end changes
* Refactor URL mutation code
2023-09-12 13:31:53 +10:00
DingDongSoLong4
24e4719abc
Model refactor, part 2 (#4092)
* Move conversions into changesetTranslator
* Improve mutation error messages
* Use models.New and models.NewPartial everywhere
* Replace getStashIDsFor functions
* Remove ImageCreateInput
* Remove unused parameters
* Refactor matching functions
---------
Co-authored-by: WithoutPants <53250216+WithoutPants@users.noreply.github.com>
2023-09-11 12:24:15 +10:00
DingDongSoLong4
c364346a59
Model refactor (#3915)
* Add mockery config file
* Move basic file/folder structs to models
* Fix hack due to import loop
* Move file interfaces to models
* Move folder interfaces to models
* Move scene interfaces to models
* Move scene marker interfaces to models
* Move image interfaces to models
* Move gallery interfaces to models
* Move gallery chapter interfaces to models
* Move studio interfaces to models
* Move movie interfaces to models
* Move performer interfaces to models
* Move tag interfaces to models
* Move autotag interfaces to models
* Regenerate mocks
2023-09-01 10:39:29 +10:00
DingDongSoLong4
1c13c9e1b1
SQLite model refactoring (#3791)
* Remove ID from PerformerPartial
* Separate studio model from sqlite model
* Separate movie model from sqlite model
* Separate tag model from sqlite model
* Separate saved filter model from sqlite model
* Separate scene marker model from sqlite model
* Separate gallery chapter model from sqlite model
* Move ErrNoRows checks into sqlite, improve empty result error messages
* Move SQLiteDate and SQLiteTimestamp to sqlite
* Use changesetTranslator everywhere, refactor for consistency
* Make PerformerStore.DestroyImage private
* Fix rating on movie create
2023-06-15 12:46:09 +10:00
WithoutPants
256e0a11ea
Fix joined hierarchical filtering (#3775)
* Fix joined hierarchical filtering
* Fix scene performer tag filter
* Generalise performer tag handler
* Add unit tests
* Add equals handling
* Make performer tags equals/not equals unsupported
* Make tags not equals unsupported
* Make not equals unsupported for performers criterion
* Support equals/not equals for studio criterion
* Fix marker scene tags equals filter
* Fix scene performer tag filter
* Make equals/not equals unsupported for hierarchical criterion
* Use existing studio handler in movie
* Hide unsupported tag modifier options
* Use existing performer tags logic where possible
* Restore old parent/child filter logic
* Disable sub-tags in equals modifier for tags criterion
2023-06-06 13:01:50 +10:00
WithoutPants
62b6457f4e
Improve studio/tag/performer filtering (#3619)
* Support excludes field
* Refactor studio filter
* Refactor tags filter
* Support excludes in tags
---------
Co-authored-by: Kermie <kermie@isinthe.house>
2023-05-25 12:03:49 +10:00
yoshnopa
a2e477e1a7
Support image clips/gifs (#3583)
Co-authored-by: WithoutPants <53250216+WithoutPants@users.noreply.github.com>
2023-05-17 09:30:51 +10:00
jpnsfw
64b7934af2
Add O-Counter for Performers and Sort/Filter Performers by O-Counter (#3588)
* initial commit of sort performer by o-count

* work on o_counter filter

* filter working

* sorting, filtering using combined scene+image count

* linting

* fix performer list view

---------

Co-authored-by: jpnsfw <none@none.com>
2023-04-24 17:01:41 -04:00
Flashy78
75f22042b7
Sort case insensitive, date by newest first (#3560)
* Case insensitive search
* Fix not adding extra sort when no sort specified.
* Using newer version of fvbommel/sortorder package
2023-04-17 15:21:13 +10:00
WithoutPants
58852f86fe
Handle large and all entity queries (#3544)
* Remove upper page size limit
* Batch GetMany function
* Remove upper query limit from UI
2023-03-16 09:08:21 +11:00
DingDongSoLong4
83cb51ec47
Error reliably on invalid filter (#3428) 2023-02-13 12:14:41 +11:00
HijackHornet
0b4b100ecc
[Feature] Images new fields : URL & Date (#3015)
Co-authored-by: WithoutPants <53250216+WithoutPants@users.noreply.github.com>
2022-12-20 11:13:41 +11:00
WithoutPants
eb7956a05a
Correct title ordering for objects without titles (#3244)
* Correct scene title ordering
* Correct ordering for other objects
* Add basename function, add to gallery title sort
2022-12-09 08:29:34 +11:00
skier233
7eae751d1c
Stash rating system (#2830)
* add rating100 fields to represent rating range 1-100
* deprecate existing (1-5) rating fields
* add half- and quarter-star options for rating system
* add decimal rating system option

Co-authored-by: WithoutPants <53250216+WithoutPants@users.noreply.github.com>
2022-11-16 09:31:44 +11:00
gitgiggety
f66333bac9
Add date filters (#2834)
* graphql: support date and timestamp filter types
* sql: add support for date & timestamp criterions
* ui: add support for date and timestamp criterions
* scenes: add support for filtering by date, created at and updated at
* image: support filtering by created at and updated at
* gallery: support filtering by date, created at and updated at
* movie: support filtering by date, created at and updated at
* studio: support filtering by date, created at and updated at
* tag: support filtering by date, created at and updated at
* performer: support filtering by bitrh & death date and created & updated at
* marker: support filtering by created & updated at and scene date, created & updated at
2022-11-15 11:52:05 +11:00