Skip to content

Commit

Permalink
Add Movie option to Scene bulk edit (#1676)
Browse files Browse the repository at this point in the history
* Add Movie option to Scene bulk edit
  • Loading branch information
gitgiggety committed Sep 7, 2021
1 parent 7a46841 commit b2b05fb
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 3 deletions.
1 change: 1 addition & 0 deletions graphql/schema/types/scene.graphql
Expand Up @@ -103,6 +103,7 @@ input BulkSceneUpdateInput {
gallery_ids: BulkUpdateIds
performer_ids: BulkUpdateIds
tag_ids: BulkUpdateIds
movie_ids: BulkUpdateIds
}

input SceneDestroyInput {
Expand Down
54 changes: 54 additions & 0 deletions pkg/api/resolver_mutation_scene.go
Expand Up @@ -304,6 +304,18 @@ func (r *mutationResolver) BulkSceneUpdate(ctx context.Context, input models.Bul
return err
}
}

// Save the movies
if translator.hasField("movie_ids") {
movies, err := adjustSceneMovieIDs(qb, sceneID, *input.MovieIds)
if err != nil {
return err
}

if err := qb.UpdateMovies(sceneID, movies); err != nil {
return err
}
}
}

return nil
Expand Down Expand Up @@ -395,6 +407,48 @@ func adjustSceneGalleryIDs(qb models.SceneReader, sceneID int, ids models.BulkUp
return adjustIDs(ret, ids), nil
}

func adjustSceneMovieIDs(qb models.SceneReader, sceneID int, updateIDs models.BulkUpdateIds) ([]models.MoviesScenes, error) {
existingMovies, err := qb.GetMovies(sceneID)
if err != nil {
return nil, err
}

// if we are setting the ids, just return the ids
if updateIDs.Mode == models.BulkUpdateIDModeSet {
existingMovies = []models.MoviesScenes{}
for _, idStr := range updateIDs.Ids {
id, _ := strconv.Atoi(idStr)
existingMovies = append(existingMovies, models.MoviesScenes{MovieID: id})
}

return existingMovies, nil
}

for _, idStr := range updateIDs.Ids {
id, _ := strconv.Atoi(idStr)

// look for the id in the list
foundExisting := false
for idx, existingMovie := range existingMovies {
if existingMovie.MovieID == id {
if updateIDs.Mode == models.BulkUpdateIDModeRemove {
// remove from the list
existingMovies = append(existingMovies[:idx], existingMovies[idx+1:]...)
}

foundExisting = true
break
}
}

if !foundExisting && updateIDs.Mode != models.BulkUpdateIDModeRemove {
existingMovies = append(existingMovies, models.MoviesScenes{MovieID: id})
}
}

return existingMovies, err
}

func (r *mutationResolver) SceneDestroy(ctx context.Context, input models.SceneDestroyInput) (bool, error) {
sceneID, err := strconv.Atoi(input.ID)
if err != nil {
Expand Down
1 change: 1 addition & 0 deletions ui/v2.5/src/components/Changelog/versions/v0100.md
@@ -1,3 +1,4 @@
### ✨ New Features
* Added Movies to Scene bulk edit dialog. ([#1676](https://github.com/stashapp/stash/pull/1676))
* Added Movies tab to Studio and Performer pages. ([#1675](https://github.com/stashapp/stash/pull/1675))
* Support filtering Movies by Performers. ([#1675](https://github.com/stashapp/stash/pull/1675))
71 changes: 69 additions & 2 deletions ui/v2.5/src/components/Scenes/EditScenesDialog.tsx
Expand Up @@ -33,6 +33,11 @@ export const EditScenesDialog: React.FC<IListOperationProps> = (
);
const [tagIds, setTagIds] = useState<string[]>();
const [existingTagIds, setExistingTagIds] = useState<string[]>();
const [movieMode, setMovieMode] = React.useState<GQL.BulkUpdateIdMode>(
GQL.BulkUpdateIdMode.Add
);
const [movieIds, setMovieIds] = useState<string[]>();
const [existingMovieIds, setExistingMovieIds] = useState<string[]>();
const [organized, setOrganized] = useState<boolean | undefined>();

const [updateScenes] = useBulkSceneUpdate(getSceneInput());
Expand All @@ -58,6 +63,7 @@ export const EditScenesDialog: React.FC<IListOperationProps> = (
const aggregateStudioId = getStudioId(props.selected);
const aggregatePerformerIds = getPerformerIds(props.selected);
const aggregateTagIds = getTagIds(props.selected);
const aggregateMovieIds = getMovieIds(props.selected);

const sceneInput: GQL.BulkSceneUpdateInput = {
ids: props.selected.map((scene) => {
Expand Down Expand Up @@ -127,6 +133,21 @@ export const EditScenesDialog: React.FC<IListOperationProps> = (
sceneInput.tag_ids = makeBulkUpdateIds(tagIds || [], tagMode);
}

// if movieIds non-empty, then we are setting them
if (
movieMode === GQL.BulkUpdateIdMode.Set &&
(!movieIds || movieIds.length === 0)
) {
// and all scenes have the same ids,
if (aggregateMovieIds.length > 0) {
// then unset the movieIds, otherwise ignore
sceneInput.movie_ids = makeBulkUpdateIds(movieIds || [], movieMode);
}
} else {
// if movieIds non-empty, then we are setting them
sceneInput.movie_ids = makeBulkUpdateIds(movieIds || [], movieMode);
}

if (organized !== undefined) {
sceneInput.organized = organized;
}
Expand Down Expand Up @@ -228,12 +249,35 @@ export const EditScenesDialog: React.FC<IListOperationProps> = (
return ret;
}

function getMovieIds(state: GQL.SlimSceneDataFragment[]) {
let ret: string[] = [];
let first = true;

state.forEach((scene: GQL.SlimSceneDataFragment) => {
if (first) {
ret = scene.movies ? scene.movies.map((m) => m.movie.id).sort() : [];
first = false;
} else {
const mIds = scene.movies
? scene.movies.map((m) => m.movie.id).sort()
: [];

if (!_.isEqual(ret, mIds)) {
ret = [];
}
}
});

return ret;
}

useEffect(() => {
const state = props.selected;
let updateRating: number | undefined;
let updateStudioID: string | undefined;
let updatePerformerIds: string[] = [];
let updateTagIds: string[] = [];
let updateMovieIds: string[] = [];
let updateOrganized: boolean | undefined;
let first = true;

Expand All @@ -244,12 +288,14 @@ export const EditScenesDialog: React.FC<IListOperationProps> = (
.map((p) => p.id)
.sort();
const sceneTagIDs = (scene.tags ?? []).map((p) => p.id).sort();
const sceneMovieIDs = (scene.movies ?? []).map((m) => m.movie.id).sort();

if (first) {
updateRating = sceneRating ?? undefined;
updateStudioID = sceneStudioID;
updatePerformerIds = scenePerformerIDs;
updateTagIds = sceneTagIDs;
updateMovieIds = sceneMovieIDs;
first = false;
updateOrganized = scene.organized;
} else {
Expand All @@ -265,6 +311,9 @@ export const EditScenesDialog: React.FC<IListOperationProps> = (
if (!_.isEqual(sceneTagIDs, updateTagIds)) {
updateTagIds = [];
}
if (!_.isEqual(sceneMovieIDs, updateMovieIds)) {
updateMovieIds = [];
}
if (scene.organized !== updateOrganized) {
updateOrganized = undefined;
}
Expand All @@ -275,8 +324,9 @@ export const EditScenesDialog: React.FC<IListOperationProps> = (
setStudioId(updateStudioID);
setExistingPerformerIds(updatePerformerIds);
setExistingTagIds(updateTagIds);
setExistingMovieIds(updateMovieIds);
setOrganized(updateOrganized);
}, [props.selected, performerMode, tagMode]);
}, [props.selected, performerMode, tagMode, movieMode]);

useEffect(() => {
if (checkboxRef.current) {
Expand All @@ -285,7 +335,7 @@ export const EditScenesDialog: React.FC<IListOperationProps> = (
}, [organized, checkboxRef]);

function renderMultiSelect(
type: "performers" | "tags",
type: "performers" | "tags" | "movies",
ids: string[] | undefined
) {
let mode = GQL.BulkUpdateIdMode.Add;
Expand All @@ -299,6 +349,10 @@ export const EditScenesDialog: React.FC<IListOperationProps> = (
mode = tagMode;
existingIds = existingTagIds;
break;
case "movies":
mode = movieMode;
existingIds = existingMovieIds;
break;
}

return (
Expand All @@ -313,6 +367,9 @@ export const EditScenesDialog: React.FC<IListOperationProps> = (
case "tags":
setTagIds(itemIDs);
break;
case "movies":
setMovieIds(itemIDs);
break;
}
}}
onSetMode={(newMode) => {
Expand All @@ -323,6 +380,9 @@ export const EditScenesDialog: React.FC<IListOperationProps> = (
case "tags":
setTagMode(newMode);
break;
case "movies":
setMovieMode(newMode);
break;
}
}}
ids={ids ?? []}
Expand Down Expand Up @@ -409,6 +469,13 @@ export const EditScenesDialog: React.FC<IListOperationProps> = (
{renderMultiSelect("tags", tagIds)}
</Form.Group>

<Form.Group controlId="movies">
<Form.Label>
<FormattedMessage id="movies" />
</Form.Label>
{renderMultiSelect("movies", movieIds)}
</Form.Group>

<Form.Group controlId="organized">
<Form.Check
type="checkbox"
Expand Down
2 changes: 1 addition & 1 deletion ui/v2.5/src/components/Shared/MultiSet.tsx
Expand Up @@ -12,7 +12,7 @@ type ValidTypes =
| GQL.SlimMovieDataFragment;

interface IMultiSetProps {
type: "performers" | "studios" | "tags";
type: "performers" | "studios" | "tags" | "movies";
existingIds?: string[];
ids?: string[];
mode: GQL.BulkUpdateIdMode;
Expand Down

0 comments on commit b2b05fb

Please sign in to comment.