More configuration options

* Allow configuration of generated file path and database path.  Closes #33
* Added checkboxes to choose what gets generated for the generate task.  Closes #32
This commit is contained in:
Stash Dev
2019-03-24 10:04:31 -07:00
parent 06d88cbeb4
commit c1f1a6ccff
16 changed files with 418 additions and 74 deletions

File diff suppressed because one or more lines are too long

View File

@@ -6,13 +6,10 @@ import (
"github.com/stashapp/stash/pkg/manager/config" "github.com/stashapp/stash/pkg/manager/config"
"github.com/stashapp/stash/pkg/models" "github.com/stashapp/stash/pkg/models"
"github.com/stashapp/stash/pkg/utils" "github.com/stashapp/stash/pkg/utils"
"path/filepath"
) )
func (r *mutationResolver) ConfigureGeneral(ctx context.Context, input *models.ConfigGeneralInput) (models.ConfigGeneralResult, error) { func (r *mutationResolver) ConfigureGeneral(ctx context.Context, input models.ConfigGeneralInput) (models.ConfigGeneralResult, error) {
if input == nil {
return makeConfigGeneralResult(), fmt.Errorf("nil input")
}
if len(input.Stashes) > 0 { if len(input.Stashes) > 0 {
for _, stashPath := range input.Stashes { for _, stashPath := range input.Stashes {
exists, err := utils.DirExists(stashPath) exists, err := utils.DirExists(stashPath)
@@ -23,6 +20,21 @@ func (r *mutationResolver) ConfigureGeneral(ctx context.Context, input *models.C
config.Set(config.Stash, input.Stashes) config.Set(config.Stash, input.Stashes)
} }
if input.DatabasePath != nil {
ext := filepath.Ext(*input.DatabasePath)
if ext != ".db" && ext != ".sqlite" && ext != ".sqlite3" {
return makeConfigGeneralResult(), fmt.Errorf("invalid database path, use extension db, sqlite, or sqlite3")
}
config.Set(config.Database, input.DatabasePath)
}
if input.GeneratedPath != nil {
if err := utils.EnsureDir(*input.GeneratedPath); err != nil {
return makeConfigGeneralResult(), err
}
config.Set(config.Generated, input.GeneratedPath)
}
if err := config.Write(); err != nil { if err := config.Write(); err != nil {
return makeConfigGeneralResult(), err return makeConfigGeneralResult(), err
} }

View File

@@ -27,6 +27,8 @@ func makeConfigResult() models.ConfigResult {
func makeConfigGeneralResult() models.ConfigGeneralResult { func makeConfigGeneralResult() models.ConfigGeneralResult {
return models.ConfigGeneralResult{ return models.ConfigGeneralResult{
Stashes: config.GetStashPaths(), Stashes: config.GetStashPaths(),
DatabasePath: config.GetDatabasePath(),
GeneratedPath: config.GetGeneratedPath(),
} }
} }

View File

@@ -3,6 +3,7 @@ package api
import ( import (
"context" "context"
"github.com/stashapp/stash/pkg/manager" "github.com/stashapp/stash/pkg/manager"
"github.com/stashapp/stash/pkg/models"
) )
func (r *queryResolver) MetadataScan(ctx context.Context) (string, error) { func (r *queryResolver) MetadataScan(ctx context.Context) (string, error) {
@@ -20,8 +21,8 @@ func (r *queryResolver) MetadataExport(ctx context.Context) (string, error) {
return "todo", nil return "todo", nil
} }
func (r *queryResolver) MetadataGenerate(ctx context.Context) (string, error) { func (r *queryResolver) MetadataGenerate(ctx context.Context, input models.GenerateMetadataInput) (string, error) {
manager.GetInstance().Generate(true, true, true, true) manager.GetInstance().Generate(input.Sprites, input.Previews, input.Markers, input.Transcodes)
return "todo", nil return "todo", nil
} }

View File

@@ -48,7 +48,9 @@ type DirectiveRoot struct {
type ComplexityRoot struct { type ComplexityRoot struct {
ConfigGeneralResult struct { ConfigGeneralResult struct {
Stashes func(childComplexity int) int Stashes func(childComplexity int) int
DatabasePath func(childComplexity int) int
GeneratedPath func(childComplexity int) int
} }
ConfigResult struct { ConfigResult struct {
@@ -112,7 +114,7 @@ type ComplexityRoot struct {
TagCreate func(childComplexity int, input TagCreateInput) int TagCreate func(childComplexity int, input TagCreateInput) int
TagUpdate func(childComplexity int, input TagUpdateInput) int TagUpdate func(childComplexity int, input TagUpdateInput) int
TagDestroy func(childComplexity int, input TagDestroyInput) int TagDestroy func(childComplexity int, input TagDestroyInput) int
ConfigureGeneral func(childComplexity int, input *ConfigGeneralInput) int ConfigureGeneral func(childComplexity int, input ConfigGeneralInput) int
} }
Performer struct { Performer struct {
@@ -163,7 +165,7 @@ type ComplexityRoot struct {
MetadataImport func(childComplexity int) int MetadataImport func(childComplexity int) int
MetadataExport func(childComplexity int) int MetadataExport func(childComplexity int) int
MetadataScan func(childComplexity int) int MetadataScan func(childComplexity int) int
MetadataGenerate func(childComplexity int) int MetadataGenerate func(childComplexity int, input GenerateMetadataInput) int
MetadataClean func(childComplexity int) int MetadataClean func(childComplexity int) int
AllPerformers func(childComplexity int) int AllPerformers func(childComplexity int) int
AllStudios func(childComplexity int) int AllStudios func(childComplexity int) int
@@ -290,7 +292,7 @@ type MutationResolver interface {
TagCreate(ctx context.Context, input TagCreateInput) (*Tag, error) TagCreate(ctx context.Context, input TagCreateInput) (*Tag, error)
TagUpdate(ctx context.Context, input TagUpdateInput) (*Tag, error) TagUpdate(ctx context.Context, input TagUpdateInput) (*Tag, error)
TagDestroy(ctx context.Context, input TagDestroyInput) (bool, error) TagDestroy(ctx context.Context, input TagDestroyInput) (bool, error)
ConfigureGeneral(ctx context.Context, input *ConfigGeneralInput) (ConfigGeneralResult, error) ConfigureGeneral(ctx context.Context, input ConfigGeneralInput) (ConfigGeneralResult, error)
} }
type PerformerResolver interface { type PerformerResolver interface {
ID(ctx context.Context, obj *Performer) (string, error) ID(ctx context.Context, obj *Performer) (string, error)
@@ -339,7 +341,7 @@ type QueryResolver interface {
MetadataImport(ctx context.Context) (string, error) MetadataImport(ctx context.Context) (string, error)
MetadataExport(ctx context.Context) (string, error) MetadataExport(ctx context.Context) (string, error)
MetadataScan(ctx context.Context) (string, error) MetadataScan(ctx context.Context) (string, error)
MetadataGenerate(ctx context.Context) (string, error) MetadataGenerate(ctx context.Context, input GenerateMetadataInput) (string, error)
MetadataClean(ctx context.Context) (string, error) MetadataClean(ctx context.Context) (string, error)
AllPerformers(ctx context.Context) ([]Performer, error) AllPerformers(ctx context.Context) ([]Performer, error)
AllStudios(ctx context.Context) ([]Studio, error) AllStudios(ctx context.Context) ([]Studio, error)
@@ -617,26 +619,19 @@ func (e *executableSchema) field_Mutation_tagDestroy_args(ctx context.Context, r
func (e *executableSchema) field_Mutation_configureGeneral_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { func (e *executableSchema) field_Mutation_configureGeneral_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
args := map[string]interface{}{} args := map[string]interface{}{}
var arg0 *ConfigGeneralInput var arg0 ConfigGeneralInput
if tmp, ok := rawArgs["input"]; ok { if tmp, ok := rawArgs["input"]; ok {
var err error var err error
var ptr1 ConfigGeneralInput arg0, err = UnmarshalConfigGeneralInput(tmp)
if tmp != nil {
ptr1, err = UnmarshalConfigGeneralInput(tmp)
arg0 = &ptr1
}
if err != nil { if err != nil {
return nil, err return nil, err
} }
if arg0 != nil { mConfigGeneralInput1, err := e.ConfigGeneralInputMiddleware(ctx, &arg0)
var err error if err != nil {
arg0, err = e.ConfigGeneralInputMiddleware(ctx, arg0) return nil, err
if err != nil {
return nil, err
}
} }
arg0 = *mConfigGeneralInput1
} }
args["input"] = arg0 args["input"] = arg0
return args, nil return args, nil
@@ -1122,6 +1117,27 @@ func (e *executableSchema) field_Query_directories_args(ctx context.Context, raw
} }
func (e *executableSchema) field_Query_metadataGenerate_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
args := map[string]interface{}{}
var arg0 GenerateMetadataInput
if tmp, ok := rawArgs["input"]; ok {
var err error
arg0, err = UnmarshalGenerateMetadataInput(tmp)
if err != nil {
return nil, err
}
mGenerateMetadataInput1, err := e.GenerateMetadataInputMiddleware(ctx, &arg0)
if err != nil {
return nil, err
}
arg0 = *mGenerateMetadataInput1
}
args["input"] = arg0
return args, nil
}
func (e *executableSchema) field_Query___type_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { func (e *executableSchema) field_Query___type_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
args := map[string]interface{}{} args := map[string]interface{}{}
var arg0 string var arg0 string
@@ -1187,6 +1203,20 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.ConfigGeneralResult.Stashes(childComplexity), true return e.complexity.ConfigGeneralResult.Stashes(childComplexity), true
case "ConfigGeneralResult.databasePath":
if e.complexity.ConfigGeneralResult.DatabasePath == nil {
break
}
return e.complexity.ConfigGeneralResult.DatabasePath(childComplexity), true
case "ConfigGeneralResult.generatedPath":
if e.complexity.ConfigGeneralResult.GeneratedPath == nil {
break
}
return e.complexity.ConfigGeneralResult.GeneratedPath(childComplexity), true
case "ConfigResult.general": case "ConfigResult.general":
if e.complexity.ConfigResult.General == nil { if e.complexity.ConfigResult.General == nil {
break break
@@ -1483,7 +1513,7 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return 0, false return 0, false
} }
return e.complexity.Mutation.ConfigureGeneral(childComplexity, args["input"].(*ConfigGeneralInput)), true return e.complexity.Mutation.ConfigureGeneral(childComplexity, args["input"].(ConfigGeneralInput)), true
case "Performer.id": case "Performer.id":
if e.complexity.Performer.Id == nil { if e.complexity.Performer.Id == nil {
@@ -1888,7 +1918,12 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
break break
} }
return e.complexity.Query.MetadataGenerate(childComplexity), true args, err := e.field_Query_metadataGenerate_args(context.TODO(), rawArgs)
if err != nil {
return 0, false
}
return e.complexity.Query.MetadataGenerate(childComplexity, args["input"].(GenerateMetadataInput)), true
case "Query.metadataClean": case "Query.metadataClean":
if e.complexity.Query.MetadataClean == nil { if e.complexity.Query.MetadataClean == nil {
@@ -2504,6 +2539,19 @@ func (ec *executionContext) _ConfigGeneralResult(ctx context.Context, sel ast.Se
out.Values[i] = graphql.MarshalString("ConfigGeneralResult") out.Values[i] = graphql.MarshalString("ConfigGeneralResult")
case "stashes": case "stashes":
out.Values[i] = ec._ConfigGeneralResult_stashes(ctx, field, obj) out.Values[i] = ec._ConfigGeneralResult_stashes(ctx, field, obj)
if out.Values[i] == graphql.Null {
invalid = true
}
case "databasePath":
out.Values[i] = ec._ConfigGeneralResult_databasePath(ctx, field, obj)
if out.Values[i] == graphql.Null {
invalid = true
}
case "generatedPath":
out.Values[i] = ec._ConfigGeneralResult_generatedPath(ctx, field, obj)
if out.Values[i] == graphql.Null {
invalid = true
}
default: default:
panic("unknown field " + strconv.Quote(field.Name)) panic("unknown field " + strconv.Quote(field.Name))
} }
@@ -2531,6 +2579,9 @@ func (ec *executionContext) _ConfigGeneralResult_stashes(ctx context.Context, fi
return obj.Stashes, nil return obj.Stashes, nil
}) })
if resTmp == nil { if resTmp == nil {
if !ec.HasError(rctx) {
ec.Errorf(ctx, "must not be null")
}
return graphql.Null return graphql.Null
} }
res := resTmp.([]string) res := resTmp.([]string)
@@ -2548,6 +2599,60 @@ func (ec *executionContext) _ConfigGeneralResult_stashes(ctx context.Context, fi
return arr1 return arr1
} }
// nolint: vetshadow
func (ec *executionContext) _ConfigGeneralResult_databasePath(ctx context.Context, field graphql.CollectedField, obj *ConfigGeneralResult) graphql.Marshaler {
ctx = ec.Tracer.StartFieldExecution(ctx, field)
defer func() { ec.Tracer.EndFieldExecution(ctx) }()
rctx := &graphql.ResolverContext{
Object: "ConfigGeneralResult",
Field: field,
Args: nil,
}
ctx = graphql.WithResolverContext(ctx, rctx)
ctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx)
resTmp := ec.FieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) {
ctx = rctx // use context from middleware stack in children
return obj.DatabasePath, nil
})
if resTmp == nil {
if !ec.HasError(rctx) {
ec.Errorf(ctx, "must not be null")
}
return graphql.Null
}
res := resTmp.(string)
rctx.Result = res
ctx = ec.Tracer.StartFieldChildExecution(ctx)
return graphql.MarshalString(res)
}
// nolint: vetshadow
func (ec *executionContext) _ConfigGeneralResult_generatedPath(ctx context.Context, field graphql.CollectedField, obj *ConfigGeneralResult) graphql.Marshaler {
ctx = ec.Tracer.StartFieldExecution(ctx, field)
defer func() { ec.Tracer.EndFieldExecution(ctx) }()
rctx := &graphql.ResolverContext{
Object: "ConfigGeneralResult",
Field: field,
Args: nil,
}
ctx = graphql.WithResolverContext(ctx, rctx)
ctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx)
resTmp := ec.FieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) {
ctx = rctx // use context from middleware stack in children
return obj.GeneratedPath, nil
})
if resTmp == nil {
if !ec.HasError(rctx) {
ec.Errorf(ctx, "must not be null")
}
return graphql.Null
}
res := resTmp.(string)
rctx.Result = res
ctx = ec.Tracer.StartFieldChildExecution(ctx)
return graphql.MarshalString(res)
}
var configResultImplementors = []string{"ConfigResult"} var configResultImplementors = []string{"ConfigResult"}
// nolint: gocyclo, errcheck, gas, goconst // nolint: gocyclo, errcheck, gas, goconst
@@ -4136,7 +4241,7 @@ func (ec *executionContext) _Mutation_configureGeneral(ctx context.Context, fiel
ctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx) ctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx)
resTmp := ec.FieldMiddleware(ctx, nil, func(rctx context.Context) (interface{}, error) { resTmp := ec.FieldMiddleware(ctx, nil, func(rctx context.Context) (interface{}, error) {
ctx = rctx // use context from middleware stack in children ctx = rctx // use context from middleware stack in children
return ec.resolvers.Mutation().ConfigureGeneral(rctx, args["input"].(*ConfigGeneralInput)) return ec.resolvers.Mutation().ConfigureGeneral(rctx, args["input"].(ConfigGeneralInput))
}) })
if resTmp == nil { if resTmp == nil {
if !ec.HasError(rctx) { if !ec.HasError(rctx) {
@@ -6153,10 +6258,17 @@ func (ec *executionContext) _Query_metadataGenerate(ctx context.Context, field g
Args: nil, Args: nil,
} }
ctx = graphql.WithResolverContext(ctx, rctx) ctx = graphql.WithResolverContext(ctx, rctx)
rawArgs := field.ArgumentMap(ec.Variables)
args, err := ec.field_Query_metadataGenerate_args(ctx, rawArgs)
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
rctx.Args = args
ctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx) ctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx)
resTmp := ec.FieldMiddleware(ctx, nil, func(rctx context.Context) (interface{}, error) { resTmp := ec.FieldMiddleware(ctx, nil, func(rctx context.Context) (interface{}, error) {
ctx = rctx // use context from middleware stack in children ctx = rctx // use context from middleware stack in children
return ec.resolvers.Query().MetadataGenerate(rctx) return ec.resolvers.Query().MetadataGenerate(rctx, args["input"].(GenerateMetadataInput))
}) })
if resTmp == nil { if resTmp == nil {
if !ec.HasError(rctx) { if !ec.HasError(rctx) {
@@ -10597,6 +10709,28 @@ func UnmarshalConfigGeneralInput(v interface{}) (ConfigGeneralInput, error) {
for idx1 := range rawIf1 { for idx1 := range rawIf1 {
it.Stashes[idx1], err = graphql.UnmarshalString(rawIf1[idx1]) it.Stashes[idx1], err = graphql.UnmarshalString(rawIf1[idx1])
} }
if err != nil {
return it, err
}
case "databasePath":
var err error
var ptr1 string
if v != nil {
ptr1, err = graphql.UnmarshalString(v)
it.DatabasePath = &ptr1
}
if err != nil {
return it, err
}
case "generatedPath":
var err error
var ptr1 string
if v != nil {
ptr1, err = graphql.UnmarshalString(v)
it.GeneratedPath = &ptr1
}
if err != nil { if err != nil {
return it, err return it, err
} }
@@ -10683,6 +10817,47 @@ func (e *executableSchema) FindFilterTypeMiddleware(ctx context.Context, obj *Fi
return obj, nil return obj, nil
} }
func UnmarshalGenerateMetadataInput(v interface{}) (GenerateMetadataInput, error) {
var it GenerateMetadataInput
var asMap = v.(map[string]interface{})
for k, v := range asMap {
switch k {
case "sprites":
var err error
it.Sprites, err = graphql.UnmarshalBoolean(v)
if err != nil {
return it, err
}
case "previews":
var err error
it.Previews, err = graphql.UnmarshalBoolean(v)
if err != nil {
return it, err
}
case "markers":
var err error
it.Markers, err = graphql.UnmarshalBoolean(v)
if err != nil {
return it, err
}
case "transcodes":
var err error
it.Transcodes, err = graphql.UnmarshalBoolean(v)
if err != nil {
return it, err
}
}
}
return it, nil
}
func (e *executableSchema) GenerateMetadataInputMiddleware(ctx context.Context, obj *GenerateMetadataInput) (*GenerateMetadataInput, error) {
return obj, nil
}
func UnmarshalPerformerCreateInput(v interface{}) (PerformerCreateInput, error) { func UnmarshalPerformerCreateInput(v interface{}) (PerformerCreateInput, error) {
var it PerformerCreateInput var it PerformerCreateInput
var asMap = v.(map[string]interface{}) var asMap = v.(map[string]interface{})
@@ -12148,11 +12323,19 @@ input SceneFilterType {
input ConfigGeneralInput { input ConfigGeneralInput {
"""Array of file paths to content""" """Array of file paths to content"""
stashes: [String!] stashes: [String!]
"""Path to the SQLite database"""
databasePath: String
"""Path to generated files"""
generatedPath: String
} }
type ConfigGeneralResult { type ConfigGeneralResult {
"""Array of file paths to content""" """Array of file paths to content"""
stashes: [String!] stashes: [String!]!
"""Path to the SQLite database"""
databasePath: String!
"""Path to generated files"""
generatedPath: String!
} }
"""All configuration settings""" """All configuration settings"""
@@ -12160,6 +12343,17 @@ type ConfigResult {
general: ConfigGeneralResult! general: ConfigGeneralResult!
} }
#######################################
# Metadata
#######################################
input GenerateMetadataInput {
sprites: Boolean!
previews: Boolean!
markers: Boolean!
transcodes: Boolean!
}
############# #############
# Root Schema # Root Schema
############# #############
@@ -12225,7 +12419,7 @@ type Query {
"""Start a scan. Returns the job ID""" """Start a scan. Returns the job ID"""
metadataScan: String! metadataScan: String!
"""Start generating content. Returns the job ID""" """Start generating content. Returns the job ID"""
metadataGenerate: String! metadataGenerate(input: GenerateMetadataInput!): String!
"""Clean metadata. Returns the job ID""" """Clean metadata. Returns the job ID"""
metadataClean: String! metadataClean: String!
@@ -12254,7 +12448,7 @@ type Mutation {
tagDestroy(input: TagDestroyInput!): Boolean! tagDestroy(input: TagDestroyInput!): Boolean!
"""Change general configuration options""" """Change general configuration options"""
configureGeneral(input: ConfigGeneralInput): ConfigGeneralResult! configureGeneral(input: ConfigGeneralInput!): ConfigGeneralResult!
} }
type Subscription { type Subscription {

View File

@@ -11,11 +11,19 @@ import (
type ConfigGeneralInput struct { type ConfigGeneralInput struct {
// Array of file paths to content // Array of file paths to content
Stashes []string `json:"stashes"` Stashes []string `json:"stashes"`
// Path to the SQLite database
DatabasePath *string `json:"databasePath"`
// Path to generated files
GeneratedPath *string `json:"generatedPath"`
} }
type ConfigGeneralResult struct { type ConfigGeneralResult struct {
// Array of file paths to content // Array of file paths to content
Stashes []string `json:"stashes"` Stashes []string `json:"stashes"`
// Path to the SQLite database
DatabasePath string `json:"databasePath"`
// Path to generated files
GeneratedPath string `json:"generatedPath"`
} }
// All configuration settings // All configuration settings
@@ -62,6 +70,13 @@ type GalleryFilesType struct {
Path *string `json:"path"` Path *string `json:"path"`
} }
type GenerateMetadataInput struct {
Sprites bool `json:"sprites"`
Previews bool `json:"previews"`
Markers bool `json:"markers"`
Transcodes bool `json:"transcodes"`
}
type MarkerStringsResultType struct { type MarkerStringsResultType struct {
Count int `json:"count"` Count int `json:"count"`
ID string `json:"id"` ID string `json:"id"`

View File

@@ -1,5 +1,7 @@
fragment ConfigGeneralData on ConfigGeneralResult { fragment ConfigGeneralData on ConfigGeneralResult {
stashes stashes
databasePath
generatedPath
} }
fragment ConfigData on ConfigResult { fragment ConfigData on ConfigResult {

View File

@@ -10,8 +10,8 @@ query MetadataScan {
metadataScan metadataScan
} }
query MetadataGenerate { query MetadataGenerate($input: GenerateMetadataInput!) {
metadataGenerate metadataGenerate(input: $input)
} }
query MetadataClean { query MetadataClean {

View File

@@ -379,11 +379,19 @@ input SceneFilterType {
input ConfigGeneralInput { input ConfigGeneralInput {
"""Array of file paths to content""" """Array of file paths to content"""
stashes: [String!] stashes: [String!]
"""Path to the SQLite database"""
databasePath: String
"""Path to generated files"""
generatedPath: String
} }
type ConfigGeneralResult { type ConfigGeneralResult {
"""Array of file paths to content""" """Array of file paths to content"""
stashes: [String!] stashes: [String!]!
"""Path to the SQLite database"""
databasePath: String!
"""Path to generated files"""
generatedPath: String!
} }
"""All configuration settings""" """All configuration settings"""
@@ -391,6 +399,17 @@ type ConfigResult {
general: ConfigGeneralResult! general: ConfigGeneralResult!
} }
#######################################
# Metadata
#######################################
input GenerateMetadataInput {
sprites: Boolean!
previews: Boolean!
markers: Boolean!
transcodes: Boolean!
}
############# #############
# Root Schema # Root Schema
############# #############
@@ -456,7 +475,7 @@ type Query {
"""Start a scan. Returns the job ID""" """Start a scan. Returns the job ID"""
metadataScan: String! metadataScan: String!
"""Start generating content. Returns the job ID""" """Start generating content. Returns the job ID"""
metadataGenerate: String! metadataGenerate(input: GenerateMetadataInput!): String!
"""Clean metadata. Returns the job ID""" """Clean metadata. Returns the job ID"""
metadataClean: String! metadataClean: String!
@@ -485,7 +504,7 @@ type Mutation {
tagDestroy(input: TagDestroyInput!): Boolean! tagDestroy(input: TagDestroyInput!): Boolean!
"""Change general configuration options""" """Change general configuration options"""
configureGeneral(input: ConfigGeneralInput): ConfigGeneralResult! configureGeneral(input: ConfigGeneralInput!): ConfigGeneralResult!
} }
type Subscription { type Subscription {

View File

@@ -9,7 +9,7 @@ import { IBaseProps } from "../../models";
import { SettingsAboutPanel } from "./SettingsAboutPanel"; import { SettingsAboutPanel } from "./SettingsAboutPanel";
import { SettingsConfigurationPanel } from "./SettingsConfigurationPanel"; import { SettingsConfigurationPanel } from "./SettingsConfigurationPanel";
import { SettingsLogsPanel } from "./SettingsLogsPanel"; import { SettingsLogsPanel } from "./SettingsLogsPanel";
import { SettingsTasksPanel } from "./SettingsTasksPanel"; import { SettingsTasksPanel } from "./SettingsTasksPanel/SettingsTasksPanel";
interface IProps extends IBaseProps {} interface IProps extends IBaseProps {}

View File

@@ -7,6 +7,7 @@ import {
H6, H6,
Spinner, Spinner,
Tag, Tag,
InputGroup,
} from "@blueprintjs/core"; } from "@blueprintjs/core";
import React, { FunctionComponent, useEffect, useState } from "react"; import React, { FunctionComponent, useEffect, useState } from "react";
import * as GQL from "../../core/generated-graphql"; import * as GQL from "../../core/generated-graphql";
@@ -21,12 +22,15 @@ interface IProps {}
export const SettingsConfigurationPanel: FunctionComponent<IProps> = (props: IProps) => { export const SettingsConfigurationPanel: FunctionComponent<IProps> = (props: IProps) => {
// Editing config state // Editing config state
const [stashes, setStashes] = useState<string[]>([]); const [stashes, setStashes] = useState<string[]>([]);
const [databasePath, setDatabasePath] = useState<string | undefined>(undefined);
const [generatedPath, setGeneratedPath] = useState<string | undefined>(undefined);
// const [config, setConfig] = useState<Partial<GQL.ConfigDataFragment>>({});
const { data, error, loading } = StashService.useConfiguration(); const { data, error, loading } = StashService.useConfiguration();
const updateGeneralConfig = StashService.useConfigureGeneral({ const updateGeneralConfig = StashService.useConfigureGeneral({
stashes, stashes,
databasePath,
generatedPath,
}); });
useEffect(() => { useEffect(() => {
@@ -34,8 +38,9 @@ export const SettingsConfigurationPanel: FunctionComponent<IProps> = (props: IPr
const conf = StashService.nullToUndefined(data.configuration) as GQL.ConfigDataFragment; const conf = StashService.nullToUndefined(data.configuration) as GQL.ConfigDataFragment;
if (!!conf.general) { if (!!conf.general) {
setStashes(conf.general.stashes || []); setStashes(conf.general.stashes || []);
setDatabasePath(conf.general.databasePath);
setGeneratedPath(conf.general.generatedPath);
} }
// setConfig(conf);
}, [data]); }, [data]);
function onStashesChanged(directories: string[]) { function onStashesChanged(directories: string[]) {
@@ -54,7 +59,7 @@ export const SettingsConfigurationPanel: FunctionComponent<IProps> = (props: IPr
return ( return (
<> <>
{!!error ? error : undefined} {!!error ? <h1>{error.message}</h1> : undefined}
{(!data || !data.configuration || loading) ? <Spinner size={Spinner.SIZE_LARGE} /> : undefined} {(!data || !data.configuration || loading) ? <Spinner size={Spinner.SIZE_LARGE} /> : undefined}
<H4>Library</H4> <H4>Library</H4>
<FormGroup <FormGroup
@@ -66,6 +71,18 @@ export const SettingsConfigurationPanel: FunctionComponent<IProps> = (props: IPr
onDirectoriesChanged={onStashesChanged} onDirectoriesChanged={onStashesChanged}
/> />
</FormGroup> </FormGroup>
<FormGroup
label="Database Path"
helperText="File location for the SQLite database (requires restart)"
>
<InputGroup defaultValue={databasePath} onChange={(e: any) => setDatabasePath(e.target.value)} />
</FormGroup>
<FormGroup
label="Generated Path"
helperText="Directory location for the generated files (scene markers, scene previews, sprites, etc)"
>
<InputGroup defaultValue={generatedPath} onChange={(e: any) => setGeneratedPath(e.target.value)} />
</FormGroup>
<Divider /> <Divider />
<Button intent="primary" onClick={() => onSave()}>Save</Button> <Button intent="primary" onClick={() => onSave()}>Save</Button>
</> </>

View File

@@ -0,0 +1,53 @@
import {
Button,
Checkbox,
FormGroup,
} from "@blueprintjs/core";
import React, { FunctionComponent, useState } from "react";
import { StashService } from "../../../core/StashService";
import { ErrorUtils } from "../../../utils/errors";
import { ToastUtils } from "../../../utils/toasts";
interface IProps {}
export const GenerateButton: FunctionComponent<IProps> = () => {
const [sprites, setSprites] = useState<boolean>(true);
const [previews, setPreviews] = useState<boolean>(true);
const [markers, setMarkers] = useState<boolean>(true);
const [transcodes, setTranscodes] = useState<boolean>(true);
async function onGenerate() {
try {
await StashService.queryMetadataGenerate({sprites, previews, markers, transcodes});
ToastUtils.success("Started generating");
} catch (e) {
ErrorUtils.handle(e);
}
}
return (
<FormGroup
helperText="Generate supporting image, sprite, video, vtt and other files."
labelFor="generate"
inline={true}
>
<Checkbox checked={sprites} label="Sprites (for the scene scrubber)" onChange={() => setSprites(!sprites)} />
<Checkbox
checked={previews}
label="Previews (video previews which play when hovering over a scene)"
onChange={() => setPreviews(!previews)}
/>
<Checkbox
checked={markers}
label="Markers (20 second videos which begin at the given timecode)"
onChange={() => setMarkers(!markers)}
/>
<Checkbox
checked={transcodes}
label="Transcodes (MP4 conversions of unsupported video formats)"
onChange={() => setTranscodes(!transcodes)}
/>
<Button id="generate" text="Generate" onClick={() => onGenerate()} />
</FormGroup>
);
};

View File

@@ -10,9 +10,12 @@ import {
Tag, Tag,
} from "@blueprintjs/core"; } from "@blueprintjs/core";
import React, { FunctionComponent, useState } from "react"; import React, { FunctionComponent, useState } from "react";
import * as GQL from "../../core/generated-graphql"; import * as GQL from "../../../core/generated-graphql";
import { StashService } from "../../core/StashService"; import { StashService } from "../../../core/StashService";
import { TextUtils } from "../../utils/text"; import { TextUtils } from "../../../utils/text";
import { GenerateButton } from "./GenerateButton";
import { ToastUtils } from "../../../utils/toasts";
import { ErrorUtils } from "../../../utils/errors";
interface IProps {} interface IProps {}
@@ -43,6 +46,15 @@ export const SettingsTasksPanel: FunctionComponent<IProps> = (props: IProps) =>
); );
} }
async function onScan() {
try {
await StashService.queryMetadataScan();
ToastUtils.success("Started scan");
} catch (e) {
ErrorUtils.handle(e);
}
}
return ( return (
<> <>
{renderImportAlert()} {renderImportAlert()}
@@ -53,18 +65,12 @@ export const SettingsTasksPanel: FunctionComponent<IProps> = (props: IProps) =>
labelFor="scan" labelFor="scan"
inline={true} inline={true}
> >
<Button id="scan" text="Scan" onClick={() => StashService.queryMetadataScan()} /> <Button id="scan" text="Scan" onClick={() => onScan()} />
</FormGroup> </FormGroup>
<Divider /> <Divider />
<H4>Generated Content</H4> <H4>Generated Content</H4>
<FormGroup <GenerateButton />
helperText="Generate supporting image, sprite, video, vtt and other files."
labelFor="generate"
inline={true}
>
<Button id="generate" text="Generate" onClick={() => StashService.queryMetadataGenerate()} />
</FormGroup>
<FormGroup <FormGroup
helperText="TODO" helperText="TODO"
labelFor="clean" labelFor="clean"

View File

@@ -74,7 +74,7 @@ export const FolderSelect: FunctionComponent<IProps> = (props: IProps) => {
return ( return (
<> <>
{!!error ? error : undefined} {!!error ? <h1>{error.message}</h1> : undefined}
{renderDialog()} {renderDialog()}
{selectedDirectories.map((path) => { {selectedDirectories.map((path) => {
return <div key={path}>{path} <a onClick={() => onRemoveDirectory(path)}>Remove</a></div>; return <div key={path}>{path} <a onClick={() => onRemoveDirectory(path)}>Remove</a></div>;

View File

@@ -166,9 +166,10 @@ export class StashService {
}); });
} }
public static queryMetadataGenerate() { public static queryMetadataGenerate(input: GQL.GenerateMetadataInput) {
return StashService.client.query<GQL.MetadataGenerateQuery>({ return StashService.client.query<GQL.MetadataGenerateQuery>({
query: GQL.MetadataGenerateDocument, query: GQL.MetadataGenerateDocument,
variables: { input },
fetchPolicy: "network-only", fetchPolicy: "network-only",
}); });
} }

View File

@@ -1,5 +1,5 @@
/* tslint:disable */ /* tslint:disable */
// Generated in 2019-03-23T12:23:40-07:00 // Generated in 2019-03-24T09:16:39-07:00
export type Maybe<T> = T | undefined; export type Maybe<T> = T | undefined;
export interface SceneFilterType { export interface SceneFilterType {
@@ -47,6 +47,16 @@ export interface PerformerFilterType {
filter_favorites?: Maybe<boolean>; filter_favorites?: Maybe<boolean>;
} }
export interface GenerateMetadataInput {
sprites: boolean;
previews: boolean;
markers: boolean;
transcodes: boolean;
}
export interface SceneUpdateInput { export interface SceneUpdateInput {
clientMutationId?: Maybe<string>; clientMutationId?: Maybe<string>;
@@ -206,6 +216,10 @@ export interface TagDestroyInput {
export interface ConfigGeneralInput { export interface ConfigGeneralInput {
/** Array of file paths to content */ /** Array of file paths to content */
stashes?: Maybe<string[]>; stashes?: Maybe<string[]>;
/** Path to the SQLite database */
databasePath?: Maybe<string>;
/** Path to generated files */
generatedPath?: Maybe<string>;
} }
export enum ResolutionEnum { export enum ResolutionEnum {
@@ -804,7 +818,9 @@ export type MetadataScanQuery = {
metadataScan: string; metadataScan: string;
}; };
export type MetadataGenerateVariables = {}; export type MetadataGenerateVariables = {
input: GenerateMetadataInput;
};
export type MetadataGenerateQuery = { export type MetadataGenerateQuery = {
__typename?: "Query"; __typename?: "Query";
@@ -863,7 +879,11 @@ export type MetadataUpdateSubscription = {
export type ConfigGeneralDataFragment = { export type ConfigGeneralDataFragment = {
__typename?: "ConfigGeneralResult"; __typename?: "ConfigGeneralResult";
stashes: Maybe<string[]>; stashes: string[];
databasePath: string;
generatedPath: string;
}; };
export type ConfigDataFragment = { export type ConfigDataFragment = {
@@ -1244,6 +1264,8 @@ import * as ReactApolloHooks from "react-apollo-hooks";
export const ConfigGeneralDataFragmentDoc = gql` export const ConfigGeneralDataFragmentDoc = gql`
fragment ConfigGeneralData on ConfigGeneralResult { fragment ConfigGeneralData on ConfigGeneralResult {
stashes stashes
databasePath
generatedPath
} }
`; `;
@@ -2276,8 +2298,8 @@ export function useMetadataScan(
); );
} }
export const MetadataGenerateDocument = gql` export const MetadataGenerateDocument = gql`
query MetadataGenerate { query MetadataGenerate($input: GenerateMetadataInput!) {
metadataGenerate metadataGenerate(input: $input)
} }
`; `;
export function useMetadataGenerate( export function useMetadataGenerate(