mirror of
https://github.com/stashapp/stash.git
synced 2025-12-06 08:26:00 +01:00
Add support for submitting performer/scene drafts to stash-box (#2234)
* Add support for submitting performer/scene drafts to stash-box Co-authored-by: Kermie <kermie@isinthe.house>
This commit is contained in:
parent
c5cd0e1c9c
commit
a3c20ce8da
23 changed files with 1235 additions and 348 deletions
|
|
@ -5,3 +5,11 @@ mutation SubmitStashBoxFingerprints($input: StashBoxFingerprintSubmissionInput!)
|
||||||
mutation StashBoxBatchPerformerTag($input: StashBoxBatchPerformerTagInput!) {
|
mutation StashBoxBatchPerformerTag($input: StashBoxBatchPerformerTagInput!) {
|
||||||
stashBoxBatchPerformerTag(input: $input)
|
stashBoxBatchPerformerTag(input: $input)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mutation SubmitStashBoxSceneDraft($input: StashBoxDraftSubmissionInput!) {
|
||||||
|
submitStashBoxSceneDraft(input: $input)
|
||||||
|
}
|
||||||
|
|
||||||
|
mutation SubmitStashBoxPerformerDraft($input: StashBoxDraftSubmissionInput!) {
|
||||||
|
submitStashBoxPerformerDraft(input: $input)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -282,6 +282,11 @@ type Mutation {
|
||||||
"""Submit fingerprints to stash-box instance"""
|
"""Submit fingerprints to stash-box instance"""
|
||||||
submitStashBoxFingerprints(input: StashBoxFingerprintSubmissionInput!): Boolean!
|
submitStashBoxFingerprints(input: StashBoxFingerprintSubmissionInput!): Boolean!
|
||||||
|
|
||||||
|
"""Submit scene as draft to stash-box instance"""
|
||||||
|
submitStashBoxSceneDraft(input: StashBoxDraftSubmissionInput!): ID
|
||||||
|
"""Submit performer as draft to stash-box instance"""
|
||||||
|
submitStashBoxPerformerDraft(input: StashBoxDraftSubmissionInput!): ID
|
||||||
|
|
||||||
"""Backup the database. Optionally returns a link to download the database file"""
|
"""Backup the database. Optionally returns a link to download the database file"""
|
||||||
backupDatabase(input: BackupDatabaseInput!): String
|
backupDatabase(input: BackupDatabaseInput!): String
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,3 +24,8 @@ input StashBoxFingerprintSubmissionInput {
|
||||||
scene_ids: [String!]!
|
scene_ids: [String!]!
|
||||||
stash_box_index: Int!
|
stash_box_index: Int!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input StashBoxDraftSubmissionInput {
|
||||||
|
id: String!
|
||||||
|
stash_box_index: Int!
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -162,3 +162,15 @@ query Me {
|
||||||
name
|
name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mutation SubmitSceneDraft($input: SceneDraftInput!) {
|
||||||
|
submitSceneDraft(input: $input) {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mutation SubmitPerformerDraft($input: PerformerDraftInput!) {
|
||||||
|
submitPerformerDraft(input: $input) {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,3 +27,62 @@ func (r *mutationResolver) StashBoxBatchPerformerTag(ctx context.Context, input
|
||||||
jobID := manager.GetInstance().StashBoxBatchPerformerTag(ctx, input)
|
jobID := manager.GetInstance().StashBoxBatchPerformerTag(ctx, input)
|
||||||
return strconv.Itoa(jobID), nil
|
return strconv.Itoa(jobID), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *mutationResolver) SubmitStashBoxSceneDraft(ctx context.Context, input models.StashBoxDraftSubmissionInput) (*string, error) {
|
||||||
|
boxes := config.GetInstance().GetStashBoxes()
|
||||||
|
|
||||||
|
if input.StashBoxIndex < 0 || input.StashBoxIndex >= len(boxes) {
|
||||||
|
return nil, fmt.Errorf("invalid stash_box_index %d", input.StashBoxIndex)
|
||||||
|
}
|
||||||
|
|
||||||
|
client := stashbox.NewClient(*boxes[input.StashBoxIndex], r.txnManager)
|
||||||
|
|
||||||
|
id, err := strconv.Atoi(input.ID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var res *string
|
||||||
|
err = r.withReadTxn(ctx, func(repo models.ReaderRepository) error {
|
||||||
|
qb := repo.Scene()
|
||||||
|
scene, err := qb.Find(id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
filepath := manager.GetInstance().Paths.Scene.GetScreenshotPath(scene.GetHash(config.GetInstance().GetVideoFileNamingAlgorithm()))
|
||||||
|
|
||||||
|
res, err = client.SubmitSceneDraft(ctx, id, boxes[input.StashBoxIndex].Endpoint, filepath)
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *mutationResolver) SubmitStashBoxPerformerDraft(ctx context.Context, input models.StashBoxDraftSubmissionInput) (*string, error) {
|
||||||
|
boxes := config.GetInstance().GetStashBoxes()
|
||||||
|
|
||||||
|
if input.StashBoxIndex < 0 || input.StashBoxIndex >= len(boxes) {
|
||||||
|
return nil, fmt.Errorf("invalid stash_box_index %d", input.StashBoxIndex)
|
||||||
|
}
|
||||||
|
|
||||||
|
client := stashbox.NewClient(*boxes[input.StashBoxIndex], r.txnManager)
|
||||||
|
|
||||||
|
id, err := strconv.Atoi(input.ID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var res *string
|
||||||
|
err = r.withReadTxn(ctx, func(repo models.ReaderRepository) error {
|
||||||
|
qb := repo.Performer()
|
||||||
|
performer, err := qb.Find(id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err = client.SubmitPerformerDraft(ctx, performer, boxes[input.StashBoxIndex].Endpoint)
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,8 @@ type Query struct {
|
||||||
FindScenesByFingerprints []*Scene "json:\"findScenesByFingerprints\" graphql:\"findScenesByFingerprints\""
|
FindScenesByFingerprints []*Scene "json:\"findScenesByFingerprints\" graphql:\"findScenesByFingerprints\""
|
||||||
FindScenesByFullFingerprints []*Scene "json:\"findScenesByFullFingerprints\" graphql:\"findScenesByFullFingerprints\""
|
FindScenesByFullFingerprints []*Scene "json:\"findScenesByFullFingerprints\" graphql:\"findScenesByFullFingerprints\""
|
||||||
QueryScenes QueryScenesResultType "json:\"queryScenes\" graphql:\"queryScenes\""
|
QueryScenes QueryScenesResultType "json:\"queryScenes\" graphql:\"queryScenes\""
|
||||||
|
FindSite *Site "json:\"findSite\" graphql:\"findSite\""
|
||||||
|
QuerySites QuerySitesResultType "json:\"querySites\" graphql:\"querySites\""
|
||||||
FindEdit *Edit "json:\"findEdit\" graphql:\"findEdit\""
|
FindEdit *Edit "json:\"findEdit\" graphql:\"findEdit\""
|
||||||
QueryEdits QueryEditsResultType "json:\"queryEdits\" graphql:\"queryEdits\""
|
QueryEdits QueryEditsResultType "json:\"queryEdits\" graphql:\"queryEdits\""
|
||||||
FindUser *User "json:\"findUser\" graphql:\"findUser\""
|
FindUser *User "json:\"findUser\" graphql:\"findUser\""
|
||||||
|
|
@ -38,48 +40,57 @@ type Query struct {
|
||||||
Me *User "json:\"me\" graphql:\"me\""
|
Me *User "json:\"me\" graphql:\"me\""
|
||||||
SearchPerformer []*Performer "json:\"searchPerformer\" graphql:\"searchPerformer\""
|
SearchPerformer []*Performer "json:\"searchPerformer\" graphql:\"searchPerformer\""
|
||||||
SearchScene []*Scene "json:\"searchScene\" graphql:\"searchScene\""
|
SearchScene []*Scene "json:\"searchScene\" graphql:\"searchScene\""
|
||||||
|
FindDraft *Draft "json:\"findDraft\" graphql:\"findDraft\""
|
||||||
|
FindDrafts []*Draft "json:\"findDrafts\" graphql:\"findDrafts\""
|
||||||
Version Version "json:\"version\" graphql:\"version\""
|
Version Version "json:\"version\" graphql:\"version\""
|
||||||
|
GetConfig StashBoxConfig "json:\"getConfig\" graphql:\"getConfig\""
|
||||||
}
|
}
|
||||||
|
|
||||||
type Mutation struct {
|
type Mutation struct {
|
||||||
SceneCreate *Scene "json:\"sceneCreate\" graphql:\"sceneCreate\""
|
SceneCreate *Scene "json:\"sceneCreate\" graphql:\"sceneCreate\""
|
||||||
SceneUpdate *Scene "json:\"sceneUpdate\" graphql:\"sceneUpdate\""
|
SceneUpdate *Scene "json:\"sceneUpdate\" graphql:\"sceneUpdate\""
|
||||||
SceneDestroy bool "json:\"sceneDestroy\" graphql:\"sceneDestroy\""
|
SceneDestroy bool "json:\"sceneDestroy\" graphql:\"sceneDestroy\""
|
||||||
PerformerCreate *Performer "json:\"performerCreate\" graphql:\"performerCreate\""
|
PerformerCreate *Performer "json:\"performerCreate\" graphql:\"performerCreate\""
|
||||||
PerformerUpdate *Performer "json:\"performerUpdate\" graphql:\"performerUpdate\""
|
PerformerUpdate *Performer "json:\"performerUpdate\" graphql:\"performerUpdate\""
|
||||||
PerformerDestroy bool "json:\"performerDestroy\" graphql:\"performerDestroy\""
|
PerformerDestroy bool "json:\"performerDestroy\" graphql:\"performerDestroy\""
|
||||||
StudioCreate *Studio "json:\"studioCreate\" graphql:\"studioCreate\""
|
StudioCreate *Studio "json:\"studioCreate\" graphql:\"studioCreate\""
|
||||||
StudioUpdate *Studio "json:\"studioUpdate\" graphql:\"studioUpdate\""
|
StudioUpdate *Studio "json:\"studioUpdate\" graphql:\"studioUpdate\""
|
||||||
StudioDestroy bool "json:\"studioDestroy\" graphql:\"studioDestroy\""
|
StudioDestroy bool "json:\"studioDestroy\" graphql:\"studioDestroy\""
|
||||||
TagCreate *Tag "json:\"tagCreate\" graphql:\"tagCreate\""
|
TagCreate *Tag "json:\"tagCreate\" graphql:\"tagCreate\""
|
||||||
TagUpdate *Tag "json:\"tagUpdate\" graphql:\"tagUpdate\""
|
TagUpdate *Tag "json:\"tagUpdate\" graphql:\"tagUpdate\""
|
||||||
TagDestroy bool "json:\"tagDestroy\" graphql:\"tagDestroy\""
|
TagDestroy bool "json:\"tagDestroy\" graphql:\"tagDestroy\""
|
||||||
UserCreate *User "json:\"userCreate\" graphql:\"userCreate\""
|
UserCreate *User "json:\"userCreate\" graphql:\"userCreate\""
|
||||||
UserUpdate *User "json:\"userUpdate\" graphql:\"userUpdate\""
|
UserUpdate *User "json:\"userUpdate\" graphql:\"userUpdate\""
|
||||||
UserDestroy bool "json:\"userDestroy\" graphql:\"userDestroy\""
|
UserDestroy bool "json:\"userDestroy\" graphql:\"userDestroy\""
|
||||||
ImageCreate *Image "json:\"imageCreate\" graphql:\"imageCreate\""
|
ImageCreate *Image "json:\"imageCreate\" graphql:\"imageCreate\""
|
||||||
ImageDestroy bool "json:\"imageDestroy\" graphql:\"imageDestroy\""
|
ImageDestroy bool "json:\"imageDestroy\" graphql:\"imageDestroy\""
|
||||||
NewUser *string "json:\"newUser\" graphql:\"newUser\""
|
NewUser *string "json:\"newUser\" graphql:\"newUser\""
|
||||||
ActivateNewUser *User "json:\"activateNewUser\" graphql:\"activateNewUser\""
|
ActivateNewUser *User "json:\"activateNewUser\" graphql:\"activateNewUser\""
|
||||||
GenerateInviteCode string "json:\"generateInviteCode\" graphql:\"generateInviteCode\""
|
GenerateInviteCode *string "json:\"generateInviteCode\" graphql:\"generateInviteCode\""
|
||||||
RescindInviteCode bool "json:\"rescindInviteCode\" graphql:\"rescindInviteCode\""
|
RescindInviteCode bool "json:\"rescindInviteCode\" graphql:\"rescindInviteCode\""
|
||||||
GrantInvite int "json:\"grantInvite\" graphql:\"grantInvite\""
|
GrantInvite int "json:\"grantInvite\" graphql:\"grantInvite\""
|
||||||
RevokeInvite int "json:\"revokeInvite\" graphql:\"revokeInvite\""
|
RevokeInvite int "json:\"revokeInvite\" graphql:\"revokeInvite\""
|
||||||
TagCategoryCreate *TagCategory "json:\"tagCategoryCreate\" graphql:\"tagCategoryCreate\""
|
TagCategoryCreate *TagCategory "json:\"tagCategoryCreate\" graphql:\"tagCategoryCreate\""
|
||||||
TagCategoryUpdate *TagCategory "json:\"tagCategoryUpdate\" graphql:\"tagCategoryUpdate\""
|
TagCategoryUpdate *TagCategory "json:\"tagCategoryUpdate\" graphql:\"tagCategoryUpdate\""
|
||||||
TagCategoryDestroy bool "json:\"tagCategoryDestroy\" graphql:\"tagCategoryDestroy\""
|
TagCategoryDestroy bool "json:\"tagCategoryDestroy\" graphql:\"tagCategoryDestroy\""
|
||||||
RegenerateAPIKey string "json:\"regenerateAPIKey\" graphql:\"regenerateAPIKey\""
|
SiteCreate *Site "json:\"siteCreate\" graphql:\"siteCreate\""
|
||||||
ResetPassword bool "json:\"resetPassword\" graphql:\"resetPassword\""
|
SiteUpdate *Site "json:\"siteUpdate\" graphql:\"siteUpdate\""
|
||||||
ChangePassword bool "json:\"changePassword\" graphql:\"changePassword\""
|
SiteDestroy bool "json:\"siteDestroy\" graphql:\"siteDestroy\""
|
||||||
SceneEdit Edit "json:\"sceneEdit\" graphql:\"sceneEdit\""
|
RegenerateAPIKey string "json:\"regenerateAPIKey\" graphql:\"regenerateAPIKey\""
|
||||||
PerformerEdit Edit "json:\"performerEdit\" graphql:\"performerEdit\""
|
ResetPassword bool "json:\"resetPassword\" graphql:\"resetPassword\""
|
||||||
StudioEdit Edit "json:\"studioEdit\" graphql:\"studioEdit\""
|
ChangePassword bool "json:\"changePassword\" graphql:\"changePassword\""
|
||||||
TagEdit Edit "json:\"tagEdit\" graphql:\"tagEdit\""
|
SceneEdit Edit "json:\"sceneEdit\" graphql:\"sceneEdit\""
|
||||||
EditVote Edit "json:\"editVote\" graphql:\"editVote\""
|
PerformerEdit Edit "json:\"performerEdit\" graphql:\"performerEdit\""
|
||||||
EditComment Edit "json:\"editComment\" graphql:\"editComment\""
|
StudioEdit Edit "json:\"studioEdit\" graphql:\"studioEdit\""
|
||||||
ApplyEdit Edit "json:\"applyEdit\" graphql:\"applyEdit\""
|
TagEdit Edit "json:\"tagEdit\" graphql:\"tagEdit\""
|
||||||
CancelEdit Edit "json:\"cancelEdit\" graphql:\"cancelEdit\""
|
EditVote Edit "json:\"editVote\" graphql:\"editVote\""
|
||||||
SubmitFingerprint bool "json:\"submitFingerprint\" graphql:\"submitFingerprint\""
|
EditComment Edit "json:\"editComment\" graphql:\"editComment\""
|
||||||
|
ApplyEdit Edit "json:\"applyEdit\" graphql:\"applyEdit\""
|
||||||
|
CancelEdit Edit "json:\"cancelEdit\" graphql:\"cancelEdit\""
|
||||||
|
SubmitFingerprint bool "json:\"submitFingerprint\" graphql:\"submitFingerprint\""
|
||||||
|
SubmitSceneDraft DraftSubmissionStatus "json:\"submitSceneDraft\" graphql:\"submitSceneDraft\""
|
||||||
|
SubmitPerformerDraft DraftSubmissionStatus "json:\"submitPerformerDraft\" graphql:\"submitPerformerDraft\""
|
||||||
|
DestroyDraft bool "json:\"destroyDraft\" graphql:\"destroyDraft\""
|
||||||
}
|
}
|
||||||
type URLFragment struct {
|
type URLFragment struct {
|
||||||
URL string "json:\"url\" graphql:\"url\""
|
URL string "json:\"url\" graphql:\"url\""
|
||||||
|
|
@ -185,12 +196,26 @@ type Me struct {
|
||||||
Name string "json:\"name\" graphql:\"name\""
|
Name string "json:\"name\" graphql:\"name\""
|
||||||
} "json:\"me\" graphql:\"me\""
|
} "json:\"me\" graphql:\"me\""
|
||||||
}
|
}
|
||||||
|
type SubmitSceneDraftPayload struct {
|
||||||
|
SubmitSceneDraft struct {
|
||||||
|
ID *string "json:\"id\" graphql:\"id\""
|
||||||
|
} "json:\"submitSceneDraft\" graphql:\"submitSceneDraft\""
|
||||||
|
}
|
||||||
|
type SubmitPerformerDraftPayload struct {
|
||||||
|
SubmitPerformerDraft struct {
|
||||||
|
ID *string "json:\"id\" graphql:\"id\""
|
||||||
|
} "json:\"submitPerformerDraft\" graphql:\"submitPerformerDraft\""
|
||||||
|
}
|
||||||
|
|
||||||
const FindSceneByFingerprintQuery = `query FindSceneByFingerprint ($fingerprint: FingerprintQueryInput!) {
|
const FindSceneByFingerprintQuery = `query FindSceneByFingerprint ($fingerprint: FingerprintQueryInput!) {
|
||||||
findSceneByFingerprint(fingerprint: $fingerprint) {
|
findSceneByFingerprint(fingerprint: $fingerprint) {
|
||||||
... SceneFragment
|
... SceneFragment
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fragment BodyModificationFragment on BodyModification {
|
||||||
|
location
|
||||||
|
description
|
||||||
|
}
|
||||||
fragment FingerprintFragment on Fingerprint {
|
fragment FingerprintFragment on Fingerprint {
|
||||||
algorithm
|
algorithm
|
||||||
hash
|
hash
|
||||||
|
|
@ -200,27 +225,9 @@ fragment URLFragment on URL {
|
||||||
url
|
url
|
||||||
type
|
type
|
||||||
}
|
}
|
||||||
fragment ImageFragment on Image {
|
fragment TagFragment on Tag {
|
||||||
id
|
|
||||||
url
|
|
||||||
width
|
|
||||||
height
|
|
||||||
}
|
|
||||||
fragment StudioFragment on Studio {
|
|
||||||
name
|
name
|
||||||
id
|
id
|
||||||
urls {
|
|
||||||
... URLFragment
|
|
||||||
}
|
|
||||||
images {
|
|
||||||
... ImageFragment
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fragment PerformerAppearanceFragment on PerformerAppearance {
|
|
||||||
as
|
|
||||||
performer {
|
|
||||||
... PerformerFragment
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
fragment PerformerFragment on Performer {
|
fragment PerformerFragment on Performer {
|
||||||
id
|
id
|
||||||
|
|
@ -256,9 +263,15 @@ fragment PerformerFragment on Performer {
|
||||||
... BodyModificationFragment
|
... BodyModificationFragment
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fragment BodyModificationFragment on BodyModification {
|
fragment FuzzyDateFragment on FuzzyDate {
|
||||||
location
|
date
|
||||||
description
|
accuracy
|
||||||
|
}
|
||||||
|
fragment MeasurementsFragment on Measurements {
|
||||||
|
band_size
|
||||||
|
cup_size
|
||||||
|
waist
|
||||||
|
hip
|
||||||
}
|
}
|
||||||
fragment SceneFragment on Scene {
|
fragment SceneFragment on Scene {
|
||||||
id
|
id
|
||||||
|
|
@ -285,19 +298,27 @@ fragment SceneFragment on Scene {
|
||||||
... FingerprintFragment
|
... FingerprintFragment
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fragment TagFragment on Tag {
|
fragment ImageFragment on Image {
|
||||||
|
id
|
||||||
|
url
|
||||||
|
width
|
||||||
|
height
|
||||||
|
}
|
||||||
|
fragment StudioFragment on Studio {
|
||||||
name
|
name
|
||||||
id
|
id
|
||||||
|
urls {
|
||||||
|
... URLFragment
|
||||||
|
}
|
||||||
|
images {
|
||||||
|
... ImageFragment
|
||||||
|
}
|
||||||
}
|
}
|
||||||
fragment FuzzyDateFragment on FuzzyDate {
|
fragment PerformerAppearanceFragment on PerformerAppearance {
|
||||||
date
|
as
|
||||||
accuracy
|
performer {
|
||||||
}
|
... PerformerFragment
|
||||||
fragment MeasurementsFragment on Measurements {
|
}
|
||||||
band_size
|
|
||||||
cup_size
|
|
||||||
waist
|
|
||||||
hip
|
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
|
@ -367,10 +388,36 @@ fragment FuzzyDateFragment on FuzzyDate {
|
||||||
date
|
date
|
||||||
accuracy
|
accuracy
|
||||||
}
|
}
|
||||||
|
fragment MeasurementsFragment on Measurements {
|
||||||
|
band_size
|
||||||
|
cup_size
|
||||||
|
waist
|
||||||
|
hip
|
||||||
|
}
|
||||||
fragment BodyModificationFragment on BodyModification {
|
fragment BodyModificationFragment on BodyModification {
|
||||||
location
|
location
|
||||||
description
|
description
|
||||||
}
|
}
|
||||||
|
fragment ImageFragment on Image {
|
||||||
|
id
|
||||||
|
url
|
||||||
|
width
|
||||||
|
height
|
||||||
|
}
|
||||||
|
fragment URLFragment on URL {
|
||||||
|
url
|
||||||
|
type
|
||||||
|
}
|
||||||
|
fragment TagFragment on Tag {
|
||||||
|
name
|
||||||
|
id
|
||||||
|
}
|
||||||
|
fragment PerformerAppearanceFragment on PerformerAppearance {
|
||||||
|
as
|
||||||
|
performer {
|
||||||
|
... PerformerFragment
|
||||||
|
}
|
||||||
|
}
|
||||||
fragment FingerprintFragment on Fingerprint {
|
fragment FingerprintFragment on Fingerprint {
|
||||||
algorithm
|
algorithm
|
||||||
hash
|
hash
|
||||||
|
|
@ -401,32 +448,6 @@ fragment SceneFragment on Scene {
|
||||||
... FingerprintFragment
|
... FingerprintFragment
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fragment URLFragment on URL {
|
|
||||||
url
|
|
||||||
type
|
|
||||||
}
|
|
||||||
fragment ImageFragment on Image {
|
|
||||||
id
|
|
||||||
url
|
|
||||||
width
|
|
||||||
height
|
|
||||||
}
|
|
||||||
fragment TagFragment on Tag {
|
|
||||||
name
|
|
||||||
id
|
|
||||||
}
|
|
||||||
fragment PerformerAppearanceFragment on PerformerAppearance {
|
|
||||||
as
|
|
||||||
performer {
|
|
||||||
... PerformerFragment
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fragment MeasurementsFragment on Measurements {
|
|
||||||
band_size
|
|
||||||
cup_size
|
|
||||||
waist
|
|
||||||
hip
|
|
||||||
}
|
|
||||||
`
|
`
|
||||||
|
|
||||||
func (c *Client) FindScenesByFullFingerprints(ctx context.Context, fingerprints []*FingerprintQueryInput, httpRequestOptions ...client.HTTPRequestOption) (*FindScenesByFullFingerprints, error) {
|
func (c *Client) FindScenesByFullFingerprints(ctx context.Context, fingerprints []*FingerprintQueryInput, httpRequestOptions ...client.HTTPRequestOption) (*FindScenesByFullFingerprints, error) {
|
||||||
|
|
@ -447,6 +468,11 @@ const SearchSceneQuery = `query SearchScene ($term: String!) {
|
||||||
... SceneFragment
|
... SceneFragment
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fragment FingerprintFragment on Fingerprint {
|
||||||
|
algorithm
|
||||||
|
hash
|
||||||
|
duration
|
||||||
|
}
|
||||||
fragment URLFragment on URL {
|
fragment URLFragment on URL {
|
||||||
url
|
url
|
||||||
type
|
type
|
||||||
|
|
@ -457,9 +483,15 @@ fragment ImageFragment on Image {
|
||||||
width
|
width
|
||||||
height
|
height
|
||||||
}
|
}
|
||||||
fragment FuzzyDateFragment on FuzzyDate {
|
fragment TagFragment on Tag {
|
||||||
date
|
name
|
||||||
accuracy
|
id
|
||||||
|
}
|
||||||
|
fragment PerformerAppearanceFragment on PerformerAppearance {
|
||||||
|
as
|
||||||
|
performer {
|
||||||
|
... PerformerFragment
|
||||||
|
}
|
||||||
}
|
}
|
||||||
fragment MeasurementsFragment on Measurements {
|
fragment MeasurementsFragment on Measurements {
|
||||||
band_size
|
band_size
|
||||||
|
|
@ -506,16 +538,6 @@ fragment StudioFragment on Studio {
|
||||||
... ImageFragment
|
... ImageFragment
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fragment TagFragment on Tag {
|
|
||||||
name
|
|
||||||
id
|
|
||||||
}
|
|
||||||
fragment PerformerAppearanceFragment on PerformerAppearance {
|
|
||||||
as
|
|
||||||
performer {
|
|
||||||
... PerformerFragment
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fragment PerformerFragment on Performer {
|
fragment PerformerFragment on Performer {
|
||||||
id
|
id
|
||||||
name
|
name
|
||||||
|
|
@ -550,10 +572,9 @@ fragment PerformerFragment on Performer {
|
||||||
... BodyModificationFragment
|
... BodyModificationFragment
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fragment FingerprintFragment on Fingerprint {
|
fragment FuzzyDateFragment on FuzzyDate {
|
||||||
algorithm
|
date
|
||||||
hash
|
accuracy
|
||||||
duration
|
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
|
@ -653,6 +674,30 @@ const FindPerformerByIDQuery = `query FindPerformerByID ($id: ID!) {
|
||||||
... PerformerFragment
|
... PerformerFragment
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fragment URLFragment on URL {
|
||||||
|
url
|
||||||
|
type
|
||||||
|
}
|
||||||
|
fragment ImageFragment on Image {
|
||||||
|
id
|
||||||
|
url
|
||||||
|
width
|
||||||
|
height
|
||||||
|
}
|
||||||
|
fragment FuzzyDateFragment on FuzzyDate {
|
||||||
|
date
|
||||||
|
accuracy
|
||||||
|
}
|
||||||
|
fragment MeasurementsFragment on Measurements {
|
||||||
|
band_size
|
||||||
|
cup_size
|
||||||
|
waist
|
||||||
|
hip
|
||||||
|
}
|
||||||
|
fragment BodyModificationFragment on BodyModification {
|
||||||
|
location
|
||||||
|
description
|
||||||
|
}
|
||||||
fragment PerformerFragment on Performer {
|
fragment PerformerFragment on Performer {
|
||||||
id
|
id
|
||||||
name
|
name
|
||||||
|
|
@ -687,30 +732,6 @@ fragment PerformerFragment on Performer {
|
||||||
... BodyModificationFragment
|
... BodyModificationFragment
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fragment URLFragment on URL {
|
|
||||||
url
|
|
||||||
type
|
|
||||||
}
|
|
||||||
fragment ImageFragment on Image {
|
|
||||||
id
|
|
||||||
url
|
|
||||||
width
|
|
||||||
height
|
|
||||||
}
|
|
||||||
fragment FuzzyDateFragment on FuzzyDate {
|
|
||||||
date
|
|
||||||
accuracy
|
|
||||||
}
|
|
||||||
fragment MeasurementsFragment on Measurements {
|
|
||||||
band_size
|
|
||||||
cup_size
|
|
||||||
waist
|
|
||||||
hip
|
|
||||||
}
|
|
||||||
fragment BodyModificationFragment on BodyModification {
|
|
||||||
location
|
|
||||||
description
|
|
||||||
}
|
|
||||||
`
|
`
|
||||||
|
|
||||||
func (c *Client) FindPerformerByID(ctx context.Context, id string, httpRequestOptions ...client.HTTPRequestOption) (*FindPerformerByID, error) {
|
func (c *Client) FindPerformerByID(ctx context.Context, id string, httpRequestOptions ...client.HTTPRequestOption) (*FindPerformerByID, error) {
|
||||||
|
|
@ -731,22 +752,10 @@ const FindSceneByIDQuery = `query FindSceneByID ($id: ID!) {
|
||||||
... SceneFragment
|
... SceneFragment
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fragment ImageFragment on Image {
|
|
||||||
id
|
|
||||||
url
|
|
||||||
width
|
|
||||||
height
|
|
||||||
}
|
|
||||||
fragment TagFragment on Tag {
|
fragment TagFragment on Tag {
|
||||||
name
|
name
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
fragment PerformerAppearanceFragment on PerformerAppearance {
|
|
||||||
as
|
|
||||||
performer {
|
|
||||||
... PerformerFragment
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fragment FuzzyDateFragment on FuzzyDate {
|
fragment FuzzyDateFragment on FuzzyDate {
|
||||||
date
|
date
|
||||||
accuracy
|
accuracy
|
||||||
|
|
@ -762,58 +771,6 @@ fragment FingerprintFragment on Fingerprint {
|
||||||
hash
|
hash
|
||||||
duration
|
duration
|
||||||
}
|
}
|
||||||
fragment URLFragment on URL {
|
|
||||||
url
|
|
||||||
type
|
|
||||||
}
|
|
||||||
fragment StudioFragment on Studio {
|
|
||||||
name
|
|
||||||
id
|
|
||||||
urls {
|
|
||||||
... URLFragment
|
|
||||||
}
|
|
||||||
images {
|
|
||||||
... ImageFragment
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fragment PerformerFragment on Performer {
|
|
||||||
id
|
|
||||||
name
|
|
||||||
disambiguation
|
|
||||||
aliases
|
|
||||||
gender
|
|
||||||
merged_ids
|
|
||||||
urls {
|
|
||||||
... URLFragment
|
|
||||||
}
|
|
||||||
images {
|
|
||||||
... ImageFragment
|
|
||||||
}
|
|
||||||
birthdate {
|
|
||||||
... FuzzyDateFragment
|
|
||||||
}
|
|
||||||
ethnicity
|
|
||||||
country
|
|
||||||
eye_color
|
|
||||||
hair_color
|
|
||||||
height
|
|
||||||
measurements {
|
|
||||||
... MeasurementsFragment
|
|
||||||
}
|
|
||||||
breast_type
|
|
||||||
career_start_year
|
|
||||||
career_end_year
|
|
||||||
tattoos {
|
|
||||||
... BodyModificationFragment
|
|
||||||
}
|
|
||||||
piercings {
|
|
||||||
... BodyModificationFragment
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fragment BodyModificationFragment on BodyModification {
|
|
||||||
location
|
|
||||||
description
|
|
||||||
}
|
|
||||||
fragment SceneFragment on Scene {
|
fragment SceneFragment on Scene {
|
||||||
id
|
id
|
||||||
title
|
title
|
||||||
|
|
@ -839,6 +796,70 @@ fragment SceneFragment on Scene {
|
||||||
... FingerprintFragment
|
... FingerprintFragment
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fragment URLFragment on URL {
|
||||||
|
url
|
||||||
|
type
|
||||||
|
}
|
||||||
|
fragment ImageFragment on Image {
|
||||||
|
id
|
||||||
|
url
|
||||||
|
width
|
||||||
|
height
|
||||||
|
}
|
||||||
|
fragment StudioFragment on Studio {
|
||||||
|
name
|
||||||
|
id
|
||||||
|
urls {
|
||||||
|
... URLFragment
|
||||||
|
}
|
||||||
|
images {
|
||||||
|
... ImageFragment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fragment PerformerAppearanceFragment on PerformerAppearance {
|
||||||
|
as
|
||||||
|
performer {
|
||||||
|
... PerformerFragment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fragment PerformerFragment on Performer {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
disambiguation
|
||||||
|
aliases
|
||||||
|
gender
|
||||||
|
merged_ids
|
||||||
|
urls {
|
||||||
|
... URLFragment
|
||||||
|
}
|
||||||
|
images {
|
||||||
|
... ImageFragment
|
||||||
|
}
|
||||||
|
birthdate {
|
||||||
|
... FuzzyDateFragment
|
||||||
|
}
|
||||||
|
ethnicity
|
||||||
|
country
|
||||||
|
eye_color
|
||||||
|
hair_color
|
||||||
|
height
|
||||||
|
measurements {
|
||||||
|
... MeasurementsFragment
|
||||||
|
}
|
||||||
|
breast_type
|
||||||
|
career_start_year
|
||||||
|
career_end_year
|
||||||
|
tattoos {
|
||||||
|
... BodyModificationFragment
|
||||||
|
}
|
||||||
|
piercings {
|
||||||
|
... BodyModificationFragment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fragment BodyModificationFragment on BodyModification {
|
||||||
|
location
|
||||||
|
description
|
||||||
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
func (c *Client) FindSceneByID(ctx context.Context, id string, httpRequestOptions ...client.HTTPRequestOption) (*FindSceneByID, error) {
|
func (c *Client) FindSceneByID(ctx context.Context, id string, httpRequestOptions ...client.HTTPRequestOption) (*FindSceneByID, error) {
|
||||||
|
|
@ -889,3 +910,43 @@ func (c *Client) Me(ctx context.Context, httpRequestOptions ...client.HTTPReques
|
||||||
|
|
||||||
return &res, nil
|
return &res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const SubmitSceneDraftQuery = `mutation SubmitSceneDraft ($input: SceneDraftInput!) {
|
||||||
|
submitSceneDraft(input: $input) {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
func (c *Client) SubmitSceneDraft(ctx context.Context, input SceneDraftInput, httpRequestOptions ...client.HTTPRequestOption) (*SubmitSceneDraftPayload, error) {
|
||||||
|
vars := map[string]interface{}{
|
||||||
|
"input": input,
|
||||||
|
}
|
||||||
|
|
||||||
|
var res SubmitSceneDraftPayload
|
||||||
|
if err := c.Client.Post(ctx, SubmitSceneDraftQuery, &res, vars, httpRequestOptions...); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const SubmitPerformerDraftQuery = `mutation SubmitPerformerDraft ($input: PerformerDraftInput!) {
|
||||||
|
submitPerformerDraft(input: $input) {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
func (c *Client) SubmitPerformerDraft(ctx context.Context, input PerformerDraftInput, httpRequestOptions ...client.HTTPRequestOption) (*SubmitPerformerDraftPayload, error) {
|
||||||
|
vars := map[string]interface{}{
|
||||||
|
"input": input,
|
||||||
|
}
|
||||||
|
|
||||||
|
var res SubmitPerformerDraftPayload
|
||||||
|
if err := c.Client.Post(ctx, SubmitPerformerDraftQuery, &res, vars, httpRequestOptions...); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &res, nil
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,10 @@ import (
|
||||||
"github.com/99designs/gqlgen/graphql"
|
"github.com/99designs/gqlgen/graphql"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type DraftData interface {
|
||||||
|
IsDraftData()
|
||||||
|
}
|
||||||
|
|
||||||
type EditDetails interface {
|
type EditDetails interface {
|
||||||
IsEditDetails()
|
IsEditDetails()
|
||||||
}
|
}
|
||||||
|
|
@ -19,6 +23,18 @@ type EditTarget interface {
|
||||||
IsEditTarget()
|
IsEditTarget()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SceneDraftPerformer interface {
|
||||||
|
IsSceneDraftPerformer()
|
||||||
|
}
|
||||||
|
|
||||||
|
type SceneDraftStudio interface {
|
||||||
|
IsSceneDraftStudio()
|
||||||
|
}
|
||||||
|
|
||||||
|
type SceneDraftTag interface {
|
||||||
|
IsSceneDraftTag()
|
||||||
|
}
|
||||||
|
|
||||||
type ActivateNewUserInput struct {
|
type ActivateNewUserInput struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Email string `json:"email"`
|
Email string `json:"email"`
|
||||||
|
|
@ -60,6 +76,37 @@ type DateCriterionInput struct {
|
||||||
Modifier CriterionModifier `json:"modifier"`
|
Modifier CriterionModifier `json:"modifier"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Draft struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Created time.Time `json:"created"`
|
||||||
|
Expires time.Time `json:"expires"`
|
||||||
|
Data DraftData `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type DraftEntity struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
ID *string `json:"id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (DraftEntity) IsSceneDraftPerformer() {}
|
||||||
|
func (DraftEntity) IsSceneDraftStudio() {}
|
||||||
|
func (DraftEntity) IsSceneDraftTag() {}
|
||||||
|
|
||||||
|
type DraftEntityInput struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
ID *string `json:"id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type DraftFingerprint struct {
|
||||||
|
Hash string `json:"hash"`
|
||||||
|
Algorithm FingerprintAlgorithm `json:"algorithm"`
|
||||||
|
Duration int `json:"duration"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type DraftSubmissionStatus struct {
|
||||||
|
ID *string `json:"id"`
|
||||||
|
}
|
||||||
|
|
||||||
type Edit struct {
|
type Edit struct {
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
User *User `json:"user"`
|
User *User `json:"user"`
|
||||||
|
|
@ -75,13 +122,15 @@ type Edit struct {
|
||||||
// Entity specific options
|
// Entity specific options
|
||||||
Options *PerformerEditOptions `json:"options"`
|
Options *PerformerEditOptions `json:"options"`
|
||||||
Comments []*EditComment `json:"comments"`
|
Comments []*EditComment `json:"comments"`
|
||||||
Votes []*VoteComment `json:"votes"`
|
Votes []*EditVote `json:"votes"`
|
||||||
// = Accepted - Rejected
|
// = Accepted - Rejected
|
||||||
VoteCount int `json:"vote_count"`
|
VoteCount int `json:"vote_count"`
|
||||||
Status VoteStatusEnum `json:"status"`
|
// Is the edit considered destructive.
|
||||||
Applied bool `json:"applied"`
|
Destructive bool `json:"destructive"`
|
||||||
Created time.Time `json:"created"`
|
Status VoteStatusEnum `json:"status"`
|
||||||
Updated time.Time `json:"updated"`
|
Applied bool `json:"applied"`
|
||||||
|
Created time.Time `json:"created"`
|
||||||
|
Updated time.Time `json:"updated"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type EditComment struct {
|
type EditComment struct {
|
||||||
|
|
@ -123,10 +172,15 @@ type EditInput struct {
|
||||||
Comment *string `json:"comment"`
|
Comment *string `json:"comment"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type EditVote struct {
|
||||||
|
User *User `json:"user"`
|
||||||
|
Date time.Time `json:"date"`
|
||||||
|
Vote VoteTypeEnum `json:"vote"`
|
||||||
|
}
|
||||||
|
|
||||||
type EditVoteInput struct {
|
type EditVoteInput struct {
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
Comment *string `json:"comment"`
|
Vote VoteTypeEnum `json:"vote"`
|
||||||
Type VoteTypeEnum `json:"type"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type EyeColorCriterionInput struct {
|
type EyeColorCriterionInput struct {
|
||||||
|
|
@ -135,24 +189,30 @@ type EyeColorCriterionInput struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type Fingerprint struct {
|
type Fingerprint struct {
|
||||||
Hash string `json:"hash"`
|
Hash string `json:"hash"`
|
||||||
Algorithm FingerprintAlgorithm `json:"algorithm"`
|
Algorithm FingerprintAlgorithm `json:"algorithm"`
|
||||||
Duration int `json:"duration"`
|
Duration int `json:"duration"`
|
||||||
Submissions int `json:"submissions"`
|
Submissions int `json:"submissions"`
|
||||||
Created time.Time `json:"created"`
|
Created time.Time `json:"created"`
|
||||||
Updated time.Time `json:"updated"`
|
Updated time.Time `json:"updated"`
|
||||||
|
UserSubmitted bool `json:"user_submitted"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type FingerprintEditInput struct {
|
type FingerprintEditInput struct {
|
||||||
Hash string `json:"hash"`
|
UserIds []string `json:"user_ids"`
|
||||||
Algorithm FingerprintAlgorithm `json:"algorithm"`
|
Hash string `json:"hash"`
|
||||||
Duration int `json:"duration"`
|
Algorithm FingerprintAlgorithm `json:"algorithm"`
|
||||||
Submissions int `json:"submissions"`
|
Duration int `json:"duration"`
|
||||||
Created time.Time `json:"created"`
|
Created time.Time `json:"created"`
|
||||||
Updated time.Time `json:"updated"`
|
// @deprecated(reason: "unused")
|
||||||
|
Submissions *int `json:"submissions"`
|
||||||
|
// @deprecated(reason: "unused")
|
||||||
|
Updated *time.Time `json:"updated"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type FingerprintInput struct {
|
type FingerprintInput struct {
|
||||||
|
// assumes current user if omitted. Ignored for non-modify Users
|
||||||
|
UserIds []string `json:"user_ids"`
|
||||||
Hash string `json:"hash"`
|
Hash string `json:"hash"`
|
||||||
Algorithm FingerprintAlgorithm `json:"algorithm"`
|
Algorithm FingerprintAlgorithm `json:"algorithm"`
|
||||||
Duration int `json:"duration"`
|
Duration int `json:"duration"`
|
||||||
|
|
@ -166,6 +226,7 @@ type FingerprintQueryInput struct {
|
||||||
type FingerprintSubmission struct {
|
type FingerprintSubmission struct {
|
||||||
SceneID string `json:"scene_id"`
|
SceneID string `json:"scene_id"`
|
||||||
Fingerprint *FingerprintInput `json:"fingerprint"`
|
Fingerprint *FingerprintInput `json:"fingerprint"`
|
||||||
|
Unmatch *bool `json:"unmatch"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type FuzzyDate struct {
|
type FuzzyDate struct {
|
||||||
|
|
@ -238,6 +299,11 @@ type MultiIDCriterionInput struct {
|
||||||
Modifier CriterionModifier `json:"modifier"`
|
Modifier CriterionModifier `json:"modifier"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type MultiStringCriterionInput struct {
|
||||||
|
Value []string `json:"value"`
|
||||||
|
Modifier CriterionModifier `json:"modifier"`
|
||||||
|
}
|
||||||
|
|
||||||
type NewUserInput struct {
|
type NewUserInput struct {
|
||||||
Email string `json:"email"`
|
Email string `json:"email"`
|
||||||
InviteKey *string `json:"invite_key"`
|
InviteKey *string `json:"invite_key"`
|
||||||
|
|
@ -272,7 +338,8 @@ type Performer struct {
|
||||||
Studios []*PerformerStudio `json:"studios"`
|
Studios []*PerformerStudio `json:"studios"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (Performer) IsEditTarget() {}
|
func (Performer) IsEditTarget() {}
|
||||||
|
func (Performer) IsSceneDraftPerformer() {}
|
||||||
|
|
||||||
type PerformerAppearance struct {
|
type PerformerAppearance struct {
|
||||||
Performer *Performer `json:"performer"`
|
Performer *Performer `json:"performer"`
|
||||||
|
|
@ -305,12 +372,55 @@ type PerformerCreateInput struct {
|
||||||
Tattoos []*BodyModificationInput `json:"tattoos"`
|
Tattoos []*BodyModificationInput `json:"tattoos"`
|
||||||
Piercings []*BodyModificationInput `json:"piercings"`
|
Piercings []*BodyModificationInput `json:"piercings"`
|
||||||
ImageIds []string `json:"image_ids"`
|
ImageIds []string `json:"image_ids"`
|
||||||
|
DraftID *string `json:"draft_id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type PerformerDestroyInput struct {
|
type PerformerDestroyInput struct {
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type PerformerDraft struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Aliases *string `json:"aliases"`
|
||||||
|
Gender *string `json:"gender"`
|
||||||
|
Birthdate *string `json:"birthdate"`
|
||||||
|
Urls []string `json:"urls"`
|
||||||
|
Ethnicity *string `json:"ethnicity"`
|
||||||
|
Country *string `json:"country"`
|
||||||
|
EyeColor *string `json:"eye_color"`
|
||||||
|
HairColor *string `json:"hair_color"`
|
||||||
|
Height *string `json:"height"`
|
||||||
|
Measurements *string `json:"measurements"`
|
||||||
|
BreastType *string `json:"breast_type"`
|
||||||
|
Tattoos *string `json:"tattoos"`
|
||||||
|
Piercings *string `json:"piercings"`
|
||||||
|
CareerStartYear *int `json:"career_start_year"`
|
||||||
|
CareerEndYear *int `json:"career_end_year"`
|
||||||
|
Image *Image `json:"image"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (PerformerDraft) IsDraftData() {}
|
||||||
|
|
||||||
|
type PerformerDraftInput struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Aliases *string `json:"aliases"`
|
||||||
|
Gender *string `json:"gender"`
|
||||||
|
Birthdate *string `json:"birthdate"`
|
||||||
|
Urls []string `json:"urls"`
|
||||||
|
Ethnicity *string `json:"ethnicity"`
|
||||||
|
Country *string `json:"country"`
|
||||||
|
EyeColor *string `json:"eye_color"`
|
||||||
|
HairColor *string `json:"hair_color"`
|
||||||
|
Height *string `json:"height"`
|
||||||
|
Measurements *string `json:"measurements"`
|
||||||
|
BreastType *string `json:"breast_type"`
|
||||||
|
Tattoos *string `json:"tattoos"`
|
||||||
|
Piercings *string `json:"piercings"`
|
||||||
|
CareerStartYear *int `json:"career_start_year"`
|
||||||
|
CareerEndYear *int `json:"career_end_year"`
|
||||||
|
Image *graphql.Upload `json:"image"`
|
||||||
|
}
|
||||||
|
|
||||||
type PerformerEdit struct {
|
type PerformerEdit struct {
|
||||||
Name *string `json:"name"`
|
Name *string `json:"name"`
|
||||||
Disambiguation *string `json:"disambiguation"`
|
Disambiguation *string `json:"disambiguation"`
|
||||||
|
|
@ -340,6 +450,7 @@ type PerformerEdit struct {
|
||||||
RemovedPiercings []*BodyModification `json:"removed_piercings"`
|
RemovedPiercings []*BodyModification `json:"removed_piercings"`
|
||||||
AddedImages []*Image `json:"added_images"`
|
AddedImages []*Image `json:"added_images"`
|
||||||
RemovedImages []*Image `json:"removed_images"`
|
RemovedImages []*Image `json:"removed_images"`
|
||||||
|
DraftID *string `json:"draft_id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (PerformerEdit) IsEditDetails() {}
|
func (PerformerEdit) IsEditDetails() {}
|
||||||
|
|
@ -363,6 +474,7 @@ type PerformerEditDetailsInput struct {
|
||||||
Tattoos []*BodyModificationInput `json:"tattoos"`
|
Tattoos []*BodyModificationInput `json:"tattoos"`
|
||||||
Piercings []*BodyModificationInput `json:"piercings"`
|
Piercings []*BodyModificationInput `json:"piercings"`
|
||||||
ImageIds []string `json:"image_ids"`
|
ImageIds []string `json:"image_ids"`
|
||||||
|
DraftID *string `json:"draft_id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type PerformerEditInput struct {
|
type PerformerEditInput struct {
|
||||||
|
|
@ -459,6 +571,11 @@ type QueryScenesResultType struct {
|
||||||
Scenes []*Scene `json:"scenes"`
|
Scenes []*Scene `json:"scenes"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type QuerySitesResultType struct {
|
||||||
|
Count int `json:"count"`
|
||||||
|
Sites []*Site `json:"sites"`
|
||||||
|
}
|
||||||
|
|
||||||
type QuerySpec struct {
|
type QuerySpec struct {
|
||||||
Page *int `json:"page"`
|
Page *int `json:"page"`
|
||||||
PerPage *int `json:"per_page"`
|
PerPage *int `json:"per_page"`
|
||||||
|
|
@ -514,6 +631,7 @@ type Scene struct {
|
||||||
Duration *int `json:"duration"`
|
Duration *int `json:"duration"`
|
||||||
Director *string `json:"director"`
|
Director *string `json:"director"`
|
||||||
Deleted bool `json:"deleted"`
|
Deleted bool `json:"deleted"`
|
||||||
|
Edits []*Edit `json:"edits"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (Scene) IsEditTarget() {}
|
func (Scene) IsEditTarget() {}
|
||||||
|
|
@ -536,13 +654,39 @@ type SceneDestroyInput struct {
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SceneDraft struct {
|
||||||
|
Title *string `json:"title"`
|
||||||
|
Details *string `json:"details"`
|
||||||
|
URL *URL `json:"url"`
|
||||||
|
Date *string `json:"date"`
|
||||||
|
Studio SceneDraftStudio `json:"studio"`
|
||||||
|
Performers []SceneDraftPerformer `json:"performers"`
|
||||||
|
Tags []SceneDraftTag `json:"tags"`
|
||||||
|
Image *Image `json:"image"`
|
||||||
|
Fingerprints []*DraftFingerprint `json:"fingerprints"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (SceneDraft) IsDraftData() {}
|
||||||
|
|
||||||
|
type SceneDraftInput struct {
|
||||||
|
Title *string `json:"title"`
|
||||||
|
Details *string `json:"details"`
|
||||||
|
URL *string `json:"url"`
|
||||||
|
Date *string `json:"date"`
|
||||||
|
Studio *DraftEntityInput `json:"studio"`
|
||||||
|
Performers []*DraftEntityInput `json:"performers"`
|
||||||
|
Tags []*DraftEntityInput `json:"tags"`
|
||||||
|
Image *graphql.Upload `json:"image"`
|
||||||
|
Fingerprints []*FingerprintInput `json:"fingerprints"`
|
||||||
|
}
|
||||||
|
|
||||||
type SceneEdit struct {
|
type SceneEdit struct {
|
||||||
Title *string `json:"title"`
|
Title *string `json:"title"`
|
||||||
Details *string `json:"details"`
|
Details *string `json:"details"`
|
||||||
AddedUrls []*URL `json:"added_urls"`
|
AddedUrls []*URL `json:"added_urls"`
|
||||||
RemovedUrls []*URL `json:"removed_urls"`
|
RemovedUrls []*URL `json:"removed_urls"`
|
||||||
Date *string `json:"date"`
|
Date *string `json:"date"`
|
||||||
StudioID *string `json:"studio_id"`
|
Studio *Studio `json:"studio"`
|
||||||
// Added or modified performer appearance entries
|
// Added or modified performer appearance entries
|
||||||
AddedPerformers []*PerformerAppearance `json:"added_performers"`
|
AddedPerformers []*PerformerAppearance `json:"added_performers"`
|
||||||
RemovedPerformers []*PerformerAppearance `json:"removed_performers"`
|
RemovedPerformers []*PerformerAppearance `json:"removed_performers"`
|
||||||
|
|
@ -554,6 +698,7 @@ type SceneEdit struct {
|
||||||
RemovedFingerprints []*Fingerprint `json:"removed_fingerprints"`
|
RemovedFingerprints []*Fingerprint `json:"removed_fingerprints"`
|
||||||
Duration *int `json:"duration"`
|
Duration *int `json:"duration"`
|
||||||
Director *string `json:"director"`
|
Director *string `json:"director"`
|
||||||
|
DraftID *string `json:"draft_id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (SceneEdit) IsEditDetails() {}
|
func (SceneEdit) IsEditDetails() {}
|
||||||
|
|
@ -567,9 +712,10 @@ type SceneEditDetailsInput struct {
|
||||||
Performers []*PerformerAppearanceInput `json:"performers"`
|
Performers []*PerformerAppearanceInput `json:"performers"`
|
||||||
TagIds []string `json:"tag_ids"`
|
TagIds []string `json:"tag_ids"`
|
||||||
ImageIds []string `json:"image_ids"`
|
ImageIds []string `json:"image_ids"`
|
||||||
Fingerprints []*FingerprintEditInput `json:"fingerprints"`
|
|
||||||
Duration *int `json:"duration"`
|
Duration *int `json:"duration"`
|
||||||
Director *string `json:"director"`
|
Director *string `json:"director"`
|
||||||
|
Fingerprints []*FingerprintInput `json:"fingerprints"`
|
||||||
|
DraftID *string `json:"draft_id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type SceneEditInput struct {
|
type SceneEditInput struct {
|
||||||
|
|
@ -599,7 +745,7 @@ type SceneFilterType struct {
|
||||||
// Filter to include scenes with performer appearing as alias
|
// Filter to include scenes with performer appearing as alias
|
||||||
Alias *StringCriterionInput `json:"alias"`
|
Alias *StringCriterionInput `json:"alias"`
|
||||||
// Filter to only include scenes with these fingerprints
|
// Filter to only include scenes with these fingerprints
|
||||||
Fingerprints *MultiIDCriterionInput `json:"fingerprints"`
|
Fingerprints *MultiStringCriterionInput `json:"fingerprints"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type SceneUpdateInput struct {
|
type SceneUpdateInput struct {
|
||||||
|
|
@ -617,6 +763,50 @@ type SceneUpdateInput struct {
|
||||||
Director *string `json:"director"`
|
Director *string `json:"director"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Site struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Description *string `json:"description"`
|
||||||
|
URL *string `json:"url"`
|
||||||
|
Regex *string `json:"regex"`
|
||||||
|
ValidTypes []ValidSiteTypeEnum `json:"valid_types"`
|
||||||
|
Icon string `json:"icon"`
|
||||||
|
Created time.Time `json:"created"`
|
||||||
|
Updated time.Time `json:"updated"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SiteCreateInput struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Description *string `json:"description"`
|
||||||
|
URL *string `json:"url"`
|
||||||
|
Regex *string `json:"regex"`
|
||||||
|
ValidTypes []ValidSiteTypeEnum `json:"valid_types"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SiteDestroyInput struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SiteUpdateInput struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Description *string `json:"description"`
|
||||||
|
URL *string `json:"url"`
|
||||||
|
Regex *string `json:"regex"`
|
||||||
|
ValidTypes []ValidSiteTypeEnum `json:"valid_types"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type StashBoxConfig struct {
|
||||||
|
HostURL string `json:"host_url"`
|
||||||
|
RequireInvite bool `json:"require_invite"`
|
||||||
|
RequireActivation bool `json:"require_activation"`
|
||||||
|
VotePromotionThreshold *int `json:"vote_promotion_threshold"`
|
||||||
|
VoteApplicationThreshold int `json:"vote_application_threshold"`
|
||||||
|
VotingPeriod int `json:"voting_period"`
|
||||||
|
MinDestructiveVotingPeriod int `json:"min_destructive_voting_period"`
|
||||||
|
VoteCronInterval string `json:"vote_cron_interval"`
|
||||||
|
}
|
||||||
|
|
||||||
type StringCriterionInput struct {
|
type StringCriterionInput struct {
|
||||||
Value string `json:"value"`
|
Value string `json:"value"`
|
||||||
Modifier CriterionModifier `json:"modifier"`
|
Modifier CriterionModifier `json:"modifier"`
|
||||||
|
|
@ -632,14 +822,14 @@ type Studio struct {
|
||||||
Deleted bool `json:"deleted"`
|
Deleted bool `json:"deleted"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (Studio) IsEditTarget() {}
|
func (Studio) IsEditTarget() {}
|
||||||
|
func (Studio) IsSceneDraftStudio() {}
|
||||||
|
|
||||||
type StudioCreateInput struct {
|
type StudioCreateInput struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Urls []*URLInput `json:"urls"`
|
Urls []*URLInput `json:"urls"`
|
||||||
ParentID *string `json:"parent_id"`
|
ParentID *string `json:"parent_id"`
|
||||||
ChildStudioIds []string `json:"child_studio_ids"`
|
ImageIds []string `json:"image_ids"`
|
||||||
ImageIds []string `json:"image_ids"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type StudioDestroyInput struct {
|
type StudioDestroyInput struct {
|
||||||
|
|
@ -649,23 +839,20 @@ type StudioDestroyInput struct {
|
||||||
type StudioEdit struct {
|
type StudioEdit struct {
|
||||||
Name *string `json:"name"`
|
Name *string `json:"name"`
|
||||||
// Added and modified URLs
|
// Added and modified URLs
|
||||||
AddedUrls []*URL `json:"added_urls"`
|
AddedUrls []*URL `json:"added_urls"`
|
||||||
RemovedUrls []*URL `json:"removed_urls"`
|
RemovedUrls []*URL `json:"removed_urls"`
|
||||||
Parent *Studio `json:"parent"`
|
Parent *Studio `json:"parent"`
|
||||||
AddedChildStudios []*Studio `json:"added_child_studios"`
|
AddedImages []*Image `json:"added_images"`
|
||||||
RemovedChildStudios []*Studio `json:"removed_child_studios"`
|
RemovedImages []*Image `json:"removed_images"`
|
||||||
AddedImages []*Image `json:"added_images"`
|
|
||||||
RemovedImages []*Image `json:"removed_images"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (StudioEdit) IsEditDetails() {}
|
func (StudioEdit) IsEditDetails() {}
|
||||||
|
|
||||||
type StudioEditDetailsInput struct {
|
type StudioEditDetailsInput struct {
|
||||||
Name *string `json:"name"`
|
Name *string `json:"name"`
|
||||||
Urls []*URLInput `json:"urls"`
|
Urls []*URLInput `json:"urls"`
|
||||||
ParentID *string `json:"parent_id"`
|
ParentID *string `json:"parent_id"`
|
||||||
ChildStudioIds []string `json:"child_studio_ids"`
|
ImageIds []string `json:"image_ids"`
|
||||||
ImageIds []string `json:"image_ids"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type StudioEditInput struct {
|
type StudioEditInput struct {
|
||||||
|
|
@ -686,12 +873,11 @@ type StudioFilterType struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type StudioUpdateInput struct {
|
type StudioUpdateInput struct {
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
Name *string `json:"name"`
|
Name *string `json:"name"`
|
||||||
Urls []*URLInput `json:"urls"`
|
Urls []*URLInput `json:"urls"`
|
||||||
ParentID *string `json:"parent_id"`
|
ParentID *string `json:"parent_id"`
|
||||||
ChildStudioIds []string `json:"child_studio_ids"`
|
ImageIds []string `json:"image_ids"`
|
||||||
ImageIds []string `json:"image_ids"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Tag struct {
|
type Tag struct {
|
||||||
|
|
@ -704,7 +890,8 @@ type Tag struct {
|
||||||
Category *TagCategory `json:"category"`
|
Category *TagCategory `json:"category"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (Tag) IsEditTarget() {}
|
func (Tag) IsEditTarget() {}
|
||||||
|
func (Tag) IsSceneDraftTag() {}
|
||||||
|
|
||||||
type TagCategory struct {
|
type TagCategory struct {
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
|
|
@ -742,11 +929,11 @@ type TagDestroyInput struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type TagEdit struct {
|
type TagEdit struct {
|
||||||
Name *string `json:"name"`
|
Name *string `json:"name"`
|
||||||
Description *string `json:"description"`
|
Description *string `json:"description"`
|
||||||
AddedAliases []string `json:"added_aliases"`
|
AddedAliases []string `json:"added_aliases"`
|
||||||
RemovedAliases []string `json:"removed_aliases"`
|
RemovedAliases []string `json:"removed_aliases"`
|
||||||
CategoryID *string `json:"category_id"`
|
Category *TagCategory `json:"category"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (TagEdit) IsEditDetails() {}
|
func (TagEdit) IsEditDetails() {}
|
||||||
|
|
@ -786,11 +973,12 @@ type TagUpdateInput struct {
|
||||||
type URL struct {
|
type URL struct {
|
||||||
URL string `json:"url"`
|
URL string `json:"url"`
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
|
Site *Site `json:"site"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type URLInput struct {
|
type URLInput struct {
|
||||||
URL string `json:"url"`
|
URL string `json:"url"`
|
||||||
Type string `json:"type"`
|
SiteID string `json:"site_id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type User struct {
|
type User struct {
|
||||||
|
|
@ -801,12 +989,11 @@ type User struct {
|
||||||
// Should not be visible to other users
|
// Should not be visible to other users
|
||||||
Email *string `json:"email"`
|
Email *string `json:"email"`
|
||||||
// Should not be visible to other users
|
// Should not be visible to other users
|
||||||
APIKey *string `json:"api_key"`
|
APIKey *string `json:"api_key"`
|
||||||
SuccessfulEdits int `json:"successful_edits"`
|
// Vote counts by type
|
||||||
UnsuccessfulEdits int `json:"unsuccessful_edits"`
|
VoteCount *UserVoteCount `json:"vote_count"`
|
||||||
SuccessfulVotes int `json:"successful_votes"`
|
// Edit counts by status
|
||||||
// Votes on unsuccessful edits
|
EditCount *UserEditCount `json:"edit_count"`
|
||||||
UnsuccessfulVotes int `json:"unsuccessful_votes"`
|
|
||||||
// Calls to the API from this user over a configurable time period
|
// Calls to the API from this user over a configurable time period
|
||||||
APICalls int `json:"api_calls"`
|
APICalls int `json:"api_calls"`
|
||||||
InvitedBy *User `json:"invited_by"`
|
InvitedBy *User `json:"invited_by"`
|
||||||
|
|
@ -834,6 +1021,16 @@ type UserDestroyInput struct {
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type UserEditCount struct {
|
||||||
|
Accepted int `json:"accepted"`
|
||||||
|
Rejected int `json:"rejected"`
|
||||||
|
Pending int `json:"pending"`
|
||||||
|
ImmediateAccepted int `json:"immediate_accepted"`
|
||||||
|
ImmediateRejected int `json:"immediate_rejected"`
|
||||||
|
Failed int `json:"failed"`
|
||||||
|
Canceled int `json:"canceled"`
|
||||||
|
}
|
||||||
|
|
||||||
type UserFilterType struct {
|
type UserFilterType struct {
|
||||||
// Filter to search user name - assumes like query unless quoted
|
// Filter to search user name - assumes like query unless quoted
|
||||||
Name *string `json:"name"`
|
Name *string `json:"name"`
|
||||||
|
|
@ -866,19 +1063,21 @@ type UserUpdateInput struct {
|
||||||
Email *string `json:"email"`
|
Email *string `json:"email"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type UserVoteCount struct {
|
||||||
|
Abstain int `json:"abstain"`
|
||||||
|
Accept int `json:"accept"`
|
||||||
|
Reject int `json:"reject"`
|
||||||
|
ImmediateAccept int `json:"immediate_accept"`
|
||||||
|
ImmediateReject int `json:"immediate_reject"`
|
||||||
|
}
|
||||||
|
|
||||||
type Version struct {
|
type Version struct {
|
||||||
Hash string `json:"hash"`
|
Hash string `json:"hash"`
|
||||||
BuildTime string `json:"build_time"`
|
BuildTime string `json:"build_time"`
|
||||||
|
BuildType string `json:"build_type"`
|
||||||
Version string `json:"version"`
|
Version string `json:"version"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type VoteComment struct {
|
|
||||||
User *User `json:"user"`
|
|
||||||
Date *string `json:"date"`
|
|
||||||
Comment *string `json:"comment"`
|
|
||||||
Type *VoteTypeEnum `json:"type"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type BreastTypeEnum string
|
type BreastTypeEnum string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
@ -1435,6 +1634,7 @@ const (
|
||||||
RoleEnumInvite RoleEnum = "INVITE"
|
RoleEnumInvite RoleEnum = "INVITE"
|
||||||
// May grant and rescind invite tokens and resind invite keys
|
// May grant and rescind invite tokens and resind invite keys
|
||||||
RoleEnumManageInvites RoleEnum = "MANAGE_INVITES"
|
RoleEnumManageInvites RoleEnum = "MANAGE_INVITES"
|
||||||
|
RoleEnumBot RoleEnum = "BOT"
|
||||||
)
|
)
|
||||||
|
|
||||||
var AllRoleEnum = []RoleEnum{
|
var AllRoleEnum = []RoleEnum{
|
||||||
|
|
@ -1445,11 +1645,12 @@ var AllRoleEnum = []RoleEnum{
|
||||||
RoleEnumAdmin,
|
RoleEnumAdmin,
|
||||||
RoleEnumInvite,
|
RoleEnumInvite,
|
||||||
RoleEnumManageInvites,
|
RoleEnumManageInvites,
|
||||||
|
RoleEnumBot,
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e RoleEnum) IsValid() bool {
|
func (e RoleEnum) IsValid() bool {
|
||||||
switch e {
|
switch e {
|
||||||
case RoleEnumRead, RoleEnumVote, RoleEnumEdit, RoleEnumModify, RoleEnumAdmin, RoleEnumInvite, RoleEnumManageInvites:
|
case RoleEnumRead, RoleEnumVote, RoleEnumEdit, RoleEnumModify, RoleEnumAdmin, RoleEnumInvite, RoleEnumManageInvites, RoleEnumBot:
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
|
@ -1605,6 +1806,49 @@ func (e TargetTypeEnum) MarshalGQL(w io.Writer) {
|
||||||
fmt.Fprint(w, strconv.Quote(e.String()))
|
fmt.Fprint(w, strconv.Quote(e.String()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ValidSiteTypeEnum string
|
||||||
|
|
||||||
|
const (
|
||||||
|
ValidSiteTypeEnumPerformer ValidSiteTypeEnum = "PERFORMER"
|
||||||
|
ValidSiteTypeEnumScene ValidSiteTypeEnum = "SCENE"
|
||||||
|
ValidSiteTypeEnumStudio ValidSiteTypeEnum = "STUDIO"
|
||||||
|
)
|
||||||
|
|
||||||
|
var AllValidSiteTypeEnum = []ValidSiteTypeEnum{
|
||||||
|
ValidSiteTypeEnumPerformer,
|
||||||
|
ValidSiteTypeEnumScene,
|
||||||
|
ValidSiteTypeEnumStudio,
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e ValidSiteTypeEnum) IsValid() bool {
|
||||||
|
switch e {
|
||||||
|
case ValidSiteTypeEnumPerformer, ValidSiteTypeEnumScene, ValidSiteTypeEnumStudio:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e ValidSiteTypeEnum) String() string {
|
||||||
|
return string(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *ValidSiteTypeEnum) UnmarshalGQL(v interface{}) error {
|
||||||
|
str, ok := v.(string)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("enums must be strings")
|
||||||
|
}
|
||||||
|
|
||||||
|
*e = ValidSiteTypeEnum(str)
|
||||||
|
if !e.IsValid() {
|
||||||
|
return fmt.Errorf("%s is not a valid ValidSiteTypeEnum", str)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e ValidSiteTypeEnum) MarshalGQL(w io.Writer) {
|
||||||
|
fmt.Fprint(w, strconv.Quote(e.String()))
|
||||||
|
}
|
||||||
|
|
||||||
type VoteStatusEnum string
|
type VoteStatusEnum string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
@ -1613,6 +1857,8 @@ const (
|
||||||
VoteStatusEnumPending VoteStatusEnum = "PENDING"
|
VoteStatusEnumPending VoteStatusEnum = "PENDING"
|
||||||
VoteStatusEnumImmediateAccepted VoteStatusEnum = "IMMEDIATE_ACCEPTED"
|
VoteStatusEnumImmediateAccepted VoteStatusEnum = "IMMEDIATE_ACCEPTED"
|
||||||
VoteStatusEnumImmediateRejected VoteStatusEnum = "IMMEDIATE_REJECTED"
|
VoteStatusEnumImmediateRejected VoteStatusEnum = "IMMEDIATE_REJECTED"
|
||||||
|
VoteStatusEnumFailed VoteStatusEnum = "FAILED"
|
||||||
|
VoteStatusEnumCanceled VoteStatusEnum = "CANCELED"
|
||||||
)
|
)
|
||||||
|
|
||||||
var AllVoteStatusEnum = []VoteStatusEnum{
|
var AllVoteStatusEnum = []VoteStatusEnum{
|
||||||
|
|
@ -1621,11 +1867,13 @@ var AllVoteStatusEnum = []VoteStatusEnum{
|
||||||
VoteStatusEnumPending,
|
VoteStatusEnumPending,
|
||||||
VoteStatusEnumImmediateAccepted,
|
VoteStatusEnumImmediateAccepted,
|
||||||
VoteStatusEnumImmediateRejected,
|
VoteStatusEnumImmediateRejected,
|
||||||
|
VoteStatusEnumFailed,
|
||||||
|
VoteStatusEnumCanceled,
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e VoteStatusEnum) IsValid() bool {
|
func (e VoteStatusEnum) IsValid() bool {
|
||||||
switch e {
|
switch e {
|
||||||
case VoteStatusEnumAccepted, VoteStatusEnumRejected, VoteStatusEnumPending, VoteStatusEnumImmediateAccepted, VoteStatusEnumImmediateRejected:
|
case VoteStatusEnumAccepted, VoteStatusEnumRejected, VoteStatusEnumPending, VoteStatusEnumImmediateAccepted, VoteStatusEnumImmediateRejected, VoteStatusEnumFailed, VoteStatusEnumCanceled:
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
|
@ -1655,7 +1903,7 @@ func (e VoteStatusEnum) MarshalGQL(w io.Writer) {
|
||||||
type VoteTypeEnum string
|
type VoteTypeEnum string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
VoteTypeEnumComment VoteTypeEnum = "COMMENT"
|
VoteTypeEnumAbstain VoteTypeEnum = "ABSTAIN"
|
||||||
VoteTypeEnumAccept VoteTypeEnum = "ACCEPT"
|
VoteTypeEnumAccept VoteTypeEnum = "ACCEPT"
|
||||||
VoteTypeEnumReject VoteTypeEnum = "REJECT"
|
VoteTypeEnumReject VoteTypeEnum = "REJECT"
|
||||||
// Immediately accepts the edit - bypassing the vote
|
// Immediately accepts the edit - bypassing the vote
|
||||||
|
|
@ -1665,7 +1913,7 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
var AllVoteTypeEnum = []VoteTypeEnum{
|
var AllVoteTypeEnum = []VoteTypeEnum{
|
||||||
VoteTypeEnumComment,
|
VoteTypeEnumAbstain,
|
||||||
VoteTypeEnumAccept,
|
VoteTypeEnumAccept,
|
||||||
VoteTypeEnumReject,
|
VoteTypeEnumReject,
|
||||||
VoteTypeEnumImmediateAccept,
|
VoteTypeEnumImmediateAccept,
|
||||||
|
|
@ -1674,7 +1922,7 @@ var AllVoteTypeEnum = []VoteTypeEnum{
|
||||||
|
|
||||||
func (e VoteTypeEnum) IsValid() bool {
|
func (e VoteTypeEnum) IsValid() bool {
|
||||||
switch e {
|
switch e {
|
||||||
case VoteTypeEnumComment, VoteTypeEnumAccept, VoteTypeEnumReject, VoteTypeEnumImmediateAccept, VoteTypeEnumImmediateReject:
|
case VoteTypeEnumAbstain, VoteTypeEnumAccept, VoteTypeEnumReject, VoteTypeEnumImmediateAccept, VoteTypeEnumImmediateReject:
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,19 @@
|
||||||
package stashbox
|
package stashbox
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"mime/multipart"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/Yamashou/gqlgenc/client"
|
"github.com/Yamashou/gqlgenc/client"
|
||||||
|
"github.com/Yamashou/gqlgenc/graphqljson"
|
||||||
|
|
||||||
"github.com/stashapp/stash/pkg/logger"
|
"github.com/stashapp/stash/pkg/logger"
|
||||||
"github.com/stashapp/stash/pkg/match"
|
"github.com/stashapp/stash/pkg/match"
|
||||||
|
|
@ -757,3 +762,270 @@ func (c Client) FindStashBoxPerformerByName(ctx context.Context, name string) (*
|
||||||
func (c Client) GetUser(ctx context.Context) (*graphql.Me, error) {
|
func (c Client) GetUser(ctx context.Context) (*graphql.Me, error) {
|
||||||
return c.client.Me(ctx)
|
return c.client.Me(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c Client) SubmitSceneDraft(ctx context.Context, sceneID int, endpoint string, imagePath string) (*string, error) {
|
||||||
|
draft := graphql.SceneDraftInput{}
|
||||||
|
var image *os.File
|
||||||
|
if err := c.txnManager.WithReadTxn(ctx, func(r models.ReaderRepository) error {
|
||||||
|
qb := r.Scene()
|
||||||
|
pqb := r.Performer()
|
||||||
|
sqb := r.Studio()
|
||||||
|
|
||||||
|
scene, err := qb.Find(sceneID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if scene.Title.Valid {
|
||||||
|
draft.Title = &scene.Title.String
|
||||||
|
}
|
||||||
|
if scene.Details.Valid {
|
||||||
|
draft.Details = &scene.Details.String
|
||||||
|
}
|
||||||
|
if len(strings.TrimSpace(scene.URL.String)) > 0 {
|
||||||
|
url := strings.TrimSpace(scene.URL.String)
|
||||||
|
draft.URL = &url
|
||||||
|
}
|
||||||
|
if scene.Date.Valid {
|
||||||
|
draft.Date = &scene.Date.String
|
||||||
|
}
|
||||||
|
|
||||||
|
if scene.StudioID.Valid {
|
||||||
|
studio, err := sqb.Find(int(scene.StudioID.Int64))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
studioDraft := graphql.DraftEntityInput{
|
||||||
|
Name: studio.Name.String,
|
||||||
|
}
|
||||||
|
|
||||||
|
stashIDs, err := sqb.GetStashIDs(studio.ID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, stashID := range stashIDs {
|
||||||
|
if stashID.Endpoint == endpoint {
|
||||||
|
studioDraft.ID = &stashID.StashID
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
draft.Studio = &studioDraft
|
||||||
|
}
|
||||||
|
|
||||||
|
fingerprints := []*graphql.FingerprintInput{}
|
||||||
|
if scene.OSHash.Valid && scene.Duration.Valid {
|
||||||
|
fingerprint := graphql.FingerprintInput{
|
||||||
|
Hash: scene.OSHash.String,
|
||||||
|
Algorithm: graphql.FingerprintAlgorithmOshash,
|
||||||
|
Duration: int(scene.Duration.Float64),
|
||||||
|
}
|
||||||
|
fingerprints = append(fingerprints, &fingerprint)
|
||||||
|
}
|
||||||
|
|
||||||
|
if scene.Checksum.Valid && scene.Duration.Valid {
|
||||||
|
fingerprint := graphql.FingerprintInput{
|
||||||
|
Hash: scene.Checksum.String,
|
||||||
|
Algorithm: graphql.FingerprintAlgorithmMd5,
|
||||||
|
Duration: int(scene.Duration.Float64),
|
||||||
|
}
|
||||||
|
fingerprints = append(fingerprints, &fingerprint)
|
||||||
|
}
|
||||||
|
|
||||||
|
if scene.Phash.Valid && scene.Duration.Valid {
|
||||||
|
fingerprint := graphql.FingerprintInput{
|
||||||
|
Hash: utils.PhashToString(scene.Phash.Int64),
|
||||||
|
Algorithm: graphql.FingerprintAlgorithmPhash,
|
||||||
|
Duration: int(scene.Duration.Float64),
|
||||||
|
}
|
||||||
|
fingerprints = append(fingerprints, &fingerprint)
|
||||||
|
}
|
||||||
|
draft.Fingerprints = fingerprints
|
||||||
|
|
||||||
|
scenePerformers, err := pqb.FindBySceneID(sceneID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
performers := []*graphql.DraftEntityInput{}
|
||||||
|
for _, p := range scenePerformers {
|
||||||
|
performerDraft := graphql.DraftEntityInput{
|
||||||
|
Name: p.Name.String,
|
||||||
|
}
|
||||||
|
|
||||||
|
stashIDs, err := pqb.GetStashIDs(p.ID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, stashID := range stashIDs {
|
||||||
|
if stashID.Endpoint == endpoint {
|
||||||
|
performerDraft.ID = &stashID.StashID
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
performers = append(performers, &performerDraft)
|
||||||
|
}
|
||||||
|
draft.Performers = performers
|
||||||
|
|
||||||
|
var tags []*graphql.DraftEntityInput
|
||||||
|
sceneTags, err := r.Tag().FindBySceneID(scene.ID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, tag := range sceneTags {
|
||||||
|
tags = append(tags, &graphql.DraftEntityInput{Name: tag.Name})
|
||||||
|
}
|
||||||
|
draft.Tags = tags
|
||||||
|
|
||||||
|
exists, _ := utils.FileExists(imagePath)
|
||||||
|
if exists {
|
||||||
|
file, err := os.Open(imagePath)
|
||||||
|
if err == nil {
|
||||||
|
image = file
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var id *string
|
||||||
|
var ret graphql.SubmitSceneDraftPayload
|
||||||
|
err := c.submitDraft(ctx, graphql.SubmitSceneDraftQuery, draft, image, &ret)
|
||||||
|
id = ret.SubmitSceneDraft.ID
|
||||||
|
|
||||||
|
return id, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Client) SubmitPerformerDraft(ctx context.Context, performer *models.Performer, endpoint string) (*string, error) {
|
||||||
|
draft := graphql.PerformerDraftInput{}
|
||||||
|
var image io.Reader
|
||||||
|
if err := c.txnManager.WithReadTxn(ctx, func(r models.ReaderRepository) error {
|
||||||
|
pqb := r.Performer()
|
||||||
|
img, _ := pqb.GetImage(performer.ID)
|
||||||
|
if img != nil {
|
||||||
|
image = bytes.NewReader(img)
|
||||||
|
}
|
||||||
|
|
||||||
|
if performer.Name.Valid {
|
||||||
|
draft.Name = performer.Name.String
|
||||||
|
}
|
||||||
|
if performer.Birthdate.Valid {
|
||||||
|
draft.Birthdate = &performer.Birthdate.String
|
||||||
|
}
|
||||||
|
if performer.Country.Valid {
|
||||||
|
draft.Country = &performer.Country.String
|
||||||
|
}
|
||||||
|
if performer.Ethnicity.Valid {
|
||||||
|
draft.Ethnicity = &performer.Ethnicity.String
|
||||||
|
}
|
||||||
|
if performer.EyeColor.Valid {
|
||||||
|
draft.EyeColor = &performer.EyeColor.String
|
||||||
|
}
|
||||||
|
if performer.FakeTits.Valid {
|
||||||
|
draft.BreastType = &performer.FakeTits.String
|
||||||
|
}
|
||||||
|
if performer.Gender.Valid {
|
||||||
|
draft.Gender = &performer.Gender.String
|
||||||
|
}
|
||||||
|
if performer.HairColor.Valid {
|
||||||
|
draft.HairColor = &performer.HairColor.String
|
||||||
|
}
|
||||||
|
if performer.Height.Valid {
|
||||||
|
draft.Height = &performer.Height.String
|
||||||
|
}
|
||||||
|
if performer.Measurements.Valid {
|
||||||
|
draft.Measurements = &performer.Measurements.String
|
||||||
|
}
|
||||||
|
if performer.Piercings.Valid {
|
||||||
|
draft.Piercings = &performer.Piercings.String
|
||||||
|
}
|
||||||
|
if performer.Tattoos.Valid {
|
||||||
|
draft.Tattoos = &performer.Tattoos.String
|
||||||
|
}
|
||||||
|
if performer.Aliases.Valid {
|
||||||
|
draft.Aliases = &performer.Aliases.String
|
||||||
|
}
|
||||||
|
|
||||||
|
var urls []string
|
||||||
|
if len(strings.TrimSpace(performer.Twitter.String)) > 0 {
|
||||||
|
urls = append(urls, "https://twitter.com/"+strings.TrimSpace(performer.Twitter.String))
|
||||||
|
}
|
||||||
|
if len(strings.TrimSpace(performer.Instagram.String)) > 0 {
|
||||||
|
urls = append(urls, "https://instagram.com/"+strings.TrimSpace(performer.Instagram.String))
|
||||||
|
}
|
||||||
|
if len(strings.TrimSpace(performer.URL.String)) > 0 {
|
||||||
|
urls = append(urls, strings.TrimSpace(performer.URL.String))
|
||||||
|
}
|
||||||
|
if len(urls) > 0 {
|
||||||
|
draft.Urls = urls
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var id *string
|
||||||
|
var ret graphql.SubmitPerformerDraftPayload
|
||||||
|
err := c.submitDraft(ctx, graphql.SubmitPerformerDraftQuery, draft, image, &ret)
|
||||||
|
id = ret.SubmitPerformerDraft.ID
|
||||||
|
|
||||||
|
return id, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) submitDraft(ctx context.Context, query string, input interface{}, image io.Reader, ret interface{}) error {
|
||||||
|
vars := map[string]interface{}{
|
||||||
|
"input": input,
|
||||||
|
}
|
||||||
|
|
||||||
|
r := &client.Request{
|
||||||
|
Query: query,
|
||||||
|
Variables: vars,
|
||||||
|
OperationName: "",
|
||||||
|
}
|
||||||
|
|
||||||
|
requestBody, err := json.Marshal(r)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("encode: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
body := &bytes.Buffer{}
|
||||||
|
writer := multipart.NewWriter(body)
|
||||||
|
if err := writer.WriteField("operations", string(requestBody)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if image != nil {
|
||||||
|
if err := writer.WriteField("map", "{ \"0\": [\"variables.input.image\"] }"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
part, _ := writer.CreateFormFile("0", "draft")
|
||||||
|
if _, err := io.Copy(part, image); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else if err := writer.WriteField("map", "{}"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.Close()
|
||||||
|
|
||||||
|
req, _ := http.NewRequestWithContext(ctx, "POST", c.box.Endpoint, body)
|
||||||
|
req.Header.Add("Content-Type", writer.FormDataContentType())
|
||||||
|
req.Header.Set("ApiKey", c.box.APIKey)
|
||||||
|
|
||||||
|
client := &http.Client{}
|
||||||
|
resp, err := client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
if err := graphqljson.Unmarshal(resp.Body, ret); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,10 @@
|
||||||
|
### ✨ New Features
|
||||||
|
* Added support for submitting performer/scene drafts to stash-box. ([#2234](https://github.com/stashapp/stash/pull/2234))
|
||||||
|
|
||||||
### 🎨 Improvements
|
### 🎨 Improvements
|
||||||
* Made Performer page consistent with Studio and Tag pages. ([#2200](https://github.com/stashapp/stash/pull/2200))
|
* Made Performer page consistent with Studio and Tag pages. ([#2200](https://github.com/stashapp/stash/pull/2200))
|
||||||
* Add gender icons to performers. ([#2179](https://github.com/stashapp/stash/pull/2179))
|
* Added gender icons to performers. ([#2179](https://github.com/stashapp/stash/pull/2179))
|
||||||
* Add button to test credentials when adding/editing stash-box endpoints. ([#2173](https://github.com/stashapp/stash/pull/2173))
|
* Added button to test credentials when adding/editing stash-box endpoints. ([#2173](https://github.com/stashapp/stash/pull/2173))
|
||||||
* Show counts on list tabs in Performer, Studio and Tag pages. ([#2169](https://github.com/stashapp/stash/pull/2169))
|
* Show counts on list tabs in Performer, Studio and Tag pages. ([#2169](https://github.com/stashapp/stash/pull/2169))
|
||||||
|
|
||||||
### 🐛 Bug fixes
|
### 🐛 Bug fixes
|
||||||
|
|
|
||||||
118
ui/v2.5/src/components/Dialogs/SubmitDraft.tsx
Normal file
118
ui/v2.5/src/components/Dialogs/SubmitDraft.tsx
Normal file
|
|
@ -0,0 +1,118 @@
|
||||||
|
import React, { useState } from "react";
|
||||||
|
import { useMutation, DocumentNode } from "@apollo/client";
|
||||||
|
import { Button, Form } from "react-bootstrap";
|
||||||
|
import * as GQL from "src/core/generated-graphql";
|
||||||
|
import { Modal } from "src/components/Shared";
|
||||||
|
import { getStashboxBase } from "src/utils";
|
||||||
|
|
||||||
|
interface IProps {
|
||||||
|
show: boolean;
|
||||||
|
entity: { name?: string | null; id: string; title?: string | null };
|
||||||
|
boxes: Pick<GQL.StashBox, "name" | "endpoint">[];
|
||||||
|
query: DocumentNode;
|
||||||
|
onHide: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
type Variables =
|
||||||
|
| GQL.SubmitStashBoxSceneDraftMutationVariables
|
||||||
|
| GQL.SubmitStashBoxPerformerDraftMutationVariables;
|
||||||
|
type Query =
|
||||||
|
| GQL.SubmitStashBoxSceneDraftMutation
|
||||||
|
| GQL.SubmitStashBoxPerformerDraftMutation;
|
||||||
|
|
||||||
|
const isSceneDraft = (
|
||||||
|
query: Query | null
|
||||||
|
): query is GQL.SubmitStashBoxSceneDraftMutation =>
|
||||||
|
(query as GQL.SubmitStashBoxSceneDraftMutation).submitStashBoxSceneDraft !==
|
||||||
|
undefined;
|
||||||
|
|
||||||
|
const getResponseId = (query: Query | null) =>
|
||||||
|
isSceneDraft(query)
|
||||||
|
? query.submitStashBoxSceneDraft
|
||||||
|
: query?.submitStashBoxPerformerDraft;
|
||||||
|
|
||||||
|
export const SubmitStashBoxDraft: React.FC<IProps> = ({
|
||||||
|
show,
|
||||||
|
boxes,
|
||||||
|
entity,
|
||||||
|
query,
|
||||||
|
onHide,
|
||||||
|
}) => {
|
||||||
|
const [submit, { data, error, loading }] = useMutation<Query, Variables>(
|
||||||
|
query
|
||||||
|
);
|
||||||
|
const [selectedBox, setSelectedBox] = useState(0);
|
||||||
|
|
||||||
|
const handleSubmit = () => {
|
||||||
|
submit({
|
||||||
|
variables: {
|
||||||
|
input: {
|
||||||
|
id: entity.id,
|
||||||
|
stash_box_index: selectedBox,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSelectBox = (e: React.ChangeEvent<HTMLSelectElement>) =>
|
||||||
|
setSelectedBox(Number.parseInt(e.currentTarget.value) ?? 0);
|
||||||
|
|
||||||
|
console.log(data);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
icon="paper-plane"
|
||||||
|
header="Submit to Stash-Box"
|
||||||
|
isRunning={loading}
|
||||||
|
show={show}
|
||||||
|
accept={{
|
||||||
|
onClick: onHide,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{data === undefined ? (
|
||||||
|
<>
|
||||||
|
<Form.Group className="form-row align-items-end">
|
||||||
|
<Form.Label className="col-6">
|
||||||
|
Selected Stash-Box endpoint:
|
||||||
|
</Form.Label>
|
||||||
|
<Form.Control
|
||||||
|
as="select"
|
||||||
|
onChange={handleSelectBox}
|
||||||
|
className="col-6"
|
||||||
|
>
|
||||||
|
{boxes.map((box, i) => (
|
||||||
|
<option value={i} key={`${box.endpoint}-${i}`}>
|
||||||
|
{box.name}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</Form.Control>
|
||||||
|
</Form.Group>
|
||||||
|
<Button onClick={handleSubmit}>
|
||||||
|
Submit {`"${entity.name ?? entity.title}"`}
|
||||||
|
</Button>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<h6>Submission successful</h6>
|
||||||
|
<div>
|
||||||
|
<a
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer noopener"
|
||||||
|
href={`${getStashboxBase(
|
||||||
|
boxes[selectedBox].endpoint
|
||||||
|
)}drafts/${getResponseId(data)}`}
|
||||||
|
>
|
||||||
|
Go to {boxes[selectedBox].name} to review draft.
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{error !== undefined && (
|
||||||
|
<>
|
||||||
|
<h6 className="mt-2">Submission failed</h6>
|
||||||
|
<div>{error.message}</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
@ -28,6 +28,7 @@ import { PerformerGalleriesPanel } from "./PerformerGalleriesPanel";
|
||||||
import { PerformerMoviesPanel } from "./PerformerMoviesPanel";
|
import { PerformerMoviesPanel } from "./PerformerMoviesPanel";
|
||||||
import { PerformerImagesPanel } from "./PerformerImagesPanel";
|
import { PerformerImagesPanel } from "./PerformerImagesPanel";
|
||||||
import { PerformerEditPanel } from "./PerformerEditPanel";
|
import { PerformerEditPanel } from "./PerformerEditPanel";
|
||||||
|
import { PerformerSubmitButton } from "./PerformerSubmitButton";
|
||||||
import GenderIcon from "../GenderIcon";
|
import GenderIcon from "../GenderIcon";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
|
|
@ -165,8 +166,13 @@ const PerformerPage: React.FC<IProps> = ({ performer }) => {
|
||||||
isEditing={false}
|
isEditing={false}
|
||||||
onSave={() => {}}
|
onSave={() => {}}
|
||||||
onImageChange={() => {}}
|
onImageChange={() => {}}
|
||||||
classNames="mb-4"
|
classNames="mb-2"
|
||||||
/>
|
customButtons={
|
||||||
|
<div>
|
||||||
|
<PerformerSubmitButton performer={performer} />
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
></DetailsEditNavbar>
|
||||||
</Row>
|
</Row>
|
||||||
</Col>
|
</Col>
|
||||||
<Tabs
|
<Tabs
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import React from "react";
|
||||||
import { FormattedMessage, useIntl } from "react-intl";
|
import { FormattedMessage, useIntl } from "react-intl";
|
||||||
import { TagLink } from "src/components/Shared";
|
import { TagLink } from "src/components/Shared";
|
||||||
import * as GQL from "src/core/generated-graphql";
|
import * as GQL from "src/core/generated-graphql";
|
||||||
import { TextUtils } from "src/utils";
|
import { TextUtils, getStashboxBase } from "src/utils";
|
||||||
import { TextField, URLField } from "src/utils/field";
|
import { TextField, URLField } from "src/utils/field";
|
||||||
|
|
||||||
interface IPerformerDetails {
|
interface IPerformerDetails {
|
||||||
|
|
@ -47,7 +47,7 @@ export const PerformerDetailsPanel: React.FC<IPerformerDetails> = ({
|
||||||
<dd>
|
<dd>
|
||||||
<ul className="pl-0">
|
<ul className="pl-0">
|
||||||
{performer.stash_ids.map((stashID) => {
|
{performer.stash_ids.map((stashID) => {
|
||||||
const base = stashID.endpoint.match(/https?:\/\/.*?\//)?.[0];
|
const base = getStashboxBase(stashID.endpoint);
|
||||||
const link = base ? (
|
const link = base ? (
|
||||||
<a
|
<a
|
||||||
href={`${base}performers/${stashID.stash_id}`}
|
href={`${base}performers/${stashID.stash_id}`}
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@ import { stashboxDisplayName } from "src/utils/stashbox";
|
||||||
import { PerformerScrapeDialog } from "./PerformerScrapeDialog";
|
import { PerformerScrapeDialog } from "./PerformerScrapeDialog";
|
||||||
import PerformerScrapeModal from "./PerformerScrapeModal";
|
import PerformerScrapeModal from "./PerformerScrapeModal";
|
||||||
import PerformerStashBoxModal, { IStashBox } from "./PerformerStashBoxModal";
|
import PerformerStashBoxModal, { IStashBox } from "./PerformerStashBoxModal";
|
||||||
|
import cx from "classnames";
|
||||||
|
|
||||||
const isScraper = (
|
const isScraper = (
|
||||||
scraper: GQL.Scraper | GQL.StashBox
|
scraper: GQL.Scraper | GQL.StashBox
|
||||||
|
|
@ -652,25 +653,25 @@ export const PerformerEditPanel: React.FC<IPerformerDetails> = ({
|
||||||
|
|
||||||
function renderButtons(classNames: string) {
|
function renderButtons(classNames: string) {
|
||||||
return (
|
return (
|
||||||
<Row>
|
<div className={cx("details-edit", classNames)}>
|
||||||
<Col className={classNames} xs={12}>
|
{!isNew && onCancelEditing ? (
|
||||||
{!isNew && onCancelEditing ? (
|
<Button
|
||||||
<Button
|
className="mr-2"
|
||||||
className="mr-2"
|
variant="primary"
|
||||||
variant="primary"
|
onClick={() => onCancelEditing()}
|
||||||
onClick={() => onCancelEditing()}
|
>
|
||||||
>
|
<FormattedMessage id="actions.cancel" />
|
||||||
<FormattedMessage id="actions.cancel" />
|
</Button>
|
||||||
</Button>
|
) : (
|
||||||
) : (
|
""
|
||||||
""
|
)}
|
||||||
)}
|
{renderScraperMenu()}
|
||||||
{renderScraperMenu()}
|
<ImageInput
|
||||||
<ImageInput
|
isEditing
|
||||||
isEditing
|
onImageChange={onImageChangeHandler}
|
||||||
onImageChange={onImageChangeHandler}
|
onImageURL={onImageChangeURL}
|
||||||
onImageURL={onImageChangeURL}
|
/>
|
||||||
/>
|
<div>
|
||||||
<Button
|
<Button
|
||||||
className="mr-2"
|
className="mr-2"
|
||||||
variant="danger"
|
variant="danger"
|
||||||
|
|
@ -678,15 +679,15 @@ export const PerformerEditPanel: React.FC<IPerformerDetails> = ({
|
||||||
>
|
>
|
||||||
<FormattedMessage id="actions.clear_image" />
|
<FormattedMessage id="actions.clear_image" />
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
</div>
|
||||||
variant="success"
|
<Button
|
||||||
disabled={!formik.dirty}
|
variant="success"
|
||||||
onClick={() => formik.submitForm()}
|
disabled={!formik.dirty}
|
||||||
>
|
onClick={() => formik.submitForm()}
|
||||||
<FormattedMessage id="actions.save" />
|
>
|
||||||
</Button>
|
<FormattedMessage id="actions.save" />
|
||||||
</Col>
|
</Button>
|
||||||
</Row>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
import { Button } from "react-bootstrap";
|
||||||
|
import React, { useState } from "react";
|
||||||
|
import { FormattedMessage } from "react-intl";
|
||||||
|
import * as GQL from "src/core/generated-graphql";
|
||||||
|
import { SubmitStashBoxDraft } from "src/components/Dialogs/SubmitDraft";
|
||||||
|
|
||||||
|
interface IPerformerOperationsProps {
|
||||||
|
performer: GQL.PerformerDataFragment;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const PerformerSubmitButton: React.FC<IPerformerOperationsProps> = ({
|
||||||
|
performer,
|
||||||
|
}) => {
|
||||||
|
const [showDraftModal, setShowDraftModal] = useState(false);
|
||||||
|
|
||||||
|
const { data } = GQL.useConfigurationQuery();
|
||||||
|
const boxes = data?.configuration?.general?.stashBoxes ?? [];
|
||||||
|
|
||||||
|
if (boxes.length === 0) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Button onClick={() => setShowDraftModal(true)}>
|
||||||
|
<FormattedMessage id="actions.submit_stash_box" />
|
||||||
|
</Button>
|
||||||
|
<SubmitStashBoxDraft
|
||||||
|
boxes={boxes}
|
||||||
|
entity={performer}
|
||||||
|
query={GQL.SubmitStashBoxPerformerDraftDocument}
|
||||||
|
show={showDraftModal}
|
||||||
|
onHide={() => setShowDraftModal(false)}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
@ -4,6 +4,7 @@ import React, { useEffect, useState, useMemo } from "react";
|
||||||
import { FormattedMessage, useIntl } from "react-intl";
|
import { FormattedMessage, useIntl } from "react-intl";
|
||||||
import { useParams, useLocation, useHistory, Link } from "react-router-dom";
|
import { useParams, useLocation, useHistory, Link } from "react-router-dom";
|
||||||
import { Helmet } from "react-helmet";
|
import { Helmet } from "react-helmet";
|
||||||
|
import Mousetrap from "mousetrap";
|
||||||
import * as GQL from "src/core/generated-graphql";
|
import * as GQL from "src/core/generated-graphql";
|
||||||
import {
|
import {
|
||||||
mutateMetadataScan,
|
mutateMetadataScan,
|
||||||
|
|
@ -22,7 +23,7 @@ import { ErrorMessage, LoadingIndicator, Icon } from "src/components/Shared";
|
||||||
import { useToast } from "src/hooks";
|
import { useToast } from "src/hooks";
|
||||||
import { ScenePlayer } from "src/components/ScenePlayer";
|
import { ScenePlayer } from "src/components/ScenePlayer";
|
||||||
import { TextUtils, JWUtils } from "src/utils";
|
import { TextUtils, JWUtils } from "src/utils";
|
||||||
import Mousetrap from "mousetrap";
|
import { SubmitStashBoxDraft } from "src/components/Dialogs/SubmitDraft";
|
||||||
import { ListFilterModel } from "src/models/list-filter/filter";
|
import { ListFilterModel } from "src/models/list-filter/filter";
|
||||||
import { SceneQueue } from "src/models/sceneQueue";
|
import { SceneQueue } from "src/models/sceneQueue";
|
||||||
import { QueueViewer } from "./QueueViewer";
|
import { QueueViewer } from "./QueueViewer";
|
||||||
|
|
@ -55,6 +56,10 @@ const ScenePage: React.FC<IProps> = ({ scene, refetch }) => {
|
||||||
const [collapsed, setCollapsed] = useState(false);
|
const [collapsed, setCollapsed] = useState(false);
|
||||||
const [showScrubber, setShowScrubber] = useState(true);
|
const [showScrubber, setShowScrubber] = useState(true);
|
||||||
|
|
||||||
|
const { data } = GQL.useConfigurationQuery();
|
||||||
|
const [showDraftModal, setShowDraftModal] = useState(false);
|
||||||
|
const boxes = data?.configuration?.general?.stashBoxes ?? [];
|
||||||
|
|
||||||
const {
|
const {
|
||||||
data: sceneStreams,
|
data: sceneStreams,
|
||||||
error: streamableError,
|
error: streamableError,
|
||||||
|
|
@ -384,6 +389,15 @@ const ScenePage: React.FC<IProps> = ({ scene, refetch }) => {
|
||||||
>
|
>
|
||||||
<FormattedMessage id="actions.generate_thumb_default" />
|
<FormattedMessage id="actions.generate_thumb_default" />
|
||||||
</Dropdown.Item>
|
</Dropdown.Item>
|
||||||
|
{boxes.length > 0 && (
|
||||||
|
<Dropdown.Item
|
||||||
|
key="submit"
|
||||||
|
className="bg-secondary text-white"
|
||||||
|
onClick={() => setShowDraftModal(true)}
|
||||||
|
>
|
||||||
|
<FormattedMessage id="actions.submit_stash_box" />
|
||||||
|
</Dropdown.Item>
|
||||||
|
)}
|
||||||
<Dropdown.Item
|
<Dropdown.Item
|
||||||
key="delete-scene"
|
key="delete-scene"
|
||||||
className="bg-secondary text-white"
|
className="bg-secondary text-white"
|
||||||
|
|
@ -633,6 +647,13 @@ const ScenePage: React.FC<IProps> = ({ scene, refetch }) => {
|
||||||
/>
|
/>
|
||||||
) : undefined}
|
) : undefined}
|
||||||
</div>
|
</div>
|
||||||
|
<SubmitStashBoxDraft
|
||||||
|
boxes={boxes}
|
||||||
|
entity={scene}
|
||||||
|
query={GQL.SubmitStashBoxSceneDraftDocument}
|
||||||
|
show={showDraftModal}
|
||||||
|
onHide={() => setShowDraftModal(false)}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { FormattedMessage, FormattedNumber, useIntl } from "react-intl";
|
import { FormattedMessage, FormattedNumber, useIntl } from "react-intl";
|
||||||
import * as GQL from "src/core/generated-graphql";
|
import * as GQL from "src/core/generated-graphql";
|
||||||
import { NavUtils, TextUtils } from "src/utils";
|
import { NavUtils, TextUtils, getStashboxBase } from "src/utils";
|
||||||
import { TextField, URLField } from "src/utils/field";
|
import { TextField, URLField } from "src/utils/field";
|
||||||
|
|
||||||
interface ISceneFileInfoPanelProps {
|
interface ISceneFileInfoPanelProps {
|
||||||
|
|
@ -49,7 +49,7 @@ export const SceneFileInfoPanel: React.FC<ISceneFileInfoPanelProps> = (
|
||||||
<dd>
|
<dd>
|
||||||
<ul>
|
<ul>
|
||||||
{props.scene.stash_ids.map((stashID) => {
|
{props.scene.stash_ids.map((stashID) => {
|
||||||
const base = stashID.endpoint.match(/https?:\/\/.*?\//)?.[0];
|
const base = getStashboxBase(stashID.endpoint);
|
||||||
const link = base ? (
|
const link = base ? (
|
||||||
<a
|
<a
|
||||||
href={`${base}scenes/${stashID.stash_id}`}
|
href={`${base}scenes/${stashID.stash_id}`}
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ interface IProps {
|
||||||
acceptSVG?: boolean;
|
acceptSVG?: boolean;
|
||||||
customButtons?: JSX.Element;
|
customButtons?: JSX.Element;
|
||||||
classNames?: string;
|
classNames?: string;
|
||||||
|
children?: JSX.Element | JSX.Element[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export const DetailsEditNavbar: React.FC<IProps> = (props: IProps) => {
|
export const DetailsEditNavbar: React.FC<IProps> = (props: IProps) => {
|
||||||
|
|
@ -90,16 +91,18 @@ export const DetailsEditNavbar: React.FC<IProps> = (props: IProps) => {
|
||||||
|
|
||||||
if (props.onAutoTag) {
|
if (props.onAutoTag) {
|
||||||
return (
|
return (
|
||||||
<Button
|
<div>
|
||||||
variant="secondary"
|
<Button
|
||||||
onClick={() => {
|
variant="secondary"
|
||||||
if (props.onAutoTag) {
|
onClick={() => {
|
||||||
props.onAutoTag();
|
if (props.onAutoTag) {
|
||||||
}
|
props.onAutoTag();
|
||||||
}}
|
}
|
||||||
>
|
}}
|
||||||
<FormattedMessage id="actions.auto_tag" />
|
>
|
||||||
</Button>
|
<FormattedMessage id="actions.auto_tag" />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -143,30 +146,30 @@ export const DetailsEditNavbar: React.FC<IProps> = (props: IProps) => {
|
||||||
acceptSVG={props.acceptSVG ?? false}
|
acceptSVG={props.acceptSVG ?? false}
|
||||||
/>
|
/>
|
||||||
{props.isEditing && props.onClearImage ? (
|
{props.isEditing && props.onClearImage ? (
|
||||||
<Button
|
<div>
|
||||||
className="mr-2"
|
<Button
|
||||||
variant="danger"
|
className="mr-2"
|
||||||
onClick={() => props.onClearImage!()}
|
variant="danger"
|
||||||
>
|
onClick={() => props.onClearImage!()}
|
||||||
{props.onClearBackImage
|
>
|
||||||
? intl.formatMessage({ id: "actions.clear_front_image" })
|
{props.onClearBackImage
|
||||||
: intl.formatMessage({ id: "actions.clear_image" })}
|
? intl.formatMessage({ id: "actions.clear_front_image" })
|
||||||
</Button>
|
: intl.formatMessage({ id: "actions.clear_image" })}
|
||||||
) : (
|
</Button>
|
||||||
""
|
</div>
|
||||||
)}
|
) : null}
|
||||||
{renderBackImageInput()}
|
{renderBackImageInput()}
|
||||||
{props.isEditing && props.onClearBackImage ? (
|
{props.isEditing && props.onClearBackImage ? (
|
||||||
<Button
|
<div>
|
||||||
className="mr-2"
|
<Button
|
||||||
variant="danger"
|
className="mr-2"
|
||||||
onClick={() => props.onClearBackImage!()}
|
variant="danger"
|
||||||
>
|
onClick={() => props.onClearBackImage!()}
|
||||||
{intl.formatMessage({ id: "actions.clear_back_image" })}
|
>
|
||||||
</Button>
|
{intl.formatMessage({ id: "actions.clear_back_image" })}
|
||||||
) : (
|
</Button>
|
||||||
""
|
</div>
|
||||||
)}
|
) : null}
|
||||||
{renderAutoTagButton()}
|
{renderAutoTagButton()}
|
||||||
{props.customButtons}
|
{props.customButtons}
|
||||||
{renderSaveButton()}
|
{renderSaveButton()}
|
||||||
|
|
|
||||||
|
|
@ -31,16 +31,24 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.details-edit {
|
.details-edit {
|
||||||
|
/*
|
||||||
|
The penultimate button should be wrapped in an unstyled div.
|
||||||
|
This allows the div to expand, to right-justify the last (save / delete) button.
|
||||||
|
*/
|
||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
justify-content: left;
|
justify-content: left;
|
||||||
|
row-gap: 0.5rem;
|
||||||
|
|
||||||
.btn {
|
.btn {
|
||||||
margin-right: 0.5rem;
|
margin-right: 0.5rem;
|
||||||
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.delete,
|
div:nth-last-child(2) {
|
||||||
.save {
|
flex: 1;
|
||||||
margin-left: auto;
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -277,6 +277,7 @@ const TagPage: React.FC<IProps> = ({ tag }) => {
|
||||||
onClearImage={() => {}}
|
onClearImage={() => {}}
|
||||||
onAutoTag={onAutoTag}
|
onAutoTag={onAutoTag}
|
||||||
onDelete={onDelete}
|
onDelete={onDelete}
|
||||||
|
classNames="mb-2"
|
||||||
customButtons={renderMergeButton()}
|
customButtons={renderMergeButton()}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
|
|
|
||||||
|
|
@ -1149,3 +1149,19 @@ export const stashBoxPerformerBatchQuery = (
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const stashBoxSubmitSceneDraft = (
|
||||||
|
input: GQL.StashBoxDraftSubmissionInput
|
||||||
|
) =>
|
||||||
|
client.mutate<GQL.SubmitStashBoxSceneDraftMutation>({
|
||||||
|
mutation: GQL.SubmitStashBoxSceneDraftDocument,
|
||||||
|
variables: { input },
|
||||||
|
});
|
||||||
|
|
||||||
|
export const stashBoxSubmitPerformerDraft = (
|
||||||
|
input: GQL.StashBoxDraftSubmissionInput
|
||||||
|
) =>
|
||||||
|
client.mutate<GQL.SubmitStashBoxPerformerDraftMutation>({
|
||||||
|
mutation: GQL.SubmitStashBoxPerformerDraftDocument,
|
||||||
|
variables: { input },
|
||||||
|
});
|
||||||
|
|
|
||||||
|
|
@ -88,6 +88,7 @@
|
||||||
"show": "Show",
|
"show": "Show",
|
||||||
"skip": "Skip",
|
"skip": "Skip",
|
||||||
"stop": "Stop",
|
"stop": "Stop",
|
||||||
|
"submit_stash_box": "Submit to Stash-Box",
|
||||||
"tasks": {
|
"tasks": {
|
||||||
"clean_confirm_message": "Are you sure you want to Clean? This will delete database information and generated content for all scenes and galleries that are no longer found in the filesystem.",
|
"clean_confirm_message": "Are you sure you want to Clean? This will delete database information and generated content for all scenes and galleries that are no longer found in the filesystem.",
|
||||||
"dry_mode_selected": "Dry Mode selected. No actual deleting will take place, only logging.",
|
"dry_mode_selected": "Dry Mode selected. No actual deleting will take place, only logging.",
|
||||||
|
|
|
||||||
|
|
@ -14,3 +14,4 @@ export { default as useFocus } from "./focus";
|
||||||
export { default as downloadFile } from "./download";
|
export { default as downloadFile } from "./download";
|
||||||
export * from "./data";
|
export * from "./data";
|
||||||
export { getStashIDs } from "./stashIds";
|
export { getStashIDs } from "./stashIds";
|
||||||
|
export * from "./stashbox";
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
export function stashboxDisplayName(name: string, index: number) {
|
export function stashboxDisplayName(name: string, index: number) {
|
||||||
return name || `Stash-Box #${index + 1}`;
|
return name || `Stash-Box #${index + 1}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const getStashboxBase = (endpoint: string) =>
|
||||||
|
endpoint.match(/(https?:\/\/.*?\/)graphql/)?.[1];
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue