input SetupInput {
  "Empty to indicate $HOME/.stash/config.yml default"
  configLocation: String!
  stashes: [StashConfigInput!]!
  "True if SFW content mode is enabled"
  sfwContentMode: Boolean
  "Empty to indicate default"
  databaseFile: String!
  "Empty to indicate default"
  generatedLocation: String!
  "Empty to indicate default"
  cacheLocation: String!
  storeBlobsInDatabase: Boolean!
  "Empty to indicate default - only applicable if storeBlobsInDatabase is false"
  blobsLocation: String!
}

enum StreamingResolutionEnum {
  "240p"
  LOW
  "480p"
  STANDARD
  "720p"
  STANDARD_HD
  "1080p"
  FULL_HD
  "4k"
  FOUR_K
  "Original"
  ORIGINAL
}

enum PreviewPreset {
  "X264_ULTRAFAST"
  ultrafast
  "X264_VERYFAST"
  veryfast
  "X264_FAST"
  fast
  "X264_MEDIUM"
  medium
  "X264_SLOW"
  slow
  "X264_SLOWER"
  slower
  "X264_VERYSLOW"
  veryslow
}

enum HashAlgorithm {
  MD5
  "oshash"
  OSHASH
}

enum BlobsStorageType {
  # blobs are stored in the database
  "Database"
  DATABASE
  # blobs are stored in the filesystem under the configured blobs directory
  "Filesystem"
  FILESYSTEM
}

input ConfigGeneralInput {
  "Array of file paths to content"
  stashes: [StashConfigInput!]
  "Path to the SQLite database"
  databasePath: String
  "Path to backup directory"
  backupDirectoryPath: String
  "Path to trash directory - if set, deleted files will be moved here instead of being permanently deleted"
  deleteTrashPath: String
  "Path to generated files"
  generatedPath: String
  "Path to import/export files"
  metadataPath: String
  "Path to scrapers"
  scrapersPath: String
  "Path to plugins"
  pluginsPath: String
  "Path to cache"
  cachePath: String
  "Path to blobs - required for filesystem blob storage"
  blobsPath: String
  "Where to store blobs"
  blobsStorage: BlobsStorageType
  "Path to the ffmpeg binary. If empty, stash will attempt to find it in the path or config directory"
  ffmpegPath: String
  "Path to the ffprobe binary. If empty, stash will attempt to find it in the path or config directory"
  ffprobePath: String
  "Whether to calculate MD5 checksums for scene video files"
  calculateMD5: Boolean
  "Hash algorithm to use for generated file naming"
  videoFileNamingAlgorithm: HashAlgorithm
  "Number of parallel tasks to start during scan/generate"
  parallelTasks: Int
  "Include audio stream in previews"
  previewAudio: Boolean
  "Number of segments in a preview file"
  previewSegments: Int
  "Preview segment duration, in seconds"
  previewSegmentDuration: Float
  "Duration of start of video to exclude when generating previews"
  previewExcludeStart: String
  "Duration of end of video to exclude when generating previews"
  previewExcludeEnd: String
  "Preset when generating preview"
  previewPreset: PreviewPreset
  "Transcode Hardware Acceleration"
  transcodeHardwareAcceleration: Boolean
  "Max generated transcode size"
  maxTranscodeSize: StreamingResolutionEnum
  "Max streaming transcode size"
  maxStreamingTranscodeSize: StreamingResolutionEnum

  """
  ffmpeg transcode input args - injected before input file
  These are applied to generated transcodes (previews and transcodes)
  """
  transcodeInputArgs: [String!]
  """
  ffmpeg transcode output args - injected before output file
  These are applied to generated transcodes (previews and transcodes)
  """
  transcodeOutputArgs: [String!]

  """
  ffmpeg stream input args - injected before input file
  These are applied when live transcoding
  """
  liveTranscodeInputArgs: [String!]
  """
  ffmpeg stream output args - injected before output file
  These are applied when live transcoding
  """
  liveTranscodeOutputArgs: [String!]

  "whether to include range in generated funscript heatmaps"
  drawFunscriptHeatmapRange: Boolean

  "Write image thumbnails to disk when generating on the fly"
  writeImageThumbnails: Boolean
  "Create Image Clips from Video extensions when Videos are disabled in Library"
  createImageClipsFromVideos: Boolean
  "Username"
  username: String
  "Password"
  password: String
  "Maximum session cookie age"
  maxSessionAge: Int
  "Name of the log file"
  logFile: String
  "Whether to also output to stderr"
  logOut: Boolean
  "Minimum log level"
  logLevel: String
  "Whether to log http access"
  logAccess: Boolean
  "Maximum log size"
  logFileMaxSize: Int
  "True if galleries should be created from folders with images"
  createGalleriesFromFolders: Boolean
  "Regex used to identify images as gallery covers"
  galleryCoverRegex: String
  "Array of video file extensions"
  videoExtensions: [String!]
  "Array of image file extensions"
  imageExtensions: [String!]
  "Array of gallery zip file extensions"
  galleryExtensions: [String!]
  "Array of file regexp to exclude from Video Scans"
  excludes: [String!]
  "Array of file regexp to exclude from Image Scans"
  imageExcludes: [String!]
  "Custom Performer Image Location"
  customPerformerImageLocation: String
  "Stash-box instances used for tagging"
  stashBoxes: [StashBoxInput!]
  "Python path - resolved using path if unset"
  pythonPath: String

  "Source of scraper packages"
  scraperPackageSources: [PackageSourceInput!]
  "Source of plugin packages"
  pluginPackageSources: [PackageSourceInput!]

  "Size of the longest dimension for each sprite in pixels"
  spriteScreenshotSize: Int

  "True if sprite generation should use the sprite interval and min/max sprites settings instead of the default"
  useCustomSpriteInterval: Boolean
  "Time between two different scrubber sprites in seconds - only used if useCustomSpriteInterval is true"
  spriteInterval: Float
  "Minimum number of sprites to be generated - only used if useCustomSpriteInterval is true"
  minimumSprites: Int
  "Minimum number of sprites to be generated - only used if useCustomSpriteInterval is true"
  maximumSprites: Int
}

type ConfigGeneralResult {
  "Array of file paths to content"
  stashes: [StashConfig!]!
  "Path to the SQLite database"
  databasePath: String!
  "Path to backup directory"
  backupDirectoryPath: String!
  "Path to trash directory - if set, deleted files will be moved here instead of being permanently deleted"
  deleteTrashPath: String!
  "Path to generated files"
  generatedPath: String!
  "Path to import/export files"
  metadataPath: String!
  "Path to the config file used"
  configFilePath: String!
  "Path to scrapers"
  scrapersPath: String!
  "Path to plugins"
  pluginsPath: String!
  "Path to cache"
  cachePath: String!
  "Path to blobs - required for filesystem blob storage"
  blobsPath: String!
  "Where to store blobs"
  blobsStorage: BlobsStorageType!
  "Path to the ffmpeg binary. If empty, stash will attempt to find it in the path or config directory"
  ffmpegPath: String!
  "Path to the ffprobe binary. If empty, stash will attempt to find it in the path or config directory"
  ffprobePath: String!
  "Whether to calculate MD5 checksums for scene video files"
  calculateMD5: Boolean!
  "Hash algorithm to use for generated file naming"
  videoFileNamingAlgorithm: HashAlgorithm!
  "Number of parallel tasks to start during scan/generate"
  parallelTasks: Int!
  "Include audio stream in previews"
  previewAudio: Boolean!
  "Number of segments in a preview file"
  previewSegments: Int!
  "Preview segment duration, in seconds"
  previewSegmentDuration: Float!
  "Duration of start of video to exclude when generating previews"
  previewExcludeStart: String!
  "Duration of end of video to exclude when generating previews"
  previewExcludeEnd: String!
  "Preset when generating preview"
  previewPreset: PreviewPreset!
  "Transcode Hardware Acceleration"
  transcodeHardwareAcceleration: Boolean!
  "Max generated transcode size"
  maxTranscodeSize: StreamingResolutionEnum
  "Max streaming transcode size"
  maxStreamingTranscodeSize: StreamingResolutionEnum

  """
  ffmpeg transcode input args - injected before input file
  These are applied to generated transcodes (previews and transcodes)
  """
  transcodeInputArgs: [String!]!
  """
  ffmpeg transcode output args - injected before output file
  These are applied to generated transcodes (previews and transcodes)
  """
  transcodeOutputArgs: [String!]!

  """
  ffmpeg stream input args - injected before input file
  These are applied when live transcoding
  """
  liveTranscodeInputArgs: [String!]!
  """
  ffmpeg stream output args - injected before output file
  These are applied when live transcoding
  """
  liveTranscodeOutputArgs: [String!]!

  "whether to include range in generated funscript heatmaps"
  drawFunscriptHeatmapRange: Boolean!

  "Write image thumbnails to disk when generating on the fly"
  writeImageThumbnails: Boolean!
  "Create Image Clips from Video extensions when Videos are disabled in Library"
  createImageClipsFromVideos: Boolean!
  "API Key"
  apiKey: String!
  "Username"
  username: String!
  "Password"
  password: String!
  "Maximum session cookie age"
  maxSessionAge: Int!
  "Name of the log file"
  logFile: String
  "Whether to also output to stderr"
  logOut: Boolean!
  "Minimum log level"
  logLevel: String!
  "Whether to log http access"
  logAccess: Boolean!
  "Maximum log size"
  logFileMaxSize: Int!
  "True if sprite generation should use the sprite interval and min/max sprites settings instead of the default"
  useCustomSpriteInterval: Boolean!
  "Time between two different scrubber sprites in seconds - only used if useCustomSpriteInterval is true"
  spriteInterval: Float!
  "Minimum number of sprites to be generated - only used if useCustomSpriteInterval is true"
  minimumSprites: Int!
  "Maximum number of sprites to be generated - only used if useCustomSpriteInterval is true"
  maximumSprites: Int!
  "Size of the longest dimension for each sprite in pixels"
  spriteScreenshotSize: Int!
  "Array of video file extensions"
  videoExtensions: [String!]!
  "Array of image file extensions"
  imageExtensions: [String!]!
  "Array of gallery zip file extensions"
  galleryExtensions: [String!]!
  "True if galleries should be created from folders with images"
  createGalleriesFromFolders: Boolean!
  "Regex used to identify images as gallery covers"
  galleryCoverRegex: String!
  "Array of file regexp to exclude from Video Scans"
  excludes: [String!]!
  "Array of file regexp to exclude from Image Scans"
  imageExcludes: [String!]!
  "Custom Performer Image Location"
  customPerformerImageLocation: String
  "Stash-box instances used for tagging"
  stashBoxes: [StashBox!]!
  "Python path - resolved using path if unset"
  pythonPath: String!

  "Source of scraper packages"
  scraperPackageSources: [PackageSource!]!
  "Source of plugin packages"
  pluginPackageSources: [PackageSource!]!
}

input ConfigDisableDropdownCreateInput {
  performer: Boolean
  tag: Boolean
  studio: Boolean
  movie: Boolean
  gallery: Boolean
}

enum ImageLightboxDisplayMode {
  ORIGINAL
  FIT_XY
  FIT_X
}

enum ImageLightboxScrollMode {
  ZOOM
  PAN_Y
}

input ConfigImageLightboxInput {
  slideshowDelay: Int
  displayMode: ImageLightboxDisplayMode
  scaleUp: Boolean
  resetZoomOnNav: Boolean
  scrollMode: ImageLightboxScrollMode
  scrollAttemptsBeforeChange: Int
  disableAnimation: Boolean
}

type ConfigImageLightboxResult {
  slideshowDelay: Int
  displayMode: ImageLightboxDisplayMode
  scaleUp: Boolean
  resetZoomOnNav: Boolean
  scrollMode: ImageLightboxScrollMode
  scrollAttemptsBeforeChange: Int!
  disableAnimation: Boolean
}

input ConfigInterfaceInput {
  "True if SFW content mode is enabled"
  sfwContentMode: Boolean

  "Ordered list of items that should be shown in the menu"
  menuItems: [String!]

  "Enable sound on mouseover previews"
  soundOnPreview: Boolean

  "Show title and tags in wall view"
  wallShowTitle: Boolean
  "Wall playback type"
  wallPlayback: String

  "Show scene scrubber by default"
  showScrubber: Boolean

  "Maximum duration (in seconds) in which a scene video will loop in the scene player"
  maximumLoopDuration: Int
  "If true, video will autostart on load in the scene player"
  autostartVideo: Boolean
  "If true, video will autostart when loading from play random or play selected"
  autostartVideoOnPlaySelected: Boolean
  "If true, next scene in playlist will be played at video end by default"
  continuePlaylistDefault: Boolean

  "If true, studio overlays will be shown as text instead of logo images"
  showStudioAsText: Boolean

  "Custom CSS"
  css: String
  cssEnabled: Boolean

  "Custom Javascript"
  javascript: String
  javascriptEnabled: Boolean

  "Custom Locales"
  customLocales: String
  customLocalesEnabled: Boolean

  "When true, disables all customizations (plugins, CSS, JavaScript, locales) for troubleshooting"
  disableCustomizations: Boolean

  "Interface language"
  language: String

  imageLightbox: ConfigImageLightboxInput

  "Set to true to disable creating new objects via the dropdown menus"
  disableDropdownCreate: ConfigDisableDropdownCreateInput

  "Handy Connection Key"
  handyKey: String
  "Funscript Time Offset"
  funscriptOffset: Int
  "Whether to use Stash Hosted Funscript"
  useStashHostedFunscript: Boolean
  "True if we should not auto-open a browser window on startup"
  noBrowser: Boolean
  "True if we should send notifications to the desktop"
  notificationsEnabled: Boolean
}

type ConfigDisableDropdownCreate {
  performer: Boolean!
  tag: Boolean!
  studio: Boolean!
  movie: Boolean!
  gallery: Boolean!
}

type ConfigInterfaceResult {
  "True if SFW content mode is enabled"
  sfwContentMode: Boolean!

  "Ordered list of items that should be shown in the menu"
  menuItems: [String!]

  "Enable sound on mouseover previews"
  soundOnPreview: Boolean

  "Show title and tags in wall view"
  wallShowTitle: Boolean
  "Wall playback type"
  wallPlayback: String

  "Show scene scrubber by default"
  showScrubber: Boolean

  "Maximum duration (in seconds) in which a scene video will loop in the scene player"
  maximumLoopDuration: Int
  "True if we should not auto-open a browser window on startup"
  noBrowser: Boolean
  "True if we should send desktop notifications"
  notificationsEnabled: Boolean
  "If true, video will autostart on load in the scene player"
  autostartVideo: Boolean
  "If true, video will autostart when loading from play random or play selected"
  autostartVideoOnPlaySelected: Boolean
  "If true, next scene in playlist will be played at video end by default"
  continuePlaylistDefault: Boolean

  "If true, studio overlays will be shown as text instead of logo images"
  showStudioAsText: Boolean

  "Custom CSS"
  css: String
  cssEnabled: Boolean

  "Custom Javascript"
  javascript: String
  javascriptEnabled: Boolean

  "Custom Locales"
  customLocales: String
  customLocalesEnabled: Boolean

  "When true, disables all customizations (plugins, CSS, JavaScript, locales) for troubleshooting"
  disableCustomizations: Boolean

  "Interface language"
  language: String

  imageLightbox: ConfigImageLightboxResult!

  "Fields are true if creating via dropdown menus are disabled"
  disableDropdownCreate: ConfigDisableDropdownCreate!

  "Handy Connection Key"
  handyKey: String
  "Funscript Time Offset"
  funscriptOffset: Int
  "Whether to use Stash Hosted Funscript"
  useStashHostedFunscript: Boolean
}

input ConfigDLNAInput {
  serverName: String
  "True if DLNA service should be enabled by default"
  enabled: Boolean
  "Defaults to 1338"
  port: Int
  "List of IPs whitelisted for DLNA service"
  whitelistedIPs: [String!]
  "List of interfaces to run DLNA on. Empty for all"
  interfaces: [String!]
  "Order to sort videos"
  videoSortOrder: String
}

type ConfigDLNAResult {
  serverName: String!
  "True if DLNA service should be enabled by default"
  enabled: Boolean!
  "Defaults to 1338"
  port: Int!
  "List of IPs whitelisted for DLNA service"
  whitelistedIPs: [String!]!
  "List of interfaces to run DLNA on. Empty for all"
  interfaces: [String!]!
  "Order to sort videos"
  videoSortOrder: String!
}

input ConfigScrapingInput {
  "Scraper user agent string"
  scraperUserAgent: String
  "Scraper CDP path. Path to chrome executable or remote address"
  scraperCDPPath: String
  "Whether the scraper should check for invalid certificates"
  scraperCertCheck: Boolean
  "Tags blacklist during scraping"
  excludeTagPatterns: [String!]
}

type ConfigScrapingResult {
  "Scraper user agent string"
  scraperUserAgent: String
  "Scraper CDP path. Path to chrome executable or remote address"
  scraperCDPPath: String
  "Whether the scraper should check for invalid certificates"
  scraperCertCheck: Boolean!
  "Tags blacklist during scraping"
  excludeTagPatterns: [String!]!
}

type ConfigDefaultSettingsResult {
  scan: ScanMetadataOptions
  identify: IdentifyMetadataTaskOptions
  autoTag: AutoTagMetadataOptions
  generate: GenerateMetadataOptions

  "If true, delete file checkbox will be checked by default"
  deleteFile: Boolean
  "If true, delete generated supporting files checkbox will be checked by default"
  deleteGenerated: Boolean
}

input ConfigDefaultSettingsInput {
  scan: ScanMetadataInput
  identify: IdentifyMetadataInput
  autoTag: AutoTagMetadataInput
  generate: GenerateMetadataInput

  "If true, delete file checkbox will be checked by default"
  deleteFile: Boolean
  "If true, delete generated files checkbox will be checked by default"
  deleteGenerated: Boolean
}

"All configuration settings"
type ConfigResult {
  general: ConfigGeneralResult!
  interface: ConfigInterfaceResult!
  dlna: ConfigDLNAResult!
  scraping: ConfigScrapingResult!
  defaults: ConfigDefaultSettingsResult!
  ui: Map!
  plugins(include: [ID!]): PluginConfigMap!
}

"Directory structure of a path"
type Directory {
  path: String!
  parent: String
  directories: [String!]!
}

"Stash configuration details"
input StashConfigInput {
  path: String!
  excludeVideo: Boolean!
  excludeImage: Boolean!
}

type StashConfig {
  path: String!
  excludeVideo: Boolean!
  excludeImage: Boolean!
}

input GenerateAPIKeyInput {
  clear: Boolean
}

type StashBoxValidationResult {
  valid: Boolean!
  status: String!
}
