Config Tweaks

Using viper for config management.  Added configuration endpoint.
This commit is contained in:
Stash Dev
2019-03-23 07:56:59 -07:00
parent b69739dcc4
commit dd22d88d07
45 changed files with 940 additions and 642 deletions

View File

@@ -0,0 +1,37 @@
package api
import (
"context"
"fmt"
"github.com/stashapp/stash/pkg/manager/config"
"github.com/stashapp/stash/pkg/models"
"github.com/stashapp/stash/pkg/utils"
)
func (r *queryResolver) ConfigureGeneral(ctx context.Context, input *models.ConfigGeneralInput) (models.ConfigGeneralResult, error) {
if input == nil {
return makeConfigGeneralResult(), fmt.Errorf("nil input")
}
if len(input.Stashes) > 0 {
for _, stashPath := range input.Stashes {
exists, err := utils.DirExists(stashPath)
if !exists {
return makeConfigGeneralResult(), err
}
}
config.Set(config.Stash, input.Stashes)
}
if err := config.Write(); err != nil {
return makeConfigGeneralResult(), err
}
return makeConfigGeneralResult(), nil
}
func makeConfigGeneralResult() models.ConfigGeneralResult {
return models.ConfigGeneralResult{
Stashes: config.GetStashPaths(),
}
}

View File

@@ -12,8 +12,7 @@ import (
"github.com/gorilla/websocket"
"github.com/rs/cors"
"github.com/stashapp/stash/pkg/logger"
"github.com/stashapp/stash/pkg/manager"
"github.com/stashapp/stash/pkg/manager/jsonschema"
"github.com/stashapp/stash/pkg/manager/config"
"github.com/stashapp/stash/pkg/models"
"github.com/stashapp/stash/pkg/utils"
"net/http"
@@ -29,6 +28,7 @@ const httpsPort = "9999"
var certsBox *packr.Box
var uiBox *packr.Box
//var legacyUiBox *packr.Box
var setupUIBox *packr.Box
@@ -99,41 +99,44 @@ func Start() {
http.Error(w, fmt.Sprintf("error: %s", err), 500)
}
stash := filepath.Clean(r.Form.Get("stash"))
generated := filepath.Clean(r.Form.Get("generated"))
metadata := filepath.Clean(r.Form.Get("metadata"))
cache := filepath.Clean(r.Form.Get("cache"))
//downloads := filepath.Clean(r.Form.Get("downloads")) // TODO
downloads := filepath.Join(metadata, "downloads")
exists, _ := utils.FileExists(stash)
fileInfo, _ := os.Stat(stash)
if !exists || !fileInfo.IsDir() {
exists, _ := utils.DirExists(stash)
if !exists || stash == "." {
http.Error(w, fmt.Sprintf("the stash path either doesn't exist, or is not a directory <%s>. Go back and try again.", stash), 500)
return
}
exists, _ = utils.FileExists(metadata)
fileInfo, _ = os.Stat(metadata)
if !exists || !fileInfo.IsDir() {
exists, _ = utils.DirExists(generated)
if !exists || generated == "." {
http.Error(w, fmt.Sprintf("the generated path either doesn't exist, or is not a directory <%s>. Go back and try again.", generated), 500)
return
}
exists, _ = utils.DirExists(metadata)
if !exists || metadata == "." {
http.Error(w, fmt.Sprintf("the metadata path either doesn't exist, or is not a directory <%s> Go back and try again.", metadata), 500)
return
}
exists, _ = utils.FileExists(cache)
fileInfo, _ = os.Stat(cache)
if !exists || !fileInfo.IsDir() {
exists, _ = utils.DirExists(cache)
if !exists || cache == "." {
http.Error(w, fmt.Sprintf("the cache path either doesn't exist, or is not a directory <%s> Go back and try again.", cache), 500)
return
}
_ = os.Mkdir(downloads, 0755)
config := &jsonschema.Config{
Stash: stash,
Metadata: metadata,
Cache: cache,
Downloads: downloads,
}
if err := manager.GetInstance().SaveConfig(config); err != nil {
config.Set(config.Stash, stash)
config.Set(config.Generated, generated)
config.Set(config.Metadata, metadata)
config.Set(config.Cache, cache)
config.Set(config.Downloads, downloads)
if err := config.Write(); err != nil {
http.Error(w, fmt.Sprintf("there was an error saving the config file: %s", err), 500)
return
}
@@ -220,7 +223,7 @@ func ConfigCheckMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ext := path.Ext(r.URL.Path)
shouldRedirect := ext == "" && r.Method == "GET" && r.URL.Path != "/init"
if !manager.HasValidConfig() && shouldRedirect {
if !config.IsValid() && shouldRedirect {
if !strings.HasPrefix(r.URL.Path, "/setup") {
http.Redirect(w, r, "/setup", 301)
return

View File

@@ -0,0 +1,47 @@
package config
import (
"github.com/spf13/viper"
)
const Stash = "stash"
const Cache = "cache"
const Generated = "generated"
const Metadata = "metadata"
const Downloads = "downloads"
const Database = "database"
func Set(key string, value interface{}) {
viper.Set(key, value)
}
func Write() error {
return viper.WriteConfig()
}
func GetStashPaths() []string {
return viper.GetStringSlice(Stash)
}
func GetCachePath() string {
return viper.GetString(Cache)
}
func GetGeneratedPath() string {
return viper.GetString(Generated)
}
func GetMetadataPath() string {
return viper.GetString(Metadata)
}
func GetDatabasePath() string {
return viper.GetString(Database)
}
func IsValid() bool {
setPaths := viper.IsSet(Stash) && viper.IsSet(Cache) && viper.IsSet(Generated) && viper.IsSet(Metadata)
// TODO: check valid paths
return setPaths
}

View File

@@ -43,7 +43,7 @@ func NewPreviewGenerator(videoFile ffmpeg.VideoFile, videoFilename string, image
func (g *PreviewGenerator) Generate() error {
instance.Paths.Generated.EmptyTmpDir()
logger.Infof("[generator] generating scene preview for %s", g.Info.VideoFile.Path)
encoder := ffmpeg.NewEncoder(instance.StaticPaths.FFMPEG)
encoder := ffmpeg.NewEncoder(instance.FFMPEGPath)
if err := g.generateConcatFile(); err != nil {
return err

View File

@@ -49,7 +49,7 @@ func NewSpriteGenerator(videoFile ffmpeg.VideoFile, imageOutputPath string, vttO
func (g *SpriteGenerator) Generate() error {
instance.Paths.Generated.EmptyTmpDir()
encoder := ffmpeg.NewEncoder(instance.StaticPaths.FFMPEG)
encoder := ffmpeg.NewEncoder(instance.FFMPEGPath)
if err := g.generateSpriteImage(&encoder); err != nil {
return err

View File

@@ -1,38 +0,0 @@
package jsonschema
import (
"encoding/json"
"fmt"
"github.com/stashapp/stash/pkg/logger"
"os"
)
type Config struct {
Stash string `json:"stash"`
Metadata string `json:"metadata"`
// Generated string `json:"generated"` // TODO: Generated directory instead of metadata
Cache string `json:"cache"`
Downloads string `json:"downloads"`
}
func LoadConfigFile(file string) *Config {
var config Config
configFile, err := os.Open(file)
defer configFile.Close()
if err != nil {
logger.Error(err.Error())
}
jsonParser := json.NewDecoder(configFile)
parseError := jsonParser.Decode(&config)
if parseError != nil {
logger.Errorf("config file parse error (ignore on first launch): %s", parseError)
}
return &config
}
func SaveConfigFile(filePath string, config *Config) error {
if config == nil {
return fmt.Errorf("config must not be nil")
}
return marshalToFile(filePath, config)
}

View File

@@ -1,19 +1,24 @@
package manager
import (
"fmt"
"github.com/fsnotify/fsnotify"
"github.com/spf13/viper"
"github.com/stashapp/stash/pkg/ffmpeg"
"github.com/stashapp/stash/pkg/logger"
"github.com/stashapp/stash/pkg/manager/jsonschema"
"github.com/stashapp/stash/pkg/manager/config"
"github.com/stashapp/stash/pkg/manager/paths"
"github.com/stashapp/stash/pkg/utils"
"sync"
)
type singleton struct {
Status JobStatus
Paths *paths.Paths
StaticPaths *paths.StaticPathsType
JSON *jsonUtils
Status JobStatus
Paths *paths.Paths
JSON *jsonUtils
FFMPEGPath string
FFProbePath string
}
var instance *singleton
@@ -26,16 +31,15 @@ func GetInstance() *singleton {
func Initialize() *singleton {
once.Do(func() {
_ = utils.EnsureDir(paths.StaticPaths.ConfigDirectory)
configFile := jsonschema.LoadConfigFile(paths.StaticPaths.ConfigFile)
_ = utils.EnsureDir(paths.GetConfigDirectory())
initConfig()
instance = &singleton{
Status: Idle,
Paths: paths.NewPaths(configFile),
StaticPaths: &paths.StaticPaths,
JSON: &jsonUtils{},
Status: Idle,
Paths: paths.NewPaths(),
JSON: &jsonUtils{},
}
instance.refreshConfig(configFile)
instance.refreshConfig()
initFFMPEG()
})
@@ -43,11 +47,45 @@ func Initialize() *singleton {
return instance
}
func initConfig() {
// The config file is called config. Leave off the file extension.
viper.SetConfigName("config")
viper.AddConfigPath("$HOME/.stash") // Look for the config in the home directory
viper.AddConfigPath(".") // Look for config in the working directory
viper.SetDefault(config.Database, paths.GetDefaultDatabaseFilePath())
// Set generated to the metadata path for backwards compat
if !viper.IsSet(config.Generated) {
viper.SetDefault(config.Generated, viper.GetString(config.Metadata))
}
err := viper.ReadInConfig() // Find and read the config file
if err != nil { // Handle errors reading the config file
_ = utils.Touch(paths.GetDefaultConfigFilePath())
if err = viper.ReadInConfig(); err != nil {
panic(err)
}
}
// Watch for changes
viper.WatchConfig()
viper.OnConfigChange(func(e fsnotify.Event) {
fmt.Println("Config file changed:", e.Name)
instance.refreshConfig()
})
//viper.Set("stash", []string{"/", "/stuff"})
//viper.WriteConfig()
}
func initFFMPEG() {
ffmpegPath, ffprobePath := ffmpeg.GetPaths(instance.StaticPaths.ConfigDirectory)
configDirectory := paths.GetConfigDirectory()
ffmpegPath, ffprobePath := ffmpeg.GetPaths(configDirectory)
if ffmpegPath == "" || ffprobePath == "" {
logger.Infof("couldn't find FFMPEG, attempting to download it")
if err := ffmpeg.Download(instance.StaticPaths.ConfigDirectory); err != nil {
if err := ffmpeg.Download(configDirectory); err != nil {
msg := `Unable to locate / automatically download FFMPEG
Check the readme for download links.
@@ -55,40 +93,18 @@ The FFMPEG and FFProbe binaries should be placed in %s
The error was: %s
`
logger.Fatalf(msg, instance.StaticPaths.ConfigDirectory, err)
logger.Fatalf(msg, configDirectory, err)
}
}
instance.StaticPaths.FFMPEG = ffmpegPath
instance.StaticPaths.FFProbe = ffprobePath
// TODO: is this valid after download?
instance.FFMPEGPath = ffmpegPath
instance.FFProbePath = ffprobePath
}
func HasValidConfig() bool {
configFileExists, _ := utils.FileExists(instance.StaticPaths.ConfigFile) // TODO: Verify JSON is correct
if configFileExists && instance.Paths.Config != nil {
return true
}
return false
}
func (s *singleton) SaveConfig(config *jsonschema.Config) error {
if err := jsonschema.SaveConfigFile(s.StaticPaths.ConfigFile, config); err != nil {
return err
}
// Reload the config
s.refreshConfig(config)
return nil
}
func (s *singleton) refreshConfig(config *jsonschema.Config) {
if config == nil {
config = jsonschema.LoadConfigFile(s.StaticPaths.ConfigFile)
}
s.Paths = paths.NewPaths(config)
if HasValidConfig() {
func (s *singleton) refreshConfig() {
s.Paths = paths.NewPaths()
if config.IsValid() {
_ = utils.EnsureDir(s.Paths.Generated.Screenshots)
_ = utils.EnsureDir(s.Paths.Generated.Vtt)
_ = utils.EnsureDir(s.Paths.Generated.Markers)

View File

@@ -3,6 +3,7 @@ package manager
import (
"github.com/bmatcuk/doublestar"
"github.com/stashapp/stash/pkg/logger"
"github.com/stashapp/stash/pkg/manager/config"
"github.com/stashapp/stash/pkg/models"
"github.com/stashapp/stash/pkg/utils"
"path/filepath"
@@ -18,12 +19,16 @@ func (s *singleton) Scan() {
go func() {
defer s.returnToIdleState()
globPath := filepath.Join(s.Paths.Config.Stash, "**/*.{zip,m4v,mp4,mov,wmv}")
globResults, _ := doublestar.Glob(globPath)
logger.Infof("Starting scan of %d files", len(globResults))
var results []string
for _, path := range config.GetStashPaths() {
globPath := filepath.Join(path, "**/*.{zip,m4v,mp4,mov,wmv}")
globResults, _ := doublestar.Glob(globPath)
results = append(results, globResults...)
}
logger.Infof("Starting scan of %d files", len(results))
var wg sync.WaitGroup
for _, path := range globResults {
for _, path := range results {
wg.Add(1)
task := ScanTask{FilePath: path}
go task.Start(&wg)

View File

@@ -1,11 +1,11 @@
package paths
import (
"github.com/stashapp/stash/pkg/manager/jsonschema"
"os/user"
"path/filepath"
)
type Paths struct {
Config *jsonschema.Config
Generated *generatedPaths
JSON *jsonPaths
@@ -14,14 +14,33 @@ type Paths struct {
SceneMarkers *sceneMarkerPaths
}
func NewPaths(config *jsonschema.Config) *Paths {
func NewPaths() *Paths {
p := Paths{}
p.Config = config
p.Generated = newGeneratedPaths(p)
p.JSON = newJSONPaths(p)
p.Generated = newGeneratedPaths()
p.JSON = newJSONPaths()
p.Gallery = newGalleryPaths(p.Config)
p.Gallery = newGalleryPaths()
p.Scene = newScenePaths(p)
p.SceneMarkers = newSceneMarkerPaths(p)
return &p
}
func GetHomeDirectory() string {
currentUser, err := user.Current()
if err != nil {
panic(err)
}
return currentUser.HomeDir
}
func GetConfigDirectory() string {
return filepath.Join(GetHomeDirectory(), ".stash")
}
func GetDefaultDatabaseFilePath() string {
return filepath.Join(GetConfigDirectory(), "stash-go.sqlite")
}
func GetDefaultConfigFilePath() string {
return filepath.Join(GetConfigDirectory(), "config.yml")
}

View File

@@ -1,24 +1,20 @@
package paths
import (
"github.com/stashapp/stash/pkg/manager/jsonschema"
"github.com/stashapp/stash/pkg/manager/config"
"path/filepath"
)
type galleryPaths struct {
config *jsonschema.Config
}
type galleryPaths struct{}
func newGalleryPaths(c *jsonschema.Config) *galleryPaths {
gp := galleryPaths{}
gp.config = c
return &gp
func newGalleryPaths() *galleryPaths {
return &galleryPaths{}
}
func (gp *galleryPaths) GetExtractedPath(checksum string) string {
return filepath.Join(gp.config.Cache, checksum)
return filepath.Join(config.GetCachePath(), checksum)
}
func (gp *galleryPaths) GetExtractedFilePath(checksum string, fileName string) string {
return filepath.Join(gp.config.Cache, checksum, fileName)
return filepath.Join(config.GetCachePath(), checksum, fileName)
}

View File

@@ -1,6 +1,7 @@
package paths
import (
"github.com/stashapp/stash/pkg/manager/config"
"github.com/stashapp/stash/pkg/utils"
"path/filepath"
)
@@ -13,13 +14,13 @@ type generatedPaths struct {
Tmp string
}
func newGeneratedPaths(p Paths) *generatedPaths {
func newGeneratedPaths() *generatedPaths {
gp := generatedPaths{}
gp.Screenshots = filepath.Join(p.Config.Metadata, "screenshots")
gp.Vtt = filepath.Join(p.Config.Metadata, "vtt")
gp.Markers = filepath.Join(p.Config.Metadata, "markers")
gp.Transcodes = filepath.Join(p.Config.Metadata, "transcodes")
gp.Tmp = filepath.Join(p.Config.Metadata, "tmp")
gp.Screenshots = filepath.Join(config.GetGeneratedPath(), "screenshots")
gp.Vtt = filepath.Join(config.GetGeneratedPath(), "vtt")
gp.Markers = filepath.Join(config.GetGeneratedPath(), "markers")
gp.Transcodes = filepath.Join(config.GetGeneratedPath(), "transcodes")
gp.Tmp = filepath.Join(config.GetGeneratedPath(), "tmp")
return &gp
}

View File

@@ -1,6 +1,7 @@
package paths
import (
"github.com/stashapp/stash/pkg/manager/config"
"path/filepath"
)
@@ -14,14 +15,14 @@ type jsonPaths struct {
Studios string
}
func newJSONPaths(p Paths) *jsonPaths {
func newJSONPaths() *jsonPaths {
jp := jsonPaths{}
jp.MappingsFile = filepath.Join(p.Config.Metadata, "mappings.json")
jp.ScrapedFile = filepath.Join(p.Config.Metadata, "scraped.json")
jp.Performers = filepath.Join(p.Config.Metadata, "performers")
jp.Scenes = filepath.Join(p.Config.Metadata, "scenes")
jp.Galleries = filepath.Join(p.Config.Metadata, "galleries")
jp.Studios = filepath.Join(p.Config.Metadata, "studios")
jp.MappingsFile = filepath.Join(config.GetMetadataPath(), "mappings.json")
jp.ScrapedFile = filepath.Join(config.GetMetadataPath(), "scraped.json")
jp.Performers = filepath.Join(config.GetMetadataPath(), "performers")
jp.Scenes = filepath.Join(config.GetMetadataPath(), "scenes")
jp.Galleries = filepath.Join(config.GetMetadataPath(), "galleries")
jp.Studios = filepath.Join(config.GetMetadataPath(), "studios")
return &jp
}

View File

@@ -1,44 +0,0 @@
package paths
import (
"os"
"os/user"
"path/filepath"
)
type StaticPathsType struct {
ExecutionDirectory string
ConfigDirectory string
ConfigFile string
DatabaseFile string
FFMPEG string
FFProbe string
}
var StaticPaths = StaticPathsType{
ExecutionDirectory: getExecutionDirectory(),
ConfigDirectory: getConfigDirectory(),
ConfigFile: filepath.Join(getConfigDirectory(), "config.json"),
DatabaseFile: filepath.Join(getConfigDirectory(), "stash-go.sqlite"),
}
func getExecutionDirectory() string {
ex, err := os.Executable()
if err != nil {
panic(err)
}
return filepath.Dir(ex)
}
func getHomeDirectory() string {
currentUser, err := user.Current()
if err != nil {
panic(err)
}
return currentUser.HomeDir
}
func getConfigDirectory() string {
return filepath.Join(getHomeDirectory(), ".stash")
}

View File

@@ -25,7 +25,7 @@ func (t *GenerateMarkersTask) Start(wg *sync.WaitGroup) {
return
}
videoFile, err := ffmpeg.NewVideoFile(instance.StaticPaths.FFProbe, t.Scene.Path)
videoFile, err := ffmpeg.NewVideoFile(instance.FFProbePath, t.Scene.Path)
if err != nil {
logger.Errorf("error reading video file: %s", err.Error())
return
@@ -35,7 +35,7 @@ func (t *GenerateMarkersTask) Start(wg *sync.WaitGroup) {
markersFolder := filepath.Join(instance.Paths.Generated.Markers, t.Scene.Checksum)
_ = utils.EnsureDir(markersFolder)
encoder := ffmpeg.NewEncoder(instance.StaticPaths.FFMPEG)
encoder := ffmpeg.NewEncoder(instance.FFMPEGPath)
for i, sceneMarker := range sceneMarkers {
index := i + 1
logger.Progressf("[generator] <%s> scene marker %d of %d", t.Scene.Checksum, index, len(sceneMarkers))

View File

@@ -21,7 +21,7 @@ func (t *GeneratePreviewTask) Start(wg *sync.WaitGroup) {
return
}
videoFile, err := ffmpeg.NewVideoFile(instance.StaticPaths.FFProbe, t.Scene.Path)
videoFile, err := ffmpeg.NewVideoFile(instance.FFProbePath, t.Scene.Path)
if err != nil {
logger.Errorf("error reading video file: %s", err.Error())
return

View File

@@ -19,7 +19,7 @@ func (t *GenerateSpriteTask) Start(wg *sync.WaitGroup) {
return
}
videoFile, err := ffmpeg.NewVideoFile(instance.StaticPaths.FFProbe, t.Scene.Path)
videoFile, err := ffmpeg.NewVideoFile(instance.FFProbePath, t.Scene.Path)
if err != nil {
logger.Errorf("error reading video file: %s", err.Error())
return

View File

@@ -6,6 +6,7 @@ import (
"github.com/jmoiron/sqlx"
"github.com/stashapp/stash/pkg/database"
"github.com/stashapp/stash/pkg/logger"
"github.com/stashapp/stash/pkg/manager/config"
"github.com/stashapp/stash/pkg/manager/jsonschema"
"github.com/stashapp/stash/pkg/models"
"github.com/stashapp/stash/pkg/utils"
@@ -33,7 +34,7 @@ func (t *ImportTask) Start(wg *sync.WaitGroup) {
}
t.Scraped = scraped
database.Reset(instance.StaticPaths.DatabaseFile)
database.Reset(config.GetDatabasePath())
ctx := context.TODO()

View File

@@ -70,7 +70,7 @@ func (t *ScanTask) scanGallery() {
}
func (t *ScanTask) scanScene() {
videoFile, err := ffmpeg.NewVideoFile(instance.StaticPaths.FFProbe, t.FilePath)
videoFile, err := ffmpeg.NewVideoFile(instance.FFProbePath, t.FilePath)
if err != nil {
logger.Error(err.Error())
return
@@ -142,7 +142,7 @@ func (t *ScanTask) makeScreenshots(probeResult ffmpeg.VideoFile, checksum string
}
func (t *ScanTask) makeScreenshot(probeResult ffmpeg.VideoFile, outputPath string, quality int, width int) {
encoder := ffmpeg.NewEncoder(instance.StaticPaths.FFMPEG)
encoder := ffmpeg.NewEncoder(instance.FFMPEGPath)
options := ffmpeg.ScreenshotOptions{
OutputPath: outputPath,
Quality: quality,

View File

@@ -26,7 +26,7 @@ func (t *GenerateTranscodeTask) Start(wg *sync.WaitGroup) {
logger.Infof("[transcode] <%s> scene has codec %s", t.Scene.Checksum, t.Scene.VideoCodec.String)
videoFile, err := ffmpeg.NewVideoFile(instance.StaticPaths.FFProbe, t.Scene.Path)
videoFile, err := ffmpeg.NewVideoFile(instance.FFProbePath, t.Scene.Path)
if err != nil {
logger.Errorf("[transcode] error reading video file: %s", err.Error())
return
@@ -36,7 +36,7 @@ func (t *GenerateTranscodeTask) Start(wg *sync.WaitGroup) {
options := ffmpeg.TranscodeOptions{
OutputPath: outputPath,
}
encoder := ffmpeg.NewEncoder(instance.StaticPaths.FFMPEG)
encoder := ffmpeg.NewEncoder(instance.FFMPEGPath)
encoder.Transcode(*videoFile, options)
if err := os.Rename(outputPath, instance.Paths.Scene.GetTranscodePath(t.Scene.Checksum)); err != nil {
logger.Errorf("[transcode] error generating transcode: %s", err.Error())

View File

@@ -47,6 +47,10 @@ type DirectiveRoot struct {
}
type ComplexityRoot struct {
ConfigGeneralResult struct {
Stashes func(childComplexity int) int
}
FindGalleriesResultType struct {
Count func(childComplexity int) int
Galleries func(childComplexity int) int
@@ -149,6 +153,7 @@ type ComplexityRoot struct {
SceneMarkerTags func(childComplexity int, scene_id string) int
ScrapeFreeones func(childComplexity int, performer_name string) int
ScrapeFreeonesPerformerList func(childComplexity int, query string) int
ConfigureGeneral func(childComplexity int, input *ConfigGeneralInput) int
MetadataImport func(childComplexity int) int
MetadataExport func(childComplexity int) int
MetadataScan func(childComplexity int) int
@@ -322,6 +327,7 @@ type QueryResolver interface {
SceneMarkerTags(ctx context.Context, scene_id string) ([]SceneMarkerTag, error)
ScrapeFreeones(ctx context.Context, performer_name string) (*ScrapedPerformer, error)
ScrapeFreeonesPerformerList(ctx context.Context, query string) ([]string, error)
ConfigureGeneral(ctx context.Context, input *ConfigGeneralInput) (ConfigGeneralResult, error)
MetadataImport(ctx context.Context) (string, error)
MetadataExport(ctx context.Context) (string, error)
MetadataScan(ctx context.Context) (string, error)
@@ -1060,6 +1066,34 @@ func (e *executableSchema) field_Query_scrapeFreeonesPerformerList_args(ctx cont
}
func (e *executableSchema) field_Query_configureGeneral_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
args := map[string]interface{}{}
var arg0 *ConfigGeneralInput
if tmp, ok := rawArgs["input"]; ok {
var err error
var ptr1 ConfigGeneralInput
if tmp != nil {
ptr1, err = UnmarshalConfigGeneralInput(tmp)
arg0 = &ptr1
}
if err != nil {
return nil, err
}
if arg0 != nil {
var err error
arg0, err = e.ConfigGeneralInputMiddleware(ctx, arg0)
if err != nil {
return nil, err
}
}
}
args["input"] = arg0
return args, nil
}
func (e *executableSchema) field_Query___type_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
args := map[string]interface{}{}
var arg0 string
@@ -1118,6 +1152,13 @@ func (e *executableSchema) Schema() *ast.Schema {
func (e *executableSchema) Complexity(typeName, field string, childComplexity int, rawArgs map[string]interface{}) (int, bool) {
switch typeName + "." + field {
case "ConfigGeneralResult.stashes":
if e.complexity.ConfigGeneralResult.Stashes == nil {
break
}
return e.complexity.ConfigGeneralResult.Stashes(childComplexity), true
case "FindGalleriesResultType.count":
if e.complexity.FindGalleriesResultType.Count == nil {
break
@@ -1755,6 +1796,18 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.Query.ScrapeFreeonesPerformerList(childComplexity, args["query"].(string)), true
case "Query.configureGeneral":
if e.complexity.Query.ConfigureGeneral == nil {
break
}
args, err := e.field_Query_configureGeneral_args(context.TODO(), rawArgs)
if err != nil {
return 0, false
}
return e.complexity.Query.ConfigureGeneral(childComplexity, args["input"].(*ConfigGeneralInput)), true
case "Query.metadataImport":
if e.complexity.Query.MetadataImport == nil {
break
@@ -2383,6 +2436,64 @@ type executionContext struct {
*executableSchema
}
var configGeneralResultImplementors = []string{"ConfigGeneralResult"}
// nolint: gocyclo, errcheck, gas, goconst
func (ec *executionContext) _ConfigGeneralResult(ctx context.Context, sel ast.SelectionSet, obj *ConfigGeneralResult) graphql.Marshaler {
fields := graphql.CollectFields(ctx, sel, configGeneralResultImplementors)
out := graphql.NewFieldSet(fields)
invalid := false
for i, field := range fields {
switch field.Name {
case "__typename":
out.Values[i] = graphql.MarshalString("ConfigGeneralResult")
case "stashes":
out.Values[i] = ec._ConfigGeneralResult_stashes(ctx, field, obj)
default:
panic("unknown field " + strconv.Quote(field.Name))
}
}
out.Dispatch()
if invalid {
return graphql.Null
}
return out
}
// nolint: vetshadow
func (ec *executionContext) _ConfigGeneralResult_stashes(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.Stashes, nil
})
if resTmp == nil {
return graphql.Null
}
res := resTmp.([]string)
rctx.Result = res
ctx = ec.Tracer.StartFieldChildExecution(ctx)
arr1 := make(graphql.Array, len(res))
for idx1 := range res {
arr1[idx1] = func() graphql.Marshaler {
return graphql.MarshalString(res[idx1])
}()
}
return arr1
}
var findGalleriesResultTypeImplementors = []string{"FindGalleriesResultType"}
// nolint: gocyclo, errcheck, gas, goconst
@@ -4824,6 +4935,15 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr
}
return res
})
case "configureGeneral":
field := field
out.Concurrently(i, func() (res graphql.Marshaler) {
res = ec._Query_configureGeneral(ctx, field)
if res == graphql.Null {
invalid = true
}
return res
})
case "metadataImport":
field := field
out.Concurrently(i, func() (res graphql.Marshaler) {
@@ -5712,6 +5832,41 @@ func (ec *executionContext) _Query_scrapeFreeonesPerformerList(ctx context.Conte
return arr1
}
// nolint: vetshadow
func (ec *executionContext) _Query_configureGeneral(ctx context.Context, field graphql.CollectedField) graphql.Marshaler {
ctx = ec.Tracer.StartFieldExecution(ctx, field)
defer func() { ec.Tracer.EndFieldExecution(ctx) }()
rctx := &graphql.ResolverContext{
Object: "Query",
Field: field,
Args: nil,
}
ctx = graphql.WithResolverContext(ctx, rctx)
rawArgs := field.ArgumentMap(ec.Variables)
args, err := ec.field_Query_configureGeneral_args(ctx, rawArgs)
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
rctx.Args = args
ctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx)
resTmp := ec.FieldMiddleware(ctx, nil, func(rctx context.Context) (interface{}, error) {
ctx = rctx // use context from middleware stack in children
return ec.resolvers.Query().ConfigureGeneral(rctx, args["input"].(*ConfigGeneralInput))
})
if resTmp == nil {
if !ec.HasError(rctx) {
ec.Errorf(ctx, "must not be null")
}
return graphql.Null
}
res := resTmp.(ConfigGeneralResult)
rctx.Result = res
ctx = ec.Tracer.StartFieldChildExecution(ctx)
return ec._ConfigGeneralResult(ctx, field.Selections, &res)
}
// nolint: vetshadow
func (ec *executionContext) _Query_metadataImport(ctx context.Context, field graphql.CollectedField) graphql.Marshaler {
ctx = ec.Tracer.StartFieldExecution(ctx, field)
@@ -10227,6 +10382,40 @@ func (ec *executionContext) ___Type_ofType(ctx context.Context, field graphql.Co
return ec.___Type(ctx, field.Selections, res)
}
func UnmarshalConfigGeneralInput(v interface{}) (ConfigGeneralInput, error) {
var it ConfigGeneralInput
var asMap = v.(map[string]interface{})
for k, v := range asMap {
switch k {
case "stashes":
var err error
var rawIf1 []interface{}
if v != nil {
if tmp1, ok := v.([]interface{}); ok {
rawIf1 = tmp1
} else {
rawIf1 = []interface{}{v}
}
}
it.Stashes = make([]string, len(rawIf1))
for idx1 := range rawIf1 {
it.Stashes[idx1], err = graphql.UnmarshalString(rawIf1[idx1])
}
if err != nil {
return it, err
}
}
}
return it, nil
}
func (e *executableSchema) ConfigGeneralInputMiddleware(ctx context.Context, obj *ConfigGeneralInput) (*ConfigGeneralInput, error) {
return obj, nil
}
func UnmarshalFindFilterType(v interface{}) (FindFilterType, error) {
var it FindFilterType
var asMap = v.(map[string]interface{})
@@ -11757,6 +11946,20 @@ input SceneFilterType {
performer_id: ID
}
#######################################
# Config
#######################################
input ConfigGeneralInput {
"""Array of file paths to content"""
stashes: [String!]
}
type ConfigGeneralResult {
"""Array of file paths to content"""
stashes: [String!]
}
#############
# Root Schema
#############
@@ -11807,6 +12010,9 @@ type Query {
"""Scrape a list of performers from a query"""
scrapeFreeonesPerformerList(query: String!): [String!]!
# Config
configureGeneral(input: ConfigGeneralInput): ConfigGeneralResult!
# Metadata
"""Start an import. Returns the job ID"""

View File

@@ -8,6 +8,16 @@ import (
"strconv"
)
type ConfigGeneralInput struct {
// Array of file paths to content
Stashes []string `json:"stashes"`
}
type ConfigGeneralResult struct {
// Array of file paths to content
Stashes []string `json:"stashes"`
}
type FindFilterType struct {
Q *string `json:"q"`
Page *int `json:"page"`

View File

@@ -1,6 +1,7 @@
package utils
import (
"fmt"
"github.com/h2non/filetype"
"github.com/h2non/filetype/types"
"os"
@@ -28,6 +29,27 @@ func FileExists(path string) (bool, error) {
}
}
func DirExists(path string) (bool, error) {
exists, _ := FileExists(path)
fileInfo, _ := os.Stat(path)
if !exists || !fileInfo.IsDir() {
return false, fmt.Errorf("path either doesn't exist, or is not a directory <%s>", path)
}
return true, nil
}
func Touch(path string) error {
var _, err = os.Stat(path)
if os.IsNotExist(err) {
var file, err = os.Create(path)
if err != nil {
return err
}
defer file.Close()
}
return nil
}
func EnsureDir(path string) error {
exists, err := FileExists(path)
if !exists {