From 0fa132cf60fa17fb05a84082f42bc6dfd0147037 Mon Sep 17 00:00:00 2001 From: Gykes <24581046+Gykes@users.noreply.github.com> Date: Tue, 13 Jan 2026 19:13:41 -0800 Subject: [PATCH] FR: Add Delete Button For Scene Covers (#6444) --- internal/api/resolver_mutation_scene.go | 17 +++++++++-------- internal/api/routes_scene.go | 7 +++++++ .../Scenes/SceneDetails/SceneEditPanel.tsx | 5 +++++ ui/v2.5/src/components/Shared/ImageInput.tsx | 15 ++++++++++++++- 4 files changed, 35 insertions(+), 9 deletions(-) diff --git a/internal/api/resolver_mutation_scene.go b/internal/api/resolver_mutation_scene.go index c08184add..cb2aa7d24 100644 --- a/internal/api/resolver_mutation_scene.go +++ b/internal/api/resolver_mutation_scene.go @@ -297,6 +297,7 @@ func (r *mutationResolver) sceneUpdate(ctx context.Context, input models.SceneUp } var coverImageData []byte + coverImageIncluded := translator.hasField("cover_image") if input.CoverImage != nil { var err error coverImageData, err = utils.ProcessImageInput(ctx, *input.CoverImage) @@ -310,21 +311,21 @@ func (r *mutationResolver) sceneUpdate(ctx context.Context, input models.SceneUp return nil, err } - if err := r.sceneUpdateCoverImage(ctx, scene, coverImageData); err != nil { - return nil, err + if coverImageIncluded { + if err := r.sceneUpdateCoverImage(ctx, scene, coverImageData); err != nil { + return nil, err + } } return scene, nil } func (r *mutationResolver) sceneUpdateCoverImage(ctx context.Context, s *models.Scene, coverImageData []byte) error { - if len(coverImageData) > 0 { - qb := r.repository.Scene + qb := r.repository.Scene - // update cover table - if err := qb.UpdateCover(ctx, s.ID, coverImageData); err != nil { - return err - } + // update cover table - empty data will clear the cover + if err := qb.UpdateCover(ctx, s.ID, coverImageData); err != nil { + return err } return nil diff --git a/internal/api/routes_scene.go b/internal/api/routes_scene.go index 95e7c9d44..2905bd53a 100644 --- a/internal/api/routes_scene.go +++ b/internal/api/routes_scene.go @@ -12,6 +12,7 @@ import ( "github.com/stashapp/stash/internal/manager" "github.com/stashapp/stash/internal/manager/config" + "github.com/stashapp/stash/internal/static" "github.com/stashapp/stash/pkg/ffmpeg" "github.com/stashapp/stash/pkg/file/video" "github.com/stashapp/stash/pkg/fsutil" @@ -243,6 +244,12 @@ func (rs sceneRoutes) streamSegment(w http.ResponseWriter, r *http.Request, stre } func (rs sceneRoutes) Screenshot(w http.ResponseWriter, r *http.Request) { + // if default flag is set, return the default image + if r.URL.Query().Get("default") == "true" { + utils.ServeImage(w, r, static.ReadAll(static.DefaultSceneImage)) + return + } + scene := r.Context().Value(sceneKey).(*models.Scene) ss := manager.SceneServer{ diff --git a/ui/v2.5/src/components/Scenes/SceneDetails/SceneEditPanel.tsx b/ui/v2.5/src/components/Scenes/SceneDetails/SceneEditPanel.tsx index 48b353165..54bf5b573 100644 --- a/ui/v2.5/src/components/Scenes/SceneDetails/SceneEditPanel.tsx +++ b/ui/v2.5/src/components/Scenes/SceneDetails/SceneEditPanel.tsx @@ -302,6 +302,10 @@ export const SceneEditPanel: React.FC = ({ ImageUtils.onImageChange(event, onImageLoad); } + function onResetCover() { + formik.setFieldValue("cover_image", null); + } + async function onScrapeClicked(s: GQL.ScraperSourceInput) { setIsLoading(true); try { @@ -856,6 +860,7 @@ export const SceneEditPanel: React.FC = ({ isEditing onImageChange={onCoverImageChange} onImageURL={onImageLoad} + onReset={scene.id ? onResetCover : undefined} /> diff --git a/ui/v2.5/src/components/Shared/ImageInput.tsx b/ui/v2.5/src/components/Shared/ImageInput.tsx index 94a83f952..7675da41f 100644 --- a/ui/v2.5/src/components/Shared/ImageInput.tsx +++ b/ui/v2.5/src/components/Shared/ImageInput.tsx @@ -18,6 +18,7 @@ interface IImageInput { text?: string; onImageChange: (event: React.ChangeEvent) => void; onImageURL?: (url: string) => void; + onReset?: () => void; acceptSVG?: boolean; } @@ -27,7 +28,14 @@ function acceptExtensions(acceptSVG: boolean = false) { export const ImageInput: React.FC = PatchComponent( "ImageInput", - ({ isEditing, text, onImageChange, onImageURL, acceptSVG = false }) => { + ({ + isEditing, + text, + onImageChange, + onImageURL, + onReset, + acceptSVG = false, + }) => { const [isShowDialog, setIsShowDialog] = useState(false); const [url, setURL] = useState(""); const intl = useIntl(); @@ -137,6 +145,11 @@ export const ImageInput: React.FC = PatchComponent( {text ?? intl.formatMessage({ id: "actions.set_image" })} + {onReset && ( + + )} ); }