Prefer studio name later in filename (#2057)

This commit is contained in:
WithoutPants
2021-11-26 08:29:25 +11:00
committed by GitHub
parent ff32f22c1a
commit 19e69f5310
5 changed files with 118 additions and 35 deletions

View File

@@ -60,14 +60,12 @@ func (t *tagger) tagPerformers(performerReader models.PerformerReader, addFunc a
} }
func (t *tagger) tagStudios(studioReader models.StudioReader, addFunc addLinkFunc) error { func (t *tagger) tagStudios(studioReader models.StudioReader, addFunc addLinkFunc) error {
others, err := match.PathToStudios(t.Path, studioReader) studio, err := match.PathToStudio(t.Path, studioReader)
if err != nil { if err != nil {
return err return err
} }
// only add first studio if studio != nil {
if len(others) > 0 {
studio := others[0]
added, err := addFunc(t.ID, studio.ID) added, err := addFunc(t.ID, studio.ID)
if err != nil { if err != nil {

View File

@@ -58,7 +58,9 @@ func getPathWords(path string) []string {
return ret return ret
} }
func nameMatchesPath(name, path string) bool { // nameMatchesPath returns the index in the path for the right-most match.
// Returns -1 if not found.
func nameMatchesPath(name, path string) int {
// escape specific regex characters // escape specific regex characters
name = regexp.QuoteMeta(name) name = regexp.QuoteMeta(name)
@@ -72,7 +74,13 @@ func nameMatchesPath(name, path string) bool {
reStr = `(?:^|_|[^\w\d])` + reStr + `(?:$|_|[^\w\d])` reStr = `(?:^|_|[^\w\d])` + reStr + `(?:$|_|[^\w\d])`
re := regexp.MustCompile(reStr) re := regexp.MustCompile(reStr)
return re.MatchString(path) found := re.FindAllStringIndex(path, -1)
if found == nil {
return -1
}
return found[len(found)-1][0]
} }
func PathToPerformers(path string, performerReader models.PerformerReader) ([]*models.Performer, error) { func PathToPerformers(path string, performerReader models.PerformerReader) ([]*models.Performer, error) {
@@ -86,7 +94,7 @@ func PathToPerformers(path string, performerReader models.PerformerReader) ([]*m
var ret []*models.Performer var ret []*models.Performer
for _, p := range performers { for _, p := range performers {
// TODO - commenting out alias handling until both sides work correctly // TODO - commenting out alias handling until both sides work correctly
if nameMatchesPath(p.Name.String, path) { // || nameMatchesPath(p.Aliases.String, path) { if nameMatchesPath(p.Name.String, path) != -1 { // || nameMatchesPath(p.Aliases.String, path) {
ret = append(ret, p) ret = append(ret, p)
} }
} }
@@ -94,7 +102,10 @@ func PathToPerformers(path string, performerReader models.PerformerReader) ([]*m
return ret, nil return ret, nil
} }
func PathToStudios(path string, reader models.StudioReader) ([]*models.Studio, error) { // PathToStudio returns the Studio that matches the given path.
// Where multiple matching studios are found, the one that matches the latest
// position in the path is returned.
func PathToStudio(path string, reader models.StudioReader) (*models.Studio, error) {
words := getPathWords(path) words := getPathWords(path)
candidates, err := reader.QueryForAutoTag(words) candidates, err := reader.QueryForAutoTag(words)
@@ -102,29 +113,26 @@ func PathToStudios(path string, reader models.StudioReader) ([]*models.Studio, e
return nil, err return nil, err
} }
var ret []*models.Studio var ret *models.Studio
index := -1
for _, c := range candidates { for _, c := range candidates {
matches := false matchIndex := nameMatchesPath(c.Name.String, path)
if nameMatchesPath(c.Name.String, path) { if matchIndex != -1 && matchIndex > index {
matches = true ret = c
index = matchIndex
} }
if !matches { aliases, err := reader.GetAliases(c.ID)
aliases, err := reader.GetAliases(c.ID) if err != nil {
if err != nil { return nil, err
return nil, err
}
for _, alias := range aliases {
if nameMatchesPath(alias, path) {
matches = true
break
}
}
} }
if matches { for _, alias := range aliases {
ret = append(ret, c) matchIndex = nameMatchesPath(alias, path)
if matchIndex != -1 && matchIndex > index {
ret = c
index = matchIndex
}
} }
} }
@@ -142,7 +150,7 @@ func PathToTags(path string, tagReader models.TagReader) ([]*models.Tag, error)
var ret []*models.Tag var ret []*models.Tag
for _, t := range tags { for _, t := range tags {
matches := false matches := false
if nameMatchesPath(t.Name, path) { if nameMatchesPath(t.Name, path) != -1 {
matches = true matches = true
} }
@@ -152,7 +160,7 @@ func PathToTags(path string, tagReader models.TagReader) ([]*models.Tag, error)
return nil, err return nil, err
} }
for _, alias := range aliases { for _, alias := range aliases {
if nameMatchesPath(alias, path) { if nameMatchesPath(alias, path) != -1 {
matches = true matches = true
break break
} }
@@ -223,7 +231,7 @@ func PathToScenes(name string, paths []string, sceneReader models.SceneReader) (
var ret []*models.Scene var ret []*models.Scene
for _, p := range scenes { for _, p := range scenes {
if nameMatchesPath(name, p.Path) { if nameMatchesPath(name, p.Path) != -1 {
ret = append(ret, p) ret = append(ret, p)
} }
} }
@@ -287,7 +295,7 @@ func PathToImages(name string, paths []string, imageReader models.ImageReader) (
var ret []*models.Image var ret []*models.Image
for _, p := range images { for _, p := range images {
if nameMatchesPath(name, p.Path) { if nameMatchesPath(name, p.Path) != -1 {
ret = append(ret, p) ret = append(ret, p)
} }
} }
@@ -351,7 +359,7 @@ func PathToGalleries(name string, paths []string, galleryReader models.GalleryRe
var ret []*models.Gallery var ret []*models.Gallery
for _, p := range gallerys { for _, p := range gallerys {
if nameMatchesPath(name, p.Path.String) { if nameMatchesPath(name, p.Path.String) != -1 {
ret = append(ret, p) ret = append(ret, p)
} }
} }

76
pkg/match/path_test.go Normal file
View File

@@ -0,0 +1,76 @@
package match
import "testing"
func Test_nameMatchesPath(t *testing.T) {
const name = "first last"
tests := []struct {
name string
path string
want int
}{
{
"exact",
name,
0,
},
{
"partial",
"first",
-1,
},
{
"separator",
"first.last",
0,
},
{
"separator",
"first-last",
0,
},
{
"separator",
"first_last",
0,
},
{
"separators",
"first.-_ last",
0,
},
{
"within string",
"before_first last/after",
6,
},
{
"not within string",
"beforefirst last/after",
-1,
},
{
"not within string",
"before/first lastafter",
-1,
},
{
"not within string",
"first last1",
-1,
},
{
"not within string",
"1first last",
-1,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := nameMatchesPath(name, tt.path); got != tt.want {
t.Errorf("nameMatchesPath() = %v, want %v", got, tt.want)
}
})
}
}

View File

@@ -46,15 +46,15 @@ func autotagMatchPerformers(path string, performerReader models.PerformerReader)
} }
func autotagMatchStudio(path string, studioReader models.StudioReader) (*models.ScrapedStudio, error) { func autotagMatchStudio(path string, studioReader models.StudioReader) (*models.ScrapedStudio, error) {
st, err := match.PathToStudios(path, studioReader) studio, err := match.PathToStudio(path, studioReader)
if err != nil { if err != nil {
return nil, fmt.Errorf("error matching studios: %w", err) return nil, fmt.Errorf("error matching studios: %w", err)
} }
if len(st) > 0 { if studio != nil {
id := strconv.Itoa(st[0].ID) id := strconv.Itoa(studio.ID)
return &models.ScrapedStudio{ return &models.ScrapedStudio{
Name: st[0].Name.String, Name: studio.Name.String,
StoredID: &id, StoredID: &id,
}, nil }, nil
} }

View File

@@ -4,6 +4,7 @@
* Add forward jump 10 second button to video player. ([#1973](https://github.com/stashapp/stash/pull/1973)) * Add forward jump 10 second button to video player. ([#1973](https://github.com/stashapp/stash/pull/1973))
### 🎨 Improvements ### 🎨 Improvements
* Prefer right-most Studio match in the file path when autotagging. ([#2057](https://github.com/stashapp/stash/pull/2057))
* Added plugin hook for Tag merge operation. ([#2010](https://github.com/stashapp/stash/pull/2010)) * Added plugin hook for Tag merge operation. ([#2010](https://github.com/stashapp/stash/pull/2010))
### 🐛 Bug fixes ### 🐛 Bug fixes