From 48035061ec65f27a191e68226487ccc77827cfb4 Mon Sep 17 00:00:00 2001 From: WithoutPants <53250216+WithoutPants@users.noreply.github.com> Date: Wed, 19 Jun 2024 19:52:33 +1000 Subject: [PATCH 1/5] Fix identify clearing parent studio when merging (#4993) * Refactor ScrapedStudio.ToPartial signature * Add unit test * Don't clear parent studio during ToPartial --- internal/identify/studio.go | 6 +- internal/manager/task_stash_box_tag.go | 12 +-- pkg/models/model_scraped_item.go | 8 +- pkg/models/model_scraped_item_test.go | 120 +++++++++++++++++++++++++ 4 files changed, 132 insertions(+), 14 deletions(-) diff --git a/internal/identify/studio.go b/internal/identify/studio.go index d05967bc4f2..51bcaf2eec9 100644 --- a/internal/identify/studio.go +++ b/internal/identify/studio.go @@ -46,17 +46,17 @@ func createMissingStudio(ctx context.Context, endpoint string, w models.StudioRe return nil, err } - studioPartial := s.Parent.ToPartial(s.Parent.StoredID, endpoint, nil, existingStashIDs) + studioPartial := s.Parent.ToPartial(*s.Parent.StoredID, endpoint, nil, existingStashIDs) parentImage, err := s.Parent.GetImage(ctx, nil) if err != nil { return nil, err } - if err := studio.ValidateModify(ctx, *studioPartial, w); err != nil { + if err := studio.ValidateModify(ctx, studioPartial, w); err != nil { return nil, err } - _, err = w.UpdatePartial(ctx, *studioPartial) + _, err = w.UpdatePartial(ctx, studioPartial) if err != nil { return nil, err } diff --git a/internal/manager/task_stash_box_tag.go b/internal/manager/task_stash_box_tag.go index 298b58e279f..8bb39960140 100644 --- a/internal/manager/task_stash_box_tag.go +++ b/internal/manager/task_stash_box_tag.go @@ -311,13 +311,13 @@ func (t *StashBoxBatchTagTask) processMatchedStudio(ctx context.Context, s *mode return err } - partial := s.ToPartial(s.StoredID, t.box.Endpoint, excluded, existingStashIDs) + partial := s.ToPartial(*s.StoredID, t.box.Endpoint, excluded, existingStashIDs) - if err := studio.ValidateModify(ctx, *partial, qb); err != nil { + if err := studio.ValidateModify(ctx, partial, qb); err != nil { return err } - if _, err := qb.UpdatePartial(ctx, *partial); err != nil { + if _, err := qb.UpdatePartial(ctx, partial); err != nil { return err } @@ -435,13 +435,13 @@ func (t *StashBoxBatchTagTask) processParentStudio(ctx context.Context, parent * return err } - partial := parent.ToPartial(parent.StoredID, t.box.Endpoint, excluded, existingStashIDs) + partial := parent.ToPartial(*parent.StoredID, t.box.Endpoint, excluded, existingStashIDs) - if err := studio.ValidateModify(ctx, *partial, qb); err != nil { + if err := studio.ValidateModify(ctx, partial, qb); err != nil { return err } - if _, err := qb.UpdatePartial(ctx, *partial); err != nil { + if _, err := qb.UpdatePartial(ctx, partial); err != nil { return err } diff --git a/pkg/models/model_scraped_item.go b/pkg/models/model_scraped_item.go index cb383c082e7..e5bbdc8dd77 100644 --- a/pkg/models/model_scraped_item.go +++ b/pkg/models/model_scraped_item.go @@ -62,9 +62,9 @@ func (s *ScrapedStudio) GetImage(ctx context.Context, excluded map[string]bool) return nil, nil } -func (s *ScrapedStudio) ToPartial(id *string, endpoint string, excluded map[string]bool, existingStashIDs []StashID) *StudioPartial { +func (s *ScrapedStudio) ToPartial(id string, endpoint string, excluded map[string]bool, existingStashIDs []StashID) StudioPartial { ret := NewStudioPartial() - ret.ID, _ = strconv.Atoi(*id) + ret.ID, _ = strconv.Atoi(id) if s.Name != "" && !excluded["name"] { ret.Name = NewOptionalString(s.Name) @@ -82,8 +82,6 @@ func (s *ScrapedStudio) ToPartial(id *string, endpoint string, excluded map[stri ret.ParentID = NewOptionalInt(parentID) } } - } else { - ret.ParentID = NewOptionalIntPtr(nil) } if s.RemoteSiteID != nil && endpoint != "" { @@ -97,7 +95,7 @@ func (s *ScrapedStudio) ToPartial(id *string, endpoint string, excluded map[stri }) } - return &ret + return ret } // A performer from a scraping operation... diff --git a/pkg/models/model_scraped_item_test.go b/pkg/models/model_scraped_item_test.go index a6e42f2fd80..4093192fab7 100644 --- a/pkg/models/model_scraped_item_test.go +++ b/pkg/models/model_scraped_item_test.go @@ -249,3 +249,123 @@ func Test_scrapedToPerformerInput(t *testing.T) { }) } } + +func TestScrapedStudio_ToPartial(t *testing.T) { + var ( + id = 1000 + idStr = strconv.Itoa(id) + storedID = "storedID" + parentStoredID = 2000 + parentStoredIDStr = strconv.Itoa(parentStoredID) + name = "name" + url = "url" + remoteSiteID = "remoteSiteID" + endpoint = "endpoint" + image = "image" + images = []string{image} + + existingEndpoint = "existingEndpoint" + existingStashID = StashID{"existingStashID", existingEndpoint} + existingStashIDs = []StashID{existingStashID} + ) + + fullStudio := ScrapedStudio{ + StoredID: &storedID, + Name: name, + URL: &url, + Parent: &ScrapedStudio{ + StoredID: &parentStoredIDStr, + }, + Image: &image, + Images: images, + RemoteSiteID: &remoteSiteID, + } + + type args struct { + id string + endpoint string + excluded map[string]bool + existingStashIDs []StashID + } + + stdArgs := args{ + id: idStr, + endpoint: endpoint, + excluded: map[string]bool{}, + existingStashIDs: existingStashIDs, + } + + excludeAll := map[string]bool{ + "name": true, + "url": true, + "parent": true, + } + + tests := []struct { + name string + o ScrapedStudio + args args + want StudioPartial + }{ + { + "full no exclusions", + fullStudio, + stdArgs, + StudioPartial{ + ID: id, + Name: NewOptionalString(name), + URL: NewOptionalString(url), + ParentID: NewOptionalInt(parentStoredID), + StashIDs: &UpdateStashIDs{ + StashIDs: append(existingStashIDs, StashID{ + Endpoint: endpoint, + StashID: remoteSiteID, + }), + Mode: RelationshipUpdateModeSet, + }, + }, + }, + { + "exclude all", + fullStudio, + args{ + id: idStr, + excluded: excludeAll, + }, + StudioPartial{ + ID: id, + }, + }, + { + "overwrite stash id", + fullStudio, + args{ + id: idStr, + excluded: excludeAll, + endpoint: existingEndpoint, + existingStashIDs: existingStashIDs, + }, + StudioPartial{ + ID: id, + StashIDs: &UpdateStashIDs{ + StashIDs: []StashID{{ + Endpoint: existingEndpoint, + StashID: remoteSiteID, + }}, + Mode: RelationshipUpdateModeSet, + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := tt.o + got := s.ToPartial(tt.args.id, tt.args.endpoint, tt.args.excluded, tt.args.existingStashIDs) + + // unset updatedAt - we don't need to compare it + got.UpdatedAt = OptionalTime{} + + assert.Equal(t, tt.want, got) + }) + } +} From 205b24499bb9136eb263eec67de6c3529a145da3 Mon Sep 17 00:00:00 2001 From: WithoutPants <53250216+WithoutPants@users.noreply.github.com> Date: Fri, 21 Jun 2024 16:15:59 +1000 Subject: [PATCH 2/5] Fix key for tagger scenes (#5000) --- ui/v2.5/src/components/Tagger/scenes/SceneTagger.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/v2.5/src/components/Tagger/scenes/SceneTagger.tsx b/ui/v2.5/src/components/Tagger/scenes/SceneTagger.tsx index c8b1c43d9ff..ab6bd226e33 100755 --- a/ui/v2.5/src/components/Tagger/scenes/SceneTagger.tsx +++ b/ui/v2.5/src/components/Tagger/scenes/SceneTagger.tsx @@ -264,7 +264,7 @@ export const Tagger: React.FC = ({ scenes, queue }) => {
{filteredScenes.map((s, i) => ( Date: Mon, 24 Jun 2024 01:03:29 -0500 Subject: [PATCH 3/5] Address resize loop (#5004) --- .../src/components/Shared/GridCard/GridCard.tsx | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/ui/v2.5/src/components/Shared/GridCard/GridCard.tsx b/ui/v2.5/src/components/Shared/GridCard/GridCard.tsx index 911064a9402..1d1a37528d9 100644 --- a/ui/v2.5/src/components/Shared/GridCard/GridCard.tsx +++ b/ui/v2.5/src/components/Shared/GridCard/GridCard.tsx @@ -42,9 +42,9 @@ interface IDimension { height: number; } -export const useContainerDimensions = < - T extends HTMLElement = HTMLDivElement ->(): [MutableRefObject, IDimension] => { +export const useContainerDimensions = ( + sensitivityThreshold = 20 +): [MutableRefObject, IDimension] => { const target = useRef(null); const [dimension, setDimension] = useState({ width: 0, @@ -53,7 +53,14 @@ export const useContainerDimensions = < useResizeObserver(target, (entry) => { const { inlineSize: width, blockSize: height } = entry.contentBoxSize[0]; - setDimension({ width, height }); + let difference = Math.abs(dimension.width - width); + // Only adjust when width changed by a significant margin. This addresses the cornercase that sees + // the dimensions toggle back and forward when the window is adjusted perfectly such that overflow + // is trigger then immediable disabled because of a resize event then continues this loop endlessly. + // the scrollbar size varies between platforms. Windows is apparently around 17 pixels. + if (difference > sensitivityThreshold) { + setDimension({ width, height }); + } }); return [target, dimension]; From e116775d60329a13d8eeda84e8de75f40879b57c Mon Sep 17 00:00:00 2001 From: dogwithakeyboard <128322708+dogwithakeyboard@users.noreply.github.com> Date: Thu, 27 Jun 2024 01:12:39 +0100 Subject: [PATCH 4/5] Check for null disambiguation on validate (#5019) --- pkg/performer/validate.go | 12 ++++++++---- pkg/performer/validate_test.go | 10 +++------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/pkg/performer/validate.go b/pkg/performer/validate.go index 0106490cf62..68f7a8ef535 100644 --- a/pkg/performer/validate.go +++ b/pkg/performer/validate.go @@ -102,11 +102,15 @@ func validateName(ctx context.Context, name string, disambig string, existingID }, } + modifier := models.CriterionModifierIsNull + if disambig != "" { - performerFilter.Disambiguation = &models.StringCriterionInput{ - Value: disambig, - Modifier: models.CriterionModifierEquals, - } + modifier = models.CriterionModifierEquals + } + + performerFilter.Disambiguation = &models.StringCriterionInput{ + Value: disambig, + Modifier: modifier, } if existingID == nil { diff --git a/pkg/performer/validate_test.go b/pkg/performer/validate_test.go index 778459f1751..33f4b1cec58 100644 --- a/pkg/performer/validate_test.go +++ b/pkg/performer/validate_test.go @@ -15,6 +15,9 @@ func nameFilter(n string) *models.PerformerFilterType { Value: n, Modifier: models.CriterionModifierEquals, }, + Disambiguation: &models.StringCriterionInput{ + Modifier: models.CriterionModifierIsNull, + }, } } @@ -41,13 +44,6 @@ func TestValidateName(t *testing.T) { newName = "new name" newDisambig = "new disambiguation" ) - // existing1 := models.Performer{ - // Name: name1, - // } - // existing2 := models.Performer{ - // Name: name2, - // Disambiguation: disambig, - // } pp := 1 findFilter := &models.FindFilterType{ From 2a373a25ca36aff1bac7f375fe61cb69aa4cd3c0 Mon Sep 17 00:00:00 2001 From: WithoutPants <53250216+WithoutPants@users.noreply.github.com> Date: Thu, 27 Jun 2024 09:26:37 +1000 Subject: [PATCH 5/5] Update changelog --- ui/v2.5/src/docs/en/Changelog/v0260.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ui/v2.5/src/docs/en/Changelog/v0260.md b/ui/v2.5/src/docs/en/Changelog/v0260.md index a3d89d676f2..8ef0c35516b 100644 --- a/ui/v2.5/src/docs/en/Changelog/v0260.md +++ b/ui/v2.5/src/docs/en/Changelog/v0260.md @@ -22,6 +22,11 @@ * Changed umask when creating config file to exclude user write (CVE-2024-32233) ([#4866](https://github.com/stashapp/stash/pull/4866)) ### 🐛 Bug fixes +* **[0.26.2]** Fixed issue where performer could not be created without disambiguation if a performer with the same name and populated disambiguation exists. ([#5019](https://github.com/stashapp/stash/pull/5019)) +* **[0.26.2]** Fix resize loop in grid views. ([#5004](https://github.com/stashapp/stash/pull/5004)) +* **[0.26.2]** Fix query field values duplicating in tagger view when scene list is updated. ([#5000](https://github.com/stashapp/stash/pull/5000)) +* **[0.26.2]** Fix identify clearing parent studio when merging studio field. ([#4993](https://github.com/stashapp/stash/pull/4993)) +* **[0.26.2]** Fix manually selected studio not being applied during scrape. ([#4953](https://github.com/stashapp/stash/pull/4953)) * **[0.26.1]** Fixed identify task defaults not displaying correctly. ([#4931](https://github.com/stashapp/stash/pull/4931)) * **[0.26.1]** Fixed issue where full hardware transcoding did not work where a filter was not required. ([#4934](https://github.com/stashapp/stash/pull/4934)) * **[0.26.1]** Fixed new performer tags not displaying correctly in the performer scrape dialog. ([#4943](https://github.com/stashapp/stash/pull/4943))