mirror of https://github.com/stashapp/stash.git
Add Movie option to Scene bulk edit (#1676)
* Add Movie option to Scene bulk edit
This commit is contained in:
parent
7a468413da
commit
b2b05fb332
|
@ -103,6 +103,7 @@ input BulkSceneUpdateInput {
|
|||
gallery_ids: BulkUpdateIds
|
||||
performer_ids: BulkUpdateIds
|
||||
tag_ids: BulkUpdateIds
|
||||
movie_ids: BulkUpdateIds
|
||||
}
|
||||
|
||||
input SceneDestroyInput {
|
||||
|
|
|
@ -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
|
||||
|
@ -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 {
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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());
|
||||
|
@ -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) => {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -299,6 +349,10 @@ export const EditScenesDialog: React.FC<IListOperationProps> = (
|
|||
mode = tagMode;
|
||||
existingIds = existingTagIds;
|
||||
break;
|
||||
case "movies":
|
||||
mode = movieMode;
|
||||
existingIds = existingMovieIds;
|
||||
break;
|
||||
}
|
||||
|
||||
return (
|
||||
|
@ -313,6 +367,9 @@ export const EditScenesDialog: React.FC<IListOperationProps> = (
|
|||
case "tags":
|
||||
setTagIds(itemIDs);
|
||||
break;
|
||||
case "movies":
|
||||
setMovieIds(itemIDs);
|
||||
break;
|
||||
}
|
||||
}}
|
||||
onSetMode={(newMode) => {
|
||||
|
@ -323,6 +380,9 @@ export const EditScenesDialog: React.FC<IListOperationProps> = (
|
|||
case "tags":
|
||||
setTagMode(newMode);
|
||||
break;
|
||||
case "movies":
|
||||
setMovieMode(newMode);
|
||||
break;
|
||||
}
|
||||
}}
|
||||
ids={ids ?? []}
|
||||
|
@ -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"
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue