diff --git a/graphql/documents/mutations/scene.graphql b/graphql/documents/mutations/scene.graphql index d2b1a96a7..43231808b 100644 --- a/graphql/documents/mutations/scene.graphql +++ b/graphql/documents/mutations/scene.graphql @@ -26,6 +26,6 @@ mutation SceneUpdate( } } -mutation SceneDestroy($id: ID!, $delete_file: Boolean) { - sceneDestroy(input: {id: $id, delete_file: $delete_file}) +mutation SceneDestroy($id: ID!, $delete_file: Boolean, $delete_generated : Boolean) { + sceneDestroy(input: {id: $id, delete_file: $delete_file, delete_generated: $delete_generated}) } \ No newline at end of file diff --git a/graphql/schema/types/scene.graphql b/graphql/schema/types/scene.graphql index ce9f8fecb..a23b2d13b 100644 --- a/graphql/schema/types/scene.graphql +++ b/graphql/schema/types/scene.graphql @@ -56,6 +56,7 @@ input SceneUpdateInput { input SceneDestroyInput { id: ID! delete_file: Boolean + delete_generated: Boolean } type FindScenesResultType { diff --git a/pkg/api/resolver_mutation_scene.go b/pkg/api/resolver_mutation_scene.go index 221cf92bf..c6dab2dc3 100644 --- a/pkg/api/resolver_mutation_scene.go +++ b/pkg/api/resolver_mutation_scene.go @@ -4,12 +4,15 @@ import ( "context" "database/sql" "os" + "path/filepath" "strconv" "time" "github.com/stashapp/stash/pkg/database" "github.com/stashapp/stash/pkg/logger" + "github.com/stashapp/stash/pkg/manager" "github.com/stashapp/stash/pkg/models" + "github.com/stashapp/stash/pkg/utils" ) func (r *mutationResolver) SceneUpdate(ctx context.Context, input models.SceneUpdateInput) (*models.Scene, error) { @@ -145,6 +148,12 @@ func (r *mutationResolver) SceneDestroy(ctx context.Context, input models.SceneD return false, err } + // if delete generated is true, then delete the generated files + // for the scene + if input.DeleteGenerated != nil && *input.DeleteGenerated { + deleteGeneratedSceneFiles(scene) + } + // if delete file is true, then delete the file as well // if it fails, just log a message if input.DeleteFile != nil && *input.DeleteFile { @@ -157,6 +166,81 @@ func (r *mutationResolver) SceneDestroy(ctx context.Context, input models.SceneD return true, nil } +func deleteGeneratedSceneFiles(scene *models.Scene) { + markersFolder := filepath.Join(manager.GetInstance().Paths.Generated.Markers, scene.Checksum) + + exists, _ := utils.FileExists(markersFolder) + if exists { + err := os.RemoveAll(markersFolder) + if err != nil { + logger.Warnf("Could not delete file %s: %s", scene.Path, err.Error()) + } + } + + thumbPath := manager.GetInstance().Paths.Scene.GetThumbnailScreenshotPath(scene.Checksum) + exists, _ = utils.FileExists(thumbPath) + if exists { + err := os.Remove(thumbPath) + if err != nil { + logger.Warnf("Could not delete file %s: %s", thumbPath, err.Error()) + } + } + + normalPath := manager.GetInstance().Paths.Scene.GetScreenshotPath(scene.Checksum) + exists, _ = utils.FileExists(normalPath) + if exists { + err := os.Remove(normalPath) + if err != nil { + logger.Warnf("Could not delete file %s: %s", normalPath, err.Error()) + } + } + + streamPreviewPath := manager.GetInstance().Paths.Scene.GetStreamPreviewPath(scene.Checksum) + exists, _ = utils.FileExists(streamPreviewPath) + if exists { + err := os.Remove(streamPreviewPath) + if err != nil { + logger.Warnf("Could not delete file %s: %s", streamPreviewPath, err.Error()) + } + } + + streamPreviewImagePath := manager.GetInstance().Paths.Scene.GetStreamPreviewImagePath(scene.Checksum) + exists, _ = utils.FileExists(streamPreviewImagePath) + if exists { + err := os.Remove(streamPreviewImagePath) + if err != nil { + logger.Warnf("Could not delete file %s: %s", streamPreviewImagePath, err.Error()) + } + } + + transcodePath := manager.GetInstance().Paths.Scene.GetTranscodePath(scene.Checksum) + exists, _ = utils.FileExists(transcodePath) + if exists { + err := os.Remove(transcodePath) + if err != nil { + logger.Warnf("Could not delete file %s: %s", transcodePath, err.Error()) + } + } + + spritePath := manager.GetInstance().Paths.Scene.GetSpriteImageFilePath(scene.Checksum) + exists, _ = utils.FileExists(spritePath) + if exists { + err := os.Remove(spritePath) + if err != nil { + logger.Warnf("Could not delete file %s: %s", spritePath, err.Error()) + } + } + + vttPath := manager.GetInstance().Paths.Scene.GetSpriteVttFilePath(scene.Checksum) + exists, _ = utils.FileExists(vttPath) + if exists { + err := os.Remove(vttPath) + if err != nil { + logger.Warnf("Could not delete file %s: %s", vttPath, err.Error()) + } + } +} + func (r *mutationResolver) SceneMarkerCreate(ctx context.Context, input models.SceneMarkerCreateInput) (*models.SceneMarker, error) { primaryTagID, _ := strconv.Atoi(input.PrimaryTagID) sceneID, _ := strconv.Atoi(input.SceneID) diff --git a/pkg/models/generated_exec.go b/pkg/models/generated_exec.go index 3a99f83e1..a285c42bf 100644 --- a/pkg/models/generated_exec.go +++ b/pkg/models/generated_exec.go @@ -2176,6 +2176,7 @@ input SceneUpdateInput { input SceneDestroyInput { id: ID! delete_file: Boolean + delete_generated: Boolean } type FindScenesResultType { @@ -8355,6 +8356,12 @@ func (ec *executionContext) unmarshalInputSceneDestroyInput(ctx context.Context, if err != nil { return it, err } + case "delete_generated": + var err error + it.DeleteGenerated, err = ec.unmarshalOBoolean2ᚖbool(ctx, v) + if err != nil { + return it, err + } } } diff --git a/pkg/models/generated_models.go b/pkg/models/generated_models.go index 16be350f3..358921d15 100644 --- a/pkg/models/generated_models.go +++ b/pkg/models/generated_models.go @@ -137,8 +137,9 @@ type PerformerUpdateInput struct { } type SceneDestroyInput struct { - ID string `json:"id"` - DeleteFile *bool `json:"delete_file"` + ID string `json:"id"` + DeleteFile *bool `json:"delete_file"` + DeleteGenerated *bool `json:"delete_generated"` } type SceneFileType struct { diff --git a/ui/v2/src/components/scenes/SceneDetails/SceneEditPanel.tsx b/ui/v2/src/components/scenes/SceneDetails/SceneEditPanel.tsx index 76e2bbcdb..6bba97acf 100644 --- a/ui/v2/src/components/scenes/SceneDetails/SceneEditPanel.tsx +++ b/ui/v2/src/components/scenes/SceneDetails/SceneEditPanel.tsx @@ -1,6 +1,8 @@ import { - Alert, Button, + Classes, + Checkbox, + Dialog, FormGroup, HTMLSelect, InputGroup, @@ -37,6 +39,7 @@ export const SceneEditPanel: FunctionComponent = (props: IProps) => { const [isDeleteAlertOpen, setIsDeleteAlertOpen] = useState(false); const [deleteFile, setDeleteFile] = useState(false); + const [deleteGenerated, setDeleteGenerated] = useState(true); // Network state const [isLoading, setIsLoading] = useState(false); @@ -98,7 +101,8 @@ export const SceneEditPanel: FunctionComponent = (props: IProps) => { function getSceneDeleteInput(): GQL.SceneDestroyInput { return { id: props.scene.id, - delete_file: deleteFile + delete_file: deleteFile, + delete_generated: deleteGenerated }; } @@ -134,19 +138,31 @@ export const SceneEditPanel: FunctionComponent = (props: IProps) => { function renderDeleteAlert() { return ( - + setIsDeleteAlertOpen(false)} - onConfirm={() => onDelete()} + title="Delete Scene?" > -

- Are you sure you want to delete this scene? Unless the file is also deleted, this scene will be re-added when scan is performed. -

-
+
+

+ Are you sure you want to delete this scene? Unless the file is also deleted, this scene will be re-added when scan is performed. +

+ setDeleteFile(!deleteFile)} /> + setDeleteGenerated(!deleteGenerated)} /> +
+ +
+
+ + +
+
+ + ); } diff --git a/ui/v2/src/core/generated-graphql.tsx b/ui/v2/src/core/generated-graphql.tsx index 3bb636e50..979497be7 100644 --- a/ui/v2/src/core/generated-graphql.tsx +++ b/ui/v2/src/core/generated-graphql.tsx @@ -1,6 +1,6 @@ /* tslint:disable */ /* eslint-disable */ -// Generated in 2019-08-15T13:55:54+10:00 +// Generated in 2019-08-15T18:05:18+10:00 export type Maybe = T | undefined; export interface SceneFilterType { @@ -92,6 +92,8 @@ export interface SceneDestroyInput { id: string; delete_file?: Maybe; + + delete_generated?: Maybe; } export interface SceneMarkerCreateInput { @@ -399,6 +401,7 @@ export type SceneUpdateSceneUpdate = SceneDataFragment; export type SceneDestroyVariables = { id: string; delete_file?: Maybe; + delete_generated?: Maybe; }; export type SceneDestroyMutation = { @@ -1792,8 +1795,18 @@ export function useSceneUpdate( >(SceneUpdateDocument, baseOptions); } export const SceneDestroyDocument = gql` - mutation SceneDestroy($id: ID!, $delete_file: Boolean) { - sceneDestroy(input: { id: $id, delete_file: $delete_file }) + mutation SceneDestroy( + $id: ID! + $delete_file: Boolean + $delete_generated: Boolean + ) { + sceneDestroy( + input: { + id: $id + delete_file: $delete_file + delete_generated: $delete_generated + } + ) } `; export function useSceneDestroy(