[Feature] Add fields director and (studio) code to scenes (#3051)

* added schema migration and updated data models
* added code and director to UI
* new fields are exported and imported
* added filters
* Add changelog entry
This commit is contained in:
HappyAxolotl
2022-11-07 08:16:52 +01:00
committed by GitHub
parent 7540d3b477
commit eff86bf2f8
35 changed files with 411 additions and 248 deletions

View File

@@ -1,7 +1,9 @@
fragment SlimSceneData on Scene { fragment SlimSceneData on Scene {
id id
title title
code
details details
director
url url
date date
rating rating

View File

@@ -1,7 +1,9 @@
fragment SceneData on Scene { fragment SceneData on Scene {
id id
title title
code
details details
director
url url
date date
rating rating

View File

@@ -105,7 +105,9 @@ fragment ScrapedSceneTagData on ScrapedTag {
fragment ScrapedSceneData on ScrapedScene { fragment ScrapedSceneData on ScrapedScene {
title title
code
details details
director
url url
date date
image image
@@ -166,7 +168,9 @@ fragment ScrapedGalleryData on ScrapedGallery {
fragment ScrapedStashBoxSceneData on ScrapedScene { fragment ScrapedStashBoxSceneData on ScrapedScene {
title title
code
details details
director
url url
date date
image image

View File

@@ -52,7 +52,9 @@ query ParseSceneFilenames($filter: FindFilterType!, $config: SceneParserInput!)
...SlimSceneData ...SlimSceneData
} }
title title
code
details details
director
url url
date date
rating rating

View File

@@ -122,7 +122,9 @@ input SceneFilterType {
NOT: SceneFilterType NOT: SceneFilterType
title: StringCriterionInput title: StringCriterionInput
code: StringCriterionInput
details: StringCriterionInput details: StringCriterionInput
director: StringCriterionInput
"""Filter by file oshash""" """Filter by file oshash"""
oshash: StringCriterionInput oshash: StringCriterionInput

View File

@@ -36,7 +36,9 @@ type Scene {
checksum: String @deprecated(reason: "Use files.fingerprints") checksum: String @deprecated(reason: "Use files.fingerprints")
oshash: String @deprecated(reason: "Use files.fingerprints") oshash: String @deprecated(reason: "Use files.fingerprints")
title: String title: String
code: String
details: String details: String
director: String
url: String url: String
date: String date: String
rating: Int rating: Int
@@ -76,7 +78,9 @@ input SceneUpdateInput {
clientMutationId: String clientMutationId: String
id: ID! id: ID!
title: String title: String
code: String
details: String details: String
director: String
url: String url: String
date: String date: String
rating: Int rating: Int
@@ -108,7 +112,9 @@ input BulkSceneUpdateInput {
clientMutationId: String clientMutationId: String
ids: [ID!] ids: [ID!]
title: String title: String
code: String
details: String details: String
director: String
url: String url: String
date: String date: String
rating: Int rating: Int
@@ -156,7 +162,9 @@ type SceneMovieID {
type SceneParserResult { type SceneParserResult {
scene: Scene! scene: Scene!
title: String title: String
code: String
details: String details: String
director: String
url: String url: String
date: String date: String
rating: Int rating: Int

View File

@@ -61,7 +61,9 @@ type ScrapedTag {
type ScrapedScene { type ScrapedScene {
title: String title: String
code: String
details: String details: String
director: String
url: String url: String
date: String date: String
@@ -82,7 +84,9 @@ type ScrapedScene {
input ScrapedSceneInput { input ScrapedSceneInput {
title: String title: String
code: String
details: String details: String
director: String
url: String url: String
date: String date: String

View File

@@ -94,7 +94,9 @@ fragment FingerprintFragment on Fingerprint {
fragment SceneFragment on Scene { fragment SceneFragment on Scene {
id id
title title
code
details details
director
duration duration
date date
urls { urls {

View File

@@ -112,7 +112,9 @@ func (r *mutationResolver) sceneUpdate(ctx context.Context, input models.SceneUp
updatedScene := models.NewScenePartial() updatedScene := models.NewScenePartial()
updatedScene.Title = translator.optionalString(input.Title, "title") updatedScene.Title = translator.optionalString(input.Title, "title")
updatedScene.Code = translator.optionalString(input.Code, "code")
updatedScene.Details = translator.optionalString(input.Details, "details") updatedScene.Details = translator.optionalString(input.Details, "details")
updatedScene.Director = translator.optionalString(input.Director, "director")
updatedScene.URL = translator.optionalString(input.URL, "url") updatedScene.URL = translator.optionalString(input.URL, "url")
updatedScene.Date = translator.optionalDate(input.Date, "date") updatedScene.Date = translator.optionalDate(input.Date, "date")
updatedScene.Rating = translator.optionalInt(input.Rating, "rating") updatedScene.Rating = translator.optionalInt(input.Rating, "rating")
@@ -246,7 +248,9 @@ func (r *mutationResolver) BulkSceneUpdate(ctx context.Context, input BulkSceneU
updatedScene := models.NewScenePartial() updatedScene := models.NewScenePartial()
updatedScene.Title = translator.optionalString(input.Title, "title") updatedScene.Title = translator.optionalString(input.Title, "title")
updatedScene.Code = translator.optionalString(input.Code, "code")
updatedScene.Details = translator.optionalString(input.Details, "details") updatedScene.Details = translator.optionalString(input.Details, "details")
updatedScene.Director = translator.optionalString(input.Director, "director")
updatedScene.URL = translator.optionalString(input.URL, "url") updatedScene.URL = translator.optionalString(input.URL, "url")
updatedScene.Date = translator.optionalDate(input.Date, "date") updatedScene.Date = translator.optionalDate(input.Date, "date")
updatedScene.Rating = translator.optionalInt(input.Rating, "rating") updatedScene.Rating = translator.optionalInt(input.Rating, "rating")

View File

@@ -26,7 +26,9 @@ type SceneParserInput struct {
type SceneParserResult struct { type SceneParserResult struct {
Scene *models.Scene `json:"scene"` Scene *models.Scene `json:"scene"`
Title *string `json:"title"` Title *string `json:"title"`
Code *string `json:"code"`
Details *string `json:"details"` Details *string `json:"details"`
Director *string `json:"director"`
URL *string `json:"url"` URL *string `json:"url"`
Date *string `json:"date"` Date *string `json:"date"`
Rating *int `json:"rating"` Rating *int `json:"rating"`

View File

@@ -39,6 +39,7 @@ type SceneMovie struct {
type Scene struct { type Scene struct {
Title string `json:"title,omitempty"` Title string `json:"title,omitempty"`
Code string `json:"code,omitempty"`
Studio string `json:"studio,omitempty"` Studio string `json:"studio,omitempty"`
URL string `json:"url,omitempty"` URL string `json:"url,omitempty"`
Date string `json:"date,omitempty"` Date string `json:"date,omitempty"`
@@ -46,6 +47,7 @@ type Scene struct {
Organized bool `json:"organized,omitempty"` Organized bool `json:"organized,omitempty"`
OCounter int `json:"o_counter,omitempty"` OCounter int `json:"o_counter,omitempty"`
Details string `json:"details,omitempty"` Details string `json:"details,omitempty"`
Director string `json:"director,omitempty"`
Galleries []GalleryRef `json:"galleries,omitempty"` Galleries []GalleryRef `json:"galleries,omitempty"`
Performers []string `json:"performers,omitempty"` Performers []string `json:"performers,omitempty"`
Movies []SceneMovie `json:"movies,omitempty"` Movies []SceneMovie `json:"movies,omitempty"`

View File

@@ -14,7 +14,9 @@ import (
type Scene struct { type Scene struct {
ID int `json:"id"` ID int `json:"id"`
Title string `json:"title"` Title string `json:"title"`
Code string `json:"code"`
Details string `json:"details"` Details string `json:"details"`
Director string `json:"director"`
URL string `json:"url"` URL string `json:"url"`
Date *Date `json:"date"` Date *Date `json:"date"`
Rating *int `json:"rating"` Rating *int `json:"rating"`
@@ -133,7 +135,9 @@ func (s *Scene) LoadRelationships(ctx context.Context, l SceneReader) error {
// the database entry. // the database entry.
type ScenePartial struct { type ScenePartial struct {
Title OptionalString Title OptionalString
Code OptionalString
Details OptionalString Details OptionalString
Director OptionalString
URL OptionalString URL OptionalString
Date OptionalDate Date OptionalDate
Rating OptionalInt Rating OptionalInt
@@ -167,7 +171,9 @@ type SceneUpdateInput struct {
ClientMutationID *string `json:"clientMutationId"` ClientMutationID *string `json:"clientMutationId"`
ID string `json:"id"` ID string `json:"id"`
Title *string `json:"title"` Title *string `json:"title"`
Code *string `json:"code"`
Details *string `json:"details"` Details *string `json:"details"`
Director *string `json:"director"`
URL *string `json:"url"` URL *string `json:"url"`
Date *string `json:"date"` Date *string `json:"date"`
Rating *int `json:"rating"` Rating *int `json:"rating"`
@@ -200,7 +206,9 @@ func (s ScenePartial) UpdateInput(id int) SceneUpdateInput {
return SceneUpdateInput{ return SceneUpdateInput{
ID: strconv.Itoa(id), ID: strconv.Itoa(id),
Title: s.Title.Ptr(), Title: s.Title.Ptr(),
Code: s.Code.Ptr(),
Details: s.Details.Ptr(), Details: s.Details.Ptr(),
Director: s.Director.Ptr(),
URL: s.URL.Ptr(), URL: s.URL.Ptr(),
Date: dateStr, Date: dateStr,
Rating: s.Rating.Ptr(), Rating: s.Rating.Ptr(),

View File

@@ -13,7 +13,9 @@ func TestScenePartial_UpdateInput(t *testing.T) {
var ( var (
title = "title" title = "title"
code = "1337"
details = "details" details = "details"
director = "director"
url = "url" url = "url"
date = "2001-02-03" date = "2001-02-03"
rating = 4 rating = 4
@@ -35,7 +37,9 @@ func TestScenePartial_UpdateInput(t *testing.T) {
id, id,
ScenePartial{ ScenePartial{
Title: NewOptionalString(title), Title: NewOptionalString(title),
Code: NewOptionalString(code),
Details: NewOptionalString(details), Details: NewOptionalString(details),
Director: NewOptionalString(director),
URL: NewOptionalString(url), URL: NewOptionalString(url),
Date: NewOptionalDate(dateObj), Date: NewOptionalDate(dateObj),
Rating: NewOptionalInt(rating), Rating: NewOptionalInt(rating),
@@ -45,7 +49,9 @@ func TestScenePartial_UpdateInput(t *testing.T) {
SceneUpdateInput{ SceneUpdateInput{
ID: idStr, ID: idStr,
Title: &title, Title: &title,
Code: &code,
Details: &details, Details: &details,
Director: &director,
URL: &url, URL: &url,
Date: &date, Date: &date,
Rating: &rating, Rating: &rating,

View File

@@ -79,7 +79,9 @@ func (ScrapedMovie) IsScrapedContent() {}
type ScrapedItem struct { type ScrapedItem struct {
ID int `db:"id" json:"id"` ID int `db:"id" json:"id"`
Title sql.NullString `db:"title" json:"title"` Title sql.NullString `db:"title" json:"title"`
Code sql.NullString `db:"code" json:"code"`
Description sql.NullString `db:"description" json:"description"` Description sql.NullString `db:"description" json:"description"`
Director sql.NullString `db:"director" json:"director"`
URL sql.NullString `db:"url" json:"url"` URL sql.NullString `db:"url" json:"url"`
Date SQLiteDate `db:"date" json:"date"` Date SQLiteDate `db:"date" json:"date"`
Rating sql.NullString `db:"rating" json:"rating"` Rating sql.NullString `db:"rating" json:"rating"`

View File

@@ -17,7 +17,9 @@ type SceneFilterType struct {
Or *SceneFilterType `json:"OR"` Or *SceneFilterType `json:"OR"`
Not *SceneFilterType `json:"NOT"` Not *SceneFilterType `json:"NOT"`
Title *StringCriterionInput `json:"title"` Title *StringCriterionInput `json:"title"`
Code *StringCriterionInput `json:"code"`
Details *StringCriterionInput `json:"details"` Details *StringCriterionInput `json:"details"`
Director *StringCriterionInput `json:"director"`
// Filter by file oshash // Filter by file oshash
Oshash *StringCriterionInput `json:"oshash"` Oshash *StringCriterionInput `json:"oshash"`
// Filter by file checksum // Filter by file checksum

View File

@@ -39,8 +39,10 @@ type TagFinder interface {
func ToBasicJSON(ctx context.Context, reader CoverGetter, scene *models.Scene) (*jsonschema.Scene, error) { func ToBasicJSON(ctx context.Context, reader CoverGetter, scene *models.Scene) (*jsonschema.Scene, error) {
newSceneJSON := jsonschema.Scene{ newSceneJSON := jsonschema.Scene{
Title: scene.Title, Title: scene.Title,
Code: scene.Code,
URL: scene.URL, URL: scene.URL,
Details: scene.Details, Details: scene.Details,
Director: scene.Director,
CreatedAt: json.JSONTime{Time: scene.CreatedAt}, CreatedAt: json.JSONTime{Time: scene.CreatedAt},
UpdatedAt: json.JSONTime{Time: scene.UpdatedAt}, UpdatedAt: json.JSONTime{Time: scene.UpdatedAt},
} }

View File

@@ -82,7 +82,9 @@ func (i *Importer) sceneJSONToScene(sceneJSON jsonschema.Scene) models.Scene {
newScene := models.Scene{ newScene := models.Scene{
// Path: i.Path, // Path: i.Path,
Title: sceneJSON.Title, Title: sceneJSON.Title,
Code: sceneJSON.Code,
Details: sceneJSON.Details, Details: sceneJSON.Details,
Director: sceneJSON.Director,
URL: sceneJSON.URL, URL: sceneJSON.URL,
PerformerIDs: models.NewRelatedIDs([]int{}), PerformerIDs: models.NewRelatedIDs([]int{}),
TagIDs: models.NewRelatedIDs([]int{}), TagIDs: models.NewRelatedIDs([]int{}),

View File

@@ -36,9 +36,11 @@ func queryURLParametersFromScrapedScene(scene ScrapedSceneInput) queryURLParamet
} }
setField("title", scene.Title) setField("title", scene.Title)
setField("code", scene.Code)
setField("url", scene.URL) setField("url", scene.URL)
setField("date", scene.Date) setField("date", scene.Date)
setField("details", scene.Details) setField("details", scene.Details)
setField("director", scene.Director)
setField("remote_site_id", scene.RemoteSiteID) setField("remote_site_id", scene.RemoteSiteID)
return ret return ret
} }

View File

@@ -6,7 +6,9 @@ import (
type ScrapedScene struct { type ScrapedScene struct {
Title *string `json:"title"` Title *string `json:"title"`
Code *string `json:"code"`
Details *string `json:"details"` Details *string `json:"details"`
Director *string `json:"director"`
URL *string `json:"url"` URL *string `json:"url"`
Date *string `json:"date"` Date *string `json:"date"`
// This should be a base64 encoded data URL // This should be a base64 encoded data URL
@@ -25,7 +27,9 @@ func (ScrapedScene) IsScrapedContent() {}
type ScrapedSceneInput struct { type ScrapedSceneInput struct {
Title *string `json:"title"` Title *string `json:"title"`
Code *string `json:"code"`
Details *string `json:"details"` Details *string `json:"details"`
Director *string `json:"director"`
URL *string `json:"url"` URL *string `json:"url"`
Date *string `json:"date"` Date *string `json:"date"`
RemoteSiteID *string `json:"remote_site_id"` RemoteSiteID *string `json:"remote_site_id"`

View File

@@ -182,7 +182,9 @@ type FingerprintFragment struct {
type SceneFragment struct { type SceneFragment struct {
ID string "json:\"id\" graphql:\"id\"" ID string "json:\"id\" graphql:\"id\""
Title *string "json:\"title\" graphql:\"title\"" Title *string "json:\"title\" graphql:\"title\""
Code *string "json:\"code\" graphql:\"code\""
Details *string "json:\"details\" graphql:\"details\"" Details *string "json:\"details\" graphql:\"details\""
Director *string "json:\"director\" graphql:\"director\""
Duration *int "json:\"duration\" graphql:\"duration\"" Duration *int "json:\"duration\" graphql:\"duration\""
Date *string "json:\"date\" graphql:\"date\"" Date *string "json:\"date\" graphql:\"date\""
Urls []*URLFragment "json:\"urls\" graphql:\"urls\"" Urls []*URLFragment "json:\"urls\" graphql:\"urls\""
@@ -237,6 +239,49 @@ const FindSceneByFingerprintDocument = `query FindSceneByFingerprint ($fingerpri
... SceneFragment ... SceneFragment
} }
} }
fragment MeasurementsFragment on Measurements {
band_size
cup_size
waist
hip
}
fragment SceneFragment on Scene {
id
title
code
details
director
duration
date
urls {
... URLFragment
}
images {
... ImageFragment
}
studio {
... StudioFragment
}
tags {
... TagFragment
}
performers {
... PerformerAppearanceFragment
}
fingerprints {
... FingerprintFragment
}
}
fragment StudioFragment on Studio {
name
id
urls {
... URLFragment
}
images {
... ImageFragment
}
}
fragment PerformerFragment on Performer { fragment PerformerFragment on Performer {
id id
name name
@@ -271,73 +316,32 @@ fragment PerformerFragment on Performer {
... BodyModificationFragment ... BodyModificationFragment
} }
} }
fragment FuzzyDateFragment on FuzzyDate {
date
accuracy
}
fragment BodyModificationFragment on BodyModification {
location
description
}
fragment FingerprintFragment on Fingerprint { fragment FingerprintFragment on Fingerprint {
algorithm algorithm
hash hash
duration duration
} }
fragment SceneFragment on Scene {
id
title
details
duration
date
urls {
... URLFragment
}
images {
... ImageFragment
}
studio {
... StudioFragment
}
tags {
... TagFragment
}
performers {
... PerformerAppearanceFragment
}
fingerprints {
... FingerprintFragment
}
}
fragment URLFragment on URL { fragment URLFragment on URL {
url url
type type
} }
fragment TagFragment on Tag {
name
id
}
fragment FuzzyDateFragment on FuzzyDate {
date
accuracy
}
fragment MeasurementsFragment on Measurements {
band_size
cup_size
waist
hip
}
fragment BodyModificationFragment on BodyModification {
location
description
}
fragment ImageFragment on Image { fragment ImageFragment on Image {
id id
url url
width width
height height
} }
fragment StudioFragment on Studio { fragment TagFragment on Tag {
name name
id id
urls {
... URLFragment
}
images {
... ImageFragment
}
} }
fragment PerformerAppearanceFragment on PerformerAppearance { fragment PerformerAppearanceFragment on PerformerAppearance {
as as
@@ -369,6 +373,22 @@ fragment URLFragment on URL {
url url
type type
} }
fragment ImageFragment on Image {
id
url
width
height
}
fragment StudioFragment on Studio {
name
id
urls {
... URLFragment
}
images {
... ImageFragment
}
}
fragment PerformerFragment on Performer { fragment PerformerFragment on Performer {
id id
name name
@@ -403,15 +423,16 @@ fragment PerformerFragment on Performer {
... BodyModificationFragment ... BodyModificationFragment
} }
} }
fragment FingerprintFragment on Fingerprint { fragment BodyModificationFragment on BodyModification {
algorithm location
hash description
duration
} }
fragment SceneFragment on Scene { fragment SceneFragment on Scene {
id id
title title
code
details details
director
duration duration
date date
urls { urls {
@@ -433,20 +454,6 @@ fragment SceneFragment on Scene {
... FingerprintFragment ... FingerprintFragment
} }
} }
fragment StudioFragment on Studio {
name
id
urls {
... URLFragment
}
images {
... ImageFragment
}
}
fragment TagFragment on Tag {
name
id
}
fragment PerformerAppearanceFragment on PerformerAppearance { fragment PerformerAppearanceFragment on PerformerAppearance {
as as
performer { performer {
@@ -463,15 +470,14 @@ fragment MeasurementsFragment on Measurements {
waist waist
hip hip
} }
fragment BodyModificationFragment on BodyModification { fragment FingerprintFragment on Fingerprint {
location algorithm
description hash
duration
} }
fragment ImageFragment on Image { fragment TagFragment on Tag {
name
id id
url
width
height
} }
` `
@@ -493,31 +499,6 @@ const FindScenesBySceneFingerprintsDocument = `query FindScenesBySceneFingerprin
... SceneFragment ... SceneFragment
} }
} }
fragment SceneFragment on Scene {
id
title
details
duration
date
urls {
... URLFragment
}
images {
... ImageFragment
}
studio {
... StudioFragment
}
tags {
... TagFragment
}
performers {
... PerformerAppearanceFragment
}
fingerprints {
... FingerprintFragment
}
}
fragment ImageFragment on Image { fragment ImageFragment on Image {
id id
url url
@@ -534,6 +515,29 @@ fragment StudioFragment on Studio {
... ImageFragment ... ImageFragment
} }
} }
fragment PerformerAppearanceFragment on PerformerAppearance {
as
performer {
... PerformerFragment
}
}
fragment FuzzyDateFragment on FuzzyDate {
date
accuracy
}
fragment FingerprintFragment on Fingerprint {
algorithm
hash
duration
}
fragment URLFragment on URL {
url
type
}
fragment TagFragment on Tag {
name
id
}
fragment PerformerFragment on Performer { fragment PerformerFragment on Performer {
id id
name name
@@ -568,29 +572,6 @@ fragment PerformerFragment on Performer {
... BodyModificationFragment ... BodyModificationFragment
} }
} }
fragment FingerprintFragment on Fingerprint {
algorithm
hash
duration
}
fragment URLFragment on URL {
url
type
}
fragment TagFragment on Tag {
name
id
}
fragment PerformerAppearanceFragment on PerformerAppearance {
as
performer {
... PerformerFragment
}
}
fragment FuzzyDateFragment on FuzzyDate {
date
accuracy
}
fragment MeasurementsFragment on Measurements { fragment MeasurementsFragment on Measurements {
band_size band_size
cup_size cup_size
@@ -601,6 +582,33 @@ fragment BodyModificationFragment on BodyModification {
location location
description description
} }
fragment SceneFragment on Scene {
id
title
code
details
director
duration
date
urls {
... URLFragment
}
images {
... ImageFragment
}
studio {
... StudioFragment
}
tags {
... TagFragment
}
performers {
... PerformerAppearanceFragment
}
fingerprints {
... FingerprintFragment
}
}
` `
func (c *Client) FindScenesBySceneFingerprints(ctx context.Context, fingerprints [][]*FingerprintQueryInput, httpRequestOptions ...client.HTTPRequestOption) (*FindScenesBySceneFingerprints, error) { func (c *Client) FindScenesBySceneFingerprints(ctx context.Context, fingerprints [][]*FingerprintQueryInput, httpRequestOptions ...client.HTTPRequestOption) (*FindScenesBySceneFingerprints, error) {
@@ -621,14 +629,27 @@ const SearchSceneDocument = `query SearchScene ($term: String!) {
... SceneFragment ... SceneFragment
} }
} }
fragment FuzzyDateFragment on FuzzyDate { fragment MeasurementsFragment on Measurements {
date band_size
accuracy cup_size
waist
hip
}
fragment BodyModificationFragment on BodyModification {
location
description
}
fragment FingerprintFragment on Fingerprint {
algorithm
hash
duration
} }
fragment SceneFragment on Scene { fragment SceneFragment on Scene {
id id
title title
code
details details
director
duration duration
date date
urls { urls {
@@ -650,45 +671,16 @@ fragment SceneFragment on Scene {
... FingerprintFragment ... FingerprintFragment
} }
} }
fragment URLFragment on URL {
url
type
}
fragment ImageFragment on Image { fragment ImageFragment on Image {
id id
url url
width width
height height
} }
fragment TagFragment on Tag {
name
id
}
fragment PerformerAppearanceFragment on PerformerAppearance {
as
performer {
... PerformerFragment
}
}
fragment BodyModificationFragment on BodyModification {
location
description
}
fragment FingerprintFragment on Fingerprint {
algorithm
hash
duration
}
fragment URLFragment on URL {
url
type
}
fragment StudioFragment on Studio {
name
id
urls {
... URLFragment
}
images {
... ImageFragment
}
}
fragment PerformerFragment on Performer { fragment PerformerFragment on Performer {
id id
name name
@@ -723,11 +715,29 @@ fragment PerformerFragment on Performer {
... BodyModificationFragment ... BodyModificationFragment
} }
} }
fragment MeasurementsFragment on Measurements { fragment FuzzyDateFragment on FuzzyDate {
band_size date
cup_size accuracy
waist }
hip fragment StudioFragment on Studio {
name
id
urls {
... URLFragment
}
images {
... ImageFragment
}
}
fragment TagFragment on Tag {
name
id
}
fragment PerformerAppearanceFragment on PerformerAppearance {
as
performer {
... PerformerFragment
}
} }
` `
@@ -749,6 +759,26 @@ const SearchPerformerDocument = `query SearchPerformer ($term: String!) {
... PerformerFragment ... PerformerFragment
} }
} }
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
@@ -787,26 +817,6 @@ fragment URLFragment on URL {
url url
type 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) SearchPerformer(ctx context.Context, term string, httpRequestOptions ...client.HTTPRequestOption) (*SearchPerformer, error) { func (c *Client) SearchPerformer(ctx context.Context, term string, httpRequestOptions ...client.HTTPRequestOption) (*SearchPerformer, error) {
@@ -827,16 +837,6 @@ const FindPerformerByIDDocument = `query FindPerformerByID ($id: ID!) {
... PerformerFragment ... PerformerFragment
} }
} }
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
@@ -885,6 +885,16 @@ fragment FuzzyDateFragment on FuzzyDate {
date date
accuracy 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) {
@@ -909,12 +919,49 @@ fragment BodyModificationFragment on BodyModification {
location location
description description
} }
fragment SceneFragment on Scene {
id
title
code
details
director
duration
date
urls {
... URLFragment
}
images {
... ImageFragment
}
studio {
... StudioFragment
}
tags {
... TagFragment
}
performers {
... PerformerAppearanceFragment
}
fingerprints {
... FingerprintFragment
}
}
fragment ImageFragment on Image { fragment ImageFragment on Image {
id id
url url
width width
height height
} }
fragment StudioFragment on Studio {
name
id
urls {
... URLFragment
}
images {
... ImageFragment
}
}
fragment FuzzyDateFragment on FuzzyDate { fragment FuzzyDateFragment on FuzzyDate {
date date
accuracy accuracy
@@ -925,6 +972,10 @@ fragment MeasurementsFragment on Measurements {
waist waist
hip hip
} }
fragment URLFragment on URL {
url
type
}
fragment TagFragment on Tag { fragment TagFragment on Tag {
name name
id id
@@ -974,45 +1025,6 @@ fragment FingerprintFragment on Fingerprint {
hash hash
duration duration
} }
fragment SceneFragment on Scene {
id
title
details
duration
date
urls {
... URLFragment
}
images {
... ImageFragment
}
studio {
... StudioFragment
}
tags {
... TagFragment
}
performers {
... PerformerAppearanceFragment
}
fingerprints {
... FingerprintFragment
}
}
fragment URLFragment on URL {
url
type
}
fragment StudioFragment on Studio {
name
id
urls {
... URLFragment
}
images {
... ImageFragment
}
}
` `
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) {

View File

@@ -88,8 +88,8 @@ type DraftEntity struct {
ID *string `json:"id,omitempty"` ID *string `json:"id,omitempty"`
} }
func (DraftEntity) IsSceneDraftStudio() {}
func (DraftEntity) IsSceneDraftTag() {} func (DraftEntity) IsSceneDraftTag() {}
func (DraftEntity) IsSceneDraftStudio() {}
func (DraftEntity) IsSceneDraftPerformer() {} func (DraftEntity) IsSceneDraftPerformer() {}
type DraftEntityInput struct { type DraftEntityInput struct {
@@ -339,8 +339,8 @@ type Performer struct {
Updated time.Time `json:"updated"` Updated time.Time `json:"updated"`
} }
func (Performer) IsSceneDraftPerformer() {}
func (Performer) IsEditTarget() {} func (Performer) IsEditTarget() {}
func (Performer) IsSceneDraftPerformer() {}
type PerformerAppearance struct { type PerformerAppearance struct {
Performer *Performer `json:"performer,omitempty"` Performer *Performer `json:"performer,omitempty"`

View File

@@ -667,8 +667,10 @@ func (c Client) sceneFragmentToScrapedScene(ctx context.Context, s *graphql.Scen
stashID := s.ID stashID := s.ID
ss := &scraper.ScrapedScene{ ss := &scraper.ScrapedScene{
Title: s.Title, Title: s.Title,
Code: s.Code,
Date: s.Date, Date: s.Date,
Details: s.Details, Details: s.Details,
Director: s.Director,
URL: findURL(s.Urls, "STUDIO"), URL: findURL(s.Urls, "STUDIO"),
Duration: s.Duration, Duration: s.Duration,
RemoteSiteID: &stashID, RemoteSiteID: &stashID,

View File

@@ -22,7 +22,7 @@ import (
"github.com/stashapp/stash/pkg/logger" "github.com/stashapp/stash/pkg/logger"
) )
var appSchemaVersion uint = 37 var appSchemaVersion uint = 38
//go:embed migrations/*.sql //go:embed migrations/*.sql
var migrationsBox embed.FS var migrationsBox embed.FS

View File

@@ -0,0 +1,2 @@
ALTER TABLE `scenes` ADD COLUMN `code` text;
ALTER TABLE `scenes` ADD COLUMN `director` text;

View File

@@ -54,7 +54,9 @@ ORDER BY files.size DESC
type sceneRow struct { type sceneRow struct {
ID int `db:"id" goqu:"skipinsert"` ID int `db:"id" goqu:"skipinsert"`
Title zero.String `db:"title"` Title zero.String `db:"title"`
Code zero.String `db:"code"`
Details zero.String `db:"details"` Details zero.String `db:"details"`
Director zero.String `db:"director"`
URL zero.String `db:"url"` URL zero.String `db:"url"`
Date models.SQLiteDate `db:"date"` Date models.SQLiteDate `db:"date"`
Rating null.Int `db:"rating"` Rating null.Int `db:"rating"`
@@ -68,7 +70,9 @@ type sceneRow struct {
func (r *sceneRow) fromScene(o models.Scene) { func (r *sceneRow) fromScene(o models.Scene) {
r.ID = o.ID r.ID = o.ID
r.Title = zero.StringFrom(o.Title) r.Title = zero.StringFrom(o.Title)
r.Code = zero.StringFrom(o.Code)
r.Details = zero.StringFrom(o.Details) r.Details = zero.StringFrom(o.Details)
r.Director = zero.StringFrom(o.Director)
r.URL = zero.StringFrom(o.URL) r.URL = zero.StringFrom(o.URL)
if o.Date != nil { if o.Date != nil {
_ = r.Date.Scan(o.Date.Time) _ = r.Date.Scan(o.Date.Time)
@@ -94,7 +98,9 @@ func (r *sceneQueryRow) resolve() *models.Scene {
ret := &models.Scene{ ret := &models.Scene{
ID: r.ID, ID: r.ID,
Title: r.Title.String, Title: r.Title.String,
Code: r.Code.String,
Details: r.Details.String, Details: r.Details.String,
Director: r.Director.String,
URL: r.URL.String, URL: r.URL.String,
Date: r.Date.DatePtr(), Date: r.Date.DatePtr(),
Rating: nullIntPtr(r.Rating), Rating: nullIntPtr(r.Rating),
@@ -123,7 +129,9 @@ type sceneRowRecord struct {
func (r *sceneRowRecord) fromPartial(o models.ScenePartial) { func (r *sceneRowRecord) fromPartial(o models.ScenePartial) {
r.setNullString("title", o.Title) r.setNullString("title", o.Title)
r.setNullString("code", o.Code)
r.setNullString("details", o.Details) r.setNullString("details", o.Details)
r.setNullString("director", o.Director)
r.setNullString("url", o.URL) r.setNullString("url", o.URL)
r.setSQLiteDate("date", o.Date) r.setSQLiteDate("date", o.Date)
r.setNullInt("rating", o.Rating) r.setNullInt("rating", o.Rating)
@@ -801,7 +809,9 @@ func (qb *SceneStore) makeFilter(ctx context.Context, sceneFilter *models.SceneF
query.handleCriterion(ctx, pathCriterionHandler(sceneFilter.Path, "folders.path", "files.basename", qb.addFoldersTable)) query.handleCriterion(ctx, pathCriterionHandler(sceneFilter.Path, "folders.path", "files.basename", qb.addFoldersTable))
query.handleCriterion(ctx, sceneFileCountCriterionHandler(qb, sceneFilter.FileCount)) query.handleCriterion(ctx, sceneFileCountCriterionHandler(qb, sceneFilter.FileCount))
query.handleCriterion(ctx, stringCriterionHandler(sceneFilter.Title, "scenes.title")) query.handleCriterion(ctx, stringCriterionHandler(sceneFilter.Title, "scenes.title"))
query.handleCriterion(ctx, stringCriterionHandler(sceneFilter.Code, "scenes.code"))
query.handleCriterion(ctx, stringCriterionHandler(sceneFilter.Details, "scenes.details")) query.handleCriterion(ctx, stringCriterionHandler(sceneFilter.Details, "scenes.details"))
query.handleCriterion(ctx, stringCriterionHandler(sceneFilter.Director, "scenes.director"))
query.handleCriterion(ctx, criterionHandlerFunc(func(ctx context.Context, f *filterBuilder) { query.handleCriterion(ctx, criterionHandlerFunc(func(ctx context.Context, f *filterBuilder) {
if sceneFilter.Oshash != nil { if sceneFilter.Oshash != nil {
qb.addSceneFilesTable(f) qb.addSceneFilesTable(f)

View File

@@ -73,7 +73,9 @@ func loadSceneRelationships(ctx context.Context, expected models.Scene, actual *
func Test_sceneQueryBuilder_Create(t *testing.T) { func Test_sceneQueryBuilder_Create(t *testing.T) {
var ( var (
title = "title" title = "title"
code = "1337"
details = "details" details = "details"
director = "director"
url = "url" url = "url"
rating = 3 rating = 3
ocounter = 5 ocounter = 5
@@ -100,7 +102,9 @@ func Test_sceneQueryBuilder_Create(t *testing.T) {
"full", "full",
models.Scene{ models.Scene{
Title: title, Title: title,
Code: code,
Details: details, Details: details,
Director: director,
URL: url, URL: url,
Date: &date, Date: &date,
Rating: &rating, Rating: &rating,
@@ -139,7 +143,9 @@ func Test_sceneQueryBuilder_Create(t *testing.T) {
"with file", "with file",
models.Scene{ models.Scene{
Title: title, Title: title,
Code: code,
Details: details, Details: details,
Director: director,
URL: url, URL: url,
Date: &date, Date: &date,
Rating: &rating, Rating: &rating,
@@ -294,7 +300,9 @@ func makeSceneFileWithID(i int) *file.VideoFile {
func Test_sceneQueryBuilder_Update(t *testing.T) { func Test_sceneQueryBuilder_Update(t *testing.T) {
var ( var (
title = "title" title = "title"
code = "1337"
details = "details" details = "details"
director = "director"
url = "url" url = "url"
rating = 3 rating = 3
ocounter = 5 ocounter = 5
@@ -320,7 +328,9 @@ func Test_sceneQueryBuilder_Update(t *testing.T) {
&models.Scene{ &models.Scene{
ID: sceneIDs[sceneIdxWithGallery], ID: sceneIDs[sceneIdxWithGallery],
Title: title, Title: title,
Code: code,
Details: details, Details: details,
Director: director,
URL: url, URL: url,
Date: &date, Date: &date,
Rating: &rating, Rating: &rating,
@@ -481,7 +491,9 @@ func clearScenePartial() models.ScenePartial {
// leave mandatory fields // leave mandatory fields
return models.ScenePartial{ return models.ScenePartial{
Title: models.OptionalString{Set: true, Null: true}, Title: models.OptionalString{Set: true, Null: true},
Code: models.OptionalString{Set: true, Null: true},
Details: models.OptionalString{Set: true, Null: true}, Details: models.OptionalString{Set: true, Null: true},
Director: models.OptionalString{Set: true, Null: true},
URL: models.OptionalString{Set: true, Null: true}, URL: models.OptionalString{Set: true, Null: true},
Date: models.OptionalDate{Set: true, Null: true}, Date: models.OptionalDate{Set: true, Null: true},
Rating: models.OptionalInt{Set: true, Null: true}, Rating: models.OptionalInt{Set: true, Null: true},
@@ -496,7 +508,9 @@ func clearScenePartial() models.ScenePartial {
func Test_sceneQueryBuilder_UpdatePartial(t *testing.T) { func Test_sceneQueryBuilder_UpdatePartial(t *testing.T) {
var ( var (
title = "title" title = "title"
code = "1337"
details = "details" details = "details"
director = "director"
url = "url" url = "url"
rating = 3 rating = 3
ocounter = 5 ocounter = 5
@@ -524,7 +538,9 @@ func Test_sceneQueryBuilder_UpdatePartial(t *testing.T) {
sceneIDs[sceneIdxWithSpacedName], sceneIDs[sceneIdxWithSpacedName],
models.ScenePartial{ models.ScenePartial{
Title: models.NewOptionalString(title), Title: models.NewOptionalString(title),
Code: models.NewOptionalString(code),
Details: models.NewOptionalString(details), Details: models.NewOptionalString(details),
Director: models.NewOptionalString(director),
URL: models.NewOptionalString(url), URL: models.NewOptionalString(url),
Date: models.NewOptionalDate(date), Date: models.NewOptionalDate(date),
Rating: models.NewOptionalInt(rating), Rating: models.NewOptionalInt(rating),
@@ -578,7 +594,9 @@ func Test_sceneQueryBuilder_UpdatePartial(t *testing.T) {
makeSceneFile(sceneIdxWithSpacedName), makeSceneFile(sceneIdxWithSpacedName),
}), }),
Title: title, Title: title,
Code: code,
Details: details, Details: details,
Director: director,
URL: url, URL: url,
Date: &date, Date: &date,
Rating: &rating, Rating: &rating,

View File

@@ -27,7 +27,7 @@ export const SceneDetailPanel: React.FC<ISceneDetailProps> = (props) => {
return ( return (
<> <>
<h6> <h6>
<FormattedMessage id="details" /> <FormattedMessage id="details" />:{" "}
</h6> </h6>
<p className="pre">{props.scene.details}</p> <p className="pre">{props.scene.details}</p>
</> </>
@@ -121,6 +121,16 @@ export const SceneDetailPanel: React.FC<ISceneDetailProps> = (props) => {
<FormattedMessage id="updated_at" />:{" "} <FormattedMessage id="updated_at" />:{" "}
{TextUtils.formatDateTime(intl, props.scene.updated_at)}{" "} {TextUtils.formatDateTime(intl, props.scene.updated_at)}{" "}
</h6> </h6>
{props.scene.code && (
<h6>
<FormattedMessage id="scene_code" />: {props.scene.code}{" "}
</h6>
)}
{props.scene.director && (
<h6>
<FormattedMessage id="director" />: {props.scene.director}{" "}
</h6>
)}
</div> </div>
{props.scene.studio && ( {props.scene.studio && (
<div className="col-3 d-xl-none"> <div className="col-3 d-xl-none">

View File

@@ -105,7 +105,9 @@ export const SceneEditPanel: React.FC<IProps> = ({
const schema = yup.object({ const schema = yup.object({
title: yup.string().optional().nullable(), title: yup.string().optional().nullable(),
code: yup.string().optional().nullable(),
details: yup.string().optional().nullable(), details: yup.string().optional().nullable(),
director: yup.string().optional().nullable(),
url: yup.string().optional().nullable(), url: yup.string().optional().nullable(),
date: yup.string().optional().nullable(), date: yup.string().optional().nullable(),
rating: yup.number().optional().nullable(), rating: yup.number().optional().nullable(),
@@ -127,7 +129,9 @@ export const SceneEditPanel: React.FC<IProps> = ({
const initialValues = useMemo( const initialValues = useMemo(
() => ({ () => ({
title: scene.title ?? "", title: scene.title ?? "",
code: scene.code ?? "",
details: scene.details ?? "", details: scene.details ?? "",
director: scene.director ?? "",
url: scene.url ?? "", url: scene.url ?? "",
date: scene.date ?? "", date: scene.date ?? "",
rating: scene.rating ?? null, rating: scene.rating ?? null,
@@ -337,7 +341,9 @@ export const SceneEditPanel: React.FC<IProps> = ({
try { try {
const input: GQL.ScrapedSceneInput = { const input: GQL.ScrapedSceneInput = {
date: fragment.date, date: fragment.date,
code: fragment.code,
details: fragment.details, details: fragment.details,
director: fragment.director,
remote_site_id: fragment.remote_site_id, remote_site_id: fragment.remote_site_id,
title: fragment.title, title: fragment.title,
url: fragment.url, url: fragment.url,
@@ -536,10 +542,18 @@ export const SceneEditPanel: React.FC<IProps> = ({
formik.setFieldValue("title", updatedScene.title); formik.setFieldValue("title", updatedScene.title);
} }
if (updatedScene.code) {
formik.setFieldValue("code", updatedScene.code);
}
if (updatedScene.details) { if (updatedScene.details) {
formik.setFieldValue("details", updatedScene.details); formik.setFieldValue("details", updatedScene.details);
} }
if (updatedScene.director) {
formik.setFieldValue("director", updatedScene.director);
}
if (updatedScene.date) { if (updatedScene.date) {
formik.setFieldValue("date", updatedScene.date); formik.setFieldValue("date", updatedScene.date);
} }
@@ -696,6 +710,7 @@ export const SceneEditPanel: React.FC<IProps> = ({
<div className="form-container row px-3"> <div className="form-container row px-3">
<div className="col-12 col-lg-7 col-xl-12"> <div className="col-12 col-lg-7 col-xl-12">
{renderTextField("title", intl.formatMessage({ id: "title" }))} {renderTextField("title", intl.formatMessage({ id: "title" }))}
{renderTextField("code", intl.formatMessage({ id: "scene_code" }))}
<Form.Group controlId="url" as={Row}> <Form.Group controlId="url" as={Row}>
<Col xs={3} className="pr-0 url-label"> <Col xs={3} className="pr-0 url-label">
<Form.Label className="col-form-label"> <Form.Label className="col-form-label">
@@ -716,6 +731,10 @@ export const SceneEditPanel: React.FC<IProps> = ({
intl.formatMessage({ id: "date" }), intl.formatMessage({ id: "date" }),
"YYYY-MM-DD" "YYYY-MM-DD"
)} )}
{renderTextField(
"director",
intl.formatMessage({ id: "director" })
)}
<Form.Group controlId="rating" as={Row}> <Form.Group controlId="rating" as={Row}>
{FormUtils.renderLabel({ {FormUtils.renderLabel({
title: intl.formatMessage({ id: "rating" }), title: intl.formatMessage({ id: "rating" }),

View File

@@ -248,12 +248,18 @@ export const SceneScrapeDialog: React.FC<ISceneScrapeDialogProps> = ({
const [title, setTitle] = useState<ScrapeResult<string>>( const [title, setTitle] = useState<ScrapeResult<string>>(
new ScrapeResult<string>(scene.title, scraped.title) new ScrapeResult<string>(scene.title, scraped.title)
); );
const [code, setCode] = useState<ScrapeResult<string>>(
new ScrapeResult<string>(scene.code, scraped.code)
);
const [url, setURL] = useState<ScrapeResult<string>>( const [url, setURL] = useState<ScrapeResult<string>>(
new ScrapeResult<string>(scene.url, scraped.url) new ScrapeResult<string>(scene.url, scraped.url)
); );
const [date, setDate] = useState<ScrapeResult<string>>( const [date, setDate] = useState<ScrapeResult<string>>(
new ScrapeResult<string>(scene.date, scraped.date) new ScrapeResult<string>(scene.date, scraped.date)
); );
const [director, setDirector] = useState<ScrapeResult<string>>(
new ScrapeResult<string>(scene.director, scraped.director)
);
const [studio, setStudio] = useState<ScrapeResult<string>>( const [studio, setStudio] = useState<ScrapeResult<string>>(
new ScrapeResult<string>(scene.studio_id, scraped.studio?.stored_id) new ScrapeResult<string>(scene.studio_id, scraped.studio?.stored_id)
); );
@@ -339,6 +345,7 @@ export const SceneScrapeDialog: React.FC<ISceneScrapeDialogProps> = ({
const [details, setDetails] = useState<ScrapeResult<string>>( const [details, setDetails] = useState<ScrapeResult<string>>(
new ScrapeResult<string>(scene.details, scraped.details) new ScrapeResult<string>(scene.details, scraped.details)
); );
const [image, setImage] = useState<ScrapeResult<string>>( const [image, setImage] = useState<ScrapeResult<string>>(
new ScrapeResult<string>(scene.cover_image, scraped.image) new ScrapeResult<string>(scene.cover_image, scraped.image)
); );
@@ -355,8 +362,10 @@ export const SceneScrapeDialog: React.FC<ISceneScrapeDialogProps> = ({
if ( if (
[ [
title, title,
code,
url, url,
date, date,
director,
studio, studio,
performers, performers,
movies, movies,
@@ -521,8 +530,10 @@ export const SceneScrapeDialog: React.FC<ISceneScrapeDialogProps> = ({
return { return {
title: title.getNewValue(), title: title.getNewValue(),
code: code.getNewValue(),
url: url.getNewValue(), url: url.getNewValue(),
date: date.getNewValue(), date: date.getNewValue(),
director: director.getNewValue(),
studio: newStudioValue studio: newStudioValue
? { ? {
stored_id: newStudioValue, stored_id: newStudioValue,
@@ -561,6 +572,11 @@ export const SceneScrapeDialog: React.FC<ISceneScrapeDialogProps> = ({
result={title} result={title}
onChange={(value) => setTitle(value)} onChange={(value) => setTitle(value)}
/> />
<ScrapedInputGroupRow
title={intl.formatMessage({ id: "scene_code" })}
result={code}
onChange={(value) => setCode(value)}
/>
<ScrapedInputGroupRow <ScrapedInputGroupRow
title={intl.formatMessage({ id: "url" })} title={intl.formatMessage({ id: "url" })}
result={url} result={url}
@@ -572,6 +588,11 @@ export const SceneScrapeDialog: React.FC<ISceneScrapeDialogProps> = ({
result={date} result={date}
onChange={(value) => setDate(value)} onChange={(value) => setDate(value)}
/> />
<ScrapedInputGroupRow
title={intl.formatMessage({ id: "director" })}
result={director}
onChange={(value) => setDirector(value)}
/>
{renderScrapedStudioRow( {renderScrapedStudioRow(
intl.formatMessage({ id: "studios" }), intl.formatMessage({ id: "studios" }),
studio, studio,

View File

@@ -1,4 +1,5 @@
### ✨ New Features ### ✨ New Features
* Added Directory and Studio Code fields to scenes. ([#3051](https://github.com/stashapp/stash/pull/3051))
* Added selector for Country field. ([#1922](https://github.com/stashapp/stash/pull/1922)) * Added selector for Country field. ([#1922](https://github.com/stashapp/stash/pull/1922))
* Added tag description filter criterion. ([#3011](https://github.com/stashapp/stash/pull/3011)) * Added tag description filter criterion. ([#3011](https://github.com/stashapp/stash/pull/3011))

View File

@@ -918,6 +918,7 @@
"scene": "Scene", "scene": "Scene",
"sceneTagger": "Scene Tagger", "sceneTagger": "Scene Tagger",
"sceneTags": "Scene Tags", "sceneTags": "Scene Tags",
"scene_code": "Studio Code",
"scene_count": "Scene Count", "scene_count": "Scene Count",
"scene_id": "Scene ID", "scene_id": "Scene ID",
"scenes": "Scenes", "scenes": "Scenes",

View File

@@ -165,6 +165,8 @@ export function makeCriteria(type: CriterionType = "none") {
case "synopsis": case "synopsis":
case "description": case "description":
return new StringCriterion(new StringCriterionOption(type, type)); return new StringCriterion(new StringCriterionOption(type, type));
case "scene_code":
return new StringCriterion(new StringCriterionOption(type, type, "code"));
case "interactive": case "interactive":
return new InteractiveCriterion(); return new InteractiveCriterion();
case "captions": case "captions":

View File

@@ -51,8 +51,10 @@ const displayModeOptions = [
const criterionOptions = [ const criterionOptions = [
createStringCriterionOption("title"), createStringCriterionOption("title"),
createStringCriterionOption("scene_code"),
createMandatoryStringCriterionOption("path"), createMandatoryStringCriterionOption("path"),
createStringCriterionOption("details"), createStringCriterionOption("details"),
createStringCriterionOption("director"),
createMandatoryStringCriterionOption("oshash", "media_info.hash"), createMandatoryStringCriterionOption("oshash", "media_info.hash"),
createStringCriterionOption( createStringCriterionOption(
"sceneChecksum", "sceneChecksum",

View File

@@ -125,4 +125,5 @@ export type CriterionType =
| "duplicated" | "duplicated"
| "ignore_auto_tag" | "ignore_auto_tag"
| "file_count" | "file_count"
| "description"; | "description"
| "scene_code";