mirror of
https://github.com/stashapp/stash.git
synced 2025-12-18 21:04:37 +03:00
Add Dry Run option to clean task (#1081)
This commit is contained in:
@@ -26,8 +26,8 @@ mutation MetadataAutoTag($input: AutoTagMetadataInput!) {
|
|||||||
metadataAutoTag(input: $input)
|
metadataAutoTag(input: $input)
|
||||||
}
|
}
|
||||||
|
|
||||||
mutation MetadataClean {
|
mutation MetadataClean($input: CleanMetadataInput!) {
|
||||||
metadataClean
|
metadataClean(input: $input)
|
||||||
}
|
}
|
||||||
|
|
||||||
mutation MigrateHashNaming {
|
mutation MigrateHashNaming {
|
||||||
|
|||||||
@@ -213,7 +213,7 @@ type Mutation {
|
|||||||
"""Start auto-tagging. Returns the job ID"""
|
"""Start auto-tagging. Returns the job ID"""
|
||||||
metadataAutoTag(input: AutoTagMetadataInput!): String!
|
metadataAutoTag(input: AutoTagMetadataInput!): String!
|
||||||
"""Clean metadata. Returns the job ID"""
|
"""Clean metadata. Returns the job ID"""
|
||||||
metadataClean: String!
|
metadataClean(input: CleanMetadataInput!): String!
|
||||||
"""Migrate generated files for the current hash naming"""
|
"""Migrate generated files for the current hash naming"""
|
||||||
migrateHashNaming: String!
|
migrateHashNaming: String!
|
||||||
|
|
||||||
|
|||||||
@@ -44,6 +44,11 @@ input ScanMetadataInput {
|
|||||||
scanGenerateSprites: Boolean!
|
scanGenerateSprites: Boolean!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input CleanMetadataInput {
|
||||||
|
"""Do a dry run. Don't delete any files"""
|
||||||
|
dryRun: Boolean!
|
||||||
|
}
|
||||||
|
|
||||||
input AutoTagMetadataInput {
|
input AutoTagMetadataInput {
|
||||||
"""IDs of performers to tag files with, or "*" for all"""
|
"""IDs of performers to tag files with, or "*" for all"""
|
||||||
performers: [String!]
|
performers: [String!]
|
||||||
|
|||||||
@@ -70,8 +70,8 @@ func (r *mutationResolver) MetadataAutoTag(ctx context.Context, input models.Aut
|
|||||||
return "todo", nil
|
return "todo", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *mutationResolver) MetadataClean(ctx context.Context) (string, error) {
|
func (r *mutationResolver) MetadataClean(ctx context.Context, input models.CleanMetadataInput) (string, error) {
|
||||||
manager.GetInstance().Clean()
|
manager.GetInstance().Clean(input)
|
||||||
return "todo", nil
|
return "todo", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -783,7 +783,7 @@ func (s *singleton) autoTagTags(tagIds []string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *singleton) Clean() {
|
func (s *singleton) Clean(input models.CleanMetadataInput) {
|
||||||
if s.Status.Status != Idle {
|
if s.Status.Status != Idle {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -803,8 +803,13 @@ func (s *singleton) Clean() {
|
|||||||
gqb := r.Gallery()
|
gqb := r.Gallery()
|
||||||
|
|
||||||
logger.Infof("Starting cleaning of tracked files")
|
logger.Infof("Starting cleaning of tracked files")
|
||||||
|
if input.DryRun {
|
||||||
|
logger.Infof("Running in Dry Mode")
|
||||||
|
}
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
scenes, err = qb.All()
|
scenes, err = qb.All()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("failed to fetch list of scenes for cleaning")
|
return errors.New("failed to fetch list of scenes for cleaning")
|
||||||
}
|
}
|
||||||
@@ -853,7 +858,7 @@ func (s *singleton) Clean() {
|
|||||||
Scene: scene,
|
Scene: scene,
|
||||||
fileNamingAlgorithm: fileNamingAlgo,
|
fileNamingAlgorithm: fileNamingAlgo,
|
||||||
}
|
}
|
||||||
go task.Start(&wg)
|
go task.Start(&wg, input.DryRun)
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -875,7 +880,7 @@ func (s *singleton) Clean() {
|
|||||||
TxnManager: s.TxnManager,
|
TxnManager: s.TxnManager,
|
||||||
Image: img,
|
Image: img,
|
||||||
}
|
}
|
||||||
go task.Start(&wg)
|
go task.Start(&wg, input.DryRun)
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -897,7 +902,7 @@ func (s *singleton) Clean() {
|
|||||||
TxnManager: s.TxnManager,
|
TxnManager: s.TxnManager,
|
||||||
Gallery: gallery,
|
Gallery: gallery,
|
||||||
}
|
}
|
||||||
go task.Start(&wg)
|
go task.Start(&wg, input.DryRun)
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,18 +21,18 @@ type CleanTask struct {
|
|||||||
fileNamingAlgorithm models.HashAlgorithm
|
fileNamingAlgorithm models.HashAlgorithm
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *CleanTask) Start(wg *sync.WaitGroup) {
|
func (t *CleanTask) Start(wg *sync.WaitGroup, dryRun bool) {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
|
|
||||||
if t.Scene != nil && t.shouldCleanScene(t.Scene) {
|
if t.Scene != nil && t.shouldCleanScene(t.Scene) && !dryRun {
|
||||||
t.deleteScene(t.Scene.ID)
|
t.deleteScene(t.Scene.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
if t.Gallery != nil && t.shouldCleanGallery(t.Gallery) {
|
if t.Gallery != nil && t.shouldCleanGallery(t.Gallery) && !dryRun {
|
||||||
t.deleteGallery(t.Gallery.ID)
|
t.deleteGallery(t.Gallery.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
if t.Image != nil && t.shouldCleanImage(t.Image) {
|
if t.Image != nil && t.shouldCleanImage(t.Image) && !dryRun {
|
||||||
t.deleteImage(t.Image.ID)
|
t.deleteImage(t.Image.ID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
* Allow configuration of visible navbar items.
|
* Allow configuration of visible navbar items.
|
||||||
|
|
||||||
### 🎨 Improvements
|
### 🎨 Improvements
|
||||||
|
* Add dry-run option for Clean task.
|
||||||
* Refresh UI when changing custom CSS options.
|
* Refresh UI when changing custom CSS options.
|
||||||
* Add batch deleting of performers, tags, studios, and movies.
|
* Add batch deleting of performers, tags, studios, and movies.
|
||||||
* Reset cache after scan/clean to ensure scenes are updated.
|
* Reset cache after scan/clean to ensure scenes are updated.
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ export const SettingsTasksPanel: React.FC = () => {
|
|||||||
const [scanGenerateSprites, setScanGenerateSprites] = useState<boolean>(
|
const [scanGenerateSprites, setScanGenerateSprites] = useState<boolean>(
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
|
const [cleanDryRun, setCleanDryRun] = useState<boolean>(false);
|
||||||
const [
|
const [
|
||||||
scanGenerateImagePreviews,
|
scanGenerateImagePreviews,
|
||||||
setScanGenerateImagePreviews,
|
setScanGenerateImagePreviews,
|
||||||
@@ -132,12 +133,31 @@ export const SettingsTasksPanel: React.FC = () => {
|
|||||||
|
|
||||||
function onClean() {
|
function onClean() {
|
||||||
setIsCleanAlertOpen(false);
|
setIsCleanAlertOpen(false);
|
||||||
mutateMetadataClean().then(() => {
|
mutateMetadataClean({
|
||||||
|
dryRun: cleanDryRun,
|
||||||
|
}).then(() => {
|
||||||
jobStatus.refetch();
|
jobStatus.refetch();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderCleanAlert() {
|
function renderCleanAlert() {
|
||||||
|
let msg;
|
||||||
|
if (cleanDryRun) {
|
||||||
|
msg = (
|
||||||
|
<p>
|
||||||
|
Dry Mode selected. No actual deleting will take place, only logging.
|
||||||
|
</p>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
msg = (
|
||||||
|
<p>
|
||||||
|
Are you sure you want to Clean? This will delete database information
|
||||||
|
and generated content for all scenes and galleries that are no longer
|
||||||
|
found in the filesystem.
|
||||||
|
</p>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
show={isCleanAlertOpen}
|
show={isCleanAlertOpen}
|
||||||
@@ -145,11 +165,7 @@ export const SettingsTasksPanel: React.FC = () => {
|
|||||||
accept={{ text: "Clean", variant: "danger", onClick: onClean }}
|
accept={{ text: "Clean", variant: "danger", onClick: onClean }}
|
||||||
cancel={{ onClick: () => setIsCleanAlertOpen(false) }}
|
cancel={{ onClick: () => setIsCleanAlertOpen(false) }}
|
||||||
>
|
>
|
||||||
<p>
|
{msg}
|
||||||
Are you sure you want to Clean? This will delete database information
|
|
||||||
and generated content for all scenes and galleries that are no longer
|
|
||||||
found in the filesystem.
|
|
||||||
</p>
|
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -442,6 +458,17 @@ export const SettingsTasksPanel: React.FC = () => {
|
|||||||
|
|
||||||
<h5>Generated Content</h5>
|
<h5>Generated Content</h5>
|
||||||
<GenerateButton />
|
<GenerateButton />
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
<h5>Maintenance</h5>
|
||||||
|
<Form.Group>
|
||||||
|
<Form.Check
|
||||||
|
id="clean-dryrun"
|
||||||
|
checked={cleanDryRun}
|
||||||
|
label="Only perform a dry run. Don't remove anything"
|
||||||
|
onChange={() => setCleanDryRun(!cleanDryRun)}
|
||||||
|
/>
|
||||||
|
</Form.Group>
|
||||||
<Form.Group>
|
<Form.Group>
|
||||||
<Button
|
<Button
|
||||||
id="clean"
|
id="clean"
|
||||||
|
|||||||
@@ -826,9 +826,10 @@ export const mutateMetadataGenerate = (input: GQL.GenerateMetadataInput) =>
|
|||||||
variables: { input },
|
variables: { input },
|
||||||
});
|
});
|
||||||
|
|
||||||
export const mutateMetadataClean = () =>
|
export const mutateMetadataClean = (input: GQL.CleanMetadataInput) =>
|
||||||
client.mutate<GQL.MetadataCleanMutation>({
|
client.mutate<GQL.MetadataCleanMutation>({
|
||||||
mutation: GQL.MetadataCleanDocument,
|
mutation: GQL.MetadataCleanDocument,
|
||||||
|
variables: { input },
|
||||||
});
|
});
|
||||||
|
|
||||||
export const mutateMigrateHashNaming = () =>
|
export const mutateMigrateHashNaming = () =>
|
||||||
|
|||||||
Reference in New Issue
Block a user