Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions gqlgen.yml
Original file line number Diff line number Diff line change
Expand Up @@ -140,4 +140,8 @@ models:
fields:
plugins:
resolver: true
Performer:
fields:
career_length:
resolver: true

16 changes: 12 additions & 4 deletions graphql/schema/types/performer.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@ type Performer {
fake_tits: String
penis_length: Float
circumcised: CircumisedEnum
career_length: String
career_length: String @deprecated(reason: "Use career_start and career_end")
career_start: Int
career_end: Int
tattoos: String
piercings: String
alias_list: [String!]!
Expand Down Expand Up @@ -77,7 +79,9 @@ input PerformerCreateInput {
fake_tits: String
penis_length: Float
circumcised: CircumisedEnum
career_length: String
career_length: String @deprecated(reason: "Use career_start and career_end")
career_start: Int
career_end: Int
tattoos: String
piercings: String
alias_list: [String!]
Expand Down Expand Up @@ -115,7 +119,9 @@ input PerformerUpdateInput {
fake_tits: String
penis_length: Float
circumcised: CircumisedEnum
career_length: String
career_length: String @deprecated(reason: "Use career_start and career_end")
career_start: Int
career_end: Int
tattoos: String
piercings: String
alias_list: [String!]
Expand Down Expand Up @@ -158,7 +164,9 @@ input BulkPerformerUpdateInput {
fake_tits: String
penis_length: Float
circumcised: CircumisedEnum
career_length: String
career_length: String @deprecated(reason: "Use career_start and career_end")
career_start: Int
career_end: Int
tattoos: String
piercings: String
alias_list: BulkUpdateStrings
Expand Down
8 changes: 6 additions & 2 deletions graphql/schema/types/scraped-performer.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ type ScrapedPerformer {
fake_tits: String
penis_length: String
circumcised: String
career_length: String
career_length: String @deprecated(reason: "Use career_start and career_end")
career_start: String
career_end: String
tattoos: String
piercings: String
# aliases must be comma-delimited to be parsed correctly
Expand Down Expand Up @@ -54,7 +56,9 @@ input ScrapedPerformerInput {
fake_tits: String
penis_length: String
circumcised: String
career_length: String
career_length: String @deprecated(reason: "Use career_start and career_end")
career_start: String
career_end: String
tattoos: String
piercings: String
aliases: String
Expand Down
24 changes: 24 additions & 0 deletions internal/api/resolver_model_performer.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package api

import (
"context"
"fmt"
"strconv"

"github.com/stashapp/stash/internal/api/loaders"
Expand Down Expand Up @@ -109,6 +110,29 @@ func (r *performerResolver) HeightCm(ctx context.Context, obj *models.Performer)
return obj.Height, nil
}

func (r *performerResolver) CareerLength(ctx context.Context, obj *models.Performer) (*string, error) {
// Compute from CareerStart and CareerEnd if available
if obj.CareerStart != nil || obj.CareerEnd != nil {
var ret string
switch {
case obj.CareerEnd == nil:
ret = fmt.Sprintf("%d -", *obj.CareerStart)
case obj.CareerStart == nil:
ret = fmt.Sprintf("- %d", *obj.CareerEnd)
default:
ret = fmt.Sprintf("%d - %d", *obj.CareerStart, *obj.CareerEnd)
}
return &ret, nil
}

// Fall back to stored CareerLength for backwards compatibility
if obj.CareerLength != "" {
return &obj.CareerLength, nil
}

return nil, nil
}

func (r *performerResolver) Birthdate(ctx context.Context, obj *models.Performer) (*string, error) {
if obj.Birthdate != nil {
ret := obj.Birthdate.String()
Expand Down
6 changes: 6 additions & 0 deletions internal/api/resolver_mutation_performer.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ func (r *mutationResolver) PerformerCreate(ctx context.Context, input models.Per
newPerformer.PenisLength = input.PenisLength
newPerformer.Circumcised = input.Circumcised
newPerformer.CareerLength = translator.string(input.CareerLength)
newPerformer.CareerStart = input.CareerStart
newPerformer.CareerEnd = input.CareerEnd
newPerformer.Tattoos = translator.string(input.Tattoos)
newPerformer.Piercings = translator.string(input.Piercings)
newPerformer.Favorite = translator.bool(input.Favorite)
Expand Down Expand Up @@ -250,6 +252,8 @@ func (r *mutationResolver) PerformerUpdate(ctx context.Context, input models.Per
updatedPerformer.PenisLength = translator.optionalFloat64(input.PenisLength, "penis_length")
updatedPerformer.Circumcised = translator.optionalString((*string)(input.Circumcised), "circumcised")
updatedPerformer.CareerLength = translator.optionalString(input.CareerLength, "career_length")
updatedPerformer.CareerStart = translator.optionalInt(input.CareerStart, "career_start")
updatedPerformer.CareerEnd = translator.optionalInt(input.CareerEnd, "career_end")
updatedPerformer.Tattoos = translator.optionalString(input.Tattoos, "tattoos")
updatedPerformer.Piercings = translator.optionalString(input.Piercings, "piercings")
updatedPerformer.Favorite = translator.optionalBool(input.Favorite, "favorite")
Expand Down Expand Up @@ -367,6 +371,8 @@ func (r *mutationResolver) BulkPerformerUpdate(ctx context.Context, input BulkPe
updatedPerformer.PenisLength = translator.optionalFloat64(input.PenisLength, "penis_length")
updatedPerformer.Circumcised = translator.optionalString((*string)(input.Circumcised), "circumcised")
updatedPerformer.CareerLength = translator.optionalString(input.CareerLength, "career_length")
updatedPerformer.CareerStart = translator.optionalInt(input.CareerStart, "career_start")
updatedPerformer.CareerEnd = translator.optionalInt(input.CareerEnd, "career_end")
updatedPerformer.Tattoos = translator.optionalString(input.Tattoos, "tattoos")
updatedPerformer.Piercings = translator.optionalString(input.Piercings, "piercings")

Expand Down
4 changes: 4 additions & 0 deletions pkg/models/model_performer.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ type Performer struct {
PenisLength *float64 `json:"penis_length"`
Circumcised *CircumisedEnum `json:"circumcised"`
CareerLength string `json:"career_length"`
CareerStart *int `json:"career_start"`
CareerEnd *int `json:"career_end"`
Tattoos string `json:"tattoos"`
Piercings string `json:"piercings"`
Favorite bool `json:"favorite"`
Expand Down Expand Up @@ -76,6 +78,8 @@ type PerformerPartial struct {
PenisLength OptionalFloat64
Circumcised OptionalString
CareerLength OptionalString
CareerStart OptionalInt
CareerEnd OptionalInt
Tattoos OptionalString
Piercings OptionalString
Favorite OptionalBool
Expand Down
14 changes: 14 additions & 0 deletions pkg/models/model_scraped_item.go
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,8 @@ type ScrapedPerformer struct {
PenisLength *string `json:"penis_length"`
Circumcised *string `json:"circumcised"`
CareerLength *string `json:"career_length"`
CareerStart *string `json:"career_start"`
CareerEnd *string `json:"career_end"`
Tattoos *string `json:"tattoos"`
Piercings *string `json:"piercings"`
Aliases *string `json:"aliases"`
Expand Down Expand Up @@ -222,6 +224,18 @@ func (p *ScrapedPerformer) ToPerformer(endpoint string, excluded map[string]bool
if p.CareerLength != nil && !excluded["career_length"] {
ret.CareerLength = *p.CareerLength
}
if p.CareerStart != nil && !excluded["career_start"] {
cs, err := strconv.Atoi(*p.CareerStart)
if err == nil {
ret.CareerStart = &cs
}
}
if p.CareerEnd != nil && !excluded["career_end"] {
ce, err := strconv.Atoi(*p.CareerEnd)
if err == nil {
ret.CareerEnd = &ce
}
}
if p.Country != nil && !excluded["country"] {
ret.Country = *p.Country
}
Expand Down
4 changes: 4 additions & 0 deletions pkg/models/performer.go
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,8 @@ type PerformerCreateInput struct {
PenisLength *float64 `json:"penis_length"`
Circumcised *CircumisedEnum `json:"circumcised"`
CareerLength *string `json:"career_length"`
CareerStart *int `json:"career_start"`
CareerEnd *int `json:"career_end"`
Tattoos *string `json:"tattoos"`
Piercings *string `json:"piercings"`
Aliases *string `json:"aliases"`
Expand Down Expand Up @@ -261,6 +263,8 @@ type PerformerUpdateInput struct {
PenisLength *float64 `json:"penis_length"`
Circumcised *CircumisedEnum `json:"circumcised"`
CareerLength *string `json:"career_length"`
CareerStart *int `json:"career_start"`
CareerEnd *int `json:"career_end"`
Tattoos *string `json:"tattoos"`
Piercings *string `json:"piercings"`
Aliases *string `json:"aliases"`
Expand Down
2 changes: 2 additions & 0 deletions pkg/scraper/performer.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ type ScrapedPerformerInput struct {
PenisLength *string `json:"penis_length"`
Circumcised *string `json:"circumcised"`
CareerLength *string `json:"career_length"`
CareerStart *string `json:"career_start"`
CareerEnd *string `json:"career_end"`
Tattoos *string `json:"tattoos"`
Piercings *string `json:"piercings"`
Aliases *string `json:"aliases"`
Expand Down
2 changes: 1 addition & 1 deletion pkg/sqlite/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ const (
cacheSizeEnv = "STASH_SQLITE_CACHE_SIZE"
)

var appSchemaVersion uint = 75
var appSchemaVersion uint = 76

//go:embed migrations/*.sql
var migrationsBox embed.FS
Expand Down
2 changes: 2 additions & 0 deletions pkg/sqlite/migrations/76_performer_career_dates.up.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
ALTER TABLE "performers" ADD COLUMN "career_start" integer;
ALTER TABLE "performers" ADD COLUMN "career_end" integer;
10 changes: 10 additions & 0 deletions pkg/sqlite/performer.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ type performerRow struct {
PenisLength null.Float `db:"penis_length"`
Circumcised zero.String `db:"circumcised"`
CareerLength zero.String `db:"career_length"`
CareerStart null.Int `db:"career_start"`
CareerEnd null.Int `db:"career_end"`
Tattoos zero.String `db:"tattoos"`
Piercings zero.String `db:"piercings"`
Favorite bool `db:"favorite"`
Expand Down Expand Up @@ -83,6 +85,8 @@ func (r *performerRow) fromPerformer(o models.Performer) {
r.Circumcised = zero.StringFrom(o.Circumcised.String())
}
r.CareerLength = zero.StringFrom(o.CareerLength)
r.CareerStart = intFromPtr(o.CareerStart)
r.CareerEnd = intFromPtr(o.CareerEnd)
r.Tattoos = zero.StringFrom(o.Tattoos)
r.Piercings = zero.StringFrom(o.Piercings)
r.Favorite = o.Favorite
Expand Down Expand Up @@ -111,6 +115,8 @@ func (r *performerRow) resolve() *models.Performer {
FakeTits: r.FakeTits.String,
PenisLength: nullFloatPtr(r.PenisLength),
CareerLength: r.CareerLength.String,
CareerStart: nullIntPtr(r.CareerStart),
CareerEnd: nullIntPtr(r.CareerEnd),
Tattoos: r.Tattoos.String,
Piercings: r.Piercings.String,
Favorite: r.Favorite,
Expand Down Expand Up @@ -156,6 +162,8 @@ func (r *performerRowRecord) fromPartial(o models.PerformerPartial) {
r.setNullFloat64("penis_length", o.PenisLength)
r.setNullString("circumcised", o.Circumcised)
r.setNullString("career_length", o.CareerLength)
r.setNullInt("career_start", o.CareerStart)
r.setNullInt("career_end", o.CareerEnd)
r.setNullString("tattoos", o.Tattoos)
r.setNullString("piercings", o.Piercings)
r.setBool("favorite", o.Favorite)
Expand Down Expand Up @@ -755,6 +763,8 @@ func (qb *PerformerStore) sortByScenesDuration(direction string) string {
var performerSortOptions = sortOptions{
"birthdate",
"career_length",
"career_start",
"career_end",
"created_at",
"galleries_count",
"height",
Expand Down
20 changes: 19 additions & 1 deletion pkg/stashbox/performer.go
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,16 @@ func performerFragmentToScrapedPerformer(p graphql.PerformerFragment) *models.Sc
sp.Height = &hs
}

if p.CareerStartYear != nil {
cs := strconv.Itoa(*p.CareerStartYear)
sp.CareerStart = &cs
}

if p.CareerEndYear != nil {
ce := strconv.Itoa(*p.CareerEndYear)
sp.CareerEnd = &ce
}

if p.BirthDate != nil {
sp.Birthdate = padFuzzyDate(p.BirthDate)
}
Expand Down Expand Up @@ -388,7 +398,15 @@ func (c Client) SubmitPerformerDraft(ctx context.Context, performer *models.Perf
aliases := strings.Join(performer.Aliases.List(), ",")
draft.Aliases = &aliases
}
if performer.CareerLength != "" {
// Use CareerStart and CareerEnd directly if available
if performer.CareerStart != nil {
draft.CareerStartYear = performer.CareerStart
}
if performer.CareerEnd != nil {
draft.CareerEndYear = performer.CareerEnd
}
// Fall back to parsing CareerLength for backwards compatibility
if draft.CareerStartYear == nil && draft.CareerEndYear == nil && performer.CareerLength != "" {
var career = strings.Split(performer.CareerLength, "-")
if i, err := strconv.Atoi(strings.TrimSpace(career[0])); err == nil {
draft.CareerStartYear = &i
Expand Down
2 changes: 2 additions & 0 deletions ui/v2.5/graphql/data/performer.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ fragment PerformerData on Performer {
penis_length
circumcised
career_length
career_start
career_end
tattoos
piercings
alias_list
Expand Down
4 changes: 4 additions & 0 deletions ui/v2.5/graphql/data/scrapers.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ fragment ScrapedPerformerData on ScrapedPerformer {
penis_length
circumcised
career_length
career_start
career_end
tattoos
piercings
aliases
Expand Down Expand Up @@ -69,6 +71,8 @@ fragment ScrapedScenePerformerData on ScrapedPerformer {
penis_length
circumcised
career_length
career_start
career_end
tattoos
piercings
aliases
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,8 @@ export const PerformerEditPanel: React.FC<IPerformerDetails> = ({
circumcised: yupInputEnum(GQL.CircumisedEnum).nullable().defined(),
tattoos: yup.string().ensure(),
piercings: yup.string().ensure(),
career_length: yup.string().ensure(),
career_start: yupInputNumber().positive().nullable().defined(),
career_end: yupInputNumber().positive().nullable().defined(),
urls: yupUniqueStringList(intl),
details: yup.string().ensure(),
tag_ids: yup.array(yup.string().required()).defined(),
Expand Down Expand Up @@ -152,7 +153,8 @@ export const PerformerEditPanel: React.FC<IPerformerDetails> = ({
circumcised: performer.circumcised ?? null,
tattoos: performer.tattoos ?? "",
piercings: performer.piercings ?? "",
career_length: performer.career_length ?? "",
career_start: performer.career_start ?? null,
career_end: performer.career_end ?? null,
urls: performer.urls ?? [],
details: performer.details ?? "",
tag_ids: (performer.tags ?? []).map((t) => t.id),
Expand Down Expand Up @@ -253,8 +255,11 @@ export const PerformerEditPanel: React.FC<IPerformerDetails> = ({
if (state.fake_tits) {
formik.setFieldValue("fake_tits", state.fake_tits);
}
if (state.career_length) {
formik.setFieldValue("career_length", state.career_length);
if (state.career_start) {
formik.setFieldValue("career_start", parseInt(state.career_start, 10));
}
if (state.career_end) {
formik.setFieldValue("career_end", parseInt(state.career_end, 10));
}
if (state.tattoos) {
formik.setFieldValue("tattoos", state.tattoos);
Expand Down Expand Up @@ -718,7 +723,8 @@ export const PerformerEditPanel: React.FC<IPerformerDetails> = ({
{renderInputField("tattoos", "textarea")}
{renderInputField("piercings", "textarea")}

{renderInputField("career_length")}
{renderInputField("career_start", "number")}
{renderInputField("career_end", "number")}

{renderURLListField("urls", onScrapePerformerURL, urlScrapable)}

Expand Down
Loading