Overhaul graphql client cache invalidation (#3912)

* Update apollo client
* Overhaul graphql client cache invalidation
* Fix tagger studio link display update
* Add graphql formatting
This commit is contained in:
DingDongSoLong4 2023-07-28 02:36:00 +02:00 committed by GitHub
parent a1da626c9f
commit 7b77b8986f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
64 changed files with 3034 additions and 1939 deletions

View file

@ -149,7 +149,7 @@ fragment ConfigDefaultSettingsData on ConfigDefaultSettingsResult {
scanGenerateThumbnails
scanGenerateClipPreviews
}
identify {
sources {
source {

View file

@ -3,4 +3,4 @@ fragment SavedFilterData on SavedFilter {
mode
name
filter
}
}

View file

@ -17,7 +17,7 @@ fragment SlimGalleryData on Gallery {
files {
...ImageFileData
}
paths {
thumbnail
}

View file

@ -26,7 +26,7 @@ fragment ImageData on Image {
studio {
...SlimStudioData
}
tags {
...SlimTagData
}

View file

@ -7,4 +7,4 @@ fragment JobData on Job {
startTime
endTime
addTime
}
}

View file

@ -10,7 +10,7 @@ fragment MovieData on Movie {
studio {
...SlimStudioData
}
synopsis
url
front_image_path

View file

@ -49,7 +49,7 @@ fragment SceneData on Scene {
studio {
...SlimStudioData
}
movies {
movie {
...MovieData

View file

@ -1,3 +1,3 @@
mutation DeleteFiles($ids: [ID!]!) {
deleteFiles(ids: $ids)
}
}

View file

@ -2,7 +2,7 @@ mutation SaveFilter($input: SaveFilterInput!) {
saveFilter(input: $input) {
...SavedFilterData
}
}
}
mutation DestroySavedFilter($input: DestroyFilterInput!) {
destroySavedFilter(input: $input)

View file

@ -1,27 +1,29 @@
mutation GalleryChapterCreate(
$title: String!,
$image_index: Int!,
$gallery_id: ID!) {
galleryChapterCreate(input: {
title: $title,
image_index: $image_index,
gallery_id: $gallery_id,
}) {
$title: String!
$image_index: Int!
$gallery_id: ID!
) {
galleryChapterCreate(
input: { title: $title, image_index: $image_index, gallery_id: $gallery_id }
) {
...GalleryChapterData
}
}
mutation GalleryChapterUpdate(
$id: ID!,
$title: String!,
$image_index: Int!,
$gallery_id: ID!) {
galleryChapterUpdate(input: {
id: $id,
title: $title,
image_index: $image_index,
gallery_id: $gallery_id,
}) {
$id: ID!
$title: String!
$image_index: Int!
$gallery_id: ID!
) {
galleryChapterUpdate(
input: {
id: $id
title: $title
image_index: $image_index
gallery_id: $gallery_id
}
) {
...GalleryChapterData
}
}

View file

@ -1,41 +1,45 @@
mutation GalleryCreate(
$input: GalleryCreateInput!) {
mutation GalleryCreate($input: GalleryCreateInput!) {
galleryCreate(input: $input) {
...GalleryData
...GalleryData
}
}
mutation GalleryUpdate(
$input: GalleryUpdateInput!) {
mutation GalleryUpdate($input: GalleryUpdateInput!) {
galleryUpdate(input: $input) {
...GalleryData
...GalleryData
}
}
mutation BulkGalleryUpdate(
$input: BulkGalleryUpdateInput!) {
mutation BulkGalleryUpdate($input: BulkGalleryUpdateInput!) {
bulkGalleryUpdate(input: $input) {
...GalleryData
...GalleryData
}
}
mutation GalleriesUpdate($input : [GalleryUpdateInput!]!) {
mutation GalleriesUpdate($input: [GalleryUpdateInput!]!) {
galleriesUpdate(input: $input) {
...GalleryData
}
}
mutation GalleryDestroy($ids: [ID!]!, $delete_file: Boolean, $delete_generated : Boolean) {
galleryDestroy(input: {ids: $ids, delete_file: $delete_file, delete_generated: $delete_generated})
mutation GalleryDestroy(
$ids: [ID!]!
$delete_file: Boolean
$delete_generated: Boolean
) {
galleryDestroy(
input: {
ids: $ids
delete_file: $delete_file
delete_generated: $delete_generated
}
)
}
mutation AddGalleryImages($gallery_id: ID!, $image_ids: [ID!]!) {
addGalleryImages(input: {gallery_id: $gallery_id, image_ids: $image_ids})
addGalleryImages(input: { gallery_id: $gallery_id, image_ids: $image_ids })
}
mutation RemoveGalleryImages($gallery_id: ID!, $image_ids: [ID!]!) {
removeGalleryImages(input: {gallery_id: $gallery_id, image_ids: $image_ids})
removeGalleryImages(input: { gallery_id: $gallery_id, image_ids: $image_ids })
}

View file

@ -1,27 +1,23 @@
mutation ImageUpdate(
$input: ImageUpdateInput!) {
mutation ImageUpdate($input: ImageUpdateInput!) {
imageUpdate(input: $input) {
...SlimImageData
...SlimImageData
}
}
mutation BulkImageUpdate(
$input: BulkImageUpdateInput!) {
mutation BulkImageUpdate($input: BulkImageUpdateInput!) {
bulkImageUpdate(input: $input) {
...SlimImageData
...SlimImageData
}
}
mutation ImagesUpdate($input : [ImageUpdateInput!]!) {
mutation ImagesUpdate($input: [ImageUpdateInput!]!) {
imagesUpdate(input: $input) {
...SlimImageData
}
}
mutation ImageIncrementO($id: ID!) {
imageIncrementO(id: $id)
imageIncrementO(id: $id)
}
mutation ImageDecrementO($id: ID!) {
@ -32,10 +28,30 @@ mutation ImageResetO($id: ID!) {
imageResetO(id: $id)
}
mutation ImageDestroy($id: ID!, $delete_file: Boolean, $delete_generated : Boolean) {
imageDestroy(input: {id: $id, delete_file: $delete_file, delete_generated: $delete_generated})
mutation ImageDestroy(
$id: ID!
$delete_file: Boolean
$delete_generated: Boolean
) {
imageDestroy(
input: {
id: $id
delete_file: $delete_file
delete_generated: $delete_generated
}
)
}
mutation ImagesDestroy($ids: [ID!]!, $delete_file: Boolean, $delete_generated : Boolean) {
imagesDestroy(input: {ids: $ids, delete_file: $delete_file, delete_generated: $delete_generated})
mutation ImagesDestroy(
$ids: [ID!]!
$delete_file: Boolean
$delete_generated: Boolean
) {
imagesDestroy(
input: {
ids: $ids
delete_file: $delete_file
delete_generated: $delete_generated
}
)
}

View file

@ -3,5 +3,5 @@ mutation StopJob($job_id: ID!) {
}
mutation StopAllJobs {
stopAllJobs
}
stopAllJobs
}

View file

@ -4,4 +4,4 @@ mutation MigrateSceneScreenshots($input: MigrateSceneScreenshotsInput!) {
mutation MigrateBlobs($input: MigrateBlobsInput!) {
migrateBlobs(input: $input)
}
}

View file

@ -1,22 +1,16 @@
mutation PerformerCreate(
$input: PerformerCreateInput!) {
mutation PerformerCreate($input: PerformerCreateInput!) {
performerCreate(input: $input) {
...PerformerData
...PerformerData
}
}
mutation PerformerUpdate(
$input: PerformerUpdateInput!) {
mutation PerformerUpdate($input: PerformerUpdateInput!) {
performerUpdate(input: $input) {
...PerformerData
}
}
mutation BulkPerformerUpdate(
$input: BulkPerformerUpdateInput!) {
mutation BulkPerformerUpdate($input: BulkPerformerUpdateInput!) {
bulkPerformerUpdate(input: $input) {
...PerformerData
}

View file

@ -2,6 +2,10 @@ mutation ReloadPlugins {
reloadPlugins
}
mutation RunPluginTask($plugin_id: ID!, $task_name: String!, $args: [PluginArgInput!]) {
mutation RunPluginTask(
$plugin_id: ID!
$task_name: String!
$args: [PluginArgInput!]
) {
runPluginTask(plugin_id: $plugin_id, task_name: $task_name, args: $args)
}

View file

@ -1,41 +1,45 @@
mutation SceneMarkerCreate(
$title: String!,
$seconds: Float!,
$scene_id: ID!,
$primary_tag_id: ID!,
$tag_ids: [ID!] = []) {
sceneMarkerCreate(input: {
title: $title,
seconds: $seconds,
scene_id: $scene_id,
primary_tag_id: $primary_tag_id,
tag_ids: $tag_ids
}) {
$title: String!
$seconds: Float!
$scene_id: ID!
$primary_tag_id: ID!
$tag_ids: [ID!] = []
) {
sceneMarkerCreate(
input: {
title: $title
seconds: $seconds
scene_id: $scene_id
primary_tag_id: $primary_tag_id
tag_ids: $tag_ids
}
) {
...SceneMarkerData
}
}
mutation SceneMarkerUpdate(
$id: ID!,
$title: String!,
$seconds: Float!,
$scene_id: ID!,
$primary_tag_id: ID!,
$tag_ids: [ID!] = []) {
sceneMarkerUpdate(input: {
id: $id,
title: $title,
seconds: $seconds,
scene_id: $scene_id,
primary_tag_id: $primary_tag_id,
tag_ids: $tag_ids
}) {
$id: ID!
$title: String!
$seconds: Float!
$scene_id: ID!
$primary_tag_id: ID!
$tag_ids: [ID!] = []
) {
sceneMarkerUpdate(
input: {
id: $id
title: $title
seconds: $seconds
scene_id: $scene_id
primary_tag_id: $primary_tag_id
tag_ids: $tag_ids
}
) {
...SceneMarkerData
}
}
mutation SceneMarkerDestroy($id: ID!) {
sceneMarkerDestroy(id: $id)
}
}

View file

@ -1,43 +1,45 @@
mutation SceneCreate(
$input: SceneCreateInput!) {
mutation SceneCreate($input: SceneCreateInput!) {
sceneCreate(input: $input) {
...SceneData
}
}
mutation SceneUpdate(
$input: SceneUpdateInput!) {
mutation SceneUpdate($input: SceneUpdateInput!) {
sceneUpdate(input: $input) {
...SceneData
}
}
mutation BulkSceneUpdate(
$input: BulkSceneUpdateInput!) {
mutation BulkSceneUpdate($input: BulkSceneUpdateInput!) {
bulkSceneUpdate(input: $input) {
...SceneData
}
}
mutation ScenesUpdate($input : [SceneUpdateInput!]!) {
mutation ScenesUpdate($input: [SceneUpdateInput!]!) {
scenesUpdate(input: $input) {
...SceneData
}
}
mutation SceneSaveActivity($id: ID!, $resume_time: Float, $playDuration: Float) {
sceneSaveActivity(id: $id, resume_time: $resume_time, playDuration: $playDuration)
mutation SceneSaveActivity(
$id: ID!
$resume_time: Float
$playDuration: Float
) {
sceneSaveActivity(
id: $id
resume_time: $resume_time
playDuration: $playDuration
)
}
mutation SceneIncrementPlayCount($id: ID!) {
sceneIncrementPlayCount(id: $id)
sceneIncrementPlayCount(id: $id)
}
mutation SceneIncrementO($id: ID!) {
sceneIncrementO(id: $id)
sceneIncrementO(id: $id)
}
mutation SceneDecrementO($id: ID!) {
@ -48,12 +50,32 @@ mutation SceneResetO($id: ID!) {
sceneResetO(id: $id)
}
mutation SceneDestroy($id: ID!, $delete_file: Boolean, $delete_generated : Boolean) {
sceneDestroy(input: {id: $id, delete_file: $delete_file, delete_generated: $delete_generated})
mutation SceneDestroy(
$id: ID!
$delete_file: Boolean
$delete_generated: Boolean
) {
sceneDestroy(
input: {
id: $id
delete_file: $delete_file
delete_generated: $delete_generated
}
)
}
mutation ScenesDestroy($ids: [ID!]!, $delete_file: Boolean, $delete_generated : Boolean) {
scenesDestroy(input: {ids: $ids, delete_file: $delete_file, delete_generated: $delete_generated})
mutation ScenesDestroy(
$ids: [ID!]!
$delete_file: Boolean
$delete_generated: Boolean
) {
scenesDestroy(
input: {
ids: $ids
delete_file: $delete_file
delete_generated: $delete_generated
}
)
}
mutation SceneGenerateScreenshot($id: ID!, $at: Float) {
@ -68,4 +90,4 @@ mutation SceneMerge($input: SceneMergeInput!) {
sceneMerge(input: $input) {
id
}
}
}

View file

@ -1,4 +1,6 @@
mutation SubmitStashBoxFingerprints($input: StashBoxFingerprintSubmissionInput!) {
mutation SubmitStashBoxFingerprints(
$input: StashBoxFingerprintSubmissionInput!
) {
submitStashBoxFingerprints(input: $input)
}

View file

@ -8,4 +8,4 @@ query DLNAStatus {
until
}
}
}
}

View file

@ -1,4 +1,7 @@
query FindGalleries($filter: FindFilterType, $gallery_filter: GalleryFilterType) {
query FindGalleries(
$filter: FindFilterType
$gallery_filter: GalleryFilterType
) {
findGalleries(gallery_filter: $gallery_filter, filter: $filter) {
count
galleries {

View file

@ -1,5 +1,13 @@
query FindImages($filter: FindFilterType, $image_filter: ImageFilterType, $image_ids: [Int!]) {
findImages(filter: $filter, image_filter: $image_filter, image_ids: $image_ids) {
query FindImages(
$filter: FindFilterType
$image_filter: ImageFilterType
$image_ids: [Int!]
) {
findImages(
filter: $filter
image_filter: $image_filter
image_ids: $image_ids
) {
count
megapixels
filesize

View file

@ -5,7 +5,7 @@ query JobQueue {
}
query FindJob($input: FindJobInput!) {
findJob(input: $input) {
...JobData
}
findJob(input: $input) {
...JobData
}
}

View file

@ -8,4 +8,4 @@ query MarkerWall($q: String) {
markerWall(q: $q) {
...SceneMarkerData
}
}
}

View file

@ -11,4 +11,4 @@ query FindMovie($id: ID!) {
findMovie(id: $id) {
...MovieData
}
}
}

View file

@ -1,4 +1,7 @@
query FindPerformers($filter: FindFilterType, $performer_filter: PerformerFilterType) {
query FindPerformers(
$filter: FindFilterType
$performer_filter: PerformerFilterType
) {
findPerformers(filter: $filter, performer_filter: $performer_filter) {
count
performers {

View file

@ -1,8 +1,11 @@
query FindSceneMarkers($filter: FindFilterType, $scene_marker_filter: SceneMarkerFilterType) {
query FindSceneMarkers(
$filter: FindFilterType
$scene_marker_filter: SceneMarkerFilterType
) {
findSceneMarkers(filter: $filter, scene_marker_filter: $scene_marker_filter) {
count
scene_markers {
...SceneMarkerData
}
}
}
}

View file

@ -1,5 +1,13 @@
query FindScenes($filter: FindFilterType, $scene_filter: SceneFilterType, $scene_ids: [Int!]) {
findScenes(filter: $filter, scene_filter: $scene_filter, scene_ids: $scene_ids) {
query FindScenes(
$filter: FindFilterType
$scene_filter: SceneFilterType
$scene_ids: [Int!]
) {
findScenes(
filter: $filter
scene_filter: $scene_filter
scene_ids: $scene_ids
) {
count
filesize
duration
@ -44,7 +52,10 @@ query FindSceneMarkerTags($id: ID!) {
}
}
query ParseSceneFilenames($filter: FindFilterType!, $config: SceneParserInput!) {
query ParseSceneFilenames(
$filter: FindFilterType!
$config: SceneParserInput!
) {
parseSceneFilenames(filter: $filter, config: $config) {
count
results {

View file

@ -1,3 +1,3 @@
query ScrapeFreeonesPerformers($q: String!) {
scrapeFreeonesPerformerList(query: $q)
}
}

View file

@ -42,13 +42,19 @@ query ListMovieScrapers {
}
}
query ScrapeSinglePerformer($source: ScraperSourceInput!, $input: ScrapeSinglePerformerInput!) {
query ScrapeSinglePerformer(
$source: ScraperSourceInput!
$input: ScrapeSinglePerformerInput!
) {
scrapeSinglePerformer(source: $source, input: $input) {
...ScrapedPerformerData
}
}
query ScrapeMultiPerformers($source: ScraperSourceInput!, $input: ScrapeMultiPerformersInput!) {
query ScrapeMultiPerformers(
$source: ScraperSourceInput!
$input: ScrapeMultiPerformersInput!
) {
scrapeMultiPerformers(source: $source, input: $input) {
...ScrapedPerformerData
}
@ -60,13 +66,19 @@ query ScrapePerformerURL($url: String!) {
}
}
query ScrapeSingleScene($source: ScraperSourceInput!, $input: ScrapeSingleSceneInput!) {
query ScrapeSingleScene(
$source: ScraperSourceInput!
$input: ScrapeSingleSceneInput!
) {
scrapeSingleScene(source: $source, input: $input) {
...ScrapedSceneData
}
}
query ScrapeMultiScenes($source: ScraperSourceInput!, $input: ScrapeMultiScenesInput!) {
query ScrapeMultiScenes(
$source: ScraperSourceInput!
$input: ScrapeMultiScenesInput!
) {
scrapeMultiScenes(source: $source, input: $input) {
...ScrapedSceneData
}
@ -78,7 +90,10 @@ query ScrapeSceneURL($url: String!) {
}
}
query ScrapeSingleGallery($source: ScraperSourceInput!, $input: ScrapeSingleGalleryInput!) {
query ScrapeSingleGallery(
$source: ScraperSourceInput!
$input: ScrapeSingleGalleryInput!
) {
scrapeSingleGallery(source: $source, input: $input) {
...ScrapedGalleryData
}

View file

@ -6,9 +6,9 @@ query Configuration {
query Directory($path: String) {
directory(path: $path) {
path
parent
directories
path
parent
directories
}
}

View file

@ -1,4 +1,4 @@
query FindStudios($filter: FindFilterType, $studio_filter: StudioFilterType ) {
query FindStudios($filter: FindFilterType, $studio_filter: StudioFilterType) {
findStudios(filter: $filter, studio_filter: $studio_filter) {
count
studios {

View file

@ -1,4 +1,4 @@
query FindTags($filter: FindFilterType, $tag_filter: TagFilterType ) {
query FindTags($filter: FindFilterType, $tag_filter: TagFilterType) {
findTags(filter: $filter, tag_filter: $tag_filter) {
count
tags {
@ -11,4 +11,4 @@ query FindTag($id: ID!) {
findTag(id: $id) {
...TagData
}
}
}

View file

@ -19,4 +19,4 @@ subscription LoggingSubscribe {
subscription ScanCompleteSubscribe {
scanCompleteSubscribe
}
}

View file

@ -1,16 +1,20 @@
"""The query root for this schema"""
"The query root for this schema"
type Query {
# Filters
findSavedFilter(id: ID!): SavedFilter
findSavedFilters(mode: FilterMode): [SavedFilter!]!
findDefaultFilter(mode: FilterMode!): SavedFilter
"""Find a scene by ID or Checksum"""
"Find a scene by ID or Checksum"
findScene(id: ID, checksum: String): Scene
findSceneByHash(input: SceneHashInput!): Scene
"""A function which queries Scene objects"""
findScenes(scene_filter: SceneFilterType, scene_ids: [Int!], filter: FindFilterType): FindScenesResultType!
"A function which queries Scene objects"
findScenes(
scene_filter: SceneFilterType
scene_ids: [Int!]
filter: FindFilterType
): FindScenesResultType!
findScenesByPathRegex(filter: FindFilterType): FindScenesResultType!
@ -19,123 +23,180 @@ type Query {
and the difference between their duration is smaller than durationDiff
"""
findDuplicateScenes(
distance: Int,
"""Max difference in seconds between files in order to be considered for similarity matching.
Fractional seconds are ok: 0.5 will mean only files that have durations within 0.5 seconds between them will be matched based on PHash distance."""
distance: Int
"""
Max difference in seconds between files in order to be considered for similarity matching.
Fractional seconds are ok: 0.5 will mean only files that have durations within 0.5 seconds between them will be matched based on PHash distance.
"""
duration_diff: Float
): [[Scene!]!]!
"""Return valid stream paths"""
"Return valid stream paths"
sceneStreams(id: ID): [SceneStreamEndpoint!]!
parseSceneFilenames(filter: FindFilterType, config: SceneParserInput!): SceneParserResultType!
parseSceneFilenames(
filter: FindFilterType
config: SceneParserInput!
): SceneParserResultType!
"""A function which queries SceneMarker objects"""
findSceneMarkers(scene_marker_filter: SceneMarkerFilterType filter: FindFilterType): FindSceneMarkersResultType!
"A function which queries SceneMarker objects"
findSceneMarkers(
scene_marker_filter: SceneMarkerFilterType
filter: FindFilterType
): FindSceneMarkersResultType!
findImage(id: ID, checksum: String): Image
"""A function which queries Scene objects"""
findImages(image_filter: ImageFilterType, image_ids: [Int!], filter: FindFilterType): FindImagesResultType!
"A function which queries Scene objects"
findImages(
image_filter: ImageFilterType
image_ids: [Int!]
filter: FindFilterType
): FindImagesResultType!
"""Find a performer by ID"""
"Find a performer by ID"
findPerformer(id: ID!): Performer
"""A function which queries Performer objects"""
findPerformers(performer_filter: PerformerFilterType, filter: FindFilterType): FindPerformersResultType!
"A function which queries Performer objects"
findPerformers(
performer_filter: PerformerFilterType
filter: FindFilterType
): FindPerformersResultType!
"""Find a studio by ID"""
"Find a studio by ID"
findStudio(id: ID!): Studio
"""A function which queries Studio objects"""
findStudios(studio_filter: StudioFilterType, filter: FindFilterType): FindStudiosResultType!
"A function which queries Studio objects"
findStudios(
studio_filter: StudioFilterType
filter: FindFilterType
): FindStudiosResultType!
"""Find a movie by ID"""
"Find a movie by ID"
findMovie(id: ID!): Movie
"""A function which queries Movie objects"""
findMovies(movie_filter: MovieFilterType, filter: FindFilterType): FindMoviesResultType!
"A function which queries Movie objects"
findMovies(
movie_filter: MovieFilterType
filter: FindFilterType
): FindMoviesResultType!
findGallery(id: ID!): Gallery
findGalleries(gallery_filter: GalleryFilterType, filter: FindFilterType): FindGalleriesResultType!
findGalleries(
gallery_filter: GalleryFilterType
filter: FindFilterType
): FindGalleriesResultType!
findTag(id: ID!): Tag
findTags(tag_filter: TagFilterType, filter: FindFilterType): FindTagsResultType!
findTags(
tag_filter: TagFilterType
filter: FindFilterType
): FindTagsResultType!
"""Retrieve random scene markers for the wall"""
"Retrieve random scene markers for the wall"
markerWall(q: String): [SceneMarker!]!
"""Retrieve random scenes for the wall"""
"Retrieve random scenes for the wall"
sceneWall(q: String): [Scene!]!
"""Get marker strings"""
"Get marker strings"
markerStrings(q: String, sort: String): [MarkerStringsResultType]!
"""Get stats"""
"Get stats"
stats: StatsResultType!
"""Organize scene markers by tag for a given scene ID"""
"Organize scene markers by tag for a given scene ID"
sceneMarkerTags(scene_id: ID!): [SceneMarkerTag!]!
logs: [LogEntry!]!
# Scrapers
"""List available scrapers"""
"List available scrapers"
listScrapers(types: [ScrapeContentType!]!): [Scraper!]!
listPerformerScrapers: [Scraper!]! @deprecated(reason: "Use listScrapers(types: [PERFORMER])")
listSceneScrapers: [Scraper!]! @deprecated(reason: "Use listScrapers(types: [SCENE])")
listGalleryScrapers: [Scraper!]! @deprecated(reason: "Use listScrapers(types: [GALLERY])")
listMovieScrapers: [Scraper!]! @deprecated(reason: "Use listScrapers(types: [MOVIE])")
listPerformerScrapers: [Scraper!]!
@deprecated(reason: "Use listScrapers(types: [PERFORMER])")
listSceneScrapers: [Scraper!]!
@deprecated(reason: "Use listScrapers(types: [SCENE])")
listGalleryScrapers: [Scraper!]!
@deprecated(reason: "Use listScrapers(types: [GALLERY])")
listMovieScrapers: [Scraper!]!
@deprecated(reason: "Use listScrapers(types: [MOVIE])")
"Scrape for a single scene"
scrapeSingleScene(
source: ScraperSourceInput!
input: ScrapeSingleSceneInput!
): [ScrapedScene!]!
"Scrape for multiple scenes"
scrapeMultiScenes(
source: ScraperSourceInput!
input: ScrapeMultiScenesInput!
): [[ScrapedScene!]!]!
"""Scrape for a single scene"""
scrapeSingleScene(source: ScraperSourceInput!, input: ScrapeSingleSceneInput!): [ScrapedScene!]!
"""Scrape for multiple scenes"""
scrapeMultiScenes(source: ScraperSourceInput!, input: ScrapeMultiScenesInput!): [[ScrapedScene!]!]!
"Scrape for a single performer"
scrapeSinglePerformer(
source: ScraperSourceInput!
input: ScrapeSinglePerformerInput!
): [ScrapedPerformer!]!
"Scrape for multiple performers"
scrapeMultiPerformers(
source: ScraperSourceInput!
input: ScrapeMultiPerformersInput!
): [[ScrapedPerformer!]!]!
"""Scrape for a single performer"""
scrapeSinglePerformer(source: ScraperSourceInput!, input: ScrapeSinglePerformerInput!): [ScrapedPerformer!]!
"""Scrape for multiple performers"""
scrapeMultiPerformers(source: ScraperSourceInput!, input: ScrapeMultiPerformersInput!): [[ScrapedPerformer!]!]!
"Scrape for a single gallery"
scrapeSingleGallery(
source: ScraperSourceInput!
input: ScrapeSingleGalleryInput!
): [ScrapedGallery!]!
"""Scrape for a single gallery"""
scrapeSingleGallery(source: ScraperSourceInput!, input: ScrapeSingleGalleryInput!): [ScrapedGallery!]!
"""Scrape for a single movie"""
scrapeSingleMovie(source: ScraperSourceInput!, input: ScrapeSingleMovieInput!): [ScrapedMovie!]!
"Scrape for a single movie"
scrapeSingleMovie(
source: ScraperSourceInput!
input: ScrapeSingleMovieInput!
): [ScrapedMovie!]!
"Scrapes content based on a URL"
scrapeURL(url: String!, ty: ScrapeContentType!): ScrapedContent
"""Scrapes a complete performer record based on a URL"""
"Scrapes a complete performer record based on a URL"
scrapePerformerURL(url: String!): ScrapedPerformer
"""Scrapes a complete scene record based on a URL"""
"Scrapes a complete scene record based on a URL"
scrapeSceneURL(url: String!): ScrapedScene
"""Scrapes a complete gallery record based on a URL"""
"Scrapes a complete gallery record based on a URL"
scrapeGalleryURL(url: String!): ScrapedGallery
"""Scrapes a complete movie record based on a URL"""
"Scrapes a complete movie record based on a URL"
scrapeMovieURL(url: String!): ScrapedMovie
"""Scrape a list of performers based on name"""
scrapePerformerList(scraper_id: ID!, query: String!): [ScrapedPerformer!]! @deprecated(reason: "use scrapeSinglePerformer")
"""Scrapes a complete performer record based on a scrapePerformerList result"""
scrapePerformer(scraper_id: ID!, scraped_performer: ScrapedPerformerInput!): ScrapedPerformer @deprecated(reason: "use scrapeSinglePerformer")
"""Scrapes a complete scene record based on an existing scene"""
scrapeScene(scraper_id: ID!, scene: SceneUpdateInput!): ScrapedScene @deprecated(reason: "use scrapeSingleScene")
"""Scrapes a complete gallery record based on an existing gallery"""
scrapeGallery(scraper_id: ID!, gallery: GalleryUpdateInput!): ScrapedGallery @deprecated(reason: "use scrapeSingleGallery")
"Scrape a list of performers based on name"
scrapePerformerList(scraper_id: ID!, query: String!): [ScrapedPerformer!]!
@deprecated(reason: "use scrapeSinglePerformer")
"Scrapes a complete performer record based on a scrapePerformerList result"
scrapePerformer(
scraper_id: ID!
scraped_performer: ScrapedPerformerInput!
): ScrapedPerformer @deprecated(reason: "use scrapeSinglePerformer")
"Scrapes a complete scene record based on an existing scene"
scrapeScene(scraper_id: ID!, scene: SceneUpdateInput!): ScrapedScene
@deprecated(reason: "use scrapeSingleScene")
"Scrapes a complete gallery record based on an existing gallery"
scrapeGallery(scraper_id: ID!, gallery: GalleryUpdateInput!): ScrapedGallery
@deprecated(reason: "use scrapeSingleGallery")
"""Scrape a list of performers from a query"""
scrapeFreeonesPerformerList(query: String!): [String!]! @deprecated(reason: "use scrapeSinglePerformer with scraper_id = builtin_freeones")
"Scrape a list of performers from a query"
scrapeFreeonesPerformerList(query: String!): [String!]!
@deprecated(
reason: "use scrapeSinglePerformer with scraper_id = builtin_freeones"
)
# Plugins
"""List loaded plugins"""
"List loaded plugins"
plugins: [Plugin!]
"""List available plugin operations"""
"List available plugin operations"
pluginTasks: [PluginTask!]
# Config
"""Returns the current, complete configuration"""
"Returns the current, complete configuration"
configuration: ConfigResult!
"""Returns an array of paths for the given path"""
"Returns an array of paths for the given path"
directory(
"The directory path to list"
path: String,
path: String
"Desired collation locale. Determines the order of the directory result. eg. 'en-US', 'pt-BR', ..."
locale: String = "en"
): Directory!
@ -182,20 +243,20 @@ type Mutation {
scenesDestroy(input: ScenesDestroyInput!): Boolean!
scenesUpdate(input: [SceneUpdateInput!]!): [Scene]
"""Increments the o-counter for a scene. Returns the new value"""
"Increments the o-counter for a scene. Returns the new value"
sceneIncrementO(id: ID!): Int!
"""Decrements the o-counter for a scene. Returns the new value"""
"Decrements the o-counter for a scene. Returns the new value"
sceneDecrementO(id: ID!): Int!
"""Resets the o-counter for a scene to 0. Returns the new value"""
"Resets the o-counter for a scene to 0. Returns the new value"
sceneResetO(id: ID!): Int!
"""Sets the resume time point (if provided) and adds the provided duration to the scene's play duration"""
"Sets the resume time point (if provided) and adds the provided duration to the scene's play duration"
sceneSaveActivity(id: ID!, resume_time: Float, playDuration: Float): Boolean!
"""Increments the play count for the scene. Returns the new play count value."""
"Increments the play count for the scene. Returns the new play count value."
sceneIncrementPlayCount(id: ID!): Int!
"""Generates screenshot at specified time in seconds. Leave empty to generate default screenshot"""
"Generates screenshot at specified time in seconds. Leave empty to generate default screenshot"
sceneGenerateScreenshot(id: ID!, at: Float): String!
sceneMarkerCreate(input: SceneMarkerCreateInput!): SceneMarker
@ -210,11 +271,11 @@ type Mutation {
imagesDestroy(input: ImagesDestroyInput!): Boolean!
imagesUpdate(input: [ImageUpdateInput!]!): [Image]
"""Increments the o-counter for an image. Returns the new value"""
"Increments the o-counter for an image. Returns the new value"
imageIncrementO(id: ID!): Int!
"""Decrements the o-counter for an image. Returns the new value"""
"Decrements the o-counter for an image. Returns the new value"
imageDecrementO(id: ID!): Int!
"""Resets the o-counter for a image to 0. Returns the new value"""
"Resets the o-counter for a image to 0. Returns the new value"
imageResetO(id: ID!): Int!
galleryCreate(input: GalleryCreateInput!): Gallery
@ -253,8 +314,10 @@ type Mutation {
tagsDestroy(ids: [ID!]!): Boolean!
tagsMerge(input: TagsMergeInput!): Tag
"""Moves the given files to the given destination. Returns true if successful.
Either the destination_folder or destination_folder_id must be provided. If both are provided, the destination_folder_id takes precedence.
"""
Moves the given files to the given destination. Returns true if successful.
Either the destination_folder or destination_folder_id must be provided.
If both are provided, the destination_folder_id takes precedence.
Destination folder must be a subfolder of one of the stash library paths.
If provided, destination_basename must be a valid filename with an extension that
matches one of the media extensions.
@ -268,94 +331,102 @@ type Mutation {
destroySavedFilter(input: DestroyFilterInput!): Boolean!
setDefaultFilter(input: SetDefaultFilterInput!): Boolean!
"""Change general configuration options"""
"Change general configuration options"
configureGeneral(input: ConfigGeneralInput!): ConfigGeneralResult!
configureInterface(input: ConfigInterfaceInput!): ConfigInterfaceResult!
configureDLNA(input: ConfigDLNAInput!): ConfigDLNAResult!
configureScraping(input: ConfigScrapingInput!): ConfigScrapingResult!
configureDefaults(input: ConfigDefaultSettingsInput!): ConfigDefaultSettingsResult!
configureDefaults(
input: ConfigDefaultSettingsInput!
): ConfigDefaultSettingsResult!
# overwrites the entire UI configuration
configureUI(input: Map!): Map!
# sets a single UI key value
configureUISetting(key: String!, value: Any): Map!
"""Generate and set (or clear) API key"""
"Generate and set (or clear) API key"
generateAPIKey(input: GenerateAPIKeyInput!): String!
"""Returns a link to download the result"""
"Returns a link to download the result"
exportObjects(input: ExportObjectsInput!): String
"""Performs an incremental import. Returns the job ID"""
"Performs an incremental import. Returns the job ID"
importObjects(input: ImportObjectsInput!): ID!
"""Start an full import. Completely wipes the database and imports from the metadata directory. Returns the job ID"""
"Start an full import. Completely wipes the database and imports from the metadata directory. Returns the job ID"
metadataImport: ID!
"""Start a full export. Outputs to the metadata directory. Returns the job ID"""
"Start a full export. Outputs to the metadata directory. Returns the job ID"
metadataExport: ID!
"""Start a scan. Returns the job ID"""
"Start a scan. Returns the job ID"
metadataScan(input: ScanMetadataInput!): ID!
"""Start generating content. Returns the job ID"""
"Start generating content. Returns the job ID"
metadataGenerate(input: GenerateMetadataInput!): ID!
"""Start auto-tagging. Returns the job ID"""
"Start auto-tagging. Returns the job ID"
metadataAutoTag(input: AutoTagMetadataInput!): ID!
"""Clean metadata. Returns the job ID"""
"Clean metadata. Returns the job ID"
metadataClean(input: CleanMetadataInput!): ID!
"""Identifies scenes using scrapers. Returns the job ID"""
"Identifies scenes using scrapers. Returns the job ID"
metadataIdentify(input: IdentifyMetadataInput!): ID!
"""Migrate generated files for the current hash naming"""
"Migrate generated files for the current hash naming"
migrateHashNaming: ID!
"""Migrates legacy scene screenshot files into the blob storage"""
"Migrates legacy scene screenshot files into the blob storage"
migrateSceneScreenshots(input: MigrateSceneScreenshotsInput!): ID!
"""Migrates blobs from the old storage system to the current one"""
"Migrates blobs from the old storage system to the current one"
migrateBlobs(input: MigrateBlobsInput!): ID!
"""Anonymise the database in a separate file. Optionally returns a link to download the database file"""
"Anonymise the database in a separate file. Optionally returns a link to download the database file"
anonymiseDatabase(input: AnonymiseDatabaseInput!): String
"""Reload scrapers"""
"Reload scrapers"
reloadScrapers: Boolean!
"""Run plugin task. Returns the job ID"""
runPluginTask(plugin_id: ID!, task_name: String!, args: [PluginArgInput!]): ID!
"Run plugin task. Returns the job ID"
runPluginTask(
plugin_id: ID!
task_name: String!
args: [PluginArgInput!]
): ID!
reloadPlugins: Boolean!
stopJob(job_id: ID!): Boolean!
stopAllJobs: Boolean!
"""Submit fingerprints to stash-box instance"""
submitStashBoxFingerprints(input: StashBoxFingerprintSubmissionInput!): Boolean!
"Submit fingerprints to stash-box instance"
submitStashBoxFingerprints(
input: StashBoxFingerprintSubmissionInput!
): Boolean!
"""Submit scene as draft to stash-box instance"""
"Submit scene as draft to stash-box instance"
submitStashBoxSceneDraft(input: StashBoxDraftSubmissionInput!): ID
"""Submit performer as draft to stash-box instance"""
"Submit performer as draft to stash-box instance"
submitStashBoxPerformerDraft(input: StashBoxDraftSubmissionInput!): ID
"""Backup the database. Optionally returns a link to download the database file"""
"Backup the database. Optionally returns a link to download the database file"
backupDatabase(input: BackupDatabaseInput!): String
"""DANGEROUS: Execute an arbitrary SQL statement that returns rows."""
"DANGEROUS: Execute an arbitrary SQL statement that returns rows."
querySQL(sql: String!, args: [Any]): SQLQueryResult!
"""DANGEROUS: Execute an arbitrary SQL statement without returning any rows."""
"DANGEROUS: Execute an arbitrary SQL statement without returning any rows."
execSQL(sql: String!, args: [Any]): SQLExecResult!
"""Run batch performer tag task. Returns the job ID."""
"Run batch performer tag task. Returns the job ID."
stashBoxBatchPerformerTag(input: StashBoxBatchPerformerTagInput!): String!
"""Enables DLNA for an optional duration. Has no effect if DLNA is enabled by default"""
"Enables DLNA for an optional duration. Has no effect if DLNA is enabled by default"
enableDLNA(input: EnableDLNAInput!): Boolean!
"""Disables DLNA for an optional duration. Has no effect if DLNA is disabled by default"""
"Disables DLNA for an optional duration. Has no effect if DLNA is disabled by default"
disableDLNA(input: DisableDLNAInput!): Boolean!
"""Enables an IP address for DLNA for an optional duration"""
"Enables an IP address for DLNA for an optional duration"
addTempDLNAIP(input: AddTempDLNAIPInput!): Boolean!
"""Removes an IP address from the temporary DLNA whitelist"""
"Removes an IP address from the temporary DLNA whitelist"
removeTempDLNAIP(input: RemoveTempDLNAIPInput!): Boolean!
}
type Subscription {
"""Update from the metadata manager"""
"Update from the metadata manager"
jobsSubscribe: JobStatusUpdate!
loggingSubscribe: [LogEntry!]!

View file

@ -1,267 +1,311 @@
input SetupInput {
"""Empty to indicate $HOME/.stash/config.yml default"""
"Empty to indicate $HOME/.stash/config.yml default"
configLocation: String!
stashes: [StashConfigInput!]!
"""Empty to indicate default"""
"Empty to indicate default"
databaseFile: String!
"""Empty to indicate default"""
"Empty to indicate default"
generatedLocation: String!
"""Empty to indicate default"""
"Empty to indicate default"
cacheLocation: String!
"""Empty to indicate database storage for blobs"""
"Empty to indicate database storage for blobs"
blobsLocation: String!
}
enum StreamingResolutionEnum {
"240p", LOW
"480p", STANDARD
"720p", STANDARD_HD
"1080p", FULL_HD
"4k", FOUR_K
"Original", ORIGINAL
"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
"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
"oshash"
OSHASH
}
enum BlobsStorageType {
# blobs are stored in the database
"Database", DATABASE
"Database"
DATABASE
# blobs are stored in the filesystem under the configured blobs directory
"Filesystem", FILESYSTEM
"Filesystem"
FILESYSTEM
}
input ConfigGeneralInput {
"""Array of file paths to content"""
"Array of file paths to content"
stashes: [StashConfigInput!]
"""Path to the SQLite database"""
"Path to the SQLite database"
databasePath: String
"""Path to backup directory"""
"Path to backup directory"
backupDirectoryPath: String
"""Path to generated files"""
"Path to generated files"
generatedPath: String
"""Path to import/export files"""
"Path to import/export files"
metadataPath: String
"""Path to scrapers"""
"Path to scrapers"
scrapersPath: String
"""Path to cache"""
"Path to cache"
cachePath: String
"""Path to blobs - required for filesystem blob storage"""
"Path to blobs - required for filesystem blob storage"
blobsPath: String
"""Where to store blobs"""
"Where to store blobs"
blobsStorage: BlobsStorageType
"""Whether to calculate MD5 checksums for scene video files"""
"Whether to calculate MD5 checksums for scene video files"
calculateMD5: Boolean
"""Hash algorithm to use for generated file naming"""
"Hash algorithm to use for generated file naming"
videoFileNamingAlgorithm: HashAlgorithm
"""Number of parallel tasks to start during scan/generate"""
"Number of parallel tasks to start during scan/generate"
parallelTasks: Int
"""Include audio stream in previews"""
"Include audio stream in previews"
previewAudio: Boolean
"""Number of segments in a preview file"""
"Number of segments in a preview file"
previewSegments: Int
"""Preview segment duration, in seconds"""
"Preview segment duration, in seconds"
previewSegmentDuration: Float
"""Duration of start of video to exclude when generating previews"""
"Duration of start of video to exclude when generating previews"
previewExcludeStart: String
"""Duration of end of video to exclude when generating previews"""
"Duration of end of video to exclude when generating previews"
previewExcludeEnd: String
"""Preset when generating preview"""
"Preset when generating preview"
previewPreset: PreviewPreset
"""Transcode Hardware Acceleration"""
"Transcode Hardware Acceleration"
transcodeHardwareAcceleration: Boolean
"""Max generated transcode size"""
"Max generated transcode size"
maxTranscodeSize: StreamingResolutionEnum
"""Max streaming transcode size"""
"Max streaming transcode size"
maxStreamingTranscodeSize: StreamingResolutionEnum
"""ffmpeg transcode input args - injected before input file
These are applied to generated transcodes (previews and transcodes)"""
"""
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)"""
"""
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"""
"""
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"""
"""
ffmpeg stream output args - injected before output file
These are applied when live transcoding
"""
liveTranscodeOutputArgs: [String!]
"""whether to include range in generated funscript heatmaps"""
"whether to include range in generated funscript heatmaps"
drawFunscriptHeatmapRange: Boolean
"""Write image thumbnails to disk when generating on the fly"""
"Write image thumbnails to disk when generating on the fly"
writeImageThumbnails: Boolean
"""Create Image Clips from Video extensions when Videos are disabled in Library"""
"Create Image Clips from Video extensions when Videos are disabled in Library"
createImageClipsFromVideos: Boolean
"""Username"""
"Username"
username: String
"""Password"""
"Password"
password: String
"""Maximum session cookie age"""
"Maximum session cookie age"
maxSessionAge: Int
"""Comma separated list of proxies to allow traffic from"""
"Comma separated list of proxies to allow traffic from"
trustedProxies: [String!] @deprecated(reason: "no longer supported")
"""Name of the log file"""
"Name of the log file"
logFile: String
"""Whether to also output to stderr"""
"Whether to also output to stderr"
logOut: Boolean
"""Minimum log level"""
"Minimum log level"
logLevel: String
"""Whether to log http access"""
"Whether to log http access"
logAccess: Boolean
"""True if galleries should be created from folders with images"""
"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"""
"Regex used to identify images as gallery covers"
galleryCoverRegex: String
"Array of video file extensions"
videoExtensions: [String!]
"""Array of image file extensions"""
"Array of image file extensions"
imageExtensions: [String!]
"""Array of gallery zip file extensions"""
"Array of gallery zip file extensions"
galleryExtensions: [String!]
"""Array of file regexp to exclude from Video Scans"""
"Array of file regexp to exclude from Video Scans"
excludes: [String!]
"""Array of file regexp to exclude from Image Scans"""
"Array of file regexp to exclude from Image Scans"
imageExcludes: [String!]
"""Custom Performer Image Location"""
"Custom Performer Image Location"
customPerformerImageLocation: String
"""Scraper user agent string"""
scraperUserAgent: String @deprecated(reason: "use mutation ConfigureScraping(input: ConfigScrapingInput) instead")
"""Scraper CDP path. Path to chrome executable or remote address"""
scraperCDPPath: String @deprecated(reason: "use mutation ConfigureScraping(input: ConfigScrapingInput) instead")
"""Whether the scraper should check for invalid certificates"""
scraperCertCheck: Boolean @deprecated(reason: "use mutation ConfigureScraping(input: ConfigScrapingInput) instead")
"""Stash-box instances used for tagging"""
"Scraper user agent string"
scraperUserAgent: String
@deprecated(
reason: "use mutation ConfigureScraping(input: ConfigScrapingInput) instead"
)
"Scraper CDP path. Path to chrome executable or remote address"
scraperCDPPath: String
@deprecated(
reason: "use mutation ConfigureScraping(input: ConfigScrapingInput) instead"
)
"Whether the scraper should check for invalid certificates"
scraperCertCheck: Boolean
@deprecated(
reason: "use mutation ConfigureScraping(input: ConfigScrapingInput) instead"
)
"Stash-box instances used for tagging"
stashBoxes: [StashBoxInput!]
"""Python path - resolved using path if unset"""
"Python path - resolved using path if unset"
pythonPath: String
}
type ConfigGeneralResult {
"""Array of file paths to content"""
"Array of file paths to content"
stashes: [StashConfig!]!
"""Path to the SQLite database"""
"Path to the SQLite database"
databasePath: String!
"""Path to backup directory"""
"Path to backup directory"
backupDirectoryPath: String!
"""Path to generated files"""
"Path to generated files"
generatedPath: String!
"""Path to import/export files"""
"Path to import/export files"
metadataPath: String!
"""Path to the config file used"""
"Path to the config file used"
configFilePath: String!
"""Path to scrapers"""
"Path to scrapers"
scrapersPath: String!
"""Path to cache"""
"Path to cache"
cachePath: String!
"""Path to blobs - required for filesystem blob storage"""
"Path to blobs - required for filesystem blob storage"
blobsPath: String!
"""Where to store blobs"""
"Where to store blobs"
blobsStorage: BlobsStorageType!
"""Whether to calculate MD5 checksums for scene video files"""
"Whether to calculate MD5 checksums for scene video files"
calculateMD5: Boolean!
"""Hash algorithm to use for generated file naming"""
"Hash algorithm to use for generated file naming"
videoFileNamingAlgorithm: HashAlgorithm!
"""Number of parallel tasks to start during scan/generate"""
"Number of parallel tasks to start during scan/generate"
parallelTasks: Int!
"""Include audio stream in previews"""
"Include audio stream in previews"
previewAudio: Boolean!
"""Number of segments in a preview file"""
"Number of segments in a preview file"
previewSegments: Int!
"""Preview segment duration, in seconds"""
"Preview segment duration, in seconds"
previewSegmentDuration: Float!
"""Duration of start of video to exclude when generating previews"""
"Duration of start of video to exclude when generating previews"
previewExcludeStart: String!
"""Duration of end of video to exclude when generating previews"""
"Duration of end of video to exclude when generating previews"
previewExcludeEnd: String!
"""Preset when generating preview"""
"Preset when generating preview"
previewPreset: PreviewPreset!
"""Transcode Hardware Acceleration"""
"Transcode Hardware Acceleration"
transcodeHardwareAcceleration: Boolean!
"""Max generated transcode size"""
"Max generated transcode size"
maxTranscodeSize: StreamingResolutionEnum
"""Max streaming transcode size"""
"Max streaming transcode size"
maxStreamingTranscodeSize: StreamingResolutionEnum
"""ffmpeg transcode input args - injected before input file
These are applied to generated transcodes (previews and transcodes)"""
"""
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)"""
"""
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"""
"""
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"""
"""
ffmpeg stream output args - injected before output file
These are applied when live transcoding
"""
liveTranscodeOutputArgs: [String!]!
"""whether to include range in generated funscript heatmaps"""
"whether to include range in generated funscript heatmaps"
drawFunscriptHeatmapRange: Boolean!
"""Write image thumbnails to disk when generating on the fly"""
"Write image thumbnails to disk when generating on the fly"
writeImageThumbnails: Boolean!
"""Create Image Clips from Video extensions when Videos are disabled in Library"""
"Create Image Clips from Video extensions when Videos are disabled in Library"
createImageClipsFromVideos: Boolean!
"""API Key"""
"API Key"
apiKey: String!
"""Username"""
"Username"
username: String!
"""Password"""
"Password"
password: String!
"""Maximum session cookie age"""
"Maximum session cookie age"
maxSessionAge: Int!
"""Comma separated list of proxies to allow traffic from"""
"Comma separated list of proxies to allow traffic from"
trustedProxies: [String!] @deprecated(reason: "no longer supported")
"""Name of the log file"""
"Name of the log file"
logFile: String
"""Whether to also output to stderr"""
"Whether to also output to stderr"
logOut: Boolean!
"""Minimum log level"""
"Minimum log level"
logLevel: String!
"""Whether to log http access"""
"Whether to log http access"
logAccess: Boolean!
"""Array of video file extensions"""
"Array of video file extensions"
videoExtensions: [String!]!
"""Array of image file extensions"""
"Array of image file extensions"
imageExtensions: [String!]!
"""Array of gallery zip file extensions"""
"Array of gallery zip file extensions"
galleryExtensions: [String!]!
"""True if galleries should be created from folders with images"""
"True if galleries should be created from folders with images"
createGalleriesFromFolders: Boolean!
"""Regex used to identify images as gallery covers"""
"Regex used to identify images as gallery covers"
galleryCoverRegex: String!
"""Array of file regexp to exclude from Video Scans"""
"Array of file regexp to exclude from Video Scans"
excludes: [String!]!
"""Array of file regexp to exclude from Image Scans"""
"Array of file regexp to exclude from Image Scans"
imageExcludes: [String!]!
"""Custom Performer Image Location"""
"Custom Performer Image Location"
customPerformerImageLocation: String
"""Scraper user agent string"""
scraperUserAgent: String @deprecated(reason: "use ConfigResult.scraping instead")
"""Scraper CDP path. Path to chrome executable or remote address"""
scraperCDPPath: String @deprecated(reason: "use ConfigResult.scraping instead")
"""Whether the scraper should check for invalid certificates"""
scraperCertCheck: Boolean! @deprecated(reason: "use ConfigResult.scraping instead")
"""Stash-box instances used for tagging"""
"Scraper user agent string"
scraperUserAgent: String
@deprecated(reason: "use ConfigResult.scraping instead")
"Scraper CDP path. Path to chrome executable or remote address"
scraperCDPPath: String
@deprecated(reason: "use ConfigResult.scraping instead")
"Whether the scraper should check for invalid certificates"
scraperCertCheck: Boolean!
@deprecated(reason: "use ConfigResult.scraping instead")
"Stash-box instances used for tagging"
stashBoxes: [StashBox!]!
"""Python path - resolved using path if unset"""
"Python path - resolved using path if unset"
pythonPath: String!
}
@ -302,64 +346,64 @@ type ConfigImageLightboxResult {
}
input ConfigInterfaceInput {
"""Ordered list of items that should be shown in the menu"""
"Ordered list of items that should be shown in the menu"
menuItems: [String!]
"""Enable sound on mouseover previews"""
"Enable sound on mouseover previews"
soundOnPreview: Boolean
"""Show title and tags in wall view"""
"Show title and tags in wall view"
wallShowTitle: Boolean
"""Wall playback type"""
"Wall playback type"
wallPlayback: String
"""Show scene scrubber by default"""
"Show scene scrubber by default"
showScrubber: Boolean
"""Maximum duration (in seconds) in which a scene video will loop in the scene player"""
"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"""
"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"""
"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"""
"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"""
"If true, studio overlays will be shown as text instead of logo images"
showStudioAsText: Boolean
"""Custom CSS"""
"Custom CSS"
css: String
cssEnabled: Boolean
"""Custom Javascript"""
"Custom Javascript"
javascript: String
javascriptEnabled: Boolean
"""Custom Locales"""
"Custom Locales"
customLocales: String
customLocalesEnabled: Boolean
"""Interface language"""
"Interface language"
language: String
"""Slideshow Delay"""
"Slideshow Delay"
slideshowDelay: Int @deprecated(reason: "Use imageLightbox.slideshowDelay")
imageLightbox: ConfigImageLightboxInput
"""Set to true to disable creating new objects via the dropdown menus"""
"Set to true to disable creating new objects via the dropdown menus"
disableDropdownCreate: ConfigDisableDropdownCreateInput
"""Handy Connection Key"""
"Handy Connection Key"
handyKey: String
"""Funscript Time Offset"""
"Funscript Time Offset"
funscriptOffset: Int
"""Whether to use Stash Hosted Funscript"""
"Whether to use Stash Hosted Funscript"
useStashHostedFunscript: Boolean
"""True if we should not auto-open a browser window on startup"""
"True if we should not auto-open a browser window on startup"
noBrowser: Boolean
"""True if we should send notifications to the desktop"""
"True if we should send notifications to the desktop"
notificationsEnabled: Boolean
}
@ -371,111 +415,112 @@ type ConfigDisableDropdownCreate {
}
type ConfigInterfaceResult {
"""Ordered list of items that should be shown in the menu"""
"Ordered list of items that should be shown in the menu"
menuItems: [String!]
"""Enable sound on mouseover previews"""
"Enable sound on mouseover previews"
soundOnPreview: Boolean
"""Show title and tags in wall view"""
"Show title and tags in wall view"
wallShowTitle: Boolean
"""Wall playback type"""
"Wall playback type"
wallPlayback: String
"""Show scene scrubber by default"""
"Show scene scrubber by default"
showScrubber: Boolean
"""Maximum duration (in seconds) in which a scene video will loop in the scene player"""
"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"""
"True if we should not auto-open a browser window on startup"
noBrowser: Boolean
"""True if we should send desktop notifications"""
"True if we should send desktop notifications"
notificationsEnabled: Boolean
"""If true, video will autostart on load in the scene player"""
"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"""
"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"""
"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"""
"If true, studio overlays will be shown as text instead of logo images"
showStudioAsText: Boolean
"""Custom CSS"""
"Custom CSS"
css: String
cssEnabled: Boolean
"""Custom Javascript"""
"Custom Javascript"
javascript: String
javascriptEnabled: Boolean
"""Custom Locales"""
"Custom Locales"
customLocales: String
customLocalesEnabled: Boolean
"""Interface language"""
"Interface language"
language: String
"""Slideshow Delay"""
"Slideshow Delay"
slideshowDelay: Int @deprecated(reason: "Use imageLightbox.slideshowDelay")
imageLightbox: ConfigImageLightboxResult!
"""Fields are true if creating via dropdown menus are disabled"""
"Fields are true if creating via dropdown menus are disabled"
disableDropdownCreate: ConfigDisableDropdownCreate!
disabledDropdownCreate: ConfigDisableDropdownCreate! @deprecated(reason: "Use disableDropdownCreate")
disabledDropdownCreate: ConfigDisableDropdownCreate!
@deprecated(reason: "Use disableDropdownCreate")
"""Handy Connection Key"""
"Handy Connection Key"
handyKey: String
"""Funscript Time Offset"""
"Funscript Time Offset"
funscriptOffset: Int
"""Whether to use Stash Hosted Funscript"""
"Whether to use Stash Hosted Funscript"
useStashHostedFunscript: Boolean
}
input ConfigDLNAInput {
serverName: String
"""True if DLNA service should be enabled by default"""
"True if DLNA service should be enabled by default"
enabled: Boolean
"""List of IPs whitelisted for DLNA service"""
"List of IPs whitelisted for DLNA service"
whitelistedIPs: [String!]
"""List of interfaces to run DLNA on. Empty for all"""
"List of interfaces to run DLNA on. Empty for all"
interfaces: [String!]
"""Order to sort videos"""
"Order to sort videos"
videoSortOrder: String
}
type ConfigDLNAResult {
serverName: String!
"""True if DLNA service should be enabled by default"""
"True if DLNA service should be enabled by default"
enabled: Boolean!
"""List of IPs whitelisted for DLNA service"""
"List of IPs whitelisted for DLNA service"
whitelistedIPs: [String!]!
"""List of interfaces to run DLNA on. Empty for all"""
"List of interfaces to run DLNA on. Empty for all"
interfaces: [String!]!
"""Order to sort videos"""
"Order to sort videos"
videoSortOrder: String!
}
input ConfigScrapingInput {
"""Scraper user agent string"""
"Scraper user agent string"
scraperUserAgent: String
"""Scraper CDP path. Path to chrome executable or remote address"""
"Scraper CDP path. Path to chrome executable or remote address"
scraperCDPPath: String
"""Whether the scraper should check for invalid certificates"""
"Whether the scraper should check for invalid certificates"
scraperCertCheck: Boolean
"""Tags blacklist during scraping"""
"Tags blacklist during scraping"
excludeTagPatterns: [String!]
}
type ConfigScrapingResult {
"""Scraper user agent string"""
"Scraper user agent string"
scraperUserAgent: String
"""Scraper CDP path. Path to chrome executable or remote address"""
"Scraper CDP path. Path to chrome executable or remote address"
scraperCDPPath: String
"""Whether the scraper should check for invalid certificates"""
"Whether the scraper should check for invalid certificates"
scraperCertCheck: Boolean!
"""Tags blacklist during scraping"""
"Tags blacklist during scraping"
excludeTagPatterns: [String!]!
}
@ -484,10 +529,10 @@ type ConfigDefaultSettingsResult {
identify: IdentifyMetadataTaskOptions
autoTag: AutoTagMetadataOptions
generate: GenerateMetadataOptions
"""If true, delete file checkbox will be checked by default"""
"If true, delete file checkbox will be checked by default"
deleteFile: Boolean
"""If true, delete generated supporting files checkbox will be checked by default"""
"If true, delete generated supporting files checkbox will be checked by default"
deleteGenerated: Boolean
}
@ -497,13 +542,13 @@ input ConfigDefaultSettingsInput {
autoTag: AutoTagMetadataInput
generate: GenerateMetadataInput
"""If true, delete file checkbox will be checked by default"""
"If true, delete file checkbox will be checked by default"
deleteFile: Boolean
"""If true, delete generated files checkbox will be checked by default"""
"If true, delete generated files checkbox will be checked by default"
deleteGenerated: Boolean
}
"""All configuration settings"""
"All configuration settings"
type ConfigResult {
general: ConfigGeneralResult!
interface: ConfigInterfaceResult!
@ -513,14 +558,14 @@ type ConfigResult {
ui: Map!
}
"""Directory structure of a path"""
"Directory structure of a path"
type Directory {
path: String!
parent: String
directories: [String!]!
path: String!
parent: String
directories: [String!]!
}
"""Stash configuration details"""
"Stash configuration details"
input StashConfigInput {
path: String!
excludeVideo: Boolean!

View file

@ -1,35 +1,33 @@
type DLNAIP {
ipAddress: String!
"""Time until IP will be no longer allowed/disallowed"""
until: Time
ipAddress: String!
"Time until IP will be no longer allowed/disallowed"
until: Time
}
type DLNAStatus {
running: Boolean!
"""If not currently running, time until it will be started. If running, time until it will be stopped"""
until: Time
recentIPAddresses: [String!]!
allowedIPAddresses: [DLNAIP!]!
running: Boolean!
"If not currently running, time until it will be started. If running, time until it will be stopped"
until: Time
recentIPAddresses: [String!]!
allowedIPAddresses: [DLNAIP!]!
}
input EnableDLNAInput {
"""Duration to enable, in minutes. 0 or null for indefinite."""
duration: Int
"Duration to enable, in minutes. 0 or null for indefinite."
duration: Int
}
input DisableDLNAInput {
"""Duration to enable, in minutes. 0 or null for indefinite."""
duration: Int
"Duration to enable, in minutes. 0 or null for indefinite."
duration: Int
}
input AddTempDLNAIPInput {
address: String!
"""Duration to enable, in minutes. 0 or null for indefinite."""
duration: Int
address: String!
"Duration to enable, in minutes. 0 or null for indefinite."
duration: Int
}
input RemoveTempDLNAIPInput {
address: String!
}
address: String!
}

View file

@ -1,111 +1,111 @@
type Fingerprint {
type: String!
value: String!
type: String!
value: String!
}
type Folder {
id: ID!
path: String!
id: ID!
path: String!
parent_folder_id: ID
zip_file_id: ID
parent_folder_id: ID
zip_file_id: ID
mod_time: Time!
mod_time: Time!
created_at: Time!
updated_at: Time!
created_at: Time!
updated_at: Time!
}
interface BaseFile {
id: ID!
path: String!
basename: String!
id: ID!
path: String!
basename: String!
parent_folder_id: ID!
zip_file_id: ID
parent_folder_id: ID!
zip_file_id: ID
mod_time: Time!
size: Int64!
mod_time: Time!
size: Int64!
fingerprints: [Fingerprint!]!
fingerprints: [Fingerprint!]!
created_at: Time!
updated_at: Time!
created_at: Time!
updated_at: Time!
}
type VideoFile implements BaseFile {
id: ID!
path: String!
basename: String!
id: ID!
path: String!
basename: String!
parent_folder_id: ID!
zip_file_id: ID
parent_folder_id: ID!
zip_file_id: ID
mod_time: Time!
size: Int64!
mod_time: Time!
size: Int64!
fingerprints: [Fingerprint!]!
fingerprints: [Fingerprint!]!
format: String!
width: Int!
height: Int!
duration: Float!
video_codec: String!
audio_codec: String!
frame_rate: Float!
bit_rate: Int!
format: String!
width: Int!
height: Int!
duration: Float!
video_codec: String!
audio_codec: String!
frame_rate: Float!
bit_rate: Int!
created_at: Time!
updated_at: Time!
created_at: Time!
updated_at: Time!
}
type ImageFile implements BaseFile {
id: ID!
path: String!
basename: String!
id: ID!
path: String!
basename: String!
parent_folder_id: ID!
zip_file_id: ID
parent_folder_id: ID!
zip_file_id: ID
mod_time: Time!
size: Int64!
mod_time: Time!
size: Int64!
fingerprints: [Fingerprint!]!
fingerprints: [Fingerprint!]!
width: Int!
height: Int!
width: Int!
height: Int!
created_at: Time!
updated_at: Time!
created_at: Time!
updated_at: Time!
}
union VisualFile = VideoFile | ImageFile
type GalleryFile implements BaseFile {
id: ID!
path: String!
basename: String!
id: ID!
path: String!
basename: String!
parent_folder_id: ID!
zip_file_id: ID
parent_folder_id: ID!
zip_file_id: ID
mod_time: Time!
size: Int64!
mod_time: Time!
size: Int64!
fingerprints: [Fingerprint!]!
fingerprints: [Fingerprint!]!
created_at: Time!
updated_at: Time!
created_at: Time!
updated_at: Time!
}
input MoveFilesInput {
ids: [ID!]!
"""valid for single or multiple file ids"""
destination_folder: String
ids: [ID!]!
"valid for single or multiple file ids"
destination_folder: String
"""valid for single or multiple file ids"""
destination_folder_id: ID
"valid for single or multiple file ids"
destination_folder_id: ID
"""valid only for single file id. If empty, existing basename is used"""
destination_basename: String
"valid only for single file id. If empty, existing basename is used"
destination_basename: String
}

View file

@ -6,28 +6,43 @@ enum SortDirectionEnum {
input FindFilterType {
q: String
page: Int
"""use per_page = -1 to indicate all results. Defaults to 25."""
"use per_page = -1 to indicate all results. Defaults to 25."
per_page: Int
sort: String
direction: SortDirectionEnum
}
enum ResolutionEnum {
"144p", VERY_LOW
"240p", LOW
"360p", R360P
"480p", STANDARD
"540p", WEB_HD
"720p", STANDARD_HD
"1080p", FULL_HD
"1440p", QUAD_HD
"1920p", VR_HD @deprecated(reason: "Use 4K instead")
"4K", FOUR_K
"5K", FIVE_K
"6K", SIX_K
"7K", SEVEN_K
"8K", EIGHT_K
"8K+", HUGE
"144p"
VERY_LOW
"240p"
LOW
"360p"
R360P
"480p"
STANDARD
"540p"
WEB_HD
"720p"
STANDARD_HD
"1080p"
FULL_HD
"1440p"
QUAD_HD
"1920p"
VR_HD @deprecated(reason: "Use 4K instead")
"4K"
FOUR_K
"5K"
FIVE_K
"6K"
SIX_K
"7K"
SEVEN_K
"8K"
EIGHT_K
"8K+"
HUGE
}
input ResolutionCriterionInput {
@ -37,13 +52,15 @@ input ResolutionCriterionInput {
input PHashDuplicationCriterionInput {
duplicated: Boolean
"""Currently unimplemented"""
"Currently unimplemented"
distance: Int
}
input StashIDCriterionInput {
"""If present, this value is treated as a predicate.
That is, it will filter based on stash_ids with the matching endpoint"""
"""
If present, this value is treated as a predicate.
That is, it will filter based on stash_ids with the matching endpoint
"""
endpoint: String
stash_id: String
modifier: CriterionModifier!
@ -58,104 +75,106 @@ input PerformerFilterType {
disambiguation: StringCriterionInput
details: StringCriterionInput
"""Filter by favorite"""
"Filter by favorite"
filter_favorites: Boolean
"""Filter by birth year"""
"Filter by birth year"
birth_year: IntCriterionInput
"""Filter by age"""
"Filter by age"
age: IntCriterionInput
"""Filter by ethnicity"""
"Filter by ethnicity"
ethnicity: StringCriterionInput
"""Filter by country"""
"Filter by country"
country: StringCriterionInput
"""Filter by eye color"""
"Filter by eye color"
eye_color: StringCriterionInput
"""Filter by height"""
height: StringCriterionInput @deprecated(reason: "Use height_cm instead")
"""Filter by height in cm"""
"Filter by height"
height: StringCriterionInput @deprecated(reason: "Use height_cm instead")
"Filter by height in cm"
height_cm: IntCriterionInput
"""Filter by measurements"""
"Filter by measurements"
measurements: StringCriterionInput
"""Filter by fake tits value"""
"Filter by fake tits value"
fake_tits: StringCriterionInput
"""Filter by penis length value"""
"Filter by penis length value"
penis_length: FloatCriterionInput
"""Filter by ciricumcision"""
"Filter by ciricumcision"
circumcised: CircumcisionCriterionInput
"""Filter by career length"""
"Filter by career length"
career_length: StringCriterionInput
"""Filter by tattoos"""
"Filter by tattoos"
tattoos: StringCriterionInput
"""Filter by piercings"""
"Filter by piercings"
piercings: StringCriterionInput
"""Filter by aliases"""
"Filter by aliases"
aliases: StringCriterionInput
"""Filter by gender"""
"Filter by gender"
gender: GenderCriterionInput
"""Filter to only include performers missing this property"""
"Filter to only include performers missing this property"
is_missing: String
"""Filter to only include performers with these tags"""
"Filter to only include performers with these tags"
tags: HierarchicalMultiCriterionInput
"""Filter by tag count"""
"Filter by tag count"
tag_count: IntCriterionInput
"""Filter by scene count"""
"Filter by scene count"
scene_count: IntCriterionInput
"""Filter by image count"""
"Filter by image count"
image_count: IntCriterionInput
"""Filter by gallery count"""
"Filter by gallery count"
gallery_count: IntCriterionInput
"""Filter by o count"""
"Filter by o count"
o_counter: IntCriterionInput
"""Filter by StashID"""
stash_id: StringCriterionInput @deprecated(reason: "Use stash_id_endpoint instead")
"""Filter by StashID"""
"Filter by StashID"
stash_id: StringCriterionInput
@deprecated(reason: "Use stash_id_endpoint instead")
"Filter by StashID"
stash_id_endpoint: StashIDCriterionInput
"""Filter by rating"""
rating: IntCriterionInput @deprecated(reason: "Use 1-100 range with rating100")
"Filter by rating"
rating: IntCriterionInput
@deprecated(reason: "Use 1-100 range with rating100")
# rating expressed as 1-100
rating100: IntCriterionInput
"""Filter by url"""
"Filter by url"
url: StringCriterionInput
"""Filter by hair color"""
"Filter by hair color"
hair_color: StringCriterionInput
"""Filter by weight"""
"Filter by weight"
weight: IntCriterionInput
"""Filter by death year"""
"Filter by death year"
death_year: IntCriterionInput
"""Filter by studios where performer appears in scene/image/gallery"""
"Filter by studios where performer appears in scene/image/gallery"
studios: HierarchicalMultiCriterionInput
"""Filter by performers where performer appears with another performer in scene/image/gallery"""
performers: MultiCriterionInput
"""Filter by autotag ignore value"""
"Filter by performers where performer appears with another performer in scene/image/gallery"
performers: MultiCriterionInput
"Filter by autotag ignore value"
ignore_auto_tag: Boolean
"""Filter by birthdate"""
"Filter by birthdate"
birthdate: DateCriterionInput
"""Filter by death date"""
"Filter by death date"
death_date: DateCriterionInput
"""Filter by creation time"""
"Filter by creation time"
created_at: TimestampCriterionInput
"""Filter by last update time"""
"Filter by last update time"
updated_at: TimestampCriterionInput
}
input SceneMarkerFilterType {
"""Filter to only include scene markers with this tag"""
"Filter to only include scene markers with this tag"
tag_id: ID @deprecated(reason: "use tags filter instead")
"""Filter to only include scene markers with these tags"""
"Filter to only include scene markers with these tags"
tags: HierarchicalMultiCriterionInput
"""Filter to only include scene markers attached to a scene with these tags"""
"Filter to only include scene markers attached to a scene with these tags"
scene_tags: HierarchicalMultiCriterionInput
"""Filter to only include scene markers with these performers"""
"Filter to only include scene markers with these performers"
performers: MultiCriterionInput
"""Filter by creation time"""
"Filter by creation time"
created_at: TimestampCriterionInput
"""Filter by last update time"""
"Filter by last update time"
updated_at: TimestampCriterionInput
"""Filter by scene date"""
"Filter by scene date"
scene_date: DateCriterionInput
"""Filter by cscene reation time"""
"Filter by cscene reation time"
scene_created_at: TimestampCriterionInput
"""Filter by lscene ast update time"""
"Filter by lscene ast update time"
scene_updated_at: TimestampCriterionInput
}
@ -170,109 +189,111 @@ input SceneFilterType {
details: StringCriterionInput
director: StringCriterionInput
"""Filter by file oshash"""
"Filter by file oshash"
oshash: StringCriterionInput
"""Filter by file checksum"""
"Filter by file checksum"
checksum: StringCriterionInput
"""Filter by file phash"""
"Filter by file phash"
phash: StringCriterionInput @deprecated(reason: "Use phash_distance instead")
"""Filter by file phash distance"""
"Filter by file phash distance"
phash_distance: PhashDistanceCriterionInput
"""Filter by path"""
"Filter by path"
path: StringCriterionInput
"""Filter by file count"""
"Filter by file count"
file_count: IntCriterionInput
"""Filter by rating"""
rating: IntCriterionInput @deprecated(reason: "Use 1-100 range with rating100")
"Filter by rating"
rating: IntCriterionInput
@deprecated(reason: "Use 1-100 range with rating100")
# rating expressed as 1-100
rating100: IntCriterionInput
"""Filter by organized"""
"Filter by organized"
organized: Boolean
"""Filter by o-counter"""
"Filter by o-counter"
o_counter: IntCriterionInput
"""Filter Scenes that have an exact phash match available"""
"Filter Scenes that have an exact phash match available"
duplicated: PHashDuplicationCriterionInput
"""Filter by resolution"""
"Filter by resolution"
resolution: ResolutionCriterionInput
"""Filter by video codec"""
"Filter by video codec"
video_codec: StringCriterionInput
"""Filter by audio codec"""
"Filter by audio codec"
audio_codec: StringCriterionInput
"""Filter by duration (in seconds)"""
"Filter by duration (in seconds)"
duration: IntCriterionInput
"""Filter to only include scenes which have markers. `true` or `false`"""
"Filter to only include scenes which have markers. `true` or `false`"
has_markers: String
"""Filter to only include scenes missing this property"""
"Filter to only include scenes missing this property"
is_missing: String
"""Filter to only include scenes with this studio"""
"Filter to only include scenes with this studio"
studios: HierarchicalMultiCriterionInput
"""Filter to only include scenes with this movie"""
"Filter to only include scenes with this movie"
movies: MultiCriterionInput
"""Filter to only include scenes with these tags"""
"Filter to only include scenes with these tags"
tags: HierarchicalMultiCriterionInput
"""Filter by tag count"""
"Filter by tag count"
tag_count: IntCriterionInput
"""Filter to only include scenes with performers with these tags"""
"Filter to only include scenes with performers with these tags"
performer_tags: HierarchicalMultiCriterionInput
"""Filter scenes that have performers that have been favorited"""
"Filter scenes that have performers that have been favorited"
performer_favorite: Boolean
"""Filter scenes by performer age at time of scene"""
"Filter scenes by performer age at time of scene"
performer_age: IntCriterionInput
"""Filter to only include scenes with these performers"""
"Filter to only include scenes with these performers"
performers: MultiCriterionInput
"""Filter by performer count"""
"Filter by performer count"
performer_count: IntCriterionInput
"""Filter by StashID"""
stash_id: StringCriterionInput @deprecated(reason: "Use stash_id_endpoint instead")
"""Filter by StashID"""
"Filter by StashID"
stash_id: StringCriterionInput
@deprecated(reason: "Use stash_id_endpoint instead")
"Filter by StashID"
stash_id_endpoint: StashIDCriterionInput
"""Filter by url"""
"Filter by url"
url: StringCriterionInput
"""Filter by interactive"""
"Filter by interactive"
interactive: Boolean
"""Filter by InteractiveSpeed"""
"Filter by InteractiveSpeed"
interactive_speed: IntCriterionInput
"""Filter by captions"""
"Filter by captions"
captions: StringCriterionInput
"""Filter by resume time"""
"Filter by resume time"
resume_time: IntCriterionInput
"""Filter by play count"""
"Filter by play count"
play_count: IntCriterionInput
"""Filter by play duration (in seconds)"""
"Filter by play duration (in seconds)"
play_duration: IntCriterionInput
"""Filter by date"""
"Filter by date"
date: DateCriterionInput
"""Filter by creation time"""
"Filter by creation time"
created_at: TimestampCriterionInput
"""Filter by last update time"""
"Filter by last update time"
updated_at: TimestampCriterionInput
}
input MovieFilterType {
name: StringCriterionInput
director: StringCriterionInput
synopsis: StringCriterionInput
"""Filter by duration (in seconds)"""
"Filter by duration (in seconds)"
duration: IntCriterionInput
"""Filter by rating"""
rating: IntCriterionInput @deprecated(reason: "Use 1-100 range with rating100")
"Filter by rating"
rating: IntCriterionInput
@deprecated(reason: "Use 1-100 range with rating100")
# rating expressed as 1-100
rating100: IntCriterionInput
"""Filter to only include movies with this studio"""
"Filter to only include movies with this studio"
studios: HierarchicalMultiCriterionInput
"""Filter to only include movies missing this property"""
"Filter to only include movies missing this property"
is_missing: String
"""Filter by url"""
"Filter by url"
url: StringCriterionInput
"""Filter to only include movies where performer appears in a scene"""
"Filter to only include movies where performer appears in a scene"
performers: MultiCriterionInput
"""Filter by date"""
"Filter by date"
date: DateCriterionInput
"""Filter by creation time"""
"Filter by creation time"
created_at: TimestampCriterionInput
"""Filter by last update time"""
"Filter by last update time"
updated_at: TimestampCriterionInput
}
@ -283,33 +304,35 @@ input StudioFilterType {
name: StringCriterionInput
details: StringCriterionInput
"""Filter to only include studios with this parent studio"""
"Filter to only include studios with this parent studio"
parents: MultiCriterionInput
"""Filter by StashID"""
stash_id: StringCriterionInput @deprecated(reason: "Use stash_id_endpoint instead")
"""Filter by StashID"""
"Filter by StashID"
stash_id: StringCriterionInput
@deprecated(reason: "Use stash_id_endpoint instead")
"Filter by StashID"
stash_id_endpoint: StashIDCriterionInput
"""Filter to only include studios missing this property"""
"Filter to only include studios missing this property"
is_missing: String
"""Filter by rating"""
rating: IntCriterionInput @deprecated(reason: "Use 1-100 range with rating100")
"Filter by rating"
rating: IntCriterionInput
@deprecated(reason: "Use 1-100 range with rating100")
# rating expressed as 1-100
rating100: IntCriterionInput
"""Filter by scene count"""
"Filter by scene count"
scene_count: IntCriterionInput
"""Filter by image count"""
"Filter by image count"
image_count: IntCriterionInput
"""Filter by gallery count"""
"Filter by gallery count"
gallery_count: IntCriterionInput
"""Filter by url"""
"Filter by url"
url: StringCriterionInput
"""Filter by studio aliases"""
"Filter by studio aliases"
aliases: StringCriterionInput
"""Filter by autotag ignore value"""
"Filter by autotag ignore value"
ignore_auto_tag: Boolean
"""Filter by creation time"""
"Filter by creation time"
created_at: TimestampCriterionInput
"""Filter by last update time"""
"Filter by last update time"
updated_at: TimestampCriterionInput
}
@ -322,51 +345,52 @@ input GalleryFilterType {
title: StringCriterionInput
details: StringCriterionInput
"""Filter by file checksum"""
"Filter by file checksum"
checksum: StringCriterionInput
"""Filter by path"""
"Filter by path"
path: StringCriterionInput
"""Filter by zip-file count"""
"Filter by zip-file count"
file_count: IntCriterionInput
"""Filter to only include galleries missing this property"""
"Filter to only include galleries missing this property"
is_missing: String
"""Filter to include/exclude galleries that were created from zip"""
"Filter to include/exclude galleries that were created from zip"
is_zip: Boolean
"""Filter by rating"""
rating: IntCriterionInput @deprecated(reason: "Use 1-100 range with rating100")
"Filter by rating"
rating: IntCriterionInput
@deprecated(reason: "Use 1-100 range with rating100")
# rating expressed as 1-100
rating100: IntCriterionInput
"""Filter by organized"""
"Filter by organized"
organized: Boolean
"""Filter by average image resolution"""
"Filter by average image resolution"
average_resolution: ResolutionCriterionInput
"""Filter to only include galleries that have chapters. `true` or `false`"""
"Filter to only include galleries that have chapters. `true` or `false`"
has_chapters: String
"""Filter to only include galleries with this studio"""
"Filter to only include galleries with this studio"
studios: HierarchicalMultiCriterionInput
"""Filter to only include galleries with these tags"""
"Filter to only include galleries with these tags"
tags: HierarchicalMultiCriterionInput
"""Filter by tag count"""
"Filter by tag count"
tag_count: IntCriterionInput
"""Filter to only include galleries with performers with these tags"""
"Filter to only include galleries with performers with these tags"
performer_tags: HierarchicalMultiCriterionInput
"""Filter to only include galleries with these performers"""
"Filter to only include galleries with these performers"
performers: MultiCriterionInput
"""Filter by performer count"""
"Filter by performer count"
performer_count: IntCriterionInput
"""Filter galleries that have performers that have been favorited"""
"Filter galleries that have performers that have been favorited"
performer_favorite: Boolean
"""Filter galleries by performer age at time of gallery"""
"Filter galleries by performer age at time of gallery"
performer_age: IntCriterionInput
"""Filter by number of images in this gallery"""
"Filter by number of images in this gallery"
image_count: IntCriterionInput
"""Filter by url"""
"Filter by url"
url: StringCriterionInput
"""Filter by date"""
"Filter by date"
date: DateCriterionInput
"""Filter by creation time"""
"Filter by creation time"
created_at: TimestampCriterionInput
"""Filter by last update time"""
"Filter by last update time"
updated_at: TimestampCriterionInput
}
@ -375,52 +399,52 @@ input TagFilterType {
OR: TagFilterType
NOT: TagFilterType
"""Filter by tag name"""
"Filter by tag name"
name: StringCriterionInput
"""Filter by tag aliases"""
"Filter by tag aliases"
aliases: StringCriterionInput
"""Filter by tag description"""
"Filter by tag description"
description: StringCriterionInput
"""Filter to only include tags missing this property"""
"Filter to only include tags missing this property"
is_missing: String
"""Filter by number of scenes with this tag"""
"Filter by number of scenes with this tag"
scene_count: IntCriterionInput
"""Filter by number of images with this tag"""
"Filter by number of images with this tag"
image_count: IntCriterionInput
"""Filter by number of galleries with this tag"""
"Filter by number of galleries with this tag"
gallery_count: IntCriterionInput
"""Filter by number of performers with this tag"""
"Filter by number of performers with this tag"
performer_count: IntCriterionInput
"""Filter by number of markers with this tag"""
"Filter by number of markers with this tag"
marker_count: IntCriterionInput
"""Filter by parent tags"""
"Filter by parent tags"
parents: HierarchicalMultiCriterionInput
"""Filter by child tags"""
"Filter by child tags"
children: HierarchicalMultiCriterionInput
"""Filter by number of parent tags the tag has"""
"Filter by number of parent tags the tag has"
parent_count: IntCriterionInput
"""Filter by number f child tags the tag has"""
"Filter by number f child tags the tag has"
child_count: IntCriterionInput
"""Filter by autotag ignore value"""
"Filter by autotag ignore value"
ignore_auto_tag: Boolean
"""Filter by creation time"""
"Filter by creation time"
created_at: TimestampCriterionInput
"""Filter by last update time"""
"Filter by last update time"
updated_at: TimestampCriterionInput
}
@ -431,77 +455,78 @@ input ImageFilterType {
title: StringCriterionInput
""" Filter by image id"""
" Filter by image id"
id: IntCriterionInput
"""Filter by file checksum"""
"Filter by file checksum"
checksum: StringCriterionInput
"""Filter by path"""
"Filter by path"
path: StringCriterionInput
"""Filter by file count"""
"Filter by file count"
file_count: IntCriterionInput
"""Filter by rating"""
rating: IntCriterionInput @deprecated(reason: "Use 1-100 range with rating100")
"Filter by rating"
rating: IntCriterionInput
@deprecated(reason: "Use 1-100 range with rating100")
# rating expressed as 1-100
rating100: IntCriterionInput
"""Filter by date"""
"Filter by date"
date: DateCriterionInput
"""Filter by url"""
"Filter by url"
url: StringCriterionInput
"""Filter by organized"""
"Filter by organized"
organized: Boolean
"""Filter by o-counter"""
"Filter by o-counter"
o_counter: IntCriterionInput
"""Filter by resolution"""
"Filter by resolution"
resolution: ResolutionCriterionInput
"""Filter to only include images missing this property"""
"Filter to only include images missing this property"
is_missing: String
"""Filter to only include images with this studio"""
"Filter to only include images with this studio"
studios: HierarchicalMultiCriterionInput
"""Filter to only include images with these tags"""
"Filter to only include images with these tags"
tags: HierarchicalMultiCriterionInput
"""Filter by tag count"""
"Filter by tag count"
tag_count: IntCriterionInput
"""Filter to only include images with performers with these tags"""
"Filter to only include images with performers with these tags"
performer_tags: HierarchicalMultiCriterionInput
"""Filter to only include images with these performers"""
"Filter to only include images with these performers"
performers: MultiCriterionInput
"""Filter by performer count"""
"Filter by performer count"
performer_count: IntCriterionInput
"""Filter images that have performers that have been favorited"""
"Filter images that have performers that have been favorited"
performer_favorite: Boolean
"""Filter to only include images with these galleries"""
"Filter to only include images with these galleries"
galleries: MultiCriterionInput
"""Filter by creation time"""
"Filter by creation time"
created_at: TimestampCriterionInput
"""Filter by last update time"""
"Filter by last update time"
updated_at: TimestampCriterionInput
}
enum CriterionModifier {
"""="""
EQUALS,
"""!="""
NOT_EQUALS,
""">"""
GREATER_THAN,
"""<"""
LESS_THAN,
"""IS NULL"""
IS_NULL,
"""IS NOT NULL"""
NOT_NULL,
"""INCLUDES ALL"""
INCLUDES_ALL,
INCLUDES,
EXCLUDES,
"""MATCHES REGEX"""
MATCHES_REGEX,
"""NOT MATCHES REGEX"""
NOT_MATCHES_REGEX,
""">= AND <="""
BETWEEN,
"""< OR >"""
NOT_BETWEEN,
"="
EQUALS
"!="
NOT_EQUALS
">"
GREATER_THAN
"<"
LESS_THAN
"IS NULL"
IS_NULL
"IS NOT NULL"
NOT_NULL
"INCLUDES ALL"
INCLUDES_ALL
INCLUDES
EXCLUDES
"MATCHES REGEX"
MATCHES_REGEX
"NOT MATCHES REGEX"
NOT_MATCHES_REGEX
">= AND <="
BETWEEN
"< OR >"
NOT_BETWEEN
}
input StringCriterionInput {
@ -531,7 +556,7 @@ input GenderCriterionInput {
value: GenderEnum
modifier: CriterionModifier!
}
input CircumcisionCriterionInput {
value: [CircumisedEnum!]
modifier: CriterionModifier!
@ -563,30 +588,30 @@ input PhashDistanceCriterionInput {
}
enum FilterMode {
SCENES,
PERFORMERS,
STUDIOS,
GALLERIES,
SCENE_MARKERS,
MOVIES,
TAGS,
IMAGES,
SCENES
PERFORMERS
STUDIOS
GALLERIES
SCENE_MARKERS
MOVIES
TAGS
IMAGES
}
type SavedFilter {
id: ID!
mode: FilterMode!
name: String!
"""JSON-encoded filter string"""
"JSON-encoded filter string"
filter: String!
}
input SaveFilterInput {
"""provide ID to overwrite existing filter"""
"provide ID to overwrite existing filter"
id: ID
mode: FilterMode!
name: String!
"""JSON-encoded filter string"""
"JSON-encoded filter string"
filter: String!
}
@ -596,6 +621,6 @@ input DestroyFilterInput {
input SetDefaultFilterInput {
mode: FilterMode!
"""JSON-encoded filter string - null to clear"""
"JSON-encoded filter string - null to clear"
filter: String
}

View file

@ -1,4 +1,4 @@
"""Gallery type"""
"Gallery type"
type Gallery {
id: ID!
checksum: String! @deprecated(reason: "Use files.fingerprints")
@ -26,7 +26,7 @@ type Gallery {
tags: [Tag!]!
performers: [Performer!]!
"""The images in the gallery"""
"The images in the gallery"
images: [Image!]! @deprecated(reason: "Use findImages")
cover: Image
}
@ -87,7 +87,7 @@ input BulkGalleryUpdateInput {
input GalleryDestroyInput {
ids: [ID!]!
"""
If true, then the zip file will be deleted if the gallery is zip-file-based.
If true, then the zip file will be deleted if the gallery is zip-file-based.
If gallery is folder-based, then any files not associated with other
galleries will be deleted, along with the folder, if it is not empty.
"""

View file

@ -13,14 +13,13 @@ type Image {
path: String! @deprecated(reason: "Use files.path")
created_at: Time!
updated_at: Time!
file_mod_time: Time @deprecated(reason: "Use files.mod_time")
file: ImageFileType! @deprecated(reason: "Use visual_files")
files: [ImageFile!]! @deprecated(reason: "Use visual_files")
visual_files: [VisualFile!]!
paths: ImagePathsType! # Resolver
galleries: [Gallery!]!
studio: Studio
tags: [Tag!]!
@ -51,7 +50,7 @@ input ImageUpdateInput {
organized: Boolean
url: String
date: String
studio_id: ID
performer_ids: [ID!]
tag_ids: [ID!]
@ -71,7 +70,7 @@ input BulkImageUpdateInput {
organized: Boolean
url: String
date: String
studio_id: ID
performer_ids: BulkUpdateIds
tag_ids: BulkUpdateIds
@ -92,9 +91,9 @@ input ImagesDestroyInput {
type FindImagesResultType {
count: Int!
"""Total megapixels of the images"""
"Total megapixels of the images"
megapixels: Float!
"""Total file size in bytes"""
"Total file size in bytes"
filesize: Float!
images: [Image!]!
}

View file

@ -1,17 +1,17 @@
"""Log entries"""
"Log entries"
scalar Time
enum LogLevel {
Trace
Debug
Info
Progress
Warning
Error
Trace
Debug
Info
Progress
Warning
Error
}
type LogEntry {
time: Time!
level: LogLevel!
message: String!
}
}

View file

@ -10,31 +10,31 @@ input GenerateMetadataInput {
markerImagePreviews: Boolean
markerScreenshots: Boolean
transcodes: Boolean
"""Generate transcodes even if not required"""
"Generate transcodes even if not required"
forceTranscodes: Boolean
phashes: Boolean
interactiveHeatmapsSpeeds: Boolean
clipPreviews: Boolean
"""scene ids to generate for"""
"scene ids to generate for"
sceneIDs: [ID!]
"""marker ids to generate for"""
"marker ids to generate for"
markerIDs: [ID!]
"""overwrite existing media"""
"overwrite existing media"
overwrite: Boolean
}
input GeneratePreviewOptionsInput {
"""Number of segments in a preview file"""
"Number of segments in a preview file"
previewSegments: Int
"""Preview segment duration, in seconds"""
"Preview segment duration, in seconds"
previewSegmentDuration: Float
"""Duration of start of video to exclude when generating previews"""
"Duration of start of video to exclude when generating previews"
previewExcludeStart: String
"""Duration of end of video to exclude when generating previews"""
"Duration of end of video to exclude when generating previews"
previewExcludeEnd: String
"""Preset when generating preview"""
"Preset when generating preview"
previewPreset: PreviewPreset
}
@ -54,15 +54,15 @@ type GenerateMetadataOptions {
}
type GeneratePreviewOptions {
"""Number of segments in a preview file"""
"Number of segments in a preview file"
previewSegments: Int
"""Preview segment duration, in seconds"""
"Preview segment duration, in seconds"
previewSegmentDuration: Float
"""Duration of start of video to exclude when generating previews"""
"Duration of start of video to exclude when generating previews"
previewExcludeStart: String
"""Duration of end of video to exclude when generating previews"""
"Duration of end of video to exclude when generating previews"
previewExcludeEnd: String
"""Preset when generating preview"""
"Preset when generating preview"
previewPreset: PreviewPreset
}
@ -78,29 +78,29 @@ input ScanMetadataInput {
# useFileMetadata is deprecated with the new file management system
# if this functionality is desired, then we can make a built in scraper instead.
"""Set name, date, details from metadata (if present)"""
"Set name, date, details from metadata (if present)"
useFileMetadata: Boolean @deprecated(reason: "Not implemented")
# stripFileExtension is deprecated since we no longer set the title from the
# stripFileExtension is deprecated since we no longer set the title from the
# filename - it is automatically returned if the object has no title. If this
# functionality is desired, then we could make this an option to not include
# the extension in the auto-generated title.
"""Strip file extension from title"""
"Strip file extension from title"
stripFileExtension: Boolean @deprecated(reason: "Not implemented")
"""Generate covers during scan"""
"Generate covers during scan"
scanGenerateCovers: Boolean
"""Generate previews during scan"""
"Generate previews during scan"
scanGeneratePreviews: Boolean
"""Generate image previews during scan"""
"Generate image previews during scan"
scanGenerateImagePreviews: Boolean
"""Generate sprites during scan"""
"Generate sprites during scan"
scanGenerateSprites: Boolean
"""Generate phashes during scan"""
"Generate phashes during scan"
scanGeneratePhashes: Boolean
"""Generate image thumbnails during scan"""
"Generate image thumbnails during scan"
scanGenerateThumbnails: Boolean
"""Generate image clip previews during scan"""
"Generate image clip previews during scan"
scanGenerateClipPreviews: Boolean
"Filter options for the scan"
@ -108,62 +108,75 @@ input ScanMetadataInput {
}
type ScanMetadataOptions {
"""Set name, date, details from metadata (if present)"""
"Set name, date, details from metadata (if present)"
useFileMetadata: Boolean! @deprecated(reason: "Not implemented")
"""Strip file extension from title"""
"Strip file extension from title"
stripFileExtension: Boolean! @deprecated(reason: "Not implemented")
"""Generate covers during scan"""
"Generate covers during scan"
scanGenerateCovers: Boolean!
"""Generate previews during scan"""
"Generate previews during scan"
scanGeneratePreviews: Boolean!
"""Generate image previews during scan"""
"Generate image previews during scan"
scanGenerateImagePreviews: Boolean!
"""Generate sprites during scan"""
"Generate sprites during scan"
scanGenerateSprites: Boolean!
"""Generate phashes during scan"""
"Generate phashes during scan"
scanGeneratePhashes: Boolean!
"""Generate image thumbnails during scan"""
"Generate image thumbnails during scan"
scanGenerateThumbnails: Boolean!
"""Generate image clip previews during scan"""
"Generate image clip previews during scan"
scanGenerateClipPreviews: Boolean!
}
input CleanMetadataInput {
paths: [String!]
"""Do a dry run. Don't delete any files"""
"Do a dry run. Don't delete any files"
dryRun: Boolean!
}
input AutoTagMetadataInput {
"""Paths to tag, null for all files"""
"Paths to tag, null for all files"
paths: [String!]
"""IDs of performers to tag files with, or "*" for all"""
"""
IDs of performers to tag files with, or "*" for all
"""
performers: [String!]
"""IDs of studios to tag files with, or "*" for all"""
"""
IDs of studios to tag files with, or "*" for all
"""
studios: [String!]
"""IDs of tags to tag files with, or "*" for all"""
"""
IDs of tags to tag files with, or "*" for all
"""
tags: [String!]
}
type AutoTagMetadataOptions {
"""IDs of performers to tag files with, or "*" for all"""
"""
IDs of performers to tag files with, or "*" for all
"""
performers: [String!]
"""IDs of studios to tag files with, or "*" for all"""
"""
IDs of studios to tag files with, or "*" for all
"""
studios: [String!]
"""IDs of tags to tag files with, or "*" for all"""
"""
IDs of tags to tag files with, or "*" for all
"""
tags: [String!]
}
enum IdentifyFieldStrategy {
"""Never sets the field value"""
"Never sets the field value"
IGNORE
"""
For multi-value fields, merge with existing.
For single-value fields, ignore if already set
"""
MERGE
"""Always replaces the value if a value is found.
"""
Always replaces the value if a value is found.
For multi-value fields, any existing values are removed and replaced with the
scraped values.
"""
@ -173,44 +186,44 @@ enum IdentifyFieldStrategy {
input IdentifyFieldOptionsInput {
field: String!
strategy: IdentifyFieldStrategy!
"""creates missing objects if needed - only applicable for performers, tags and studios"""
"creates missing objects if needed - only applicable for performers, tags and studios"
createMissing: Boolean
}
input IdentifyMetadataOptionsInput {
"""any fields missing from here are defaulted to MERGE and createMissing false"""
"any fields missing from here are defaulted to MERGE and createMissing false"
fieldOptions: [IdentifyFieldOptionsInput!]
"""defaults to true if not provided"""
"defaults to true if not provided"
setCoverImage: Boolean
setOrganized: Boolean
"""defaults to true if not provided"""
"defaults to true if not provided"
includeMalePerformers: Boolean
"""defaults to true if not provided"""
"defaults to true if not provided"
skipMultipleMatches: Boolean
"""tag to tag skipped multiple matches with"""
"tag to tag skipped multiple matches with"
skipMultipleMatchTag: String
"""defaults to true if not provided"""
"defaults to true if not provided"
skipSingleNamePerformers: Boolean
"""tag to tag skipped single name performers with"""
"tag to tag skipped single name performers with"
skipSingleNamePerformerTag: String
}
input IdentifySourceInput {
source: ScraperSourceInput!
"""Options defined for a source override the defaults"""
"Options defined for a source override the defaults"
options: IdentifyMetadataOptionsInput
}
input IdentifyMetadataInput {
"""An ordered list of sources to identify items with. Only the first source that finds a match is used."""
"An ordered list of sources to identify items with. Only the first source that finds a match is used."
sources: [IdentifySourceInput!]!
"""Options defined here override the configured defaults"""
"Options defined here override the configured defaults"
options: IdentifyMetadataOptionsInput
"""scene ids to identify"""
"scene ids to identify"
sceneIDs: [ID!]
"""paths of scenes to identify - ignored if scene ids are set"""
"paths of scenes to identify - ignored if scene ids are set"
paths: [String!]
}
@ -218,38 +231,38 @@ input IdentifyMetadataInput {
type IdentifyFieldOptions {
field: String!
strategy: IdentifyFieldStrategy!
"""creates missing objects if needed - only applicable for performers, tags and studios"""
"creates missing objects if needed - only applicable for performers, tags and studios"
createMissing: Boolean
}
type IdentifyMetadataOptions {
"""any fields missing from here are defaulted to MERGE and createMissing false"""
"any fields missing from here are defaulted to MERGE and createMissing false"
fieldOptions: [IdentifyFieldOptions!]
"""defaults to true if not provided"""
"defaults to true if not provided"
setCoverImage: Boolean
setOrganized: Boolean
"""defaults to true if not provided"""
"defaults to true if not provided"
includeMalePerformers: Boolean
"""defaults to true if not provided"""
"defaults to true if not provided"
skipMultipleMatches: Boolean
"""tag to tag skipped multiple matches with"""
"tag to tag skipped multiple matches with"
skipMultipleMatchTag: String
"""defaults to true if not provided"""
"defaults to true if not provided"
skipSingleNamePerformers: Boolean
"""tag to tag skipped single name performers with"""
"tag to tag skipped single name performers with"
skipSingleNamePerformerTag: String
}
type IdentifySource {
source: ScraperSource!
"""Options defined for a source override the defaults"""
"Options defined for a source override the defaults"
options: IdentifyMetadataOptions
}
type IdentifyMetadataTaskOptions {
"""An ordered list of sources to identify items with. Only the first source that finds a match is used."""
"An ordered list of sources to identify items with. Only the first source that finds a match is used."
sources: [IdentifySource!]!
"""Options defined here override the configured defaults"""
"Options defined here override the configured defaults"
options: IdentifyMetadataOptions
}

View file

@ -3,7 +3,7 @@ type Movie {
name: String!
checksum: String! @deprecated(reason: "MD5 hash of name, use name directly")
aliases: String
"""Duration in seconds"""
"Duration in seconds"
duration: Int
date: String
# rating expressed as 1-5
@ -26,7 +26,7 @@ type Movie {
input MovieCreateInput {
name: String!
aliases: String
"""Duration in seconds"""
"Duration in seconds"
duration: Int
date: String
# rating expressed as 1-5
@ -37,9 +37,9 @@ input MovieCreateInput {
director: String
synopsis: String
url: String
"""This should be a URL or a base64 encoded data URL"""
"This should be a URL or a base64 encoded data URL"
front_image: String
"""This should be a URL or a base64 encoded data URL"""
"This should be a URL or a base64 encoded data URL"
back_image: String
}
@ -57,9 +57,9 @@ input MovieUpdateInput {
director: String
synopsis: String
url: String
"""This should be a URL or a base64 encoded data URL"""
"This should be a URL or a base64 encoded data URL"
front_image: String
"""This should be a URL or a base64 encoded data URL"""
"This should be a URL or a base64 encoded data URL"
back_image: String
}

View file

@ -6,7 +6,7 @@ enum GenderEnum {
INTERSEX
NON_BINARY
}
enum CircumisedEnum {
CUT
UNCUT
@ -14,7 +14,7 @@ enum CircumisedEnum {
type Performer {
id: ID!
checksum: String @deprecated(reason: "Not used")
checksum: String @deprecated(reason: "Not used")
name: String!
disambiguation: String
url: String
@ -87,7 +87,7 @@ input PerformerCreateInput {
instagram: String
favorite: Boolean
tag_ids: [ID!]
"""This should be a URL or a base64 encoded data URL"""
"This should be a URL or a base64 encoded data URL"
image: String
stash_ids: [StashIDInput!]
# rating expressed as 1-5
@ -127,7 +127,7 @@ input PerformerUpdateInput {
instagram: String
favorite: Boolean
tag_ids: [ID!]
"""This should be a URL or a base64 encoded data URL"""
"This should be a URL or a base64 encoded data URL"
image: String
stash_ids: [StashIDInput!]
# rating expressed as 1-5

View file

@ -1,43 +1,42 @@
type Plugin {
id: ID!
name: String!
description: String
url: String
version: String
id: ID!
name: String!
description: String
url: String
version: String
tasks: [PluginTask!]
hooks: [PluginHook!]
tasks: [PluginTask!]
hooks: [PluginHook!]
}
type PluginTask {
name: String!
description: String
plugin: Plugin!
name: String!
description: String
plugin: Plugin!
}
type PluginHook {
name: String!
description: String
hooks: [String!]
plugin: Plugin!
name: String!
description: String
hooks: [String!]
plugin: Plugin!
}
type PluginResult {
error: String
result: String
error: String
result: String
}
input PluginArgInput {
key: String!
value: PluginValueInput
key: String!
value: PluginValueInput
}
input PluginValueInput {
str: String
i: Int
b: Boolean
f: Float
o: [PluginArgInput!]
a: [PluginValueInput!]
str: String
i: Int
b: Boolean
f: Float
o: [PluginArgInput!]
a: [PluginValueInput!]
}

View file

@ -1,4 +1,3 @@
"""
Timestamp is a point in time. It is always output as RFC3339-compatible time points.
It can be input as a RFC3339 string, or as "<4h" for "4 hours in the past" or ">5m"
@ -11,4 +10,4 @@ scalar Map
scalar Any
scalar Int64
scalar Int64

View file

@ -1,4 +1,4 @@
type SceneMarkerTag {
tag: Tag!
scene_markers: [SceneMarker!]!
}
}

View file

@ -8,11 +8,11 @@ type SceneMarker {
created_at: Time!
updated_at: Time!
"""The path to stream this marker"""
"The path to stream this marker"
stream: String! # Resolver
"""The path to the preview image for this marker"""
"The path to the preview image for this marker"
preview: String! # Resolver
"""The path to the screenshot image for this marker"""
"The path to the screenshot image for this marker"
screenshot: String! # Resolver
}
@ -42,4 +42,4 @@ type MarkerStringsResultType {
count: Int!
id: ID!
title: String!
}
}

View file

@ -57,19 +57,18 @@ type Scene {
created_at: Time!
updated_at: Time!
file_mod_time: Time
"""The last time play count was updated"""
"The last time play count was updated"
last_played_at: Time
"""The time index a scene was left at"""
"The time index a scene was left at"
resume_time: Float
"""The total time a scene has spent playing"""
"The total time a scene has spent playing"
play_duration: Float
"""The number ot times a scene has been played"""
"The number ot times a scene has been played"
play_count: Int
file: SceneFileType! @deprecated(reason: "Use files")
files: [VideoFile!]!
paths: ScenePathsType! # Resolver
scene_markers: [SceneMarker!]!
galleries: [Gallery!]!
studio: Studio
@ -78,7 +77,7 @@ type Scene {
performers: [Performer!]!
stash_ids: [StashID!]!
"""Return valid stream paths"""
"Return valid stream paths"
sceneStreams: [SceneStreamEndpoint!]!
}
@ -105,12 +104,15 @@ input SceneCreateInput {
performer_ids: [ID!]
movies: [SceneMovieInput!]
tag_ids: [ID!]
"""This should be a URL or a base64 encoded data URL"""
"This should be a URL or a base64 encoded data URL"
cover_image: String
stash_ids: [StashIDInput!]
"""The first id will be assigned as primary. Files will be reassigned from
existing scenes if applicable. Files must not already be primary for another scene"""
"""
The first id will be assigned as primary.
Files will be reassigned from existing scenes if applicable.
Files must not already be primary for another scene.
"""
file_ids: [ID!]
}
@ -135,15 +137,15 @@ input SceneUpdateInput {
performer_ids: [ID!]
movies: [SceneMovieInput!]
tag_ids: [ID!]
"""This should be a URL or a base64 encoded data URL"""
"This should be a URL or a base64 encoded data URL"
cover_image: String
stash_ids: [StashIDInput!]
"""The time index a scene was left at"""
"The time index a scene was left at"
resume_time: Float
"""The total time a scene has spent playing"""
"The total time a scene has spent playing"
play_duration: Float
"""The number ot times a scene has been played"""
"The number ot times a scene has been played"
play_count: Int
primary_file_id: ID
@ -179,7 +181,7 @@ input BulkSceneUpdateInput {
gallery_ids: BulkUpdateIds
performer_ids: BulkUpdateIds
tag_ids: BulkUpdateIds
movie_ids: BulkUpdateIds
movie_ids: BulkUpdateIds
}
input SceneDestroyInput {
@ -196,17 +198,17 @@ input ScenesDestroyInput {
type FindScenesResultType {
count: Int!
"""Total duration in seconds"""
"Total duration in seconds"
duration: Float!
"""Total file size in bytes"""
"Total file size in bytes"
filesize: Float!
scenes: [Scene!]!
}
input SceneParserInput {
ignoreWords: [String!],
whitespaceCharacters: String,
capitalizeTitle: Boolean,
ignoreWords: [String!]
whitespaceCharacters: String
capitalizeTitle: Boolean
ignoreOrganized: Boolean
}
@ -256,8 +258,10 @@ input AssignSceneFileInput {
}
input SceneMergeInput {
"""If destination scene has no files, then the primary file of the
first source scene will be assigned as primary"""
"""
If destination scene has no files, then the primary file of the
first source scene will be assigned as primary
"""
source: [ID!]!
destination: ID!
# values defined here will override values in the destination

View file

@ -1,4 +1,4 @@
"""A movie from a scraping operation..."""
"A movie from a scraping operation..."
type ScrapedMovie {
stored_id: ID
name: String
@ -11,9 +11,9 @@ type ScrapedMovie {
synopsis: String
studio: ScrapedStudio
"""This should be a base64 encoded data URL"""
"This should be a base64 encoded data URL"
front_image: String
"""This should be a base64 encoded data URL"""
"This should be a base64 encoded data URL"
back_image: String
}

View file

@ -1,6 +1,6 @@
"""A performer from a scraping operation..."""
"A performer from a scraping operation..."
type ScrapedPerformer {
"""Set if performer matched"""
"Set if performer matched"
stored_id: ID
name: String
disambiguation: String
@ -24,7 +24,7 @@ type ScrapedPerformer {
aliases: String
tags: [ScrapedTag!]
"""This should be a base64 encoded data URL"""
"This should be a base64 encoded data URL"
image: String @deprecated(reason: "use images instead")
images: [String!]
details: String
@ -35,7 +35,7 @@ type ScrapedPerformer {
}
input ScrapedPerformerInput {
"""Set if performer matched"""
"Set if performer matched"
stored_id: ID
name: String
disambiguation: String
@ -64,4 +64,4 @@ input ScrapedPerformerInput {
hair_color: String
weight: String
remote_site_id: String
}
}

View file

@ -1,9 +1,9 @@
enum ScrapeType {
"""From text query"""
"From text query"
NAME
"""From existing object"""
"From existing object"
FRAGMENT
"""From URL"""
"From URL"
URL
}
@ -16,35 +16,35 @@ enum ScrapeContentType {
}
"Scraped Content is the forming union over the different scrapers"
union ScrapedContent = ScrapedStudio
| ScrapedTag
| ScrapedScene
| ScrapedGallery
| ScrapedMovie
| ScrapedPerformer
union ScrapedContent =
ScrapedStudio
| ScrapedTag
| ScrapedScene
| ScrapedGallery
| ScrapedMovie
| ScrapedPerformer
type ScraperSpec {
"""URLs matching these can be scraped with"""
urls: [String!]
supported_scrapes: [ScrapeType!]!
"URLs matching these can be scraped with"
urls: [String!]
supported_scrapes: [ScrapeType!]!
}
type Scraper {
id: ID!
name: String!
"""Details for performer scraper"""
performer: ScraperSpec
"""Details for scene scraper"""
scene: ScraperSpec
"""Details for gallery scraper"""
gallery: ScraperSpec
"""Details for movie scraper"""
movie: ScraperSpec
id: ID!
name: String!
"Details for performer scraper"
performer: ScraperSpec
"Details for scene scraper"
scene: ScraperSpec
"Details for gallery scraper"
gallery: ScraperSpec
"Details for movie scraper"
movie: ScraperSpec
}
type ScrapedStudio {
"""Set if studio matched"""
"Set if studio matched"
stored_id: ID
name: String!
url: String
@ -54,7 +54,7 @@ type ScrapedStudio {
}
type ScrapedTag {
"""Set if tag matched"""
"Set if tag matched"
stored_id: ID
name: String!
}
@ -68,11 +68,10 @@ type ScrapedScene {
urls: [String!]
date: String
"""This should be a base64 encoded data URL"""
"This should be a base64 encoded data URL"
image: String
file: SceneFileType # Resolver
studio: ScrapedStudio
tags: [ScrapedTag!]
performers: [ScrapedPerformer!]
@ -118,84 +117,84 @@ input ScrapedGalleryInput {
}
input ScraperSourceInput {
"""Index of the configured stash-box instance to use. Should be unset if scraper_id is set"""
"Index of the configured stash-box instance to use. Should be unset if scraper_id is set"
stash_box_index: Int @deprecated(reason: "use stash_box_endpoint")
"""Stash-box endpoint"""
"Stash-box endpoint"
stash_box_endpoint: String
"""Scraper ID to scrape with. Should be unset if stash_box_index is set"""
"Scraper ID to scrape with. Should be unset if stash_box_index is set"
scraper_id: ID
}
type ScraperSource {
"""Index of the configured stash-box instance to use. Should be unset if scraper_id is set"""
"Index of the configured stash-box instance to use. Should be unset if scraper_id is set"
stash_box_index: Int @deprecated(reason: "use stash_box_endpoint")
"""Stash-box endpoint"""
"Stash-box endpoint"
stash_box_endpoint: String
"""Scraper ID to scrape with. Should be unset if stash_box_index is set"""
"Scraper ID to scrape with. Should be unset if stash_box_index is set"
scraper_id: ID
}
input ScrapeSingleSceneInput {
"""Instructs to query by string"""
"Instructs to query by string"
query: String
"""Instructs to query by scene fingerprints"""
"Instructs to query by scene fingerprints"
scene_id: ID
"""Instructs to query by scene fragment"""
"Instructs to query by scene fragment"
scene_input: ScrapedSceneInput
}
input ScrapeMultiScenesInput {
"""Instructs to query by scene fingerprints"""
"Instructs to query by scene fingerprints"
scene_ids: [ID!]
}
input ScrapeSinglePerformerInput {
"""Instructs to query by string"""
"Instructs to query by string"
query: String
"""Instructs to query by performer id"""
"Instructs to query by performer id"
performer_id: ID
"""Instructs to query by performer fragment"""
"Instructs to query by performer fragment"
performer_input: ScrapedPerformerInput
}
input ScrapeMultiPerformersInput {
"""Instructs to query by scene fingerprints"""
"Instructs to query by scene fingerprints"
performer_ids: [ID!]
}
input ScrapeSingleGalleryInput {
"""Instructs to query by string"""
"Instructs to query by string"
query: String
"""Instructs to query by gallery id"""
"Instructs to query by gallery id"
gallery_id: ID
"""Instructs to query by gallery fragment"""
"Instructs to query by gallery fragment"
gallery_input: ScrapedGalleryInput
}
input ScrapeSingleMovieInput {
"""Instructs to query by string"""
"Instructs to query by string"
query: String
"""Instructs to query by movie id"""
"Instructs to query by movie id"
movie_id: ID
"""Instructs to query by gallery fragment"""
"Instructs to query by gallery fragment"
movie_input: ScrapedMovieInput
}
input StashBoxSceneQueryInput {
"""Index of the configured stash-box instance to use"""
"Index of the configured stash-box instance to use"
stash_box_index: Int!
"""Instructs query by scene fingerprints"""
"Instructs query by scene fingerprints"
scene_ids: [ID!]
"""Query by query string"""
"Query by query string"
q: String
}
input StashBoxPerformerQueryInput {
"""Index of the configured stash-box instance to use"""
"Index of the configured stash-box instance to use"
stash_box_index: Int!
"""Instructs query by scene fingerprints"""
"Instructs query by scene fingerprints"
performer_ids: [ID!]
"""Query by query string"""
"Query by query string"
q: String
}
@ -210,7 +209,7 @@ type StashBoxFingerprint {
duration: Int!
}
"""If neither performer_ids nor performer_names are set, tag all performers"""
"If neither performer_ids nor performer_names are set, tag all performers"
input StashBoxBatchPerformerTagInput {
"Stash endpoint to use for the performer tagging"
endpoint: Int!

View file

@ -1,7 +1,7 @@
type SQLQueryResult {
"""The column names, in the order they appear in the result set."""
"The column names, in the order they appear in the result set."
columns: [String!]!
"""The returned rows."""
"The returned rows."
rows: [[Any]!]!
}
@ -12,7 +12,8 @@ type SQLExecResult {
"""
rows_affected: Int64
"""
The integer generated by the database in response to a command. Typically this will be from an "auto increment" column when inserting a new row.
The integer generated by the database in response to a command.
Typically this will be from an "auto increment" column when inserting a new row.
Not all databases support this feature, and the syntax of such statements varies.
"""
last_insert_id: Int64

View file

@ -1,13 +1,13 @@
type StashBox {
endpoint: String!
api_key: String!
name: String!
endpoint: String!
api_key: String!
name: String!
}
input StashBoxInput {
endpoint: String!
api_key: String!
name: String!
endpoint: String!
api_key: String!
name: String!
}
type StashID {

View file

@ -29,7 +29,7 @@ input StudioCreateInput {
name: String!
url: String
parent_id: ID
"""This should be a URL or a base64 encoded data URL"""
"This should be a URL or a base64 encoded data URL"
image: String
stash_ids: [StashIDInput!]
# rating expressed as 1-5
@ -45,8 +45,8 @@ input StudioUpdateInput {
id: ID!
name: String
url: String
parent_id: ID,
"""This should be a URL or a base64 encoded data URL"""
parent_id: ID
"This should be a URL or a base64 encoded data URL"
image: String
stash_ids: [StashIDInput!]
# rating expressed as 1-5

View file

@ -13,7 +13,6 @@ type Tag {
image_count(depth: Int): Int! # Resolver
gallery_count(depth: Int): Int! # Resolver
performer_count(depth: Int): Int! # Resolver
parents: [Tag!]!
children: [Tag!]!
}
@ -24,7 +23,7 @@ input TagCreateInput {
aliases: [String!]
ignore_auto_tag: Boolean
"""This should be a URL or a base64 encoded data URL"""
"This should be a URL or a base64 encoded data URL"
image: String
parent_ids: [ID!]
@ -38,7 +37,7 @@ input TagUpdateInput {
aliases: [String!]
ignore_auto_tag: Boolean
"""This should be a URL or a base64 encoded data URL"""
"This should be a URL or a base64 encoded data URL"
image: String
parent_ids: [ID!]

View file

@ -131,7 +131,9 @@ query FindScenesByFullFingerprints($fingerprints: [FingerprintQueryInput!]!) {
}
}
query FindScenesBySceneFingerprints($fingerprints: [[FingerprintQueryInput!]!]!) {
query FindScenesBySceneFingerprints(
$fingerprints: [[FingerprintQueryInput!]!]!
) {
findScenesBySceneFingerprints(fingerprints: $fingerprints) {
...SceneFragment
}

View file

@ -12,14 +12,14 @@
"lint:css": "stylelint --cache \"src/**/*.scss\"",
"lint:js": "eslint --cache src/",
"check": "tsc --noEmit",
"format": "prettier --write .",
"format-check": "prettier --check .",
"format": "prettier --write . ../../graphql",
"format-check": "prettier --check . ../../graphql",
"gqlgen": "gql-gen --config codegen.yml",
"extract": "NODE_ENV=development extract-messages -l=en,de -o src/locale -d en --flat false 'src/**/!(*.test).tsx'"
},
"dependencies": {
"@ant-design/react-slick": "^1.0.0",
"@apollo/client": "^3.7.8",
"@apollo/client": "^3.7.17",
"@formatjs/intl-getcanonicallocales": "^2.0.5",
"@formatjs/intl-locale": "^3.0.11",
"@formatjs/intl-numberformat": "^8.3.3",

View file

@ -39,8 +39,12 @@ export interface ITaggerContextState {
doSceneFragmentScrape: (sceneID: string) => Promise<void>;
doMultiSceneFragmentScrape: (sceneIDs: string[]) => Promise<void>;
stopMultiScrape: () => void;
createNewTag: (toCreate: GQL.ScrapedTag) => Promise<string | undefined>;
createNewTag: (
tag: GQL.ScrapedTag,
toCreate: GQL.TagCreateInput
) => Promise<string | undefined>;
createNewPerformer: (
performer: GQL.ScrapedPerformer,
toCreate: GQL.PerformerCreateInput
) => Promise<string | undefined>;
linkPerformer: (
@ -48,6 +52,7 @@ export interface ITaggerContextState {
performerID: string
) => Promise<void>;
createNewStudio: (
studio: GQL.ScrapedStudio,
toCreate: GQL.StudioCreateInput
) => Promise<string | undefined>;
linkStudio: (studio: GQL.ScrapedStudio, studioID: string) => Promise<void>;
@ -484,16 +489,19 @@ export const TaggerContext: React.FC = ({ children }) => {
return newSearchResults;
}
async function createNewTag(toCreate: GQL.ScrapedTag) {
const tagInput: GQL.TagCreateInput = { name: toCreate.name ?? "" };
async function createNewTag(
tag: GQL.ScrapedTag,
toCreate: GQL.TagCreateInput
) {
try {
const result = await createTag({
variables: {
input: tagInput,
input: toCreate,
},
});
const tagID = result.data?.tagCreate?.id;
if (tagID === undefined) return undefined;
const newSearchResults = mapResults((r) => {
if (!r.tags) {
@ -503,7 +511,7 @@ export const TaggerContext: React.FC = ({ children }) => {
return {
...r,
tags: r.tags.map((t) => {
if (t.name === toCreate.name) {
if (t.name === tag.name) {
return {
...t,
stored_id: tagID,
@ -531,7 +539,10 @@ export const TaggerContext: React.FC = ({ children }) => {
}
}
async function createNewPerformer(toCreate: GQL.PerformerCreateInput) {
async function createNewPerformer(
performer: GQL.ScrapedPerformer,
toCreate: GQL.PerformerCreateInput
) {
try {
const result = await createPerformer({
variables: {
@ -540,6 +551,7 @@ export const TaggerContext: React.FC = ({ children }) => {
});
const performerID = result.data?.performerCreate?.id;
if (performerID === undefined) return undefined;
const newSearchResults = mapResults((r) => {
if (!r.performers) {
@ -548,15 +560,15 @@ export const TaggerContext: React.FC = ({ children }) => {
return {
...r,
performers: r.performers.map((t) => {
if (t.name === toCreate.name) {
performers: r.performers.map((p) => {
if (p.remote_site_id === performer.remote_site_id) {
return {
...t,
...p,
stored_id: performerID,
};
}
return t;
return p;
}),
};
});
@ -640,7 +652,12 @@ export const TaggerContext: React.FC = ({ children }) => {
}
}
async function createNewStudio(toCreate: GQL.StudioCreateInput) {
async function createNewStudio(
studio: GQL.ScrapedStudio,
toCreate: GQL.StudioCreateInput
) {
if (!currentSource?.stashboxEndpoint) return;
try {
const result = await createStudio({
variables: {
@ -649,6 +666,7 @@ export const TaggerContext: React.FC = ({ children }) => {
});
const studioID = result.data?.studioCreate?.id;
if (studioID === undefined) return undefined;
const newSearchResults = mapResults((r) => {
if (!r.studio) {
@ -658,7 +676,7 @@ export const TaggerContext: React.FC = ({ children }) => {
return {
...r,
studio:
r.studio.name === toCreate.name
r.studio.remote_site_id === studio.remote_site_id
? {
...r.studio,
stored_id: studioID,
@ -720,7 +738,7 @@ export const TaggerContext: React.FC = ({ children }) => {
return {
...r,
studio:
r.remote_site_id === studio.remote_site_id
r.studio.remote_site_id === studio.remote_site_id
? {
...r.studio,
stored_id: studioID,

View file

@ -396,26 +396,20 @@ const StashSearchResult: React.FC<IStashSearchResultProps> = ({
await saveScene(sceneCreateInput, includeStashID);
}
function performerModalCallback(
toCreate?: GQL.PerformerCreateInput | undefined
) {
if (toCreate) {
createNewPerformer(toCreate);
}
}
function showPerformerModal(t: GQL.ScrapedPerformer) {
createPerformerModal(t, performerModalCallback);
}
function studioModalCallback(toCreate?: GQL.StudioCreateInput | undefined) {
if (toCreate) {
createNewStudio(toCreate);
}
createPerformerModal(t, (toCreate) => {
if (toCreate) {
createNewPerformer(t, toCreate);
}
});
}
function showStudioModal(t: GQL.ScrapedStudio) {
createStudioModal(t, studioModalCallback);
createStudioModal(t, (toCreate) => {
if (toCreate) {
createNewStudio(t, toCreate);
}
});
}
// constants to get around dot-notation eslint rule
@ -660,7 +654,8 @@ const StashSearchResult: React.FC<IStashSearchResultProps> = ({
);
async function onCreateTag(t: GQL.ScrapedTag) {
const newTagID = await createNewTag(t);
const toCreate: GQL.TagCreateInput = { name: t.name };
const newTagID = await createNewTag(t, toCreate);
if (newTagID !== undefined) {
setTagIDs([...tagIDs, newTagID]);
}

File diff suppressed because it is too large Load diff

View file

@ -12,60 +12,55 @@ import { onError } from "@apollo/client/link/error";
import { getMainDefinition } from "@apollo/client/utilities";
import { createUploadLink } from "apollo-upload-client";
import * as GQL from "src/core/generated-graphql";
import { FieldReadFunction } from "@apollo/client/cache";
// A read function that returns a cache reference with the given
// typename if no valid reference is available.
// Allows to return a cached object rather than fetching.
const readReference = (typename: string): FieldReadFunction => {
return (existing, { args, canRead, toReference }) =>
canRead(existing)
? existing
: toReference({
__typename: typename,
id: args?.id,
});
};
// A read function that returns null if no valid reference is available.
// Means that a dangling reference implies the object was deleted.
const readDanglingNull: FieldReadFunction = (existing, { canRead }) =>
canRead(existing) ? existing : null;
// Policies that tell apollo what the type of the returned object will be.
// In many cases this allows it to return from cache immediately rather than fetching.
const typePolicies: TypePolicies = {
Query: {
fields: {
findImage: {
read: (_, { args, toReference }) =>
toReference({
__typename: "Image",
id: args?.id,
}),
read: readReference("Image"),
},
findPerformer: {
read: (_, { args, toReference }) =>
toReference({
__typename: "Performer",
id: args?.id,
}),
read: readReference("Performer"),
},
findStudio: {
read: (_, { args, toReference }) =>
toReference({
__typename: "Studio",
id: args?.id,
}),
read: readReference("Studio"),
},
findMovie: {
read: (_, { args, toReference }) =>
toReference({
__typename: "Movie",
id: args?.id,
}),
read: readReference("Movie"),
},
findGallery: {
read: (_, { args, toReference }) =>
toReference({
__typename: "Gallery",
id: args?.id,
}),
read: readReference("Gallery"),
},
findScene: {
read: (_, { args, toReference }) =>
toReference({
__typename: "Scene",
id: args?.id,
}),
read: readReference("Scene"),
},
findTag: {
read: (_, { args, toReference }) =>
toReference({
__typename: "Tag",
id: args?.id,
}),
read: readReference("Tag"),
},
findSavedFilter: {
read: readReference("SavedFilter"),
},
findDefaultFilter: {
read: readDanglingNull,
},
},
},
@ -74,6 +69,37 @@ const typePolicies: TypePolicies = {
scene_markers: {
merge: false,
},
studio: {
read: readDanglingNull,
},
},
},
Image: {
fields: {
studio: {
read: readDanglingNull,
},
},
},
Movie: {
fields: {
studio: {
read: readDanglingNull,
},
},
},
Gallery: {
fields: {
studio: {
read: readDanglingNull,
},
},
},
Studio: {
fields: {
parent_studio: {
read: readDanglingNull,
},
},
},
Tag: {
@ -89,6 +115,7 @@ const typePolicies: TypePolicies = {
};
const possibleTypes = {
BaseFile: ["VideoFile", "ImageFile", "GalleryFile"],
VisualFile: ["VideoFile", "ImageFile"],
};

View file

@ -21,18 +21,18 @@
resize-observer-polyfill "^1.5.1"
throttle-debounce "^5.0.0"
"@apollo/client@^3.7.0", "@apollo/client@^3.7.8":
version "3.7.8"
resolved "https://registry.yarnpkg.com/@apollo/client/-/client-3.7.8.tgz#e1c8dfd02cbbe1baf9b18fa86918904efd9cc580"
integrity sha512-o1NxF4ytET2w9HSVMLwYUEEdv6H3XPpbh9M+ABVGnUVT0s6T9pgqRtYO4pFP1TmeDmb1pbRfVhFwh3gC167j5Q==
"@apollo/client@^3.7.0", "@apollo/client@^3.7.17":
version "3.7.17"
resolved "https://registry.yarnpkg.com/@apollo/client/-/client-3.7.17.tgz#1d2538729fd8ef138aa301a7cf62704474e57b72"
integrity sha512-0EErSHEtKPNl5wgWikHJbKFAzJ/k11O0WO2QyqZSHpdxdAnw7UWHY4YiLbHCFG7lhrD+NTQ3Z/H9Jn4rcikoJA==
dependencies:
"@graphql-typed-document-node/core" "^3.1.1"
"@wry/context" "^0.7.0"
"@wry/equality" "^0.5.0"
"@wry/trie" "^0.3.0"
"@wry/trie" "^0.4.0"
graphql-tag "^2.12.6"
hoist-non-react-statics "^3.3.2"
optimism "^0.16.1"
optimism "^0.16.2"
prop-types "^15.7.2"
response-iterator "^0.2.6"
symbol-observable "^4.0.0"
@ -2718,6 +2718,13 @@
dependencies:
tslib "^2.3.0"
"@wry/trie@^0.4.0":
version "0.4.3"
resolved "https://registry.yarnpkg.com/@wry/trie/-/trie-0.4.3.tgz#077d52c22365871bf3ffcbab8e95cb8bc5689af4"
integrity sha512-I6bHwH0fSf6RqQcnnXLJKhkSXG45MFral3GxPaY4uAl0LYDZM+YDVDAiU9bYwjTuysy1S0IeecWtmq1SZA3M1w==
dependencies:
tslib "^2.3.0"
"@xmldom/xmldom@^0.8.3":
version "0.8.6"
resolved "https://registry.yarnpkg.com/@xmldom/xmldom/-/xmldom-0.8.6.tgz#8a1524eb5bd5e965c1e3735476f0262469f71440"
@ -6197,7 +6204,7 @@ onetime@^5.1.0:
dependencies:
mimic-fn "^2.1.0"
optimism@^0.16.1:
optimism@^0.16.2:
version "0.16.2"
resolved "https://registry.yarnpkg.com/optimism/-/optimism-0.16.2.tgz#519b0c78b3b30954baed0defe5143de7776bf081"
integrity sha512-zWNbgWj+3vLEjZNIh/okkY2EUfX+vB9TJopzIZwT1xxaMqC5hRLLraePod4c5n4He08xuXNH+zhKFFCu390wiQ==