Performer urls (#4958)

* Populate URLs from legacy fields
* Return nil properly in xpath/json scrapers
* Improve migration logging
This commit is contained in:
WithoutPants
2024-06-18 13:41:05 +10:00
committed by GitHub
parent fda4776d30
commit f26766033e
47 changed files with 992 additions and 379 deletions

View File

@@ -34,16 +34,14 @@ func (s *StringOrStringList) UnmarshalJSON(data []byte) error {
}
type Performer struct {
Name string `json:"name,omitempty"`
Disambiguation string `json:"disambiguation,omitempty"`
Gender string `json:"gender,omitempty"`
URL string `json:"url,omitempty"`
Twitter string `json:"twitter,omitempty"`
Instagram string `json:"instagram,omitempty"`
Birthdate string `json:"birthdate,omitempty"`
Ethnicity string `json:"ethnicity,omitempty"`
Country string `json:"country,omitempty"`
EyeColor string `json:"eye_color,omitempty"`
Name string `json:"name,omitempty"`
Disambiguation string `json:"disambiguation,omitempty"`
Gender string `json:"gender,omitempty"`
URLs []string `json:"urls,omitempty"`
Birthdate string `json:"birthdate,omitempty"`
Ethnicity string `json:"ethnicity,omitempty"`
Country string `json:"country,omitempty"`
EyeColor string `json:"eye_color,omitempty"`
// this should be int, but keeping string for backwards compatibility
Height string `json:"height,omitempty"`
Measurements string `json:"measurements,omitempty"`
@@ -66,6 +64,11 @@ type Performer struct {
Weight int `json:"weight,omitempty"`
StashIDs []models.StashID `json:"stash_ids,omitempty"`
IgnoreAutoTag bool `json:"ignore_auto_tag,omitempty"`
// deprecated - for import only
URL string `json:"url,omitempty"`
Twitter string `json:"twitter,omitempty"`
Instagram string `json:"instagram,omitempty"`
}
func (s Performer) Filename() string {

View File

@@ -383,6 +383,29 @@ func (_m *PerformerReaderWriter) GetTagIDs(ctx context.Context, relatedID int) (
return r0, r1
}
// GetURLs provides a mock function with given fields: ctx, relatedID
func (_m *PerformerReaderWriter) GetURLs(ctx context.Context, relatedID int) ([]string, error) {
ret := _m.Called(ctx, relatedID)
var r0 []string
if rf, ok := ret.Get(0).(func(context.Context, int) []string); ok {
r0 = rf(ctx, relatedID)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]string)
}
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context, int) error); ok {
r1 = rf(ctx, relatedID)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// HasImage provides a mock function with given fields: ctx, performerID
func (_m *PerformerReaderWriter) HasImage(ctx context.Context, performerID int) (bool, error) {
ret := _m.Called(ctx, performerID)

View File

@@ -10,9 +10,6 @@ type Performer struct {
Name string `json:"name"`
Disambiguation string `json:"disambiguation"`
Gender *GenderEnum `json:"gender"`
URL string `json:"url"`
Twitter string `json:"twitter"`
Instagram string `json:"instagram"`
Birthdate *Date `json:"birthdate"`
Ethnicity string `json:"ethnicity"`
Country string `json:"country"`
@@ -37,6 +34,7 @@ type Performer struct {
IgnoreAutoTag bool `json:"ignore_auto_tag"`
Aliases RelatedStrings `json:"aliases"`
URLs RelatedStrings `json:"urls"`
TagIDs RelatedIDs `json:"tag_ids"`
StashIDs RelatedStashIDs `json:"stash_ids"`
}
@@ -55,9 +53,7 @@ type PerformerPartial struct {
Name OptionalString
Disambiguation OptionalString
Gender OptionalString
URL OptionalString
Twitter OptionalString
Instagram OptionalString
URLs *UpdateStrings
Birthdate OptionalDate
Ethnicity OptionalString
Country OptionalString
@@ -99,6 +95,12 @@ func (s *Performer) LoadAliases(ctx context.Context, l AliasLoader) error {
})
}
func (s *Performer) LoadURLs(ctx context.Context, l URLLoader) error {
return s.URLs.load(func() ([]string, error) {
return l.GetURLs(ctx, s.ID)
})
}
func (s *Performer) LoadTagIDs(ctx context.Context, l TagIDLoader) error {
return s.TagIDs.load(func() ([]int, error) {
return l.GetTagIDs(ctx, s.ID)

View File

@@ -107,9 +107,10 @@ type ScrapedPerformer struct {
Name *string `json:"name"`
Disambiguation *string `json:"disambiguation"`
Gender *string `json:"gender"`
URL *string `json:"url"`
Twitter *string `json:"twitter"`
Instagram *string `json:"instagram"`
URLs []string `json:"urls"`
URL *string `json:"url"` // deprecated
Twitter *string `json:"twitter"` // deprecated
Instagram *string `json:"instagram"` // deprecated
Birthdate *string `json:"birthdate"`
Ethnicity *string `json:"ethnicity"`
Country *string `json:"country"`
@@ -191,9 +192,7 @@ func (p *ScrapedPerformer) ToPerformer(endpoint string, excluded map[string]bool
ret.Weight = &w
}
}
if p.Instagram != nil && !excluded["instagram"] {
ret.Instagram = *p.Instagram
}
if p.Measurements != nil && !excluded["measurements"] {
ret.Measurements = *p.Measurements
}
@@ -221,11 +220,27 @@ func (p *ScrapedPerformer) ToPerformer(endpoint string, excluded map[string]bool
ret.Circumcised = &v
}
}
if p.Twitter != nil && !excluded["twitter"] {
ret.Twitter = *p.Twitter
}
if p.URL != nil && !excluded["url"] {
ret.URL = *p.URL
// if URLs are provided, only use those
if len(p.URLs) > 0 {
if !excluded["urls"] {
ret.URLs = NewRelatedStrings(p.URLs)
}
} else {
urls := []string{}
if p.URL != nil && !excluded["url"] {
urls = append(urls, *p.URL)
}
if p.Twitter != nil && !excluded["twitter"] {
urls = append(urls, *p.Twitter)
}
if p.Instagram != nil && !excluded["instagram"] {
urls = append(urls, *p.Instagram)
}
if len(urls) > 0 {
ret.URLs = NewRelatedStrings(urls)
}
}
if p.RemoteSiteID != nil && endpoint != "" {
@@ -309,9 +324,6 @@ func (p *ScrapedPerformer) ToPartial(endpoint string, excluded map[string]bool,
ret.Weight = NewOptionalInt(w)
}
}
if p.Instagram != nil && !excluded["instagram"] {
ret.Instagram = NewOptionalString(*p.Instagram)
}
if p.Measurements != nil && !excluded["measurements"] {
ret.Measurements = NewOptionalString(*p.Measurements)
}
@@ -330,11 +342,33 @@ func (p *ScrapedPerformer) ToPartial(endpoint string, excluded map[string]bool,
if p.Tattoos != nil && !excluded["tattoos"] {
ret.Tattoos = NewOptionalString(*p.Tattoos)
}
if p.Twitter != nil && !excluded["twitter"] {
ret.Twitter = NewOptionalString(*p.Twitter)
}
if p.URL != nil && !excluded["url"] {
ret.URL = NewOptionalString(*p.URL)
// if URLs are provided, only use those
if len(p.URLs) > 0 {
if !excluded["urls"] {
ret.URLs = &UpdateStrings{
Values: p.URLs,
Mode: RelationshipUpdateModeSet,
}
}
} else {
urls := []string{}
if p.URL != nil && !excluded["url"] {
urls = append(urls, *p.URL)
}
if p.Twitter != nil && !excluded["twitter"] {
urls = append(urls, *p.Twitter)
}
if p.Instagram != nil && !excluded["instagram"] {
urls = append(urls, *p.Instagram)
}
if len(urls) > 0 {
ret.URLs = &UpdateStrings{
Values: urls,
Mode: RelationshipUpdateModeSet,
}
}
}
if p.RemoteSiteID != nil && endpoint != "" {

View File

@@ -161,9 +161,9 @@ func Test_scrapedToPerformerInput(t *testing.T) {
Tattoos: nextVal(),
Piercings: nextVal(),
Aliases: nextVal(),
URL: nextVal(),
Twitter: nextVal(),
Instagram: nextVal(),
URL: nextVal(),
Details: nextVal(),
RemoteSiteID: &remoteSiteID,
},
@@ -186,9 +186,7 @@ func Test_scrapedToPerformerInput(t *testing.T) {
Tattoos: *nextVal(),
Piercings: *nextVal(),
Aliases: NewRelatedStrings([]string{*nextVal()}),
Twitter: *nextVal(),
Instagram: *nextVal(),
URL: *nextVal(),
URLs: NewRelatedStrings([]string{*nextVal(), *nextVal(), *nextVal()}),
Details: *nextVal(),
StashIDs: NewRelatedStashIDs([]StashID{
{

View File

@@ -203,7 +203,8 @@ type PerformerFilterType struct {
type PerformerCreateInput struct {
Name string `json:"name"`
Disambiguation *string `json:"disambiguation"`
URL *string `json:"url"`
URL *string `json:"url"` // deprecated
Urls []string `json:"urls"`
Gender *GenderEnum `json:"gender"`
Birthdate *string `json:"birthdate"`
Ethnicity *string `json:"ethnicity"`
@@ -220,8 +221,8 @@ type PerformerCreateInput struct {
Piercings *string `json:"piercings"`
Aliases *string `json:"aliases"`
AliasList []string `json:"alias_list"`
Twitter *string `json:"twitter"`
Instagram *string `json:"instagram"`
Twitter *string `json:"twitter"` // deprecated
Instagram *string `json:"instagram"` // deprecated
Favorite *bool `json:"favorite"`
TagIds []string `json:"tag_ids"`
// This should be a URL or a base64 encoded data URL
@@ -239,7 +240,8 @@ type PerformerUpdateInput struct {
ID string `json:"id"`
Name *string `json:"name"`
Disambiguation *string `json:"disambiguation"`
URL *string `json:"url"`
URL *string `json:"url"` // deprecated
Urls []string `json:"urls"`
Gender *GenderEnum `json:"gender"`
Birthdate *string `json:"birthdate"`
Ethnicity *string `json:"ethnicity"`
@@ -256,8 +258,8 @@ type PerformerUpdateInput struct {
Piercings *string `json:"piercings"`
Aliases *string `json:"aliases"`
AliasList []string `json:"alias_list"`
Twitter *string `json:"twitter"`
Instagram *string `json:"instagram"`
Twitter *string `json:"twitter"` // deprecated
Instagram *string `json:"instagram"` // deprecated
Favorite *bool `json:"favorite"`
TagIds []string `json:"tag_ids"`
// This should be a URL or a base64 encoded data URL

View File

@@ -78,6 +78,7 @@ type PerformerReader interface {
AliasLoader
StashIDLoader
TagIDLoader
URLLoader
All(ctx context.Context) ([]*Performer, error)
GetImage(ctx context.Context, performerID int) ([]byte, error)