mirror of
https://github.com/stashapp/stash.git
synced 2025-12-17 12:24:38 +03:00
Gallery filter fix (#1147)
* Fix gallery performer and tags filters * Add unit tests
This commit is contained in:
@@ -233,7 +233,7 @@ func (qb *galleryQueryBuilder) Query(galleryFilter *models.GalleryFilterType, fi
|
|||||||
}
|
}
|
||||||
|
|
||||||
query.body += " LEFT JOIN tags on tags_join.tag_id = tags.id"
|
query.body += " LEFT JOIN tags on tags_join.tag_id = tags.id"
|
||||||
whereClause, havingClause := getMultiCriterionClause("galleries", "tags", "tags_join", "gallery_id", "tag_id", tagsFilter)
|
whereClause, havingClause := getMultiCriterionClause("galleries", "tags", "galleries_tags", "gallery_id", "tag_id", tagsFilter)
|
||||||
query.addWhere(whereClause)
|
query.addWhere(whereClause)
|
||||||
query.addHaving(havingClause)
|
query.addHaving(havingClause)
|
||||||
}
|
}
|
||||||
@@ -244,7 +244,7 @@ func (qb *galleryQueryBuilder) Query(galleryFilter *models.GalleryFilterType, fi
|
|||||||
}
|
}
|
||||||
|
|
||||||
query.body += " LEFT JOIN performers ON performers_join.performer_id = performers.id"
|
query.body += " LEFT JOIN performers ON performers_join.performer_id = performers.id"
|
||||||
whereClause, havingClause := getMultiCriterionClause("galleries", "performers", "performers_join", "gallery_id", "performer_id", performersFilter)
|
whereClause, havingClause := getMultiCriterionClause("galleries", "performers", "performers_galleries", "gallery_id", "performer_id", performersFilter)
|
||||||
query.addWhere(whereClause)
|
query.addWhere(whereClause)
|
||||||
query.addHaving(havingClause)
|
query.addHaving(havingClause)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
package sqlite_test
|
package sqlite_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"strconv"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
@@ -272,6 +273,252 @@ func TestGalleryQueryIsMissingScene(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func queryGallery(t *testing.T, sqb models.GalleryReader, galleryFilter *models.GalleryFilterType, findFilter *models.FindFilterType) []*models.Gallery {
|
||||||
|
galleries, _, err := sqb.Query(galleryFilter, findFilter)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Error querying gallery: %s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
return galleries
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGalleryQueryIsMissingStudio(t *testing.T) {
|
||||||
|
withTxn(func(r models.Repository) error {
|
||||||
|
sqb := r.Gallery()
|
||||||
|
isMissing := "studio"
|
||||||
|
galleryFilter := models.GalleryFilterType{
|
||||||
|
IsMissing: &isMissing,
|
||||||
|
}
|
||||||
|
|
||||||
|
q := getGalleryStringValue(galleryIdxWithStudio, titleField)
|
||||||
|
findFilter := models.FindFilterType{
|
||||||
|
Q: &q,
|
||||||
|
}
|
||||||
|
|
||||||
|
galleries := queryGallery(t, sqb, &galleryFilter, &findFilter)
|
||||||
|
|
||||||
|
assert.Len(t, galleries, 0)
|
||||||
|
|
||||||
|
findFilter.Q = nil
|
||||||
|
galleries = queryGallery(t, sqb, &galleryFilter, &findFilter)
|
||||||
|
|
||||||
|
// ensure non of the ids equal the one with studio
|
||||||
|
for _, gallery := range galleries {
|
||||||
|
assert.NotEqual(t, galleryIDs[galleryIdxWithStudio], gallery.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGalleryQueryIsMissingPerformers(t *testing.T) {
|
||||||
|
withTxn(func(r models.Repository) error {
|
||||||
|
sqb := r.Gallery()
|
||||||
|
isMissing := "performers"
|
||||||
|
galleryFilter := models.GalleryFilterType{
|
||||||
|
IsMissing: &isMissing,
|
||||||
|
}
|
||||||
|
|
||||||
|
q := getGalleryStringValue(galleryIdxWithPerformer, titleField)
|
||||||
|
findFilter := models.FindFilterType{
|
||||||
|
Q: &q,
|
||||||
|
}
|
||||||
|
|
||||||
|
galleries := queryGallery(t, sqb, &galleryFilter, &findFilter)
|
||||||
|
|
||||||
|
assert.Len(t, galleries, 0)
|
||||||
|
|
||||||
|
findFilter.Q = nil
|
||||||
|
galleries = queryGallery(t, sqb, &galleryFilter, &findFilter)
|
||||||
|
|
||||||
|
assert.True(t, len(galleries) > 0)
|
||||||
|
|
||||||
|
// ensure non of the ids equal the one with movies
|
||||||
|
for _, gallery := range galleries {
|
||||||
|
assert.NotEqual(t, galleryIDs[galleryIdxWithPerformer], gallery.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGalleryQueryIsMissingTags(t *testing.T) {
|
||||||
|
withTxn(func(r models.Repository) error {
|
||||||
|
sqb := r.Gallery()
|
||||||
|
isMissing := "tags"
|
||||||
|
galleryFilter := models.GalleryFilterType{
|
||||||
|
IsMissing: &isMissing,
|
||||||
|
}
|
||||||
|
|
||||||
|
q := getGalleryStringValue(galleryIdxWithTwoTags, titleField)
|
||||||
|
findFilter := models.FindFilterType{
|
||||||
|
Q: &q,
|
||||||
|
}
|
||||||
|
|
||||||
|
galleries := queryGallery(t, sqb, &galleryFilter, &findFilter)
|
||||||
|
|
||||||
|
assert.Len(t, galleries, 0)
|
||||||
|
|
||||||
|
findFilter.Q = nil
|
||||||
|
galleries = queryGallery(t, sqb, &galleryFilter, &findFilter)
|
||||||
|
|
||||||
|
assert.True(t, len(galleries) > 0)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGalleryQueryPerformers(t *testing.T) {
|
||||||
|
withTxn(func(r models.Repository) error {
|
||||||
|
sqb := r.Gallery()
|
||||||
|
performerCriterion := models.MultiCriterionInput{
|
||||||
|
Value: []string{
|
||||||
|
strconv.Itoa(performerIDs[performerIdxWithGallery]),
|
||||||
|
strconv.Itoa(performerIDs[performerIdx1WithGallery]),
|
||||||
|
},
|
||||||
|
Modifier: models.CriterionModifierIncludes,
|
||||||
|
}
|
||||||
|
|
||||||
|
galleryFilter := models.GalleryFilterType{
|
||||||
|
Performers: &performerCriterion,
|
||||||
|
}
|
||||||
|
|
||||||
|
galleries := queryGallery(t, sqb, &galleryFilter, nil)
|
||||||
|
|
||||||
|
assert.Len(t, galleries, 2)
|
||||||
|
|
||||||
|
// ensure ids are correct
|
||||||
|
for _, gallery := range galleries {
|
||||||
|
assert.True(t, gallery.ID == galleryIDs[galleryIdxWithPerformer] || gallery.ID == galleryIDs[galleryIdxWithTwoPerformers])
|
||||||
|
}
|
||||||
|
|
||||||
|
performerCriterion = models.MultiCriterionInput{
|
||||||
|
Value: []string{
|
||||||
|
strconv.Itoa(performerIDs[performerIdx1WithGallery]),
|
||||||
|
strconv.Itoa(performerIDs[performerIdx2WithGallery]),
|
||||||
|
},
|
||||||
|
Modifier: models.CriterionModifierIncludesAll,
|
||||||
|
}
|
||||||
|
|
||||||
|
galleries = queryGallery(t, sqb, &galleryFilter, nil)
|
||||||
|
|
||||||
|
assert.Len(t, galleries, 1)
|
||||||
|
assert.Equal(t, galleryIDs[galleryIdxWithTwoPerformers], galleries[0].ID)
|
||||||
|
|
||||||
|
performerCriterion = models.MultiCriterionInput{
|
||||||
|
Value: []string{
|
||||||
|
strconv.Itoa(performerIDs[performerIdx1WithGallery]),
|
||||||
|
},
|
||||||
|
Modifier: models.CriterionModifierExcludes,
|
||||||
|
}
|
||||||
|
|
||||||
|
q := getGalleryStringValue(galleryIdxWithTwoPerformers, titleField)
|
||||||
|
findFilter := models.FindFilterType{
|
||||||
|
Q: &q,
|
||||||
|
}
|
||||||
|
|
||||||
|
galleries = queryGallery(t, sqb, &galleryFilter, &findFilter)
|
||||||
|
assert.Len(t, galleries, 0)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGalleryQueryTags(t *testing.T) {
|
||||||
|
withTxn(func(r models.Repository) error {
|
||||||
|
sqb := r.Gallery()
|
||||||
|
tagCriterion := models.MultiCriterionInput{
|
||||||
|
Value: []string{
|
||||||
|
strconv.Itoa(tagIDs[tagIdxWithGallery]),
|
||||||
|
strconv.Itoa(tagIDs[tagIdx1WithGallery]),
|
||||||
|
},
|
||||||
|
Modifier: models.CriterionModifierIncludes,
|
||||||
|
}
|
||||||
|
|
||||||
|
galleryFilter := models.GalleryFilterType{
|
||||||
|
Tags: &tagCriterion,
|
||||||
|
}
|
||||||
|
|
||||||
|
galleries := queryGallery(t, sqb, &galleryFilter, nil)
|
||||||
|
assert.Len(t, galleries, 2)
|
||||||
|
|
||||||
|
// ensure ids are correct
|
||||||
|
for _, gallery := range galleries {
|
||||||
|
assert.True(t, gallery.ID == galleryIDs[galleryIdxWithTag] || gallery.ID == galleryIDs[galleryIdxWithTwoTags])
|
||||||
|
}
|
||||||
|
|
||||||
|
tagCriterion = models.MultiCriterionInput{
|
||||||
|
Value: []string{
|
||||||
|
strconv.Itoa(tagIDs[tagIdx1WithGallery]),
|
||||||
|
strconv.Itoa(tagIDs[tagIdx2WithGallery]),
|
||||||
|
},
|
||||||
|
Modifier: models.CriterionModifierIncludesAll,
|
||||||
|
}
|
||||||
|
|
||||||
|
galleries = queryGallery(t, sqb, &galleryFilter, nil)
|
||||||
|
|
||||||
|
assert.Len(t, galleries, 1)
|
||||||
|
assert.Equal(t, galleryIDs[galleryIdxWithTwoTags], galleries[0].ID)
|
||||||
|
|
||||||
|
tagCriterion = models.MultiCriterionInput{
|
||||||
|
Value: []string{
|
||||||
|
strconv.Itoa(tagIDs[tagIdx1WithGallery]),
|
||||||
|
},
|
||||||
|
Modifier: models.CriterionModifierExcludes,
|
||||||
|
}
|
||||||
|
|
||||||
|
q := getGalleryStringValue(galleryIdxWithTwoTags, titleField)
|
||||||
|
findFilter := models.FindFilterType{
|
||||||
|
Q: &q,
|
||||||
|
}
|
||||||
|
|
||||||
|
galleries = queryGallery(t, sqb, &galleryFilter, &findFilter)
|
||||||
|
assert.Len(t, galleries, 0)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGalleryQueryStudio(t *testing.T) {
|
||||||
|
withTxn(func(r models.Repository) error {
|
||||||
|
sqb := r.Gallery()
|
||||||
|
studioCriterion := models.MultiCriterionInput{
|
||||||
|
Value: []string{
|
||||||
|
strconv.Itoa(studioIDs[studioIdxWithGallery]),
|
||||||
|
},
|
||||||
|
Modifier: models.CriterionModifierIncludes,
|
||||||
|
}
|
||||||
|
|
||||||
|
galleryFilter := models.GalleryFilterType{
|
||||||
|
Studios: &studioCriterion,
|
||||||
|
}
|
||||||
|
|
||||||
|
galleries := queryGallery(t, sqb, &galleryFilter, nil)
|
||||||
|
|
||||||
|
assert.Len(t, galleries, 1)
|
||||||
|
|
||||||
|
// ensure id is correct
|
||||||
|
assert.Equal(t, galleryIDs[galleryIdxWithStudio], galleries[0].ID)
|
||||||
|
|
||||||
|
studioCriterion = models.MultiCriterionInput{
|
||||||
|
Value: []string{
|
||||||
|
strconv.Itoa(studioIDs[studioIdxWithGallery]),
|
||||||
|
},
|
||||||
|
Modifier: models.CriterionModifierExcludes,
|
||||||
|
}
|
||||||
|
|
||||||
|
q := getGalleryStringValue(galleryIdxWithStudio, titleField)
|
||||||
|
findFilter := models.FindFilterType{
|
||||||
|
Q: &q,
|
||||||
|
}
|
||||||
|
|
||||||
|
galleries = queryGallery(t, sqb, &galleryFilter, &findFilter)
|
||||||
|
assert.Len(t, galleries, 0)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// TODO Count
|
// TODO Count
|
||||||
// TODO All
|
// TODO All
|
||||||
// TODO Query
|
// TODO Query
|
||||||
|
|||||||
@@ -44,6 +44,14 @@ func TestPerformerFindBySceneID(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestPerformerFindByNames(t *testing.T) {
|
func TestPerformerFindByNames(t *testing.T) {
|
||||||
|
getNames := func(p []*models.Performer) []string {
|
||||||
|
var ret []string
|
||||||
|
for _, pp := range p {
|
||||||
|
ret = append(ret, pp.Name.String)
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
withTxn(func(r models.Repository) error {
|
withTxn(func(r models.Repository) error {
|
||||||
var names []string
|
var names []string
|
||||||
|
|
||||||
@@ -72,19 +80,20 @@ func TestPerformerFindByNames(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Error finding performers: %s", err.Error())
|
t.Errorf("Error finding performers: %s", err.Error())
|
||||||
}
|
}
|
||||||
assert.Len(t, performers, 2) // performerIdxWithScene and performerIdx1WithScene
|
retNames := getNames(performers)
|
||||||
assert.Equal(t, performerNames[performerIdxWithScene], performers[0].Name.String)
|
assert.Equal(t, names, retNames)
|
||||||
assert.Equal(t, performerNames[performerIdx1WithScene], performers[1].Name.String)
|
|
||||||
|
|
||||||
performers, err = pqb.FindByNames(names, true) // find performers by names ( 2 names nocase)
|
performers, err = pqb.FindByNames(names, true) // find performers by names ( 2 names nocase)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Error finding performers: %s", err.Error())
|
t.Errorf("Error finding performers: %s", err.Error())
|
||||||
}
|
}
|
||||||
assert.Len(t, performers, 4) // performerIdxWithScene and performerIdxWithDupName , performerIdx1WithScene and performerIdx1WithDupName
|
retNames = getNames(performers)
|
||||||
assert.Equal(t, performerNames[performerIdxWithScene], performers[0].Name.String)
|
assert.Equal(t, []string{
|
||||||
assert.Equal(t, performerNames[performerIdx1WithScene], performers[1].Name.String)
|
performerNames[performerIdxWithScene],
|
||||||
assert.Equal(t, performerNames[performerIdx1WithDupName], performers[2].Name.String)
|
performerNames[performerIdx1WithScene],
|
||||||
assert.Equal(t, performerNames[performerIdxWithDupName], performers[3].Name.String)
|
performerNames[performerIdx1WithDupName],
|
||||||
|
performerNames[performerIdxWithDupName],
|
||||||
|
}, retNames)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -22,14 +22,14 @@ import (
|
|||||||
|
|
||||||
const totalScenes = 12
|
const totalScenes = 12
|
||||||
const totalImages = 6 // TODO - add one for zip file
|
const totalImages = 6 // TODO - add one for zip file
|
||||||
const performersNameCase = 6
|
const performersNameCase = 9
|
||||||
const performersNameNoCase = 2
|
const performersNameNoCase = 2
|
||||||
const moviesNameCase = 2
|
const moviesNameCase = 2
|
||||||
const moviesNameNoCase = 1
|
const moviesNameNoCase = 1
|
||||||
const totalGalleries = 3
|
const totalGalleries = 8
|
||||||
const tagsNameNoCase = 2
|
const tagsNameNoCase = 2
|
||||||
const tagsNameCase = 9
|
const tagsNameCase = 12
|
||||||
const studiosNameCase = 5
|
const studiosNameCase = 6
|
||||||
const studiosNameNoCase = 1
|
const studiosNameNoCase = 1
|
||||||
|
|
||||||
var sceneIDs []int
|
var sceneIDs []int
|
||||||
@@ -69,10 +69,13 @@ const performerIdx2WithScene = 2
|
|||||||
const performerIdxWithImage = 3
|
const performerIdxWithImage = 3
|
||||||
const performerIdx1WithImage = 4
|
const performerIdx1WithImage = 4
|
||||||
const performerIdx2WithImage = 5
|
const performerIdx2WithImage = 5
|
||||||
|
const performerIdxWithGallery = 6
|
||||||
|
const performerIdx1WithGallery = 7
|
||||||
|
const performerIdx2WithGallery = 8
|
||||||
|
|
||||||
// performers with dup names start from the end
|
// performers with dup names start from the end
|
||||||
const performerIdx1WithDupName = 6
|
const performerIdx1WithDupName = 9
|
||||||
const performerIdxWithDupName = 7
|
const performerIdxWithDupName = 10
|
||||||
|
|
||||||
const movieIdxWithScene = 0
|
const movieIdxWithScene = 0
|
||||||
const movieIdxWithStudio = 1
|
const movieIdxWithStudio = 1
|
||||||
@@ -82,6 +85,11 @@ const movieIdxWithDupName = 2
|
|||||||
|
|
||||||
const galleryIdxWithScene = 0
|
const galleryIdxWithScene = 0
|
||||||
const galleryIdxWithImage = 1
|
const galleryIdxWithImage = 1
|
||||||
|
const galleryIdxWithPerformer = 2
|
||||||
|
const galleryIdxWithTwoPerformers = 3
|
||||||
|
const galleryIdxWithTag = 4
|
||||||
|
const galleryIdxWithTwoTags = 5
|
||||||
|
const galleryIdxWithStudio = 6
|
||||||
|
|
||||||
const tagIdxWithScene = 0
|
const tagIdxWithScene = 0
|
||||||
const tagIdx1WithScene = 1
|
const tagIdx1WithScene = 1
|
||||||
@@ -92,19 +100,23 @@ const tagIdxWithCoverImage = 5
|
|||||||
const tagIdxWithImage = 6
|
const tagIdxWithImage = 6
|
||||||
const tagIdx1WithImage = 7
|
const tagIdx1WithImage = 7
|
||||||
const tagIdx2WithImage = 8
|
const tagIdx2WithImage = 8
|
||||||
|
const tagIdxWithGallery = 9
|
||||||
|
const tagIdx1WithGallery = 10
|
||||||
|
const tagIdx2WithGallery = 11
|
||||||
|
|
||||||
// tags with dup names start from the end
|
// tags with dup names start from the end
|
||||||
const tagIdx1WithDupName = 9
|
const tagIdx1WithDupName = 12
|
||||||
const tagIdxWithDupName = 10
|
const tagIdxWithDupName = 13
|
||||||
|
|
||||||
const studioIdxWithScene = 0
|
const studioIdxWithScene = 0
|
||||||
const studioIdxWithMovie = 1
|
const studioIdxWithMovie = 1
|
||||||
const studioIdxWithChildStudio = 2
|
const studioIdxWithChildStudio = 2
|
||||||
const studioIdxWithParentStudio = 3
|
const studioIdxWithParentStudio = 3
|
||||||
const studioIdxWithImage = 4
|
const studioIdxWithImage = 4
|
||||||
|
const studioIdxWithGallery = 5
|
||||||
|
|
||||||
// studios with dup names start from the end
|
// studios with dup names start from the end
|
||||||
const studioIdxWithDupName = 5
|
const studioIdxWithDupName = 6
|
||||||
|
|
||||||
const markerIdxWithScene = 0
|
const markerIdxWithScene = 0
|
||||||
|
|
||||||
@@ -237,6 +249,18 @@ func populateDB() error {
|
|||||||
return fmt.Errorf("error linking studio parent: %s", err.Error())
|
return fmt.Errorf("error linking studio parent: %s", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := linkGalleryPerformers(r.Gallery()); err != nil {
|
||||||
|
return fmt.Errorf("error linking gallery performers: %s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := linkGalleryTags(r.Gallery()); err != nil {
|
||||||
|
return fmt.Errorf("error linking gallery tags: %s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := linkGalleryStudio(r.Gallery(), galleryIdxWithStudio, studioIdxWithGallery); err != nil {
|
||||||
|
return fmt.Errorf("error linking gallery studio: %s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
if err := createMarker(r.SceneMarker(), sceneIdxWithMarker, tagIdxWithPrimaryMarker, []int{tagIdxWithMarker}); err != nil {
|
if err := createMarker(r.SceneMarker(), sceneIdxWithMarker, tagIdxWithPrimaryMarker, []int{tagIdxWithMarker}); err != nil {
|
||||||
return fmt.Errorf("error creating scene marker: %s", err.Error())
|
return fmt.Errorf("error creating scene marker: %s", err.Error())
|
||||||
}
|
}
|
||||||
@@ -756,3 +780,65 @@ func linkStudioParent(qb models.StudioWriter, parentIndex, childIndex int) error
|
|||||||
func addTagImage(qb models.TagWriter, tagIndex int) error {
|
func addTagImage(qb models.TagWriter, tagIndex int) error {
|
||||||
return qb.UpdateImage(tagIDs[tagIndex], models.DefaultTagImage)
|
return qb.UpdateImage(tagIDs[tagIndex], models.DefaultTagImage)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func linkGalleryTags(iqb models.GalleryReaderWriter) error {
|
||||||
|
if err := linkGalleryTag(iqb, galleryIdxWithTag, tagIdxWithGallery); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := linkGalleryTag(iqb, galleryIdxWithTwoTags, tagIdx1WithGallery); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := linkGalleryTag(iqb, galleryIdxWithTwoTags, tagIdx2WithGallery); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func linkGalleryTag(iqb models.GalleryReaderWriter, galleryIndex, tagIndex int) error {
|
||||||
|
galleryID := galleryIDs[galleryIndex]
|
||||||
|
tags, err := iqb.GetTagIDs(galleryID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
tags = append(tags, tagIDs[tagIndex])
|
||||||
|
|
||||||
|
return iqb.UpdateTags(galleryID, tags)
|
||||||
|
}
|
||||||
|
|
||||||
|
func linkGalleryStudio(qb models.GalleryWriter, galleryIndex, studioIndex int) error {
|
||||||
|
gallery := models.GalleryPartial{
|
||||||
|
ID: galleryIDs[galleryIndex],
|
||||||
|
StudioID: &sql.NullInt64{Int64: int64(studioIDs[studioIndex]), Valid: true},
|
||||||
|
}
|
||||||
|
_, err := qb.UpdatePartial(gallery)
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func linkGalleryPerformers(qb models.GalleryReaderWriter) error {
|
||||||
|
if err := linkGalleryPerformer(qb, galleryIdxWithPerformer, performerIdxWithGallery); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := linkGalleryPerformer(qb, galleryIdxWithTwoPerformers, performerIdx1WithGallery); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := linkGalleryPerformer(qb, galleryIdxWithTwoPerformers, performerIdx2WithGallery); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func linkGalleryPerformer(iqb models.GalleryReaderWriter, galleryIndex, performerIndex int) error {
|
||||||
|
galleryID := galleryIDs[galleryIndex]
|
||||||
|
performers, err := iqb.GetPerformerIDs(galleryID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
performers = append(performers, performerIDs[performerIndex])
|
||||||
|
|
||||||
|
return iqb.UpdatePerformers(galleryID, performers)
|
||||||
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
* Added Rescan button to scene, image, gallery details overflow button.
|
* Added Rescan button to scene, image, gallery details overflow button.
|
||||||
|
|
||||||
### 🐛 Bug fixes
|
### 🐛 Bug fixes
|
||||||
|
* Fix SQL error when filtering galleries excluding performers or tags.
|
||||||
* Fix version checking for armv7 and arm64.
|
* Fix version checking for armv7 and arm64.
|
||||||
* Change "Is NULL" filter to include empty string values.
|
* Change "Is NULL" filter to include empty string values.
|
||||||
* Prevent scene card previews playing in full-screen on iOS devices.
|
* Prevent scene card previews playing in full-screen on iOS devices.
|
||||||
|
|||||||
Reference in New Issue
Block a user