Add options to delete file and generated files

This commit is contained in:
WithoutPants
2019-08-16 07:21:35 +10:00
parent cfe2636837
commit 7ee1b3f052
7 changed files with 141 additions and 19 deletions

View File

@@ -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})
}

View File

@@ -56,6 +56,7 @@ input SceneUpdateInput {
input SceneDestroyInput {
id: ID!
delete_file: Boolean
delete_generated: Boolean
}
type FindScenesResultType {

View File

@@ -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)

View File

@@ -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
}
}
}

View File

@@ -139,6 +139,7 @@ type PerformerUpdateInput struct {
type SceneDestroyInput struct {
ID string `json:"id"`
DeleteFile *bool `json:"delete_file"`
DeleteGenerated *bool `json:"delete_generated"`
}
type SceneFileType struct {

View File

@@ -1,6 +1,8 @@
import {
Alert,
Button,
Classes,
Checkbox,
Dialog,
FormGroup,
HTMLSelect,
InputGroup,
@@ -37,6 +39,7 @@ export const SceneEditPanel: FunctionComponent<IProps> = (props: IProps) => {
const [isDeleteAlertOpen, setIsDeleteAlertOpen] = useState<boolean>(false);
const [deleteFile, setDeleteFile] = useState<boolean>(false);
const [deleteGenerated, setDeleteGenerated] = useState<boolean>(true);
// Network state
const [isLoading, setIsLoading] = useState(false);
@@ -98,7 +101,8 @@ export const SceneEditPanel: FunctionComponent<IProps> = (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<IProps> = (props: IProps) => {
function renderDeleteAlert() {
return (
<Alert
cancelButtonText="Cancel"
confirmButtonText="Delete"
<>
<Dialog
canOutsideClickClose={false}
canEscapeKeyClose={false}
icon="trash"
intent="danger"
isCloseButtonShown={false}
isOpen={isDeleteAlertOpen}
onCancel={() => setIsDeleteAlertOpen(false)}
onConfirm={() => onDelete()}
title="Delete Scene?"
>
<div className={Classes.DIALOG_BODY}>
<p>
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.
</p>
</Alert>
<Checkbox checked={deleteFile} label="Delete file" onChange={() => setDeleteFile(!deleteFile)} />
<Checkbox checked={deleteGenerated} label="Delete generated supporting files" onChange={() => setDeleteGenerated(!deleteGenerated)} />
</div>
<div className={Classes.DIALOG_FOOTER}>
<div className={Classes.DIALOG_FOOTER_ACTIONS}>
<Button intent="danger" onClick={() => onDelete()}>Delete</Button>
<Button onClick={() => setIsDeleteAlertOpen(false)}>Cancel</Button>
</div>
</div>
</Dialog>
</>
);
}

View File

@@ -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> = T | undefined;
export interface SceneFilterType {
@@ -92,6 +92,8 @@ export interface SceneDestroyInput {
id: string;
delete_file?: Maybe<boolean>;
delete_generated?: Maybe<boolean>;
}
export interface SceneMarkerCreateInput {
@@ -399,6 +401,7 @@ export type SceneUpdateSceneUpdate = SceneDataFragment;
export type SceneDestroyVariables = {
id: string;
delete_file?: Maybe<boolean>;
delete_generated?: Maybe<boolean>;
};
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(