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.
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.
* Translated using Weblate (French)
Currently translated at 100.0% (1341 of 1341 strings)
Translation: stash/stash
Translate-URL: https://translate.codeberg.org/projects/stash/stash/fr/
* Translated using Weblate (Turkish)
Currently translated at 75.3% (1010 of 1341 strings)
Translation: stash/stash
Translate-URL: https://translate.codeberg.org/projects/stash/stash/tr/
* Translated using Weblate (Ukrainian)
Currently translated at 100.0% (1341 of 1341 strings)
Translation: stash/stash
Translate-URL: https://translate.codeberg.org/projects/stash/stash/uk/
* Translated using Weblate (French)
Currently translated at 99.9% (1345 of 1346 strings)
Translation: stash/stash
Translate-URL: https://translate.codeberg.org/projects/stash/stash/fr/
* Translated using Weblate (Korean)
Currently translated at 100.0% (1346 of 1346 strings)
Translation: stash/stash
Translate-URL: https://translate.codeberg.org/projects/stash/stash/ko/
* Translated using Weblate (French)
Currently translated at 100.0% (1346 of 1346 strings)
Translation: stash/stash
Translate-URL: https://translate.codeberg.org/projects/stash/stash/fr/
* Translated using Weblate (Ukrainian)
Currently translated at 100.0% (1346 of 1346 strings)
Translation: stash/stash
Translate-URL: https://translate.codeberg.org/projects/stash/stash/uk/
* Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (1346 of 1346 strings)
Translation: stash/stash
Translate-URL: https://translate.codeberg.org/projects/stash/stash/zh_Hans/
* Translated using Weblate (Portuguese (Brazil))
Currently translated at 67.3% (906 of 1346 strings)
Translation: stash/stash
Translate-URL: https://translate.codeberg.org/projects/stash/stash/pt_BR/
* Update translation files
Updated by "Cleanup translation files" add-on in Weblate.
Translation: stash/stash
Translate-URL: https://translate.codeberg.org/projects/stash/stash/
* Translated using Weblate (French)
Currently translated at 100.0% (1348 of 1348 strings)
Translation: stash/stash
Translate-URL: https://translate.codeberg.org/projects/stash/stash/fr/
* Translated using Weblate (Czech)
Currently translated at 100.0% (1351 of 1351 strings)
Translation: stash/stash
Translate-URL: https://translate.codeberg.org/projects/stash/stash/cs/
* Translated using Weblate (Spanish)
Currently translated at 100.0% (1351 of 1351 strings)
Translation: stash/stash
Translate-URL: https://translate.codeberg.org/projects/stash/stash/es/
* Translated using Weblate (Korean)
Currently translated at 100.0% (1351 of 1351 strings)
Translation: stash/stash
Translate-URL: https://translate.codeberg.org/projects/stash/stash/ko/
* Translated using Weblate (Ukrainian)
Currently translated at 100.0% (1351 of 1351 strings)
Translation: stash/stash
Translate-URL: https://translate.codeberg.org/projects/stash/stash/uk/
* Translated using Weblate (French)
Currently translated at 100.0% (1351 of 1351 strings)
Translation: stash/stash
Translate-URL: https://translate.codeberg.org/projects/stash/stash/fr/
* Translated using Weblate (Spanish)
Currently translated at 100.0% (1351 of 1351 strings)
Translation: stash/stash
Translate-URL: https://translate.codeberg.org/projects/stash/stash/es/
* Translated using Weblate (Arabic)
Currently translated at 56.9% (769 of 1351 strings)
Translation: stash/stash
Translate-URL: https://translate.codeberg.org/projects/stash/stash/ar/
* Translated using Weblate (Polish)
Currently translated at 80.1% (1083 of 1351 strings)
Translation: stash/stash
Translate-URL: https://translate.codeberg.org/projects/stash/stash/pl/
* Translated using Weblate (Ukrainian)
Currently translated at 100.0% (1351 of 1351 strings)
Translation: stash/stash
Translate-URL: https://translate.codeberg.org/projects/stash/stash/uk/
* Translated using Weblate (Arabic)
Currently translated at 58.0% (784 of 1351 strings)
Translation: stash/stash
Translate-URL: https://translate.codeberg.org/projects/stash/stash/ar/
---------
Co-authored-by: doodoo <doodoo@noreply.codeberg.org>
Co-authored-by: slickdaddy <slickdaddy@noreply.codeberg.org>
Co-authored-by: Saenko <saenko@noreply.codeberg.org>
Co-authored-by: lugged9922 <lugged9922@noreply.codeberg.org>
Co-authored-by: wql219 <wql219@noreply.codeberg.org>
Co-authored-by: tiagodamian <tiagodamian@noreply.codeberg.org>
Co-authored-by: Codeberg Translate <translate@codeberg.org>
Co-authored-by: NymeriaCZ <nymeriacz@noreply.codeberg.org>
Co-authored-by: donlothario <donlothario@noreply.codeberg.org>
Co-authored-by: gallegonovato <gallegonovato@noreply.codeberg.org>
Co-authored-by: interj4 <interj4@noreply.codeberg.org>
Co-authored-by: brnd <brnd@noreply.codeberg.org>
This is more consistent with other places that stash IDs are shown,
simplifies the code a bit, and lets you see at a glance which stash
box is being used.
* Add short cuts when only getting zip/folder ids
* Don't show zip folders when viewing scenes and galleries.
Zip folders have no results for scenes and galleries, but will for images.
* Add StudioLogo component
If no studio image is set, shows the studio icon with the studio name.
* Add option to always show studio text
* Implement studio as text option
* Add studio logo to image
* Clarify existing show studio as text option
* Make modal field/value styling consistent
Fixes URL list in studio list styling
* Add stash id pill to studio and tag modals
* Fix create parent check box
* Allow excluding parent studio
Disabled the create checkbox if parent studio is not excluded and does not exist.
* Don't render modal on every studio
* Show dialog when refreshing tags
* Add GUID search for performers in PerformerSelect component
* Refactor and apply to all objects with stash ids
---------
Co-authored-by: KennyG <kennyg@kennyg.com>
Co-authored-by: WithoutPants <53250216+WithoutPants@users.noreply.github.com>
* Add option to ignore zip file contents while cleaning
Speeds up the clean process with the assumption that files within zip files are not deleted.
* Add UI for new option
* Keep creatable select input focused after creating a new item
When onCreateOption fires, setLoading(true) sets isDisabled on
AsyncCreatableSelect, which triggers a blur and the user loses focus.
Remove isLoading from the isDisabled condition so the input stays
interactive during the async creation; the loading spinner still shows.
Fixes#3998
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* Remove unused isLoading destructure in SelectComponent
isLoading flows through via ...props spread in componentProps and
no longer needs to be explicitly destructured.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* Apply Prettier formatting to FilterSelect.tsx
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat: add scenes_size sort option for performers
Adds sorting performers by total file size of associated scenes.
Follows the existing scenes_duration pattern.
Ref: stashapp/stash#5530
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: add scenes_size sort option for studios
Adds sorting studios by total file size of associated scenes.
Follows the existing scenes_duration pattern.
Ref: stashapp/stash#5530
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat(ui): add Scenes Size sort option for performers and studios
Adds 'Scenes Size' to the sort dropdown for performer and studio
list views, with i18n label.
Ref: stashapp/stash#5530
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: extend scenes_size sort to tags
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* Move reused functions/components to separate files
* Add alwaysShow field to ScrapedDialogRow
* Add stash ids to performer merge dialog
* Reuse StashIDsField in TagMergeDialog
* Always show stash ids when available on scene and tag merge dialogs
* Convert career start/end to date
* Update UI to accept dates for career length fields
* Fix date filtering
---------
Co-authored-by: Gykes <24581046+Gykes@users.noreply.github.com>
* Add BulkUpdateDateInput
* Refactor edit scenes dialog
* Improve bulk date input styling
* Make fields inline in edit performers dialog
* Refactor edit images dialog
* Refactor edit galleries dialog
* Add date and synopsis to bulk update group input
* Refactor edit groups dialog
* Change edit dialog titles to 'Edit x entities'
* Update styling of bulk fields to be consistent with other UI
* Rename BulkUpdateTextInput to generic BulkUpdate
We'll collect other bulk inputs here
* Add and use BulkUpdateFormGroup
* Handle null dates correctly
* Add date clear button and validation
* Show scene resolution and duration in tagger
A scene's duration and resolution is often useful to ensure you have
found the right scene. This PR adds the same resolution/duration
overlay from the grid view to the tagger view.
* Show the stash box for each stash ID in the scene merge dialog
Currently, this dialog only shows the ID but not the stash box it
corresponds to. This is not very useful because the ID does not mean
anything to a user.
This renders the ID as "Stashdb | 1234...", mimicing the StashIDPill.
* Use StashIDPill instead
Currently, this dialog just shows a text "Stash-Box Source".
This change instead re-uses the StashIDPill, with the main advantage
that you can immediately tell which stash box is being used.
* Add useDebouncedState hook
* Add basename to folder sort whitelist
* Add parent_folder criterion to gallery
* Add selection on enter if single result