stash/pkg/models/model_scraped_item.go
WithoutPants 15a7b8a859
Movie group renames (#5039)
* Rename Movie and MoviePartial to Group/GroupPartial
* Rename Movie interfaces
* Update movie url builders to use group
* Rename movieRoutes to groupRoutes
* Update dataloader
* Update names in sqlite package
* Rename in resolvers
* Add GroupByURL to scraper config
* Scraper backward compatibility hacks
2024-07-04 09:10:26 +10:00

485 lines
13 KiB
Go

package models
import (
"context"
"strconv"
"github.com/stashapp/stash/pkg/sliceutil/stringslice"
"github.com/stashapp/stash/pkg/utils"
)
type ScrapedStudio struct {
// Set if studio matched
StoredID *string `json:"stored_id"`
Name string `json:"name"`
URL *string `json:"url"`
Parent *ScrapedStudio `json:"parent"`
Image *string `json:"image"`
Images []string `json:"images"`
RemoteSiteID *string `json:"remote_site_id"`
}
func (ScrapedStudio) IsScrapedContent() {}
func (s *ScrapedStudio) ToStudio(endpoint string, excluded map[string]bool) *Studio {
// Populate a new studio from the input
ret := NewStudio()
ret.Name = s.Name
if s.RemoteSiteID != nil && endpoint != "" {
ret.StashIDs = NewRelatedStashIDs([]StashID{
{
Endpoint: endpoint,
StashID: *s.RemoteSiteID,
},
})
}
if s.URL != nil && !excluded["url"] {
ret.URL = *s.URL
}
if s.Parent != nil && s.Parent.StoredID != nil && !excluded["parent"] && !excluded["parent_studio"] {
parentId, _ := strconv.Atoi(*s.Parent.StoredID)
ret.ParentID = &parentId
}
return &ret
}
func (s *ScrapedStudio) GetImage(ctx context.Context, excluded map[string]bool) ([]byte, error) {
// Process the base 64 encoded image string
if len(s.Images) > 0 && !excluded["image"] {
var err error
img, err := utils.ProcessImageInput(ctx, *s.Image)
if err != nil {
return nil, err
}
return img, nil
}
return nil, nil
}
func (s *ScrapedStudio) ToPartial(id string, endpoint string, excluded map[string]bool, existingStashIDs []StashID) StudioPartial {
ret := NewStudioPartial()
ret.ID, _ = strconv.Atoi(id)
if s.Name != "" && !excluded["name"] {
ret.Name = NewOptionalString(s.Name)
}
if s.URL != nil && !excluded["url"] {
ret.URL = NewOptionalString(*s.URL)
}
if s.Parent != nil && !excluded["parent"] {
if s.Parent.StoredID != nil {
parentID, _ := strconv.Atoi(*s.Parent.StoredID)
if parentID > 0 {
// This is to be set directly as we know it has a value and the translator won't have the field
ret.ParentID = NewOptionalInt(parentID)
}
}
}
if s.RemoteSiteID != nil && endpoint != "" {
ret.StashIDs = &UpdateStashIDs{
StashIDs: existingStashIDs,
Mode: RelationshipUpdateModeSet,
}
ret.StashIDs.Set(StashID{
Endpoint: endpoint,
StashID: *s.RemoteSiteID,
})
}
return ret
}
// A performer from a scraping operation...
type ScrapedPerformer struct {
// Set if performer matched
StoredID *string `json:"stored_id"`
Name *string `json:"name"`
Disambiguation *string `json:"disambiguation"`
Gender *string `json:"gender"`
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"`
EyeColor *string `json:"eye_color"`
Height *string `json:"height"`
Measurements *string `json:"measurements"`
FakeTits *string `json:"fake_tits"`
PenisLength *string `json:"penis_length"`
Circumcised *string `json:"circumcised"`
CareerLength *string `json:"career_length"`
Tattoos *string `json:"tattoos"`
Piercings *string `json:"piercings"`
Aliases *string `json:"aliases"`
Tags []*ScrapedTag `json:"tags"`
// This should be a base64 encoded data URL
Image *string `json:"image"` // deprecated: use Images
Images []string `json:"images"`
Details *string `json:"details"`
DeathDate *string `json:"death_date"`
HairColor *string `json:"hair_color"`
Weight *string `json:"weight"`
RemoteSiteID *string `json:"remote_site_id"`
}
func (ScrapedPerformer) IsScrapedContent() {}
func (p *ScrapedPerformer) ToPerformer(endpoint string, excluded map[string]bool) *Performer {
ret := NewPerformer()
ret.Name = *p.Name
if p.Aliases != nil && !excluded["aliases"] {
ret.Aliases = NewRelatedStrings(stringslice.FromString(*p.Aliases, ","))
}
if p.Birthdate != nil && !excluded["birthdate"] {
date, err := ParseDate(*p.Birthdate)
if err == nil {
ret.Birthdate = &date
}
}
if p.DeathDate != nil && !excluded["death_date"] {
date, err := ParseDate(*p.DeathDate)
if err == nil {
ret.DeathDate = &date
}
}
if p.CareerLength != nil && !excluded["career_length"] {
ret.CareerLength = *p.CareerLength
}
if p.Country != nil && !excluded["country"] {
ret.Country = *p.Country
}
if p.Ethnicity != nil && !excluded["ethnicity"] {
ret.Ethnicity = *p.Ethnicity
}
if p.EyeColor != nil && !excluded["eye_color"] {
ret.EyeColor = *p.EyeColor
}
if p.HairColor != nil && !excluded["hair_color"] {
ret.HairColor = *p.HairColor
}
if p.FakeTits != nil && !excluded["fake_tits"] {
ret.FakeTits = *p.FakeTits
}
if p.Gender != nil && !excluded["gender"] {
v := GenderEnum(*p.Gender)
if v.IsValid() {
ret.Gender = &v
}
}
if p.Height != nil && !excluded["height"] {
h, err := strconv.Atoi(*p.Height)
if err == nil {
ret.Height = &h
}
}
if p.Weight != nil && !excluded["weight"] {
w, err := strconv.Atoi(*p.Weight)
if err == nil {
ret.Weight = &w
}
}
if p.Measurements != nil && !excluded["measurements"] {
ret.Measurements = *p.Measurements
}
if p.Disambiguation != nil && !excluded["disambiguation"] {
ret.Disambiguation = *p.Disambiguation
}
if p.Details != nil && !excluded["details"] {
ret.Details = *p.Details
}
if p.Piercings != nil && !excluded["piercings"] {
ret.Piercings = *p.Piercings
}
if p.Tattoos != nil && !excluded["tattoos"] {
ret.Tattoos = *p.Tattoos
}
if p.PenisLength != nil && !excluded["penis_length"] {
l, err := strconv.ParseFloat(*p.PenisLength, 64)
if err == nil {
ret.PenisLength = &l
}
}
if p.Circumcised != nil && !excluded["circumcised"] {
v := CircumisedEnum(*p.Circumcised)
if v.IsValid() {
ret.Circumcised = &v
}
}
// 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 != "" {
ret.StashIDs = NewRelatedStashIDs([]StashID{
{
Endpoint: endpoint,
StashID: *p.RemoteSiteID,
},
})
}
return &ret
}
func (p *ScrapedPerformer) GetImage(ctx context.Context, excluded map[string]bool) ([]byte, error) {
// Process the base 64 encoded image string
if len(p.Images) > 0 && !excluded["image"] {
var err error
img, err := utils.ProcessImageInput(ctx, p.Images[0])
if err != nil {
return nil, err
}
return img, nil
}
return nil, nil
}
func (p *ScrapedPerformer) ToPartial(endpoint string, excluded map[string]bool, existingStashIDs []StashID) PerformerPartial {
ret := NewPerformerPartial()
if p.Aliases != nil && !excluded["aliases"] {
ret.Aliases = &UpdateStrings{
Values: stringslice.FromString(*p.Aliases, ","),
Mode: RelationshipUpdateModeSet,
}
}
if p.Birthdate != nil && !excluded["birthdate"] {
date, err := ParseDate(*p.Birthdate)
if err == nil {
ret.Birthdate = NewOptionalDate(date)
}
}
if p.DeathDate != nil && !excluded["death_date"] {
date, err := ParseDate(*p.DeathDate)
if err == nil {
ret.DeathDate = NewOptionalDate(date)
}
}
if p.CareerLength != nil && !excluded["career_length"] {
ret.CareerLength = NewOptionalString(*p.CareerLength)
}
if p.Country != nil && !excluded["country"] {
ret.Country = NewOptionalString(*p.Country)
}
if p.Ethnicity != nil && !excluded["ethnicity"] {
ret.Ethnicity = NewOptionalString(*p.Ethnicity)
}
if p.EyeColor != nil && !excluded["eye_color"] {
ret.EyeColor = NewOptionalString(*p.EyeColor)
}
if p.HairColor != nil && !excluded["hair_color"] {
ret.HairColor = NewOptionalString(*p.HairColor)
}
if p.FakeTits != nil && !excluded["fake_tits"] {
ret.FakeTits = NewOptionalString(*p.FakeTits)
}
if p.Gender != nil && !excluded["gender"] {
ret.Gender = NewOptionalString(*p.Gender)
}
if p.Height != nil && !excluded["height"] {
h, err := strconv.Atoi(*p.Height)
if err == nil {
ret.Height = NewOptionalInt(h)
}
}
if p.Weight != nil && !excluded["weight"] {
w, err := strconv.Atoi(*p.Weight)
if err == nil {
ret.Weight = NewOptionalInt(w)
}
}
if p.Measurements != nil && !excluded["measurements"] {
ret.Measurements = NewOptionalString(*p.Measurements)
}
if p.Name != nil && !excluded["name"] {
ret.Name = NewOptionalString(*p.Name)
}
if p.Disambiguation != nil && !excluded["disambiguation"] {
ret.Disambiguation = NewOptionalString(*p.Disambiguation)
}
if p.Details != nil && !excluded["details"] {
ret.Details = NewOptionalString(*p.Details)
}
if p.Piercings != nil && !excluded["piercings"] {
ret.Piercings = NewOptionalString(*p.Piercings)
}
if p.Tattoos != nil && !excluded["tattoos"] {
ret.Tattoos = NewOptionalString(*p.Tattoos)
}
// 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 != "" {
ret.StashIDs = &UpdateStashIDs{
StashIDs: existingStashIDs,
Mode: RelationshipUpdateModeSet,
}
ret.StashIDs.Set(StashID{
Endpoint: endpoint,
StashID: *p.RemoteSiteID,
})
}
return ret
}
type ScrapedTag struct {
// Set if tag matched
StoredID *string `json:"stored_id"`
Name string `json:"name"`
}
func (ScrapedTag) IsScrapedContent() {}
// A movie from a scraping operation...
type ScrapedMovie struct {
StoredID *string `json:"stored_id"`
Name *string `json:"name"`
Aliases *string `json:"aliases"`
Duration *string `json:"duration"`
Date *string `json:"date"`
Rating *string `json:"rating"`
Director *string `json:"director"`
URLs []string `json:"urls"`
Synopsis *string `json:"synopsis"`
Studio *ScrapedStudio `json:"studio"`
Tags []*ScrapedTag `json:"tags"`
// This should be a base64 encoded data URL
FrontImage *string `json:"front_image"`
// This should be a base64 encoded data URL
BackImage *string `json:"back_image"`
// deprecated
URL *string `json:"url"`
}
func (ScrapedMovie) IsScrapedContent() {}
func (m ScrapedMovie) ScrapedGroup() ScrapedGroup {
ret := ScrapedGroup{
StoredID: m.StoredID,
Name: m.Name,
Aliases: m.Aliases,
Duration: m.Duration,
Date: m.Date,
Rating: m.Rating,
Director: m.Director,
URLs: m.URLs,
Synopsis: m.Synopsis,
Studio: m.Studio,
Tags: m.Tags,
FrontImage: m.FrontImage,
BackImage: m.BackImage,
}
if len(m.URLs) == 0 && m.URL != nil {
ret.URLs = []string{*m.URL}
}
return ret
}
// ScrapedGroup is a group from a scraping operation
type ScrapedGroup struct {
StoredID *string `json:"stored_id"`
Name *string `json:"name"`
Aliases *string `json:"aliases"`
Duration *string `json:"duration"`
Date *string `json:"date"`
Rating *string `json:"rating"`
Director *string `json:"director"`
URLs []string `json:"urls"`
Synopsis *string `json:"synopsis"`
Studio *ScrapedStudio `json:"studio"`
Tags []*ScrapedTag `json:"tags"`
// This should be a base64 encoded data URL
FrontImage *string `json:"front_image"`
// This should be a base64 encoded data URL
BackImage *string `json:"back_image"`
}
func (ScrapedGroup) IsScrapedContent() {}
func (g ScrapedGroup) ScrapedMovie() ScrapedMovie {
ret := ScrapedMovie{
StoredID: g.StoredID,
Name: g.Name,
Aliases: g.Aliases,
Duration: g.Duration,
Date: g.Date,
Rating: g.Rating,
Director: g.Director,
URLs: g.URLs,
Synopsis: g.Synopsis,
Studio: g.Studio,
Tags: g.Tags,
FrontImage: g.FrontImage,
BackImage: g.BackImage,
}
if len(g.URLs) > 0 {
ret.URL = &g.URLs[0]
}
return ret
}