mirror of
https://github.com/stashapp/stash.git
synced 2026-06-11 07:41:08 -05:00
Compare commits
408 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2bb04a623f | ||
|
|
8be2c4b6d2 | ||
|
|
38a06be148 | ||
|
|
e3225db5c0 | ||
|
|
56767c11a8 | ||
|
|
ce1219b350 | ||
|
|
ed9f35a973 | ||
|
|
030bc5d7c1 | ||
|
|
a597bd255c | ||
|
|
8ac3353103 | ||
|
|
d0c60bab50 | ||
|
|
a9d31889b4 | ||
|
|
5dbf1797e9 | ||
|
|
3ea233dc06 | ||
|
|
107d1113e5 | ||
|
|
bd28aa6fd9 | ||
|
|
00ae40ad72 | ||
|
|
65826fdbb3 | ||
|
|
4311e56109 | ||
|
|
50db9466cb | ||
|
|
ab4f56213f | ||
|
|
15f91fda13 | ||
|
|
29fb570582 | ||
|
|
2cf084130f | ||
|
|
170f45c445 | ||
|
|
a354f9b36b | ||
|
|
b8e2f2a0fa | ||
|
|
a665a56ef0 | ||
|
|
d48dbeb864 | ||
|
|
4961c967ee | ||
|
|
95a78de3aa | ||
|
|
7b77b8986f | ||
|
|
a1da626c9f | ||
|
|
2ae30028ac | ||
|
|
b3fa3c326a | ||
|
|
9f2d12834b | ||
|
|
424aad8307 | ||
|
|
4b07c5b60b | ||
|
|
df70b182a4 | ||
|
|
1229f092a4 | ||
|
|
eb8a69e326 | ||
|
|
40124ee5a4 | ||
|
|
ec14ad7564 | ||
|
|
8872892c42 | ||
|
|
4730f90c26 | ||
|
|
7c226fe2b7 | ||
|
|
29636d500a | ||
|
|
5580525c2d | ||
|
|
67d4f9729a | ||
|
|
76a4bfa49a | ||
|
|
3e810cf8b1 | ||
|
|
c1352f9048 | ||
|
|
f665aa8bc2 | ||
|
|
b2b52bcc41 | ||
|
|
96f222997a | ||
|
|
278a0642f4 | ||
|
|
0c0ba19a23 | ||
|
|
969af2ab69 | ||
|
|
cbdd4d3cbf | ||
|
|
ff22577ce0 | ||
|
|
4f0e0e1d99 | ||
|
|
8e235a26ee | ||
|
|
c499c20a7b | ||
|
|
f0d901a697 | ||
|
|
93b41fb650 | ||
|
|
5c38836ade | ||
|
|
cec9195543 | ||
|
|
0268565099 | ||
|
|
b4879ef758 | ||
|
|
cfc3912dcd | ||
|
|
f440e06dc7 | ||
|
|
bcf9019ca3 | ||
|
|
0087bc941c | ||
|
|
873d4dade6 | ||
|
|
f65e87773c | ||
|
|
47c3e855c8 | ||
|
|
4f11a2820f | ||
|
|
d81a0fcffb | ||
|
|
1c13c9e1b1 | ||
|
|
9180a68c45 | ||
|
|
1ba1564d8a | ||
|
|
6bcf1f8838 | ||
|
|
2e40a41c1e | ||
|
|
09df203bcf | ||
|
|
de4237e626 | ||
|
|
0c999080c2 | ||
|
|
e22291d912 | ||
|
|
256e0a11ea | ||
|
|
4acf843229 | ||
|
|
c8a796e125 | ||
|
|
94450da8b5 | ||
|
|
74cef93d19 | ||
|
|
9c8a6ee495 | ||
|
|
88179ed54e | ||
|
|
d0847d1ebf | ||
|
|
fc53380310 | ||
|
|
241aae9100 | ||
|
|
1c59d91690 | ||
|
|
cc9ded05a3 | ||
|
|
62b6457f4e | ||
|
|
45e61b9228 | ||
|
|
3eb805ca2d | ||
|
|
2a85d512f4 | ||
|
|
ed7640b7b1 | ||
|
|
94dda49352 | ||
|
|
776c7e6c35 | ||
|
|
58a6c22072 | ||
|
|
124adb3f5b | ||
|
|
702101ecce | ||
|
|
0a14394113 | ||
|
|
06e924d010 | ||
|
|
9a41841bd2 | ||
|
|
11344c51b7 | ||
|
|
a2e477e1a7 | ||
|
|
0e199a525f | ||
|
|
0069c48e7e | ||
|
|
61c0098ae6 | ||
|
|
e7abeeb4df | ||
|
|
490a2aca08 | ||
|
|
c77ff8989b | ||
|
|
ca45c391da | ||
|
|
242f61b5df | ||
|
|
39ebd92e60 | ||
|
|
b1c61d2846 | ||
|
|
b7d179e448 | ||
|
|
f3f7ee7fd2 | ||
|
|
79bc5c914f | ||
|
|
899d1b9395 | ||
|
|
002b71bd67 | ||
|
|
67a2161c62 | ||
|
|
1717474a81 | ||
|
|
1606f1b17e | ||
|
|
d6b4d16ff4 | ||
|
|
55e0d5c82f | ||
|
|
c9c5b55721 | ||
|
|
89ed6e9a67 | ||
|
|
da1ef146c6 | ||
|
|
55d3deee49 | ||
|
|
7939e7595b | ||
|
|
23e52738c6 | ||
|
|
85c893fd81 | ||
|
|
8d3f632d4c | ||
|
|
3bc5caa6de | ||
|
|
64b7934af2 | ||
|
|
152f9114b2 | ||
|
|
203afb3d1b | ||
|
|
90683bd263 | ||
|
|
b4b7cf02b6 | ||
|
|
87abe8c38c | ||
|
|
2cf73ded83 | ||
|
|
b85c5d928a | ||
|
|
c859fa6bf8 | ||
|
|
22e2ce4838 | ||
|
|
dcc73c4873 | ||
|
|
62a1bc22c9 | ||
|
|
5711ff6d21 | ||
|
|
aebb8b07df | ||
|
|
6a6545305c | ||
|
|
32cefea524 | ||
|
|
75f22042b7 | ||
|
|
e685f80e3d | ||
|
|
9b8d124ac8 | ||
|
|
0cd0151251 | ||
|
|
a6ef924d06 | ||
|
|
3ab8f4aca6 | ||
|
|
2d8b6e1722 | ||
|
|
cb8fc3788a | ||
|
|
a8f9310c0f | ||
|
|
046fd1c0be | ||
|
|
0050e4abbf | ||
|
|
2bcab7b0be | ||
|
|
806964086b | ||
|
|
a8816e0635 | ||
|
|
1f578db2d6 | ||
|
|
7e66741998 | ||
|
|
6a1458fb2c | ||
|
|
0841d6877a | ||
|
|
b967b63288 | ||
|
|
b6b275edc8 | ||
|
|
b602ed2381 | ||
|
|
b1608128d6 | ||
|
|
cf0e7a4574 | ||
|
|
fcfbdc47bc | ||
|
|
fc7c3f588e | ||
|
|
09c724b8d5 | ||
|
|
f6387c1018 | ||
|
|
496c36493b | ||
|
|
44c58d6e3c | ||
|
|
c1ca34303e | ||
|
|
4f909d2457 | ||
|
|
2b9f573b30 | ||
|
|
88b3b87f01 | ||
|
|
9a24e6356e | ||
|
|
5a41001246 | ||
|
|
7cff71c35f | ||
|
|
c3081700c0 | ||
|
|
9bae98cf57 | ||
|
|
943a6d3be7 | ||
|
|
7e8f941155 | ||
|
|
32c91c4855 | ||
|
|
58852f86fe | ||
|
|
ac67d640db | ||
|
|
e2b52a4bf6 | ||
|
|
e22c938d74 | ||
|
|
99b6d316c3 | ||
|
|
bc3730d49f | ||
|
|
798b3e6dd7 | ||
|
|
c4d08c5225 | ||
|
|
9aa7ec575a | ||
|
|
b7183900ac | ||
|
|
579c5ad8b9 | ||
|
|
1c8aa46da5 | ||
|
|
e90b00d3bd | ||
|
|
57951fe6a0 | ||
|
|
7a2ee7cdda | ||
|
|
0c1b02380e | ||
|
|
d4fb6b2acf | ||
|
|
9ede271c05 | ||
|
|
6b59b9643c | ||
|
|
2d4384169a | ||
|
|
71e1451c94 | ||
|
|
42fde9bc9f | ||
|
|
381486904b | ||
|
|
7b07810c12 | ||
|
|
7c0f4763ad | ||
|
|
3dcc23c001 | ||
|
|
a081b62823 | ||
|
|
b1325ce03f | ||
|
|
f992b9a0de | ||
|
|
1d13f46e23 | ||
|
|
078f99a7ec | ||
|
|
30809e16fa | ||
|
|
445e0a7311 | ||
|
|
967a25f64a | ||
|
|
dc934d73fa | ||
|
|
05669f5503 | ||
|
|
f767635080 | ||
|
|
75a8d572cc | ||
|
|
2b84392df7 | ||
|
|
edc22629b6 | ||
|
|
2d528733ff | ||
|
|
8b6f7db4ef | ||
|
|
d0f30ebf39 | ||
|
|
87e74d1171 | ||
|
|
8f17721d54 | ||
|
|
066e0b3d5f | ||
|
|
e9fa7d071e | ||
|
|
dd5cff2aec | ||
|
|
c7c4d5b126 | ||
|
|
ccbe3c4e92 | ||
|
|
96ce260a40 | ||
|
|
28b8473f2d | ||
|
|
51469cfc7f | ||
|
|
b3c23950e2 | ||
|
|
bb6fa04654 | ||
|
|
390f72207c | ||
|
|
f92ba7ba53 | ||
|
|
4e34de4c1e | ||
|
|
bd747317d4 | ||
|
|
a1851b3713 | ||
|
|
0c9eeef143 | ||
|
|
8ab095f675 | ||
|
|
ebf3a4ba8e | ||
|
|
2f312ac651 | ||
|
|
7d1a565803 | ||
|
|
8437e10027 | ||
|
|
a1e7f8940b | ||
|
|
6a5a2060bf | ||
|
|
d00966c335 | ||
|
|
8bd5f91e58 | ||
|
|
83cb51ec47 | ||
|
|
ca38a355d2 | ||
|
|
d2865b0796 | ||
|
|
3cf97f6e27 | ||
|
|
f0988817c8 | ||
|
|
692c1e55ac | ||
|
|
18b44e9381 | ||
|
|
7761ac19de | ||
|
|
deb5110623 | ||
|
|
9875a21674 | ||
|
|
901a7e59ec | ||
|
|
cb808c7be2 | ||
|
|
cb3545a303 | ||
|
|
6f2057a51e | ||
|
|
53f9530524 | ||
|
|
65d1353f2c | ||
|
|
1cba910435 | ||
|
|
ef2af977d3 | ||
|
|
d80ec1d7a1 | ||
|
|
7ccfa07843 | ||
|
|
32e8496314 | ||
|
|
c52d8c9314 | ||
|
|
71a751d997 | ||
|
|
f5ff1139b0 | ||
|
|
cf0ce6cb08 | ||
|
|
08560923d2 | ||
|
|
0e2bd125a8 | ||
|
|
b67abb89ff | ||
|
|
a36b895e4b | ||
|
|
7df26e2f56 | ||
|
|
515202d28e | ||
|
|
639a9da65b | ||
|
|
01d40c1b9e | ||
|
|
ef622659ff | ||
|
|
8bac413d74 | ||
|
|
9351a0b2a4 | ||
|
|
0b4b100ecc | ||
|
|
cc4b0f7b11 | ||
|
|
150c496949 | ||
|
|
74506bc5e8 | ||
|
|
05b0fb23f4 | ||
|
|
8629a0713d | ||
|
|
0aab2c382f | ||
|
|
74b585a05f | ||
|
|
7c58305b05 | ||
|
|
ce080c1b07 | ||
|
|
a67eee8f4c | ||
|
|
2715dcb72a | ||
|
|
eb7956a05a | ||
|
|
78bb2d8425 | ||
|
|
2064ea27b0 | ||
|
|
782bed9df8 | ||
|
|
c9b0841184 | ||
|
|
38d6af8b66 | ||
|
|
dc875ed5d7 | ||
|
|
b5b9023b3e | ||
|
|
87cea80e7b | ||
|
|
e614ca8d26 | ||
|
|
4daf0a14a2 | ||
|
|
d2395e579c | ||
|
|
8a649f0268 | ||
|
|
0b19a00ba8 | ||
|
|
5e332514fa | ||
|
|
646f8bc02e | ||
|
|
9350be12d9 | ||
|
|
02ec98b302 | ||
|
|
a8f4c2c29c | ||
|
|
57ad12e43b | ||
|
|
f0a3a3dd44 | ||
|
|
27998c35a1 | ||
|
|
03cd9529bd | ||
|
|
3072333118 | ||
|
|
821587b166 | ||
|
|
b175f1865f | ||
|
|
5a2242e78d | ||
|
|
54c495d867 | ||
|
|
e84221ccbe | ||
|
|
8b59a3b014 | ||
|
|
f76a440e54 | ||
|
|
aafbba7d77 | ||
|
|
7bb35b2b09 | ||
|
|
af28fd0f3b | ||
|
|
abc9ec648a | ||
|
|
045ba55def | ||
|
|
0664c5b974 | ||
|
|
f39fa416a9 | ||
|
|
420c6fa9d7 | ||
|
|
b1c00a64fc | ||
|
|
4ff163d375 | ||
|
|
c1f271fc52 | ||
|
|
2cce547986 | ||
|
|
f0bf780c2e | ||
|
|
3660bf2d1a | ||
|
|
ca9c8e0a34 | ||
|
|
3a63f1f9b7 | ||
|
|
ffca8f0c0f | ||
|
|
0443439fae | ||
|
|
dc820e29af | ||
|
|
7eae751d1c | ||
|
|
f66333bac9 | ||
|
|
ce17230c13 | ||
|
|
4a054ab081 | ||
|
|
d0b0be4dd4 | ||
|
|
9df66024d1 | ||
|
|
c83ebf7c1c | ||
|
|
eb795ff9ab | ||
|
|
a2ca266cb3 | ||
|
|
3bc0de3f3a | ||
|
|
30a7482ddf | ||
|
|
04514fbc88 | ||
|
|
f1d57c3d62 | ||
|
|
404a68c994 | ||
|
|
d2743cf5fb | ||
|
|
b9e07ade92 | ||
|
|
962bc7df4e | ||
|
|
f1c454eb09 | ||
|
|
eff86bf2f8 | ||
|
|
7540d3b477 | ||
|
|
653db3cc1d | ||
|
|
2609095c7a | ||
|
|
bba7c23957 | ||
|
|
f25881a3bf | ||
|
|
270bc317cb | ||
|
|
b1fa933868 | ||
|
|
2cd9ef6302 | ||
|
|
db29246883 | ||
|
|
7b7d6758ef | ||
|
|
1c0042c4c2 | ||
|
|
a60afc162f | ||
|
|
2b80b6d8d5 | ||
|
|
3ac3fe09b8 | ||
|
|
02c2ad3f58 | ||
|
|
479ebfc88d | ||
|
|
1c92336798 | ||
|
|
5fae3cf127 | ||
|
|
47395ce13f | ||
|
|
091950615e | ||
|
|
4db0e48f73 |
2
.github/FUNDING.yml
vendored
2
.github/FUNDING.yml
vendored
@@ -1,6 +1,6 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
# github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
||||
github: stashapp
|
||||
# patreon: # Replace with a single Patreon username
|
||||
open_collective: stashapp
|
||||
# ko_fi: # Replace with a single Ko-fi username
|
||||
|
||||
10
.github/workflows/build.yml
vendored
10
.github/workflows/build.yml
vendored
@@ -12,7 +12,7 @@ concurrency:
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
COMPILER_IMAGE: stashapp/compiler:6
|
||||
COMPILER_IMAGE: stashapp/compiler:7
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@@ -27,7 +27,7 @@ jobs:
|
||||
run: docker pull $COMPILER_IMAGE
|
||||
|
||||
- name: Cache node modules
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3
|
||||
env:
|
||||
cache-name: cache-node_modules
|
||||
with:
|
||||
@@ -35,7 +35,7 @@ jobs:
|
||||
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('ui/v2.5/yarn.lock') }}
|
||||
|
||||
- name: Cache UI build
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3
|
||||
id: cache-ui
|
||||
env:
|
||||
cache-name: cache-ui
|
||||
@@ -44,7 +44,7 @@ jobs:
|
||||
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('ui/v2.5/yarn.lock', 'ui/v2.5/public/**', 'ui/v2.5/src/**', 'graphql/**/*.graphql') }}
|
||||
|
||||
- name: Cache go build
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3
|
||||
env:
|
||||
# increment the number suffix to bump the cache
|
||||
cache-name: cache-go-cache-1
|
||||
@@ -68,7 +68,7 @@ jobs:
|
||||
- name: Validate UI
|
||||
# skip UI validation for pull requests if UI is unchanged
|
||||
if: ${{ github.event_name != 'pull_request' || steps.cache-ui.outputs.cache-hit != 'true' }}
|
||||
run: docker exec -t build /bin/bash -c "make validate-frontend"
|
||||
run: docker exec -t build /bin/bash -c "make validate-ui"
|
||||
|
||||
# Static validation happens in the linter workflow in parallel to this workflow
|
||||
# Run Dynamic validation here, to make sure we pass all the projects integration tests
|
||||
|
||||
2
.github/workflows/golangci-lint.yml
vendored
2
.github/workflows/golangci-lint.yml
vendored
@@ -9,7 +9,7 @@ on:
|
||||
pull_request:
|
||||
|
||||
env:
|
||||
COMPILER_IMAGE: stashapp/compiler:6
|
||||
COMPILER_IMAGE: stashapp/compiler:7
|
||||
|
||||
jobs:
|
||||
golangci:
|
||||
|
||||
9
.gitignore
vendored
9
.gitignore
vendored
@@ -17,12 +17,17 @@
|
||||
|
||||
# GraphQL generated output
|
||||
internal/api/generated_*.go
|
||||
ui/v2.5/src/core/generated-*.tsx
|
||||
|
||||
####
|
||||
# Jetbrains
|
||||
####
|
||||
|
||||
|
||||
####
|
||||
# Visual Studio
|
||||
####
|
||||
/.vs
|
||||
|
||||
# User-specific stuff
|
||||
.idea/**/workspace.xml
|
||||
.idea/**/tasks.xml
|
||||
@@ -56,5 +61,7 @@ node_modules
|
||||
*.db
|
||||
|
||||
/stash
|
||||
/phasher
|
||||
dist
|
||||
.DS_Store
|
||||
/.local*
|
||||
|
||||
328
Makefile
328
Makefile
@@ -7,89 +7,192 @@ ifeq (${SHELL}, cmd)
|
||||
endif
|
||||
|
||||
ifdef IS_WIN_SHELL
|
||||
SEPARATOR := &&
|
||||
SET := set
|
||||
RM := del /s /q
|
||||
RMDIR := rmdir /s /q
|
||||
else
|
||||
SEPARATOR := ;
|
||||
SET := export
|
||||
endif
|
||||
|
||||
IS_WIN_OS =
|
||||
ifeq ($(OS),Windows_NT)
|
||||
IS_WIN_OS = true
|
||||
RM := rm -f
|
||||
RMDIR := rm -rf
|
||||
endif
|
||||
|
||||
# set LDFLAGS environment variable to any extra ldflags required
|
||||
# set OUTPUT to generate a specific binary name
|
||||
|
||||
LDFLAGS := $(LDFLAGS)
|
||||
|
||||
# set OUTPUT environment variable to generate a specific binary name
|
||||
# this will apply to both `stash` and `phasher`, so build them separately
|
||||
# alternatively use STASH_OUTPUT or PHASHER_OUTPUT to set the value individually
|
||||
ifdef OUTPUT
|
||||
OUTPUT := -o $(OUTPUT)
|
||||
STASH_OUTPUT := $(OUTPUT)
|
||||
PHASHER_OUTPUT := $(OUTPUT)
|
||||
endif
|
||||
ifdef STASH_OUTPUT
|
||||
STASH_OUTPUT := -o $(STASH_OUTPUT)
|
||||
endif
|
||||
ifdef PHASHER_OUTPUT
|
||||
PHASHER_OUTPUT := -o $(PHASHER_OUTPUT)
|
||||
endif
|
||||
|
||||
export CGO_ENABLED = 1
|
||||
# set GO_BUILD_FLAGS environment variable to any extra build flags required
|
||||
GO_BUILD_FLAGS := $(GO_BUILD_FLAGS)
|
||||
|
||||
.PHONY: release pre-build
|
||||
# set GO_BUILD_TAGS environment variable to any extra build tags required
|
||||
GO_BUILD_TAGS := $(GO_BUILD_TAGS)
|
||||
GO_BUILD_TAGS += sqlite_stat4
|
||||
|
||||
release: generate ui build-release
|
||||
# set STASH_NOLEGACY environment variable or uncomment to disable legacy browser support
|
||||
# STASH_NOLEGACY := true
|
||||
|
||||
pre-build:
|
||||
# set STASH_SOURCEMAPS environment variable or uncomment to enable UI sourcemaps
|
||||
# STASH_SOURCEMAPS := true
|
||||
|
||||
export CGO_ENABLED := 1
|
||||
|
||||
.PHONY: release
|
||||
release: pre-ui generate ui build-release
|
||||
|
||||
# targets to set various build flags
|
||||
|
||||
.PHONY: flags-release
|
||||
flags-release:
|
||||
$(eval LDFLAGS += -s -w)
|
||||
$(eval GO_BUILD_FLAGS += -trimpath)
|
||||
|
||||
.PHONY: flags-pie
|
||||
flags-pie:
|
||||
$(eval GO_BUILD_FLAGS += -buildmode=pie)
|
||||
|
||||
.PHONY: flags-static
|
||||
flags-static:
|
||||
$(eval LDFLAGS += -extldflags=-static)
|
||||
$(eval GO_BUILD_TAGS += sqlite_omit_load_extension osusergo netgo)
|
||||
|
||||
.PHONY: flags-static-pie
|
||||
flags-static-pie:
|
||||
$(eval LDFLAGS += -extldflags=-static-pie)
|
||||
$(eval GO_BUILD_FLAGS += -buildmode=pie)
|
||||
$(eval GO_BUILD_TAGS += sqlite_omit_load_extension osusergo netgo)
|
||||
|
||||
.PHONY: flags-static-windows
|
||||
flags-static-windows:
|
||||
$(eval LDFLAGS += -extldflags=-static-pie)
|
||||
$(eval GO_BUILD_FLAGS += -buildmode=pie)
|
||||
$(eval GO_BUILD_TAGS += sqlite_omit_load_extension osusergo)
|
||||
|
||||
.PHONY: build-info
|
||||
build-info:
|
||||
ifndef BUILD_DATE
|
||||
$(eval BUILD_DATE := $(shell go run -mod=vendor scripts/getDate.go))
|
||||
$(eval BUILD_DATE := $(shell go run scripts/getDate.go))
|
||||
endif
|
||||
|
||||
ifndef GITHASH
|
||||
$(eval GITHASH := $(shell git rev-parse --short HEAD))
|
||||
endif
|
||||
|
||||
ifndef STASH_VERSION
|
||||
$(eval STASH_VERSION := $(shell git describe --tags --exclude latest_develop))
|
||||
endif
|
||||
|
||||
ifndef OFFICIAL_BUILD
|
||||
$(eval OFFICIAL_BUILD := false)
|
||||
$(eval OFFICIAL_BUILD := false)
|
||||
endif
|
||||
|
||||
build: pre-build
|
||||
build:
|
||||
$(eval LDFLAGS := $(LDFLAGS) -X 'github.com/stashapp/stash/internal/api.version=$(STASH_VERSION)' -X 'github.com/stashapp/stash/internal/api.buildstamp=$(BUILD_DATE)' -X 'github.com/stashapp/stash/internal/api.githash=$(GITHASH)')
|
||||
$(eval LDFLAGS := $(LDFLAGS) -X 'github.com/stashapp/stash/internal/manager/config.officialBuild=$(OFFICIAL_BUILD)')
|
||||
go build $(OUTPUT) -mod=vendor -v -tags "sqlite_omit_load_extension sqlite_stat4 osusergo netgo" $(GO_BUILD_FLAGS) -ldflags "$(LDFLAGS) $(EXTRA_LDFLAGS) $(PLATFORM_SPECIFIC_LDFLAGS)" ./cmd/stash
|
||||
.PHONY: build-flags
|
||||
build-flags: build-info
|
||||
$(eval BUILD_LDFLAGS := $(LDFLAGS))
|
||||
$(eval BUILD_LDFLAGS += -X 'github.com/stashapp/stash/internal/build.buildstamp=$(BUILD_DATE)')
|
||||
$(eval BUILD_LDFLAGS += -X 'github.com/stashapp/stash/internal/build.githash=$(GITHASH)')
|
||||
$(eval BUILD_LDFLAGS += -X 'github.com/stashapp/stash/internal/build.version=$(STASH_VERSION)')
|
||||
$(eval BUILD_LDFLAGS += -X 'github.com/stashapp/stash/internal/build.officialBuild=$(OFFICIAL_BUILD)')
|
||||
$(eval BUILD_FLAGS := -v -tags "$(GO_BUILD_TAGS)" $(GO_BUILD_FLAGS) -ldflags "$(BUILD_LDFLAGS)")
|
||||
|
||||
# strips debug symbols from the release build
|
||||
build-release: EXTRA_LDFLAGS := -s -w
|
||||
build-release: GO_BUILD_FLAGS := -trimpath
|
||||
build-release: build
|
||||
.PHONY: stash
|
||||
stash: build-flags
|
||||
go build $(STASH_OUTPUT) $(BUILD_FLAGS) ./cmd/stash
|
||||
|
||||
build-release-static: EXTRA_LDFLAGS := -extldflags=-static -s -w
|
||||
build-release-static: GO_BUILD_FLAGS := -trimpath
|
||||
build-release-static: build
|
||||
.PHONY: stash-release
|
||||
stash-release: flags-release
|
||||
stash-release: flags-pie
|
||||
stash-release: stash
|
||||
|
||||
.PHONY: stash-release-static
|
||||
stash-release-static: flags-release
|
||||
stash-release-static: flags-static-pie
|
||||
stash-release-static: stash
|
||||
|
||||
.PHONY: stash-release-static-windows
|
||||
stash-release-static-windows: flags-release
|
||||
stash-release-static-windows: flags-static-windows
|
||||
stash-release-static-windows: stash
|
||||
|
||||
.PHONY: phasher
|
||||
phasher: build-flags
|
||||
go build $(PHASHER_OUTPUT) $(BUILD_FLAGS) ./cmd/phasher
|
||||
|
||||
.PHONY: phasher-release
|
||||
phasher-release: flags-release
|
||||
phasher-release: flags-pie
|
||||
phasher-release: phasher
|
||||
|
||||
.PHONY: phasher-release-static
|
||||
phasher-release-static: flags-release
|
||||
phasher-release-static: flags-static-pie
|
||||
phasher-release-static: phasher
|
||||
|
||||
.PHONY: phasher-release-static-windows
|
||||
phasher-release-static-windows: flags-release
|
||||
phasher-release-static-windows: flags-static-windows
|
||||
phasher-release-static-windows: phasher
|
||||
|
||||
# builds dynamically-linked debug binaries
|
||||
.PHONY: build
|
||||
build: stash phasher
|
||||
|
||||
# builds dynamically-linked release binaries
|
||||
.PHONY: build-release
|
||||
build-release: stash-release phasher-release
|
||||
|
||||
# builds statically-linked release binaries
|
||||
.PHONY: build-release-static
|
||||
build-release-static: stash-release-static phasher-release-static
|
||||
|
||||
# build-release-static, but excluding netgo, which is not needed on windows
|
||||
.PHONY: build-release-static-windows
|
||||
build-release-static-windows: stash-release-static-windows phasher-release-static-windows
|
||||
|
||||
# cross-compile- targets should be run within the compiler docker container
|
||||
.PHONY: cross-compile-windows
|
||||
cross-compile-windows: export GOOS := windows
|
||||
cross-compile-windows: export GOARCH := amd64
|
||||
cross-compile-windows: export CC := x86_64-w64-mingw32-gcc
|
||||
cross-compile-windows: export CXX := x86_64-w64-mingw32-g++
|
||||
cross-compile-windows: OUTPUT := -o dist/stash-win.exe
|
||||
cross-compile-windows: build-release-static
|
||||
cross-compile-windows: STASH_OUTPUT := -o dist/stash-win.exe
|
||||
cross-compile-windows: PHASHER_OUTPUT := -o dist/phasher-win.exe
|
||||
cross-compile-windows: flags-release
|
||||
cross-compile-windows: flags-static-windows
|
||||
cross-compile-windows: build
|
||||
|
||||
.PHONY: cross-compile-macos-intel
|
||||
cross-compile-macos-intel: export GOOS := darwin
|
||||
cross-compile-macos-intel: export GOARCH := amd64
|
||||
cross-compile-macos-intel: export CC := o64-clang
|
||||
cross-compile-macos-intel: export CXX := o64-clang++
|
||||
cross-compile-macos-intel: OUTPUT := -o dist/stash-macos-intel
|
||||
cross-compile-macos-intel: STASH_OUTPUT := -o dist/stash-macos-intel
|
||||
cross-compile-macos-intel: PHASHER_OUTPUT := -o dist/phasher-macos-intel
|
||||
cross-compile-macos-intel: flags-release
|
||||
# can't use static build for OSX
|
||||
cross-compile-macos-intel: build-release
|
||||
cross-compile-macos-intel: flags-pie
|
||||
cross-compile-macos-intel: build
|
||||
|
||||
.PHONY: cross-compile-macos-applesilicon
|
||||
cross-compile-macos-applesilicon: export GOOS := darwin
|
||||
cross-compile-macos-applesilicon: export GOARCH := arm64
|
||||
cross-compile-macos-applesilicon: export CC := oa64e-clang
|
||||
cross-compile-macos-applesilicon: export CXX := oa64e-clang++
|
||||
cross-compile-macos-applesilicon: OUTPUT := -o dist/stash-macos-applesilicon
|
||||
cross-compile-macos-applesilicon: STASH_OUTPUT := -o dist/stash-macos-applesilicon
|
||||
cross-compile-macos-applesilicon: PHASHER_OUTPUT := -o dist/phasher-macos-applesilicon
|
||||
cross-compile-macos-applesilicon: flags-release
|
||||
# can't use static build for OSX
|
||||
cross-compile-macos-applesilicon: build-release
|
||||
cross-compile-macos-applesilicon: flags-pie
|
||||
cross-compile-macos-applesilicon: build
|
||||
|
||||
cross-compile-macos:
|
||||
.PHONY: cross-compile-macos
|
||||
cross-compile-macos:
|
||||
rm -rf dist/Stash.app dist/Stash-macos.zip
|
||||
make cross-compile-macos-applesilicon
|
||||
make cross-compile-macos-intel
|
||||
@@ -103,39 +206,61 @@ cross-compile-macos:
|
||||
cd dist && zip -r Stash-macos.zip Stash.app && cd ..
|
||||
rm -rf dist/Stash.app
|
||||
|
||||
.PHONY: cross-compile-freebsd
|
||||
cross-compile-freebsd: export GOOS := freebsd
|
||||
cross-compile-freebsd: export GOARCH := amd64
|
||||
cross-compile-freebsd: OUTPUT := -o dist/stash-freebsd
|
||||
cross-compile-freebsd: build-release-static
|
||||
cross-compile-freebsd: STASH_OUTPUT := -o dist/stash-freebsd
|
||||
cross-compile-freebsd: PHASHER_OUTPUT := -o dist/phasher-freebsd
|
||||
cross-compile-freebsd: flags-release
|
||||
cross-compile-freebsd: flags-static-pie
|
||||
cross-compile-freebsd: build
|
||||
|
||||
.PHONY: cross-compile-linux
|
||||
cross-compile-linux: export GOOS := linux
|
||||
cross-compile-linux: export GOARCH := amd64
|
||||
cross-compile-linux: OUTPUT := -o dist/stash-linux
|
||||
cross-compile-linux: build-release-static
|
||||
cross-compile-linux: STASH_OUTPUT := -o dist/stash-linux
|
||||
cross-compile-linux: PHASHER_OUTPUT := -o dist/phasher-linux
|
||||
cross-compile-linux: flags-release
|
||||
cross-compile-linux: flags-static-pie
|
||||
cross-compile-linux: build
|
||||
|
||||
.PHONY: cross-compile-linux-arm64v8
|
||||
cross-compile-linux-arm64v8: export GOOS := linux
|
||||
cross-compile-linux-arm64v8: export GOARCH := arm64
|
||||
cross-compile-linux-arm64v8: export CC := aarch64-linux-gnu-gcc
|
||||
cross-compile-linux-arm64v8: OUTPUT := -o dist/stash-linux-arm64v8
|
||||
cross-compile-linux-arm64v8: build-release-static
|
||||
cross-compile-linux-arm64v8: STASH_OUTPUT := -o dist/stash-linux-arm64v8
|
||||
cross-compile-linux-arm64v8: PHASHER_OUTPUT := -o dist/phasher-linux-arm64v8
|
||||
cross-compile-linux-arm64v8: flags-release
|
||||
cross-compile-linux-arm64v8: flags-static-pie
|
||||
cross-compile-linux-arm64v8: build
|
||||
|
||||
.PHONY: cross-compile-linux-arm32v7
|
||||
cross-compile-linux-arm32v7: export GOOS := linux
|
||||
cross-compile-linux-arm32v7: export GOARCH := arm
|
||||
cross-compile-linux-arm32v7: export GOARM := 7
|
||||
cross-compile-linux-arm32v7: export CC := arm-linux-gnueabihf-gcc
|
||||
cross-compile-linux-arm32v7: OUTPUT := -o dist/stash-linux-arm32v7
|
||||
cross-compile-linux-arm32v7: build-release-static
|
||||
cross-compile-linux-arm32v7: STASH_OUTPUT := -o dist/stash-linux-arm32v7
|
||||
cross-compile-linux-arm32v7: PHASHER_OUTPUT := -o dist/phasher-linux-arm32v7
|
||||
cross-compile-linux-arm32v7: flags-release
|
||||
cross-compile-linux-arm32v7: flags-static
|
||||
cross-compile-linux-arm32v7: build
|
||||
|
||||
.PHONY: cross-compile-linux-arm32v6
|
||||
cross-compile-linux-arm32v6: export GOOS := linux
|
||||
cross-compile-linux-arm32v6: export GOARCH := arm
|
||||
cross-compile-linux-arm32v6: export GOARM := 6
|
||||
cross-compile-linux-arm32v6: export CC := arm-linux-gnueabi-gcc
|
||||
cross-compile-linux-arm32v6: OUTPUT := -o dist/stash-linux-arm32v6
|
||||
cross-compile-linux-arm32v6: build-release-static
|
||||
cross-compile-linux-arm32v6: STASH_OUTPUT := -o dist/stash-linux-arm32v6
|
||||
cross-compile-linux-arm32v6: PHASHER_OUTPUT := -o dist/phasher-linux-arm32v6
|
||||
cross-compile-linux-arm32v6: flags-release
|
||||
cross-compile-linux-arm32v6: flags-static
|
||||
cross-compile-linux-arm32v6: build
|
||||
|
||||
.PHONY: cross-compile-all
|
||||
cross-compile-all:
|
||||
make cross-compile-windows
|
||||
make cross-compile-macos
|
||||
make cross-compile-macos-intel
|
||||
make cross-compile-macos-applesilicon
|
||||
make cross-compile-linux
|
||||
make cross-compile-linux-arm64v8
|
||||
make cross-compile-linux-arm32v7
|
||||
@@ -143,33 +268,34 @@ cross-compile-all:
|
||||
|
||||
.PHONY: touch-ui
|
||||
touch-ui:
|
||||
ifndef IS_WIN_SHELL
|
||||
@mkdir -p ui/v2.5/build
|
||||
@touch ui/v2.5/build/index.html
|
||||
else
|
||||
ifdef IS_WIN_SHELL
|
||||
@if not exist "ui\\v2.5\\build" mkdir ui\\v2.5\\build
|
||||
@type nul >> ui/v2.5/build/index.html
|
||||
else
|
||||
@mkdir -p ui/v2.5/build
|
||||
@touch ui/v2.5/build/index.html
|
||||
endif
|
||||
|
||||
# Regenerates GraphQL files
|
||||
generate: generate-backend generate-frontend
|
||||
.PHONY: generate
|
||||
generate: generate-backend generate-ui
|
||||
|
||||
.PHONY: generate-frontend
|
||||
generate-frontend:
|
||||
.PHONY: generate-ui
|
||||
generate-ui:
|
||||
cd ui/v2.5 && yarn run gqlgen
|
||||
|
||||
.PHONY: generate-backend
|
||||
generate-backend: touch-ui
|
||||
go generate -mod=vendor ./cmd/stash
|
||||
generate-backend: touch-ui
|
||||
go generate ./cmd/stash
|
||||
|
||||
.PHONY: generate-dataloaders
|
||||
generate-dataloaders:
|
||||
go generate -mod=vendor ./internal/api/loaders
|
||||
go generate ./internal/api/loaders
|
||||
|
||||
# Regenerates stash-box client files
|
||||
.PHONY: generate-stash-box-client
|
||||
generate-stash-box-client:
|
||||
go run -mod=vendor github.com/Yamashou/gqlgenc
|
||||
go run github.com/Yamashou/gqlgenc
|
||||
|
||||
# Runs gofmt -w on the project's source code, modifying any files that do not match its style.
|
||||
.PHONY: fmt
|
||||
@@ -183,17 +309,34 @@ lint:
|
||||
# runs unit tests - excluding integration tests
|
||||
.PHONY: test
|
||||
test:
|
||||
go test -mod=vendor ./...
|
||||
go test ./...
|
||||
|
||||
# runs all tests - including integration tests
|
||||
.PHONY: it
|
||||
it:
|
||||
go test -mod=vendor -tags=integration ./...
|
||||
go test -tags=integration ./...
|
||||
|
||||
# generates test mocks
|
||||
.PHONY: generate-test-mocks
|
||||
generate-test-mocks:
|
||||
go run -mod=vendor github.com/vektra/mockery/v2 --dir ./pkg/models --name '.*ReaderWriter' --outpkg mocks --output ./pkg/models/mocks
|
||||
go run github.com/vektra/mockery/v2 --dir ./pkg/models --name '.*ReaderWriter' --outpkg mocks --output ./pkg/models/mocks
|
||||
|
||||
# runs server
|
||||
# sets the config file to use the local dev config
|
||||
.PHONY: server-start
|
||||
server-start: export STASH_CONFIG_FILE := config.yml
|
||||
server-start: build-flags
|
||||
ifdef IS_WIN_SHELL
|
||||
@if not exist ".local" mkdir .local
|
||||
else
|
||||
@mkdir -p .local
|
||||
endif
|
||||
cd .local && go run $(BUILD_FLAGS) ../cmd/stash
|
||||
|
||||
# removes local dev config files
|
||||
.PHONY: server-clean
|
||||
server-clean:
|
||||
$(RMDIR) .local
|
||||
|
||||
# installs UI dependencies. Run when first cloning repository, or if UI
|
||||
# dependencies have changed
|
||||
@@ -201,42 +344,57 @@ generate-test-mocks:
|
||||
pre-ui:
|
||||
cd ui/v2.5 && yarn install --frozen-lockfile
|
||||
|
||||
.PHONY: ui-env
|
||||
ui-env: build-info
|
||||
$(eval export VITE_APP_DATE := $(BUILD_DATE))
|
||||
$(eval export VITE_APP_GITHASH := $(GITHASH))
|
||||
$(eval export VITE_APP_STASH_VERSION := $(STASH_VERSION))
|
||||
ifdef STASH_NOLEGACY
|
||||
$(eval export VITE_APP_NOLEGACY := true)
|
||||
endif
|
||||
ifdef STASH_SOURCEMAPS
|
||||
$(eval export VITE_APP_SOURCEMAPS := true)
|
||||
endif
|
||||
|
||||
.PHONY: ui
|
||||
ui: pre-build
|
||||
$(SET) VITE_APP_DATE="$(BUILD_DATE)" $(SEPARATOR) \
|
||||
$(SET) VITE_APP_GITHASH=$(GITHASH) $(SEPARATOR) \
|
||||
$(SET) VITE_APP_STASH_VERSION=$(STASH_VERSION) $(SEPARATOR) \
|
||||
ui: ui-env
|
||||
cd ui/v2.5 && yarn build
|
||||
|
||||
.PHONY: ui-nolegacy
|
||||
ui-nolegacy: STASH_NOLEGACY := true
|
||||
ui-nolegacy: ui
|
||||
|
||||
.PHONY: ui-sourcemaps
|
||||
ui-sourcemaps: STASH_SOURCEMAPS := true
|
||||
ui-sourcemaps: ui
|
||||
|
||||
.PHONY: ui-start
|
||||
ui-start: pre-build
|
||||
$(SET) VITE_APP_DATE="$(BUILD_DATE)" $(SEPARATOR) \
|
||||
$(SET) VITE_APP_GITHASH=$(GITHASH) $(SEPARATOR) \
|
||||
$(SET) VITE_APP_STASH_VERSION=$(STASH_VERSION) $(SEPARATOR) \
|
||||
ui-start: ui-env
|
||||
cd ui/v2.5 && yarn start --host
|
||||
|
||||
.PHONY: fmt-ui
|
||||
fmt-ui:
|
||||
cd ui/v2.5 && yarn format
|
||||
|
||||
# runs tests and checks on the UI and builds it
|
||||
.PHONY: ui-validate
|
||||
ui-validate:
|
||||
cd ui/v2.5 && yarn run validate
|
||||
|
||||
# runs all of the tests and checks required for a PR to be accepted
|
||||
.PHONY: validate
|
||||
validate: validate-frontend validate-backend
|
||||
|
||||
# runs all of the frontend PR-acceptance steps
|
||||
.PHONY: validate-frontend
|
||||
validate-frontend: ui-validate
|
||||
.PHONY: validate-ui
|
||||
validate-ui:
|
||||
cd ui/v2.5 && yarn run validate
|
||||
|
||||
# runs all of the backend PR-acceptance steps
|
||||
.PHONY: validate-backend
|
||||
validate-backend: lint it
|
||||
|
||||
# runs all of the tests and checks required for a PR to be accepted
|
||||
.PHONY: validate
|
||||
validate: validate-ui validate-backend
|
||||
|
||||
# locally builds and tags a 'stash/build' docker image
|
||||
.PHONY: docker-build
|
||||
docker-build: pre-build
|
||||
docker-build: build-info
|
||||
docker build --build-arg GITHASH=$(GITHASH) --build-arg STASH_VERSION=$(STASH_VERSION) -t stash/build -f docker/build/x86_64/Dockerfile .
|
||||
|
||||
# locally builds and tags a 'stash/cuda-build' docker image
|
||||
.PHONY: docker-cuda-build
|
||||
docker-cuda-build: build-info
|
||||
docker build --build-arg GITHASH=$(GITHASH) --build-arg STASH_VERSION=$(STASH_VERSION) -t stash/cuda-build -f docker/build/x86_64/Dockerfile-CUDA .
|
||||
|
||||
29
README.md
29
README.md
@@ -3,8 +3,13 @@ https://stashapp.cc
|
||||
|
||||
[](https://github.com/stashapp/stash/actions/workflows/build.yml)
|
||||
[](https://hub.docker.com/r/stashapp/stash 'DockerHub')
|
||||
[](https://github.com/sponsors/stashapp)
|
||||
[](https://opencollective.com/stashapp)
|
||||
[](https://goreportcard.com/report/github.com/stashapp/stash)
|
||||
[](https://matrix.to/#/#stashapp:unredacted.org)
|
||||
[](https://discord.gg/2TsNFKt)
|
||||
[](https://github.com/stashapp/stash/releases/latest)
|
||||
[](https://github.com/stashapp/stash/labels/bounty)
|
||||
|
||||
### **Stash is a self-hosted webapp written in Go which organizes and serves your porn.**
|
||||

|
||||
@@ -26,7 +31,7 @@ For further information you can [read the in-app manual](ui/v2.5/src/docs/en).
|
||||
|
||||
## First Run
|
||||
#### Windows Users: Security Prompt
|
||||
Running the app might present a security prompt since the binary isn't yet signed. Bypass this by clicking "more info" and then the "run anyway" button.
|
||||
Running the app might present a security prompt since the binary isn't yet signed. Bypass this by clicking "more info" and then the "run anyway" button.
|
||||
#### FFMPEG
|
||||
Stash requires ffmpeg. If you don't have it installed, Stash will download a copy for you. It is recommended that Linux users install `ffmpeg` from their distro's package manager.
|
||||
|
||||
@@ -39,32 +44,32 @@ On first run, Stash will prompt you for some configuration options and media dir
|
||||
|
||||
Stash can pull metadata (performers, tags, descriptions, studios, and more) directly from many sites through the use of [scrapers](https://github.com/stashapp/stash/tree/develop/ui/v2.5/src/docs/en/Scraping.md), which integrate directly into Stash.
|
||||
|
||||
Many community-maintained scrapers are available for download at the [Community Scrapers Collection](https://github.com/stashapp/CommunityScrapers). The community also maintains StashDB, a crowd-sourced repository of scene, studio, and performer information, that can automatically identify much of a typical media collection. Inquire in the Discord for details. Identifying an entire collection will typically require a mix of multiple sources.
|
||||
Many community-maintained scrapers are available for download from [CommunityScrapers repository](https://github.com/stashapp/CommunityScrapers). The community also maintains StashDB, a crowd-sourced repository of scene, studio, and performer information, that can automatically identify much of a typical media collection. Inquire in the Discord for details. Identifying an entire collection will typically require a mix of multiple sources.
|
||||
|
||||
<sub>StashDB is the canonical instance of our open source metadata API, [stash-box](https://github.com/stashapp/stash-box).</sub>
|
||||
<sub>[StashDB](http://stashdb.org) is the canonical instance of our open source metadata API, [stash-box](https://github.com/stashapp/stash-box).</sub>
|
||||
|
||||
# Translation
|
||||
[](https://translate.stashapp.cc/engage/stash/)
|
||||
🇧🇷 🇨🇳 🇩🇰 🇳🇱 🇬🇧 🇫🇮 🇫🇷 🇩🇪 🇮🇹 🇯🇵 🇰🇷 🇵🇱 🇪🇸 🇸🇪 🇹🇼 🇹🇷
|
||||
🇧🇷 🇨🇳 🇩🇰 🇳🇱 🇬🇧 🇪🇪 🇫🇮 🇫🇷 🇩🇪 🇮🇹 🇯🇵 🇰🇷 🇵🇱 🇷🇺 🇪🇸 🇸🇪 🇹🇼 🇹🇷
|
||||
|
||||
Stash is available in 16 languages (so far!) and it could be in your language too. If you want to help us translate Stash into your language, you can make an account at [translate.stashapp.cc](https://translate.stashapp.cc/projects/stash/stash-desktop-client/) to get started contributing new languages or improving existing ones. Thanks!
|
||||
Stash is available in 25 languages (so far!) and it could be in your language too. If you want to help us translate Stash into your language, you can make an account at [translate.stashapp.cc](https://translate.stashapp.cc/projects/stash/stash-desktop-client/) to get started contributing new languages or improving existing ones. Thanks!
|
||||
|
||||
# Support (FAQ)
|
||||
|
||||
Answers to other Frequently Asked Questions can be found [on our Wiki](https://github.com/stashapp/stash/wiki/FAQ)
|
||||
Check out our documentation on [Stash-Docs](https://docs.stashapp.cc) for information about the software, questions, guides, add-ons and more.
|
||||
|
||||
For issues not addressed there, there are a few options.
|
||||
|
||||
* Read the [Wiki](https://github.com/stashapp/stash/wiki)
|
||||
* Check the in-app documentation, in the top right corner of the app (also available [here](https://github.com/stashapp/stash/tree/develop/ui/v2.5/src/docs/en)
|
||||
For more help you can:
|
||||
* Check the in-app documentation, in the top right corner of the app (it's also mirrored on [Stash-Docs](https://docs.stashapp.cc/in-app-manual))
|
||||
* Join the [Matrix space](https://matrix.to/#/#stashapp:unredacted.org)
|
||||
* Join the [Discord server](https://discord.gg/2TsNFKt), where the community can offer support.
|
||||
* Start a [discussion on GitHub](https://github.com/stashapp/stash/discussions)
|
||||
|
||||
# Customization
|
||||
|
||||
## Themes and CSS Customization
|
||||
There is a [directory of community-created themes](https://github.com/stashapp/stash/wiki/Themes) on our Wiki, along with instructions on how to install them.
|
||||
There is a [directory of community-created themes](https://docs.stashapp.cc/user-interface-ui/themes) on Stash-Docs, along with instructions on how to install them.
|
||||
|
||||
You can also make Stash interface fit your desired style with [Custom CSS snippets](https://github.com/stashapp/stash/wiki/Custom-CSS-snippets).
|
||||
You can also change the Stash interface to fit your desired style with various snippets from [Custom CSS snippets](https://docs.stashapp.cc/user-interface-ui/custom-css-snippets).
|
||||
|
||||
# For Developers
|
||||
|
||||
|
||||
83
cmd/phasher/main.go
Normal file
83
cmd/phasher/main.go
Normal file
@@ -0,0 +1,83 @@
|
||||
// TODO: document in README.md
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
flag "github.com/spf13/pflag"
|
||||
"github.com/stashapp/stash/pkg/ffmpeg"
|
||||
"github.com/stashapp/stash/pkg/file"
|
||||
"github.com/stashapp/stash/pkg/hash/videophash"
|
||||
)
|
||||
|
||||
func customUsage() {
|
||||
fmt.Fprintf(os.Stderr, "Usage:\n")
|
||||
fmt.Fprintf(os.Stderr, "%s [OPTIONS] VIDEOFILE...\n\nOptions:\n", os.Args[0])
|
||||
flag.PrintDefaults()
|
||||
}
|
||||
|
||||
func printPhash(ff *ffmpeg.FFMpeg, ffp ffmpeg.FFProbe, inputfile string, quiet *bool) error {
|
||||
ffvideoFile, err := ffp.NewVideoFile(inputfile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// All we need for videophash.Generate() is
|
||||
// videoFile.Path (from BaseFile)
|
||||
// videoFile.Duration
|
||||
// The rest of the struct isn't needed.
|
||||
vf := &file.VideoFile{
|
||||
BaseFile: &file.BaseFile{Path: inputfile},
|
||||
Duration: ffvideoFile.FileDuration,
|
||||
}
|
||||
|
||||
phash, err := videophash.Generate(ff, vf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if *quiet {
|
||||
fmt.Printf("%x\n", *phash)
|
||||
} else {
|
||||
fmt.Printf("%x %v\n", *phash, vf.Path)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
flag.Usage = customUsage
|
||||
quiet := flag.BoolP("quiet", "q", false, "print only the phash")
|
||||
help := flag.BoolP("help", "h", false, "print this help output")
|
||||
flag.Parse()
|
||||
|
||||
if *help {
|
||||
flag.Usage()
|
||||
os.Exit(2)
|
||||
}
|
||||
|
||||
args := flag.Args()
|
||||
|
||||
if len(args) < 1 {
|
||||
fmt.Fprintf(os.Stderr, "Missing VIDEOFILE argument.\n")
|
||||
flag.Usage()
|
||||
os.Exit(2)
|
||||
}
|
||||
|
||||
if len(args) > 1 {
|
||||
fmt.Fprintln(os.Stderr, "Files will be processed sequentially! Consier using GNU Parallel.")
|
||||
fmt.Fprintf(os.Stderr, "Example: parallel %v ::: *.mp4\n", os.Args[0])
|
||||
}
|
||||
|
||||
ffmpegPath, ffprobePath := ffmpeg.GetPaths(nil)
|
||||
encoder := ffmpeg.NewEncoder(ffmpegPath)
|
||||
encoder.InitHWSupport(context.TODO())
|
||||
ffprobe := ffmpeg.FFProbe(ffprobePath)
|
||||
|
||||
for _, item := range args {
|
||||
if err := printPhash(encoder, ffprobe, item, quiet); err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -34,7 +34,7 @@ func main() {
|
||||
}()
|
||||
|
||||
go handleSignals()
|
||||
desktop.Start(manager.GetInstance(), &manager.FaviconProvider{UIBox: ui.UIBox})
|
||||
desktop.Start(manager.GetInstance(), &ui.FaviconProvider)
|
||||
|
||||
blockForever()
|
||||
}
|
||||
|
||||
@@ -2,21 +2,21 @@
|
||||
|
||||
# Build Frontend
|
||||
FROM node:alpine as frontend
|
||||
RUN apk add --no-cache make
|
||||
RUN apk add --no-cache make git
|
||||
## cache node_modules separately
|
||||
COPY ./ui/v2.5/package.json ./ui/v2.5/yarn.lock /stash/ui/v2.5/
|
||||
WORKDIR /stash
|
||||
RUN yarn --cwd ui/v2.5 install --frozen-lockfile.
|
||||
COPY Makefile /stash/
|
||||
COPY ./graphql /stash/graphql/
|
||||
COPY ./ui /stash/ui/
|
||||
RUN make generate-frontend
|
||||
RUN make pre-ui
|
||||
RUN make generate-ui
|
||||
ARG GITHASH
|
||||
ARG STASH_VERSION
|
||||
RUN BUILD_DATE=$(date +"%Y-%m-%d %H:%M:%S") make ui
|
||||
|
||||
# Build Backend
|
||||
FROM golang:1.17-alpine as backend
|
||||
FROM golang:1.19-alpine as backend
|
||||
RUN apk add --no-cache make alpine-sdk
|
||||
WORKDIR /stash
|
||||
COPY ./go* ./*.go Makefile gqlgen.yml .gqlgenc.yml /stash/
|
||||
@@ -29,7 +29,7 @@ COPY --from=frontend /stash /stash/
|
||||
RUN make generate-backend
|
||||
ARG GITHASH
|
||||
ARG STASH_VERSION
|
||||
RUN make build
|
||||
RUN make stash-release
|
||||
|
||||
# Final Runnable Image
|
||||
FROM alpine:latest
|
||||
|
||||
51
docker/build/x86_64/Dockerfile-CUDA
Normal file
51
docker/build/x86_64/Dockerfile-CUDA
Normal file
@@ -0,0 +1,51 @@
|
||||
# This dockerfile should be built with `make docker-cuda-build` from the stash root.
|
||||
|
||||
# Build Frontend
|
||||
FROM node:alpine as frontend
|
||||
RUN apk add --no-cache make git
|
||||
## cache node_modules separately
|
||||
COPY ./ui/v2.5/package.json ./ui/v2.5/yarn.lock /stash/ui/v2.5/
|
||||
WORKDIR /stash
|
||||
COPY Makefile /stash/
|
||||
COPY ./graphql /stash/graphql/
|
||||
COPY ./ui /stash/ui/
|
||||
RUN make pre-ui
|
||||
RUN make generate-ui
|
||||
ARG GITHASH
|
||||
ARG STASH_VERSION
|
||||
RUN BUILD_DATE=$(date +"%Y-%m-%d %H:%M:%S") make ui
|
||||
|
||||
# Build Backend
|
||||
FROM golang:1.19-bullseye as backend
|
||||
RUN apt update && apt install -y build-essential golang
|
||||
WORKDIR /stash
|
||||
COPY ./go* ./*.go Makefile gqlgen.yml .gqlgenc.yml /stash/
|
||||
COPY ./scripts /stash/scripts/
|
||||
COPY ./vendor /stash/vendor/
|
||||
COPY ./pkg /stash/pkg/
|
||||
COPY ./cmd /stash/cmd
|
||||
COPY ./internal /stash/internal
|
||||
COPY --from=frontend /stash /stash/
|
||||
RUN make generate-backend
|
||||
ARG GITHASH
|
||||
ARG STASH_VERSION
|
||||
RUN make stash-release
|
||||
|
||||
# Final Runnable Image
|
||||
FROM nvidia/cuda:12.0.1-base-ubuntu22.04
|
||||
RUN apt update && apt upgrade -y && apt install -y ca-certificates libvips-tools ffmpeg wget intel-media-va-driver-non-free vainfo
|
||||
RUN rm -rf /var/lib/apt/lists/*
|
||||
COPY --from=backend /stash/stash /usr/bin/
|
||||
|
||||
# NVENC Patch
|
||||
RUN mkdir -p /usr/local/bin /patched-lib
|
||||
RUN wget https://raw.githubusercontent.com/keylase/nvidia-patch/master/patch.sh -O /usr/local/bin/patch.sh
|
||||
RUN wget https://raw.githubusercontent.com/keylase/nvidia-patch/master/docker-entrypoint.sh -O /usr/local/bin/docker-entrypoint.sh
|
||||
RUN chmod +x /usr/local/bin/patch.sh /usr/local/bin/docker-entrypoint.sh /usr/bin/stash
|
||||
|
||||
ENV LANG C.UTF-8
|
||||
ENV NVIDIA_VISIBLE_DEVICES all
|
||||
ENV NVIDIA_DRIVER_CAPABILITIES=video,utility
|
||||
ENV STASH_CONFIG_FILE=/root/.stash/config.yml
|
||||
EXPOSE 9999
|
||||
ENTRYPOINT ["docker-entrypoint.sh", "stash"]
|
||||
@@ -11,8 +11,11 @@ RUN if [ "$TARGETPLATFORM" = "linux/arm/v6" ]; then BIN=stash-linux-arm32v6; \
|
||||
|
||||
FROM --platform=$TARGETPLATFORM alpine:latest AS app
|
||||
COPY --from=binary /stash /usr/bin/
|
||||
RUN apk add --no-cache ca-certificates python3 py3-requests py3-requests-toolbelt py3-lxml py3-pip ffmpeg vips-tools ruby && pip install --no-cache-dir mechanicalsoup cloudscraper && gem install faraday
|
||||
RUN ln -s /usr/bin/python3 /usr/bin/python
|
||||
RUN apk add --no-cache --virtual .build-deps gcc python3-dev musl-dev \
|
||||
&& apk add --no-cache ca-certificates python3 py3-requests py3-requests-toolbelt py3-lxml py3-pip ffmpeg vips-tools ruby tzdata \
|
||||
&& pip install mechanicalsoup cloudscraper bencoder.pyx \
|
||||
&& gem install faraday \
|
||||
&& apk del .build-deps
|
||||
ENV STASH_CONFIG_FILE=/root/.stash/config.yml
|
||||
|
||||
EXPOSE 9999
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM golang:1.17
|
||||
FROM golang:1.19
|
||||
|
||||
LABEL maintainer="https://discord.gg/2TsNFKt"
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
user=stashapp
|
||||
repo=compiler
|
||||
version=6
|
||||
version=7
|
||||
|
||||
latest:
|
||||
docker build -t ${user}/${repo}:latest .
|
||||
|
||||
@@ -36,5 +36,7 @@ services:
|
||||
- ./metadata:/metadata
|
||||
## Any other cache content.
|
||||
- ./cache:/cache
|
||||
## Where to store binary blob data (scene covers, images)
|
||||
- ./blobs:/blobs
|
||||
## Where to store generated content (screenshots,previews,transcodes,sprites)
|
||||
- ./generated:/generated
|
||||
|
||||
@@ -6,46 +6,94 @@
|
||||
* [GolangCI](https://golangci-lint.run/) - A meta-linter which runs several linters in parallel
|
||||
* To install, follow the [local installation instructions](https://golangci-lint.run/usage/install/#local-installation)
|
||||
* [Yarn](https://yarnpkg.com/en/docs/install) - Yarn package manager
|
||||
* Run `yarn install --frozen-lockfile` in the `stash/ui/v2.5` folder (before running make generate for first time).
|
||||
|
||||
NOTE: You may need to run the `go get` commands outside the project directory to avoid modifying the projects module file.
|
||||
|
||||
## Environment
|
||||
|
||||
### Windows
|
||||
|
||||
1. Download and install [Go for Windows](https://golang.org/dl/)
|
||||
2. Download and extract [MingW64](https://sourceforge.net/projects/mingw-w64/files/) (scroll down and select x86_64-posix-seh, dont use the autoinstaller it doesnt work)
|
||||
3. Search for "advanced system settings" and open the system properties dialog.
|
||||
2. Download and extract [MinGW64](https://sourceforge.net/projects/mingw-w64/files/) (scroll down and select x86_64-posix-seh, don't use the autoinstaller, it doesn't work)
|
||||
3. Search for "Advanced System Settings" and open the System Properties dialog.
|
||||
1. Click the `Environment Variables` button
|
||||
2. Under system variables find the `Path`. Edit and add `C:\MinGW\bin` (replace with the correct path to where you extracted MingW64).
|
||||
2. Under System Variables find `Path`. Edit and add `C:\MinGW\bin` (replace with the correct path to where you extracted MingW64).
|
||||
|
||||
NOTE: The `make` command in Windows will be `mingw32-make` with MingW. For example `make pre-ui` will be `mingw32-make pre-ui`
|
||||
NOTE: The `make` command in Windows will be `mingw32-make` with MinGW. For example, `make pre-ui` will be `mingw32-make pre-ui`.
|
||||
|
||||
### macOS
|
||||
|
||||
1. If you don't have it already, install the [Homebrew package manager](https://brew.sh).
|
||||
2. Install dependencies: `brew install go git yarn gcc make`
|
||||
2. Install dependencies: `brew install go git yarn gcc make node ffmpeg`
|
||||
|
||||
### Linux
|
||||
|
||||
#### Arch Linux
|
||||
|
||||
1. Install dependencies: `sudo pacman -S go git yarn gcc make nodejs ffmpeg --needed`
|
||||
|
||||
#### Ubuntu
|
||||
|
||||
1. Install dependencies: `sudo apt-get install golang git gcc nodejs ffmpeg -y`
|
||||
2. Enable corepack in Node.js: `corepack enable`
|
||||
3. Install yarn: `corepack prepare yarn@stable --activate`
|
||||
|
||||
## Commands
|
||||
|
||||
* `make pre-ui` - Installs the UI dependencies. Only needs to be run once before building the UI for the first time, or if the dependencies are updated
|
||||
* `make generate` - Generate Go and UI GraphQL files
|
||||
* `make fmt-ui` - Formats the UI source code
|
||||
* `make ui` - Builds the frontend
|
||||
* `make build` - Builds the binary (make sure to build the UI as well... see below)
|
||||
* `make pre-ui` - Installs the UI dependencies. This only needs to be run once after cloning the repository, or if the dependencies are updated.
|
||||
* `make generate` - Generates Go and UI GraphQL files. Requires `make pre-ui` to have been run.
|
||||
* `make generate-stash-box-client` - Generate Go files for the Stash-box client code.
|
||||
* `make ui` - Builds the UI. Requires `make pre-ui` to have been run.
|
||||
* `make stash` - Builds the `stash` binary (make sure to build the UI as well... see below)
|
||||
* `make stash-release` - Builds a release version the `stash` binary, with debug information removed
|
||||
* `make phasher` - Builds the `phasher` binary
|
||||
* `make phasher-release` - Builds a release version the `phasher` binary, with debug information removed
|
||||
* `make build` - Builds both the `stash` and `phasher` binaries
|
||||
* `make build-release` - Builds release versions of both the `stash` and `phasher` binaries
|
||||
* `make docker-build` - Locally builds and tags a complete 'stash/build' docker image
|
||||
* `make lint` - Run the linter on the backend
|
||||
* `make fmt` - Run `go fmt`
|
||||
* `make it` - Run the unit and integration tests
|
||||
* `make validate` - Run all of the tests and checks required to submit a PR
|
||||
* `make ui-start` - Runs the UI in development mode. Requires a running stash server to connect to. Stash server port can be changed from the default of `9999` using environment variable `VITE_APP_PLATFORM_PORT`. UI runs on port `3000` or the next available port.
|
||||
* `make docker-cuda-build` - Locally builds and tags a complete 'stash/cuda-build' docker image
|
||||
* `make validate` - Runs all of the tests and checks required to submit a PR
|
||||
* `make lint` - Runs `golangci-lint` on the backend
|
||||
* `make it` - Runs all unit and integration tests
|
||||
* `make fmt` - Formats the Go source code
|
||||
* `make fmt-ui` - Formats the UI source code
|
||||
* `make server-start` - Runs a development stash server in the `.local` directory
|
||||
* `make server-clean` - Removes the `.local` directory and all of its contents
|
||||
* `make ui-start` - Runs the UI in development mode. Requires a running Stash server to connect to. The server port can be changed from the default of `9999` using the environment variable `VITE_APP_PLATFORM_PORT`. The UI runs on port `3000` or the next available port.
|
||||
|
||||
## Local development quickstart
|
||||
|
||||
1. Run `make pre-ui` to install UI dependencies
|
||||
2. Run `make generate` to create generated files
|
||||
3. In one terminal, run `make server-start` to run the server code
|
||||
4. In a separate terminal, run `make ui-start` to run the UI in development mode
|
||||
5. Open the UI in a browser: `http://localhost:3000/`
|
||||
|
||||
Changes to the UI code can be seen by reloading the browser page.
|
||||
|
||||
Changes to the backend code require a server restart (`CTRL-C` in the server terminal, followed by `make server-start` again) to be seen.
|
||||
|
||||
On first launch:
|
||||
|
||||
1. On the "Stash Setup Wizard" screen, choose a directory with some files to test with
|
||||
2. Press "Next" to use the default locations for the database and generated content
|
||||
3. Press the "Confirm" and "Finish" buttons to get into the UI
|
||||
4. On the side menu, navigate to "Tasks -> Library -> Scan" and press the "Scan" button
|
||||
5. You're all set! Set any other configurations you'd like and test your code changes.
|
||||
|
||||
To start fresh with new configuration:
|
||||
|
||||
1. Stop the server (`CTRL-C` in the server terminal)
|
||||
2. Run `make server-clean` to clear all config, database, and generated files (under `.local`)
|
||||
3. Run `make server-start` to restart the server
|
||||
4. Follow the "On first launch" steps above
|
||||
|
||||
## Building a release
|
||||
|
||||
1. Run `make generate` to create generated files
|
||||
2. Run `make ui` to compile the frontend
|
||||
3. Run `make build` to build the executable for your current platform
|
||||
Simply run `make` or `make release`, or equivalently:
|
||||
|
||||
1. Run `make pre-ui` to install UI dependencies
|
||||
2. Run `make generate` to create generated files
|
||||
3. Run `make ui` to build the frontend
|
||||
4. Run `make build-release` to build a release executable for your current platform
|
||||
|
||||
## Cross compiling
|
||||
|
||||
|
||||
34
go.mod
34
go.mod
@@ -9,13 +9,13 @@ require (
|
||||
github.com/chromedp/chromedp v0.7.3
|
||||
github.com/corona10/goimagehash v1.0.3
|
||||
github.com/disintegration/imaging v1.6.0
|
||||
github.com/fvbommel/sortorder v1.0.2
|
||||
github.com/go-chi/chi v4.0.2+incompatible
|
||||
github.com/gofrs/uuid v4.4.0+incompatible
|
||||
github.com/golang-jwt/jwt/v4 v4.0.0
|
||||
github.com/golang-migrate/migrate/v4 v4.15.0-beta.1
|
||||
github.com/gorilla/securecookie v1.1.1
|
||||
github.com/gorilla/sessions v1.2.0
|
||||
github.com/gorilla/websocket v1.4.2
|
||||
github.com/gorilla/websocket v1.5.0
|
||||
github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a
|
||||
github.com/jmoiron/sqlx v1.3.1
|
||||
github.com/json-iterator/go v1.1.12
|
||||
@@ -24,30 +24,31 @@ require (
|
||||
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8
|
||||
github.com/remeh/sizedwaitgroup v1.0.0
|
||||
github.com/robertkrimen/otto v0.0.0-20200922221731-ef014fd054ac
|
||||
github.com/rs/cors v1.6.0
|
||||
github.com/shurcooL/graphql v0.0.0-20181231061246-d48a9a75455f
|
||||
github.com/sirupsen/logrus v1.8.1
|
||||
github.com/spf13/afero v1.8.2 // indirect
|
||||
github.com/spf13/pflag v1.0.5
|
||||
github.com/spf13/viper v1.10.1
|
||||
github.com/stretchr/testify v1.7.0
|
||||
github.com/stretchr/testify v1.7.1
|
||||
github.com/tidwall/gjson v1.9.3
|
||||
github.com/tidwall/pretty v1.2.0 // indirect
|
||||
github.com/vektra/mockery/v2 v2.10.0
|
||||
golang.org/x/crypto v0.0.0-20220321153916-2c7772ba3064
|
||||
golang.org/x/image v0.0.0-20210220032944-ac19c3e999fb
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b
|
||||
golang.org/x/sys v0.0.0-20220808155132-1c4a2a72c664
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211
|
||||
golang.org/x/text v0.3.7
|
||||
golang.org/x/image v0.5.0
|
||||
golang.org/x/net v0.7.0
|
||||
golang.org/x/sys v0.5.0
|
||||
golang.org/x/term v0.5.0
|
||||
golang.org/x/text v0.7.0
|
||||
golang.org/x/tools v0.1.12 // indirect
|
||||
gopkg.in/sourcemap.v1 v1.0.5 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/WithoutPants/sortorder v0.0.0-20230616003020-921c9ef69552
|
||||
github.com/asticode/go-astisub v0.20.0
|
||||
github.com/doug-martin/goqu/v9 v9.18.0
|
||||
github.com/go-chi/cors v1.2.1
|
||||
github.com/go-chi/httplog v0.2.1
|
||||
github.com/go-toast/toast v0.0.0-20190211030409-01e6764cf0a4
|
||||
github.com/hashicorp/golang-lru v0.5.4
|
||||
@@ -57,7 +58,9 @@ require (
|
||||
github.com/spf13/cast v1.4.1
|
||||
github.com/vearutop/statigz v1.1.6
|
||||
github.com/vektah/dataloaden v0.3.0
|
||||
github.com/vektah/gqlparser/v2 v2.4.1
|
||||
github.com/vektah/gqlparser/v2 v2.4.2
|
||||
github.com/xWTF/chardet v0.0.0-20230208095535-c780f2ac244e
|
||||
github.com/zencoder/go-dash/v3 v3.0.2
|
||||
gopkg.in/guregu/null.v4 v4.0.0
|
||||
)
|
||||
|
||||
@@ -82,9 +85,9 @@ require (
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/magiconair/properties v1.8.6 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/matryer/moq v0.2.6 // indirect
|
||||
github.com/matryer/moq v0.2.3 // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||
github.com/mitchellh/mapstructure v1.4.3 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect
|
||||
@@ -99,13 +102,14 @@ require (
|
||||
github.com/stretchr/objx v0.2.0 // indirect
|
||||
github.com/subosito/gotenv v1.2.0 // indirect
|
||||
github.com/tidwall/match v1.1.1 // indirect
|
||||
github.com/urfave/cli/v2 v2.4.0 // indirect
|
||||
github.com/urfave/cli/v2 v2.8.1 // indirect
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
|
||||
go.uber.org/atomic v1.7.0 // indirect
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
|
||||
gopkg.in/ini.v1 v1.66.4 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
||||
replace git.apache.org/thrift.git => github.com/apache/thrift v0.0.0-20180902110319-2566ecd5d999
|
||||
|
||||
go 1.17
|
||||
go 1.19
|
||||
|
||||
57
go.sum
57
go.sum
@@ -71,6 +71,8 @@ github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3
|
||||
github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/RoaringBitmap/roaring v0.4.7/go.mod h1:8khRDP4HmeXns4xIj9oGrKSz7XTQiJx2zgh7AcNke4w=
|
||||
github.com/WithoutPants/sortorder v0.0.0-20230616003020-921c9ef69552 h1:eukVk+mGmbSZppLw8WJGpEUgMC570eb32y7FOsPW4Kc=
|
||||
github.com/WithoutPants/sortorder v0.0.0-20230616003020-921c9ef69552/go.mod h1:LKbO1i6L1lSlwWx4NHWVECxubHNKFz2YQoEMGXAFVy8=
|
||||
github.com/Yamashou/gqlgenc v0.0.6 h1:wfMTtuVSrX2N1z5/ssecxx+E7l1fa0FOq5mwFW47oY4=
|
||||
github.com/Yamashou/gqlgenc v0.0.6/go.mod h1:WOXjogecRGpD1WKgxnnyHJo0/Dxn44p/LNRoE6mtFQo=
|
||||
github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM=
|
||||
@@ -233,8 +235,6 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo
|
||||
github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI=
|
||||
github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU=
|
||||
github.com/fsouza/fake-gcs-server v1.17.0/go.mod h1:D1rTE4YCyHFNa99oyJJ5HyclvN/0uQR+pM/VdlL83bw=
|
||||
github.com/fvbommel/sortorder v1.0.2 h1:mV4o8B2hKboCdkJm+a7uX/SIpZob4JzUpc5GGnM45eo=
|
||||
github.com/fvbommel/sortorder v1.0.2/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE=
|
||||
github.com/glycerine/goconvey v0.0.0-20180728074245-46e3a41ad493/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24=
|
||||
@@ -242,6 +242,8 @@ github.com/go-chi/chi v4.0.2+incompatible h1:maB6vn6FqCxrpz4FqWdh4+lwpyZIQS7YEAU
|
||||
github.com/go-chi/chi v4.0.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
|
||||
github.com/go-chi/chi/v5 v5.0.0 h1:DBPx88FjZJH3FsICfDAfIfnb7XxKIYVGG6lOPlhENAg=
|
||||
github.com/go-chi/chi/v5 v5.0.0/go.mod h1:BBug9lr0cqtdAhsu6R4AAdvufI0/XBzAQSsUqJpoZOs=
|
||||
github.com/go-chi/cors v1.2.1 h1:xEC8UT3Rlp2QuWNEr4Fs/c2EAGVKBwy/1vHx3bppil4=
|
||||
github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58=
|
||||
github.com/go-chi/httplog v0.2.1 h1:KgCtIUkYNlfIsUPzE3utxd1KDKOvCrnAKaqdo0rmrh0=
|
||||
github.com/go-chi/httplog v0.2.1/go.mod h1:JyHOFO9twSfGoTin/RoP25Lx2a9Btq10ug+sgxe0+bo=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
@@ -293,6 +295,8 @@ github.com/gocql/gocql v0.0.0-20190301043612-f6df8288f9b4/go.mod h1:4Fw1eo5iaEhD
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||
github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA=
|
||||
github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang-jwt/jwt/v4 v4.0.0 h1:RAqyYixv1p7uEnocuy8P1nru5wprCh/MH2BIlW5z5/o=
|
||||
@@ -396,8 +400,9 @@ github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyC
|
||||
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
|
||||
github.com/gorilla/sessions v1.2.0 h1:S7P+1Hm5V/AT9cjEcUD5uDaQSX0OE577aCXgoaKpYbQ=
|
||||
github.com/gorilla/sessions v1.2.0/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
|
||||
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
|
||||
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
||||
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4=
|
||||
github.com/hashicorp/consul/api v1.11.0/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M=
|
||||
@@ -555,9 +560,8 @@ github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJ
|
||||
github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE=
|
||||
github.com/markbates/pkger v0.15.1/go.mod h1:0JoVlrol20BSywW79rN3kdFFsE5xYM+rSCQDXbLhiuI=
|
||||
github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0=
|
||||
github.com/matryer/moq v0.2.3 h1:Q06vEqnBYjjfx5KKgHfYRKE/lvlRu+Nj+xodG4YdHnU=
|
||||
github.com/matryer/moq v0.2.3/go.mod h1:9RtPYjTnH1bSBIkpvtHkFN7nbWAnO7oRpdJkEIn6UtE=
|
||||
github.com/matryer/moq v0.2.6 h1:X4+LF09udTsi2P+Z+1UhSb4p3K8IyiF7KSNFDR9M3M0=
|
||||
github.com/matryer/moq v0.2.6/go.mod h1:kITsx543GOENm48TUAQyJ9+SAvFSr7iGQXPoth/VUBk=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
|
||||
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
@@ -591,8 +595,9 @@ github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:F
|
||||
github.com/mitchellh/mapstructure v0.0.0-20180220230111-00c29f56e238/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v1.2.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/mitchellh/mapstructure v1.4.3 h1:OVowDSCllw/YjdLkam3/sm7wEtOy59d8ndGgCcyj8cs=
|
||||
github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
@@ -667,8 +672,6 @@ github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6L
|
||||
github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rs/cors v1.6.0 h1:G9tHG9lebljV9mfp9SNPDL36nCDxmo3zTlAf1YgvzmI=
|
||||
github.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
|
||||
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
|
||||
github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
||||
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
|
||||
@@ -700,7 +703,6 @@ github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6Mwd
|
||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
|
||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s=
|
||||
github.com/snowflakedb/gosnowflake v1.4.3/go.mod h1:1kyg2XEduwti88V11PKRHImhXLK5WpGiayY6lFNYb98=
|
||||
@@ -735,8 +737,9 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
|
||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||
github.com/tidwall/gjson v1.9.3 h1:hqzS9wAHMO+KVBBkLxYdkEeeFHuqr95GfClRLKlgK0E=
|
||||
@@ -749,22 +752,27 @@ github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhso
|
||||
github.com/tinylib/msgp v1.0.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
|
||||
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
|
||||
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
|
||||
github.com/urfave/cli/v2 v2.4.0 h1:m2pxjjDFgDxSPtO8WSdbndj17Wu2y8vOT86wE/tjr+I=
|
||||
github.com/urfave/cli/v2 v2.4.0/go.mod h1:NX9W0zmTvedE5oDoOMs2RTC8RvdK98NTYZE5LbaEYPg=
|
||||
github.com/urfave/cli/v2 v2.8.1 h1:CGuYNZF9IKZY/rfBe3lJpccSoIY1ytfvmgQT90cNOl4=
|
||||
github.com/urfave/cli/v2 v2.8.1/go.mod h1:Z41J9TPoffeoqP0Iza0YbAhGvymRdZAd2uPmZ5JxRdY=
|
||||
github.com/vearutop/statigz v1.1.6 h1:si1zvulh/6P4S/SjFticuKQ8/EgQISglaRuycj8PWso=
|
||||
github.com/vearutop/statigz v1.1.6/go.mod h1:czAv7iXgPv/s+xsgXpVEhhD0NSOQ4wZPgmM/n7LANDI=
|
||||
github.com/vektah/dataloaden v0.3.0 h1:ZfVN2QD6swgvp+tDqdH/OIT/wu3Dhu0cus0k5gIZS84=
|
||||
github.com/vektah/dataloaden v0.3.0/go.mod h1:/HUdMve7rvxZma+2ZELQeNh88+003LL7Pf/CZ089j8U=
|
||||
github.com/vektah/gqlparser/v2 v2.4.0/go.mod h1:flJWIR04IMQPGz+BXLrORkrARBxv/rtyIAFvd/MceW0=
|
||||
github.com/vektah/gqlparser/v2 v2.4.1 h1:QOyEn8DAPMUMARGMeshKDkDgNmVoEaEGiDB0uWxcSlQ=
|
||||
github.com/vektah/gqlparser/v2 v2.4.1/go.mod h1:flJWIR04IMQPGz+BXLrORkrARBxv/rtyIAFvd/MceW0=
|
||||
github.com/vektah/gqlparser/v2 v2.4.2 h1:29TGc6QmhEUq5fll+2FPoTmhUhR65WEKN4VK/jo0OlM=
|
||||
github.com/vektah/gqlparser/v2 v2.4.2/go.mod h1:flJWIR04IMQPGz+BXLrORkrARBxv/rtyIAFvd/MceW0=
|
||||
github.com/vektra/mockery/v2 v2.10.0 h1:MiiQWxwdq7/ET6dCXLaJzSGEN17k758H7JHS9kOdiks=
|
||||
github.com/vektra/mockery/v2 v2.10.0/go.mod h1:m/WO2UzWzqgVX3nvqpRQq70I4Z7jbSCRhdmkgtp+Ab4=
|
||||
github.com/willf/bitset v1.1.9/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
|
||||
github.com/xWTF/chardet v0.0.0-20230208095535-c780f2ac244e h1:GruPsb+44XvYAzuAgJW1d1WHqmcI73L2XSjsbx/eJZw=
|
||||
github.com/xWTF/chardet v0.0.0-20230208095535-c780f2ac244e/go.mod h1:wA8kQ8WFipMciY9WcWzqQgZordm/P7l8IZdvx1crwmc=
|
||||
github.com/xanzy/go-gitlab v0.15.0/go.mod h1:8zdQa/ri1dfn8eS3Ir1SyfvOKlw7WBJ8DVThkpGiXrs=
|
||||
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
|
||||
github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs=
|
||||
github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM=
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
|
||||
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
|
||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
@@ -775,6 +783,8 @@ github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1
|
||||
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
|
||||
github.com/zencoder/go-dash/v3 v3.0.2 h1:oP1+dOh+Gp57PkvdCyMfbHtrHaxfl3w4kR3KBBbuqQE=
|
||||
github.com/zencoder/go-dash/v3 v3.0.2/go.mod h1:30R5bKy1aUYY45yesjtZ9l8trNc2TwNqbS17WVQmCzk=
|
||||
gitlab.com/nyarla/go-crypt v0.0.0-20160106005555-d9a5dc2b789b/go.mod h1:T3BPAOm2cqquPa0MKWeNkmOM5RQsRhkrwMWonFMN7fE=
|
||||
go.etcd.io/etcd/api/v3 v3.5.1/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.1/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
|
||||
@@ -839,8 +849,8 @@ golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMk
|
||||
golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/image v0.0.0-20210220032944-ac19c3e999fb h1:fqpd0EBDzlHRCjiphRR5Zo/RSWWQlWv34418dnEixWk=
|
||||
golang.org/x/image v0.0.0-20210220032944-ac19c3e999fb/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/image v0.5.0 h1:5JMiNunQeQw++mMOz48/ISeNu3Iweh/JaZU8ZLqHRrI=
|
||||
golang.org/x/image v0.5.0/go.mod h1:FVC7BI/5Ym8R25iw5OLsgshdUBbT1h5jZTpA+mvAdZ4=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
@@ -924,8 +934,9 @@ golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qx
|
||||
golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b h1:PxfKdU9lEEDYjdIzOtC4qFWgkU2rGHdKlKowJSMN9h0=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
|
||||
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/oauth2 v0.0.0-20180227000427-d7d64896b5ff/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
@@ -1049,16 +1060,16 @@ golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220808155132-1c4a2a72c664 h1:v1W7bwXHsnLLloWYTVEdvGvA7BHMeBYsPcF0GLDxIRs=
|
||||
golang.org/x/sys v0.0.0-20220808155132-1c4a2a72c664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
@@ -1067,8 +1078,9 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
@@ -1336,8 +1348,9 @@ gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gorm.io/driver/postgres v1.0.8/go.mod h1:4eOzrI1MUfm6ObJU/UcmbXyiHSs8jSwH95G5P5dxcAg=
|
||||
gorm.io/gorm v1.20.12/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=
|
||||
gorm.io/gorm v1.21.4/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=
|
||||
|
||||
18
gqlgen.yml
18
gqlgen.yml
@@ -23,10 +23,10 @@ autobind:
|
||||
|
||||
models:
|
||||
# Scalars
|
||||
Timestamp:
|
||||
model: github.com/stashapp/stash/pkg/models.Timestamp
|
||||
Int64:
|
||||
model: github.com/stashapp/stash/pkg/models.Int64
|
||||
model: github.com/99designs/gqlgen/graphql.Int64
|
||||
Timestamp:
|
||||
model: github.com/stashapp/stash/internal/api.Timestamp
|
||||
# define to force resolvers
|
||||
Image:
|
||||
model: github.com/stashapp/stash/pkg/models.Image
|
||||
@@ -34,6 +34,8 @@ models:
|
||||
title:
|
||||
resolver: true
|
||||
# autobind on config causes generation issues
|
||||
BlobsStorageType:
|
||||
model: github.com/stashapp/stash/internal/manager/config.BlobsStorageType
|
||||
StashConfig:
|
||||
model: github.com/stashapp/stash/internal/manager/config.StashConfig
|
||||
StashConfigInput:
|
||||
@@ -52,12 +54,6 @@ models:
|
||||
model: github.com/stashapp/stash/internal/manager/config.ScanMetadataOptions
|
||||
AutoTagMetadataOptions:
|
||||
model: github.com/stashapp/stash/internal/manager/config.AutoTagMetadataOptions
|
||||
SceneParserInput:
|
||||
model: github.com/stashapp/stash/internal/manager.SceneParserInput
|
||||
SceneParserResult:
|
||||
model: github.com/stashapp/stash/internal/manager.SceneParserResult
|
||||
SceneMovieID:
|
||||
model: github.com/stashapp/stash/internal/manager.SceneMovieID
|
||||
SystemStatus:
|
||||
model: github.com/stashapp/stash/internal/manager.SystemStatus
|
||||
SystemStatusEnum:
|
||||
@@ -78,8 +74,8 @@ models:
|
||||
model: github.com/stashapp/stash/internal/manager.AutoTagMetadataInput
|
||||
CleanMetadataInput:
|
||||
model: github.com/stashapp/stash/internal/manager.CleanMetadataInput
|
||||
StashBoxBatchPerformerTagInput:
|
||||
model: github.com/stashapp/stash/internal/manager.StashBoxBatchPerformerTagInput
|
||||
StashBoxBatchTagInput:
|
||||
model: github.com/stashapp/stash/internal/manager.StashBoxBatchTagInput
|
||||
SceneStreamEndpoint:
|
||||
model: github.com/stashapp/stash/internal/manager.SceneStreamEndpoint
|
||||
ExportObjectTypeInput:
|
||||
|
||||
@@ -10,6 +10,8 @@ fragment ConfigGeneralData on ConfigGeneralResult {
|
||||
metadataPath
|
||||
scrapersPath
|
||||
cachePath
|
||||
blobsPath
|
||||
blobsStorage
|
||||
calculateMD5
|
||||
videoFileNamingAlgorithm
|
||||
parallelTasks
|
||||
@@ -19,9 +21,11 @@ fragment ConfigGeneralData on ConfigGeneralResult {
|
||||
previewExcludeStart
|
||||
previewExcludeEnd
|
||||
previewPreset
|
||||
transcodeHardwareAcceleration
|
||||
maxTranscodeSize
|
||||
maxStreamingTranscodeSize
|
||||
writeImageThumbnails
|
||||
createImageClipsFromVideos
|
||||
apiKey
|
||||
username
|
||||
password
|
||||
@@ -31,6 +35,7 @@ fragment ConfigGeneralData on ConfigGeneralResult {
|
||||
logLevel
|
||||
logAccess
|
||||
createGalleriesFromFolders
|
||||
galleryCoverRegex
|
||||
videoExtensions
|
||||
imageExtensions
|
||||
galleryExtensions
|
||||
@@ -46,6 +51,11 @@ fragment ConfigGeneralData on ConfigGeneralResult {
|
||||
api_key
|
||||
}
|
||||
pythonPath
|
||||
transcodeInputArgs
|
||||
transcodeOutputArgs
|
||||
liveTranscodeInputArgs
|
||||
liveTranscodeOutputArgs
|
||||
drawFunscriptHeatmapRange
|
||||
}
|
||||
|
||||
fragment ConfigInterfaceData on ConfigInterfaceResult {
|
||||
@@ -63,6 +73,8 @@ fragment ConfigInterfaceData on ConfigInterfaceResult {
|
||||
showStudioAsText
|
||||
css
|
||||
cssEnabled
|
||||
javascript
|
||||
javascriptEnabled
|
||||
customLocales
|
||||
customLocalesEnabled
|
||||
language
|
||||
@@ -78,9 +90,11 @@ fragment ConfigInterfaceData on ConfigInterfaceResult {
|
||||
performer
|
||||
tag
|
||||
studio
|
||||
movie
|
||||
}
|
||||
handyKey
|
||||
funscriptOffset
|
||||
useStashHostedFunscript
|
||||
}
|
||||
|
||||
fragment ConfigDLNAData on ConfigDLNAResult {
|
||||
@@ -88,6 +102,7 @@ fragment ConfigDLNAData on ConfigDLNAResult {
|
||||
enabled
|
||||
whitelistedIPs
|
||||
interfaces
|
||||
videoSortOrder
|
||||
}
|
||||
|
||||
fragment ConfigScrapingData on ConfigScrapingResult {
|
||||
@@ -110,6 +125,10 @@ fragment IdentifyMetadataOptionsData on IdentifyMetadataOptions {
|
||||
setCoverImage
|
||||
setOrganized
|
||||
includeMalePerformers
|
||||
skipMultipleMatches
|
||||
skipMultipleMatchTag
|
||||
skipSingleNamePerformers
|
||||
skipSingleNamePerformerTag
|
||||
}
|
||||
|
||||
fragment ScraperSourceData on ScraperSource {
|
||||
@@ -122,13 +141,15 @@ fragment ConfigDefaultSettingsData on ConfigDefaultSettingsResult {
|
||||
scan {
|
||||
useFileMetadata
|
||||
stripFileExtension
|
||||
scanGenerateCovers
|
||||
scanGeneratePreviews
|
||||
scanGenerateImagePreviews
|
||||
scanGenerateSprites
|
||||
scanGeneratePhashes
|
||||
scanGenerateThumbnails
|
||||
scanGenerateClipPreviews
|
||||
}
|
||||
|
||||
|
||||
identify {
|
||||
sources {
|
||||
source {
|
||||
@@ -150,6 +171,7 @@ fragment ConfigDefaultSettingsData on ConfigDefaultSettingsResult {
|
||||
}
|
||||
|
||||
generate {
|
||||
covers
|
||||
sprites
|
||||
previews
|
||||
imagePreviews
|
||||
@@ -166,6 +188,7 @@ fragment ConfigDefaultSettingsData on ConfigDefaultSettingsResult {
|
||||
transcodes
|
||||
phashes
|
||||
interactiveHeatmapsSpeeds
|
||||
clipPreviews
|
||||
}
|
||||
|
||||
deleteFile
|
||||
|
||||
@@ -7,6 +7,7 @@ fragment VideoFileData on VideoFile {
|
||||
id
|
||||
path
|
||||
size
|
||||
mod_time
|
||||
duration
|
||||
video_codec
|
||||
audio_codec
|
||||
@@ -24,6 +25,7 @@ fragment ImageFileData on ImageFile {
|
||||
id
|
||||
path
|
||||
size
|
||||
mod_time
|
||||
width
|
||||
height
|
||||
fingerprints {
|
||||
@@ -36,8 +38,51 @@ fragment GalleryFileData on GalleryFile {
|
||||
id
|
||||
path
|
||||
size
|
||||
mod_time
|
||||
fingerprints {
|
||||
type
|
||||
value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fragment VisualFileData on VisualFile {
|
||||
... on BaseFile {
|
||||
id
|
||||
path
|
||||
size
|
||||
mod_time
|
||||
fingerprints {
|
||||
type
|
||||
value
|
||||
}
|
||||
}
|
||||
... on ImageFile {
|
||||
id
|
||||
path
|
||||
size
|
||||
mod_time
|
||||
width
|
||||
height
|
||||
fingerprints {
|
||||
type
|
||||
value
|
||||
}
|
||||
}
|
||||
... on VideoFile {
|
||||
id
|
||||
path
|
||||
size
|
||||
mod_time
|
||||
duration
|
||||
video_codec
|
||||
audio_codec
|
||||
width
|
||||
height
|
||||
frame_rate
|
||||
bit_rate
|
||||
fingerprints {
|
||||
type
|
||||
value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,4 +3,4 @@ fragment SavedFilterData on SavedFilter {
|
||||
mode
|
||||
name
|
||||
filter
|
||||
}
|
||||
}
|
||||
|
||||
9
graphql/documents/data/gallery-chapter.graphql
Normal file
9
graphql/documents/data/gallery-chapter.graphql
Normal file
@@ -0,0 +1,9 @@
|
||||
fragment GalleryChapterData on GalleryChapter {
|
||||
id
|
||||
title
|
||||
image_index
|
||||
|
||||
gallery {
|
||||
id
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@ fragment SlimGalleryData on Gallery {
|
||||
date
|
||||
url
|
||||
details
|
||||
rating
|
||||
rating100
|
||||
organized
|
||||
files {
|
||||
...GalleryFileData
|
||||
@@ -14,14 +14,19 @@ fragment SlimGalleryData on Gallery {
|
||||
}
|
||||
image_count
|
||||
cover {
|
||||
id
|
||||
files {
|
||||
...ImageFileData
|
||||
}
|
||||
|
||||
paths {
|
||||
thumbnail
|
||||
}
|
||||
}
|
||||
chapters {
|
||||
id
|
||||
title
|
||||
image_index
|
||||
}
|
||||
studio {
|
||||
id
|
||||
name
|
||||
|
||||
@@ -6,7 +6,7 @@ fragment GalleryData on Gallery {
|
||||
date
|
||||
url
|
||||
details
|
||||
rating
|
||||
rating100
|
||||
organized
|
||||
|
||||
files {
|
||||
@@ -16,8 +16,8 @@ fragment GalleryData on Gallery {
|
||||
...FolderData
|
||||
}
|
||||
|
||||
images {
|
||||
...SlimImageData
|
||||
chapters {
|
||||
...GalleryChapterData
|
||||
}
|
||||
cover {
|
||||
...SlimImageData
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
fragment SlimImageData on Image {
|
||||
id
|
||||
title
|
||||
rating
|
||||
date
|
||||
url
|
||||
rating100
|
||||
organized
|
||||
o_counter
|
||||
|
||||
@@ -11,6 +13,7 @@ fragment SlimImageData on Image {
|
||||
|
||||
paths {
|
||||
thumbnail
|
||||
preview
|
||||
image
|
||||
}
|
||||
|
||||
@@ -43,4 +46,8 @@ fragment SlimImageData on Image {
|
||||
favorite
|
||||
image_path
|
||||
}
|
||||
|
||||
visual_files {
|
||||
...VisualFileData
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
fragment ImageData on Image {
|
||||
id
|
||||
title
|
||||
rating
|
||||
rating100
|
||||
date
|
||||
url
|
||||
organized
|
||||
o_counter
|
||||
created_at
|
||||
@@ -13,6 +15,7 @@ fragment ImageData on Image {
|
||||
|
||||
paths {
|
||||
thumbnail
|
||||
preview
|
||||
image
|
||||
}
|
||||
|
||||
@@ -23,7 +26,7 @@ fragment ImageData on Image {
|
||||
studio {
|
||||
...SlimStudioData
|
||||
}
|
||||
|
||||
|
||||
tags {
|
||||
...SlimTagData
|
||||
}
|
||||
@@ -31,4 +34,8 @@ fragment ImageData on Image {
|
||||
performers {
|
||||
...PerformerData
|
||||
}
|
||||
|
||||
visual_files {
|
||||
...VisualFileData
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,4 +7,4 @@ fragment JobData on Job {
|
||||
startTime
|
||||
endTime
|
||||
addTime
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,4 +2,5 @@ fragment SlimMovieData on Movie {
|
||||
id
|
||||
name
|
||||
front_image_path
|
||||
rating100
|
||||
}
|
||||
|
||||
@@ -1,17 +1,16 @@
|
||||
fragment MovieData on Movie {
|
||||
id
|
||||
checksum
|
||||
name
|
||||
aliases
|
||||
duration
|
||||
date
|
||||
rating
|
||||
rating100
|
||||
director
|
||||
|
||||
studio {
|
||||
...SlimStudioData
|
||||
}
|
||||
|
||||
|
||||
synopsis
|
||||
url
|
||||
front_image_path
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
fragment SlimPerformerData on Performer {
|
||||
id
|
||||
name
|
||||
disambiguation
|
||||
gender
|
||||
url
|
||||
twitter
|
||||
@@ -13,11 +14,14 @@ fragment SlimPerformerData on Performer {
|
||||
ethnicity
|
||||
hair_color
|
||||
eye_color
|
||||
height
|
||||
height_cm
|
||||
fake_tits
|
||||
penis_length
|
||||
circumcised
|
||||
career_length
|
||||
tattoos
|
||||
piercings
|
||||
alias_list
|
||||
tags {
|
||||
id
|
||||
name
|
||||
@@ -26,7 +30,7 @@ fragment SlimPerformerData on Performer {
|
||||
endpoint
|
||||
stash_id
|
||||
}
|
||||
rating
|
||||
rating100
|
||||
death_date
|
||||
weight
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ fragment PerformerData on Performer {
|
||||
id
|
||||
checksum
|
||||
name
|
||||
disambiguation
|
||||
url
|
||||
gender
|
||||
twitter
|
||||
@@ -10,13 +11,15 @@ fragment PerformerData on Performer {
|
||||
ethnicity
|
||||
country
|
||||
eye_color
|
||||
height
|
||||
height_cm
|
||||
measurements
|
||||
fake_tits
|
||||
penis_length
|
||||
circumcised
|
||||
career_length
|
||||
tattoos
|
||||
piercings
|
||||
aliases
|
||||
alias_list
|
||||
favorite
|
||||
ignore_auto_tag
|
||||
image_path
|
||||
@@ -24,6 +27,8 @@ fragment PerformerData on Performer {
|
||||
image_count
|
||||
gallery_count
|
||||
movie_count
|
||||
performer_count
|
||||
o_counter
|
||||
|
||||
tags {
|
||||
...SlimTagData
|
||||
@@ -33,7 +38,7 @@ fragment PerformerData on Performer {
|
||||
stash_id
|
||||
endpoint
|
||||
}
|
||||
rating
|
||||
rating100
|
||||
details
|
||||
death_date
|
||||
hair_color
|
||||
|
||||
@@ -1,14 +1,19 @@
|
||||
fragment SlimSceneData on Scene {
|
||||
id
|
||||
title
|
||||
code
|
||||
details
|
||||
url
|
||||
director
|
||||
urls
|
||||
date
|
||||
rating
|
||||
rating100
|
||||
o_counter
|
||||
organized
|
||||
interactive
|
||||
interactive_speed
|
||||
resume_time
|
||||
play_duration
|
||||
play_count
|
||||
|
||||
files {
|
||||
...VideoFileData
|
||||
@@ -20,7 +25,6 @@ fragment SlimSceneData on Scene {
|
||||
stream
|
||||
webp
|
||||
vtt
|
||||
chapters_vtt
|
||||
sprite
|
||||
funscript
|
||||
interactive_heatmap
|
||||
@@ -42,6 +46,9 @@ fragment SlimSceneData on Scene {
|
||||
files {
|
||||
path
|
||||
}
|
||||
folder {
|
||||
path
|
||||
}
|
||||
title
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
fragment SceneData on Scene {
|
||||
id
|
||||
title
|
||||
code
|
||||
details
|
||||
url
|
||||
director
|
||||
urls
|
||||
date
|
||||
rating
|
||||
rating100
|
||||
o_counter
|
||||
organized
|
||||
interactive
|
||||
@@ -15,6 +17,10 @@ fragment SceneData on Scene {
|
||||
}
|
||||
created_at
|
||||
updated_at
|
||||
resume_time
|
||||
last_played_at
|
||||
play_duration
|
||||
play_count
|
||||
|
||||
files {
|
||||
...VideoFileData
|
||||
@@ -26,7 +32,6 @@ fragment SceneData on Scene {
|
||||
stream
|
||||
webp
|
||||
vtt
|
||||
chapters_vtt
|
||||
sprite
|
||||
funscript
|
||||
interactive_heatmap
|
||||
@@ -44,7 +49,7 @@ fragment SceneData on Scene {
|
||||
studio {
|
||||
...SlimStudioData
|
||||
}
|
||||
|
||||
|
||||
movies {
|
||||
movie {
|
||||
...MovieData
|
||||
|
||||
@@ -1,6 +1,22 @@
|
||||
fragment ScrapedStudioData on ScrapedStudio {
|
||||
stored_id
|
||||
name
|
||||
url
|
||||
parent {
|
||||
stored_id
|
||||
name
|
||||
url
|
||||
image
|
||||
remote_site_id
|
||||
}
|
||||
image
|
||||
remote_site_id
|
||||
}
|
||||
|
||||
fragment ScrapedPerformerData on ScrapedPerformer {
|
||||
stored_id
|
||||
name
|
||||
disambiguation
|
||||
gender
|
||||
url
|
||||
twitter
|
||||
@@ -12,6 +28,8 @@ fragment ScrapedPerformerData on ScrapedPerformer {
|
||||
height
|
||||
measurements
|
||||
fake_tits
|
||||
penis_length
|
||||
circumcised
|
||||
career_length
|
||||
tattoos
|
||||
piercings
|
||||
@@ -30,6 +48,7 @@ fragment ScrapedPerformerData on ScrapedPerformer {
|
||||
fragment ScrapedScenePerformerData on ScrapedPerformer {
|
||||
stored_id
|
||||
name
|
||||
disambiguation
|
||||
gender
|
||||
url
|
||||
twitter
|
||||
@@ -41,6 +60,8 @@ fragment ScrapedScenePerformerData on ScrapedPerformer {
|
||||
height
|
||||
measurements
|
||||
fake_tits
|
||||
penis_length
|
||||
circumcised
|
||||
career_length
|
||||
tattoos
|
||||
piercings
|
||||
@@ -95,6 +116,14 @@ fragment ScrapedSceneStudioData on ScrapedStudio {
|
||||
stored_id
|
||||
name
|
||||
url
|
||||
parent {
|
||||
stored_id
|
||||
name
|
||||
url
|
||||
image
|
||||
remote_site_id
|
||||
}
|
||||
image
|
||||
remote_site_id
|
||||
}
|
||||
|
||||
@@ -105,8 +134,10 @@ fragment ScrapedSceneTagData on ScrapedTag {
|
||||
|
||||
fragment ScrapedSceneData on ScrapedScene {
|
||||
title
|
||||
code
|
||||
details
|
||||
url
|
||||
director
|
||||
urls
|
||||
date
|
||||
image
|
||||
remote_site_id
|
||||
@@ -166,7 +197,9 @@ fragment ScrapedGalleryData on ScrapedGallery {
|
||||
|
||||
fragment ScrapedStashBoxSceneData on ScrapedScene {
|
||||
title
|
||||
code
|
||||
details
|
||||
director
|
||||
url
|
||||
date
|
||||
image
|
||||
|
||||
@@ -10,6 +10,6 @@ fragment SlimStudioData on Studio {
|
||||
id
|
||||
}
|
||||
details
|
||||
rating
|
||||
rating100
|
||||
aliases
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
fragment StudioData on Studio {
|
||||
id
|
||||
checksum
|
||||
name
|
||||
url
|
||||
parent_studio {
|
||||
@@ -17,14 +16,20 @@ fragment StudioData on Studio {
|
||||
ignore_auto_tag
|
||||
image_path
|
||||
scene_count
|
||||
scene_count_all: scene_count(depth: -1)
|
||||
image_count
|
||||
image_count_all: image_count(depth: -1)
|
||||
gallery_count
|
||||
gallery_count_all: gallery_count(depth: -1)
|
||||
performer_count
|
||||
performer_count_all: performer_count(depth: -1)
|
||||
movie_count
|
||||
movie_count_all: movie_count(depth: -1)
|
||||
stash_ids {
|
||||
stash_id
|
||||
endpoint
|
||||
}
|
||||
details
|
||||
rating
|
||||
rating100
|
||||
aliases
|
||||
}
|
||||
|
||||
@@ -6,10 +6,15 @@ fragment TagData on Tag {
|
||||
ignore_auto_tag
|
||||
image_path
|
||||
scene_count
|
||||
scene_count_all: scene_count(depth: -1)
|
||||
scene_marker_count
|
||||
scene_marker_count_all: scene_marker_count(depth: -1)
|
||||
image_count
|
||||
image_count_all: image_count(depth: -1)
|
||||
gallery_count
|
||||
gallery_count_all: gallery_count(depth: -1)
|
||||
performer_count
|
||||
performer_count_all: performer_count(depth: -1)
|
||||
|
||||
parents {
|
||||
...SlimTagData
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
mutation DeleteFiles($ids: [ID!]!) {
|
||||
deleteFiles(ids: $ids)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ mutation SaveFilter($input: SaveFilterInput!) {
|
||||
saveFilter(input: $input) {
|
||||
...SavedFilterData
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mutation DestroySavedFilter($input: DestroyFilterInput!) {
|
||||
destroySavedFilter(input: $input)
|
||||
|
||||
33
graphql/documents/mutations/gallery-chapter.graphql
Normal file
33
graphql/documents/mutations/gallery-chapter.graphql
Normal file
@@ -0,0 +1,33 @@
|
||||
mutation GalleryChapterCreate(
|
||||
$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
|
||||
}
|
||||
) {
|
||||
...GalleryChapterData
|
||||
}
|
||||
}
|
||||
|
||||
mutation GalleryChapterDestroy($id: ID!) {
|
||||
galleryChapterDestroy(id: $id)
|
||||
}
|
||||
@@ -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 })
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3,5 +3,5 @@ mutation StopJob($job_id: ID!) {
|
||||
}
|
||||
|
||||
mutation StopAllJobs {
|
||||
stopAllJobs
|
||||
}
|
||||
stopAllJobs
|
||||
}
|
||||
|
||||
@@ -41,3 +41,11 @@ mutation MigrateHashNaming {
|
||||
mutation BackupDatabase($input: BackupDatabaseInput!) {
|
||||
backupDatabase(input: $input)
|
||||
}
|
||||
|
||||
mutation AnonymiseDatabase($input: AnonymiseDatabaseInput!) {
|
||||
anonymiseDatabase(input: $input)
|
||||
}
|
||||
|
||||
mutation OptimiseDatabase {
|
||||
optimiseDatabase
|
||||
}
|
||||
|
||||
7
graphql/documents/mutations/migration.graphql
Normal file
7
graphql/documents/mutations/migration.graphql
Normal file
@@ -0,0 +1,7 @@
|
||||
mutation MigrateSceneScreenshots($input: MigrateSceneScreenshotsInput!) {
|
||||
migrateSceneScreenshots(input: $input)
|
||||
}
|
||||
|
||||
mutation MigrateBlobs($input: MigrateBlobsInput!) {
|
||||
migrateBlobs(input: $input)
|
||||
}
|
||||
@@ -1,17 +1,5 @@
|
||||
mutation MovieCreate(
|
||||
$name: String!,
|
||||
$aliases: String,
|
||||
$duration: Int,
|
||||
$date: String,
|
||||
$rating: Int,
|
||||
$studio_id: ID,
|
||||
$director: String,
|
||||
$synopsis: String,
|
||||
$url: String,
|
||||
$front_image: String,
|
||||
$back_image: String) {
|
||||
|
||||
movieCreate(input: { name: $name, aliases: $aliases, duration: $duration, date: $date, rating: $rating, studio_id: $studio_id, director: $director, synopsis: $synopsis, url: $url, front_image: $front_image, back_image: $back_image }) {
|
||||
mutation MovieCreate($input: MovieCreateInput!) {
|
||||
movieCreate(input: $input) {
|
||||
...MovieData
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,27 +1,45 @@
|
||||
mutation SceneUpdate(
|
||||
$input: SceneUpdateInput!) {
|
||||
mutation SceneCreate($input: SceneCreateInput!) {
|
||||
sceneCreate(input: $input) {
|
||||
...SceneData
|
||||
}
|
||||
}
|
||||
|
||||
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 SceneIncrementPlayCount($id: ID!) {
|
||||
sceneIncrementPlayCount(id: $id)
|
||||
}
|
||||
|
||||
mutation SceneIncrementO($id: ID!) {
|
||||
sceneIncrementO(id: $id)
|
||||
sceneIncrementO(id: $id)
|
||||
}
|
||||
|
||||
mutation SceneDecrementO($id: ID!) {
|
||||
@@ -32,14 +50,44 @@ 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) {
|
||||
sceneGenerateScreenshot(id: $id, at: $at)
|
||||
}
|
||||
|
||||
mutation SceneAssignFile($input: AssignSceneFileInput!) {
|
||||
sceneAssignFile(input: $input)
|
||||
}
|
||||
|
||||
mutation SceneMerge($input: SceneMergeInput!) {
|
||||
sceneMerge(input: $input) {
|
||||
id
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
mutation SubmitStashBoxFingerprints($input: StashBoxFingerprintSubmissionInput!) {
|
||||
mutation SubmitStashBoxFingerprints(
|
||||
$input: StashBoxFingerprintSubmissionInput!
|
||||
) {
|
||||
submitStashBoxFingerprints(input: $input)
|
||||
}
|
||||
|
||||
mutation StashBoxBatchPerformerTag($input: StashBoxBatchPerformerTagInput!) {
|
||||
mutation StashBoxBatchPerformerTag($input: StashBoxBatchTagInput!) {
|
||||
stashBoxBatchPerformerTag(input: $input)
|
||||
}
|
||||
|
||||
mutation StashBoxBatchStudioTag($input: StashBoxBatchTagInput!) {
|
||||
stashBoxBatchStudioTag(input: $input)
|
||||
}
|
||||
|
||||
mutation SubmitStashBoxSceneDraft($input: StashBoxDraftSubmissionInput!) {
|
||||
submitStashBoxSceneDraft(input: $input)
|
||||
}
|
||||
|
||||
@@ -8,4 +8,4 @@ query DLNAStatus {
|
||||
until
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -5,7 +5,7 @@ query JobQueue {
|
||||
}
|
||||
|
||||
query FindJob($input: FindJobInput!) {
|
||||
findJob(input: $input) {
|
||||
...JobData
|
||||
}
|
||||
findJob(input: $input) {
|
||||
...JobData
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,4 +8,4 @@ query MarkerWall($q: String) {
|
||||
markerWall(q: $q) {
|
||||
...SceneMarkerData
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,26 +6,27 @@ query MarkerStrings($q: String, $sort: String) {
|
||||
}
|
||||
}
|
||||
|
||||
query AllTags {
|
||||
allTags {
|
||||
...TagData
|
||||
}
|
||||
}
|
||||
|
||||
query AllPerformersForFilter {
|
||||
allPerformers {
|
||||
...SlimPerformerData
|
||||
id
|
||||
name
|
||||
disambiguation
|
||||
alias_list
|
||||
}
|
||||
}
|
||||
|
||||
query AllStudiosForFilter {
|
||||
allStudios {
|
||||
...SlimStudioData
|
||||
id
|
||||
name
|
||||
aliases
|
||||
}
|
||||
}
|
||||
|
||||
query AllMoviesForFilter {
|
||||
allMovies {
|
||||
...SlimMovieData
|
||||
id
|
||||
name
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,16 +40,20 @@ query AllTagsForFilter {
|
||||
|
||||
query Stats {
|
||||
stats {
|
||||
scene_count,
|
||||
scenes_size,
|
||||
scenes_duration,
|
||||
image_count,
|
||||
images_size,
|
||||
gallery_count,
|
||||
performer_count,
|
||||
studio_count,
|
||||
movie_count,
|
||||
scene_count
|
||||
scenes_size
|
||||
scenes_duration
|
||||
image_count
|
||||
images_size
|
||||
gallery_count
|
||||
performer_count
|
||||
studio_count
|
||||
movie_count
|
||||
tag_count
|
||||
total_o_count
|
||||
total_play_duration
|
||||
total_play_count
|
||||
scenes_played
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,7 +72,9 @@ query Version {
|
||||
|
||||
query LatestVersion {
|
||||
latestversion {
|
||||
version
|
||||
shorthash
|
||||
release_date
|
||||
url
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,4 +11,4 @@ query FindMovie($id: ID!) {
|
||||
findMovie(id: $id) {
|
||||
...MovieData
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -20,8 +28,8 @@ query FindScenesByPathRegex($filter: FindFilterType) {
|
||||
}
|
||||
}
|
||||
|
||||
query FindDuplicateScenes($distance: Int) {
|
||||
findDuplicateScenes(distance: $distance) {
|
||||
query FindDuplicateScenes($distance: Int, $duration_diff: Float) {
|
||||
findDuplicateScenes(distance: $distance, duration_diff: $duration_diff) {
|
||||
...SlimSceneData
|
||||
}
|
||||
}
|
||||
@@ -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 {
|
||||
@@ -52,7 +63,9 @@ query ParseSceneFilenames($filter: FindFilterType!, $config: SceneParserInput!)
|
||||
...SlimSceneData
|
||||
}
|
||||
title
|
||||
code
|
||||
details
|
||||
director
|
||||
url
|
||||
date
|
||||
rating
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
query ScrapeFreeonesPerformers($q: String!) {
|
||||
scrapeFreeonesPerformerList(query: $q)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,13 +42,28 @@ query ListMovieScrapers {
|
||||
}
|
||||
}
|
||||
|
||||
query ScrapeSinglePerformer($source: ScraperSourceInput!, $input: ScrapeSinglePerformerInput!) {
|
||||
query ScrapeSingleStudio(
|
||||
$source: ScraperSourceInput!
|
||||
$input: ScrapeSingleStudioInput!
|
||||
) {
|
||||
scrapeSingleStudio(source: $source, input: $input) {
|
||||
...ScrapedStudioData
|
||||
}
|
||||
}
|
||||
|
||||
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 +75,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 +99,10 @@ query ScrapeSceneURL($url: String!) {
|
||||
}
|
||||
}
|
||||
|
||||
query ScrapeSingleGallery($source: ScraperSourceInput!, $input: ScrapeSingleGalleryInput!) {
|
||||
query ScrapeSingleGallery(
|
||||
$source: ScraperSourceInput!
|
||||
$input: ScrapeSingleGalleryInput!
|
||||
) {
|
||||
scrapeSingleGallery(source: $source, input: $input) {
|
||||
...ScrapedGalleryData
|
||||
}
|
||||
|
||||
@@ -6,9 +6,9 @@ query Configuration {
|
||||
|
||||
query Directory($path: String) {
|
||||
directory(path: $path) {
|
||||
path
|
||||
parent
|
||||
directories
|
||||
path
|
||||
parent
|
||||
directories
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,4 +19,4 @@ subscription LoggingSubscribe {
|
||||
|
||||
subscription ScanCompleteSubscribe {
|
||||
scanCompleteSubscribe
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,133 +1,208 @@
|
||||
"""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!
|
||||
|
||||
""" Returns any groups of scenes that are perceptual duplicates within the queried distance """
|
||||
findDuplicateScenes(distance: Int): [[Scene!]!]!
|
||||
"""
|
||||
Returns any groups of scenes that are perceptual duplicates within the queried distance
|
||||
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.
|
||||
"""
|
||||
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 studio"
|
||||
scrapeSingleStudio(
|
||||
source: ScraperSourceInput!
|
||||
input: ScrapeSingleStudioInput!
|
||||
): [ScrapedStudio!]!
|
||||
|
||||
"""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 performer 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!
|
||||
@@ -144,6 +219,10 @@ type Query {
|
||||
|
||||
# Get everything
|
||||
|
||||
allScenes: [Scene!]!
|
||||
allSceneMarkers: [SceneMarker!]!
|
||||
allImages: [Image!]!
|
||||
allGalleries: [Gallery!]!
|
||||
allPerformers: [Performer!]!
|
||||
allStudios: [Studio!]!
|
||||
allMovies: [Movie!]!
|
||||
@@ -155,44 +234,54 @@ type Query {
|
||||
version: Version!
|
||||
|
||||
# LatestVersion
|
||||
latestversion: ShortVersion!
|
||||
latestversion: LatestVersion!
|
||||
}
|
||||
|
||||
type Mutation {
|
||||
setup(input: SetupInput!): Boolean!
|
||||
migrate(input: MigrateInput!): Boolean!
|
||||
|
||||
sceneCreate(input: SceneCreateInput!): Scene
|
||||
sceneUpdate(input: SceneUpdateInput!): Scene
|
||||
sceneMerge(input: SceneMergeInput!): Scene
|
||||
bulkSceneUpdate(input: BulkSceneUpdateInput!): [Scene!]
|
||||
sceneDestroy(input: SceneDestroyInput!): Boolean!
|
||||
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!
|
||||
|
||||
"""Generates screenshot at specified time in seconds. Leave empty to generate default screenshot"""
|
||||
"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."
|
||||
sceneIncrementPlayCount(id: ID!): Int!
|
||||
|
||||
"Generates screenshot at specified time in seconds. Leave empty to generate default screenshot"
|
||||
sceneGenerateScreenshot(id: ID!, at: Float): String!
|
||||
|
||||
sceneMarkerCreate(input: SceneMarkerCreateInput!): SceneMarker
|
||||
sceneMarkerUpdate(input: SceneMarkerUpdateInput!): SceneMarker
|
||||
sceneMarkerDestroy(id: ID!): Boolean!
|
||||
|
||||
sceneAssignFile(input: AssignSceneFileInput!): Boolean!
|
||||
|
||||
imageUpdate(input: ImageUpdateInput!): Image
|
||||
bulkImageUpdate(input: BulkImageUpdateInput!): [Image!]
|
||||
imageDestroy(input: ImageDestroyInput!): Boolean!
|
||||
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
|
||||
@@ -204,6 +293,10 @@ type Mutation {
|
||||
addGalleryImages(input: GalleryAddInput!): Boolean!
|
||||
removeGalleryImages(input: GalleryRemoveInput!): Boolean!
|
||||
|
||||
galleryChapterCreate(input: GalleryChapterCreateInput!): GalleryChapter
|
||||
galleryChapterUpdate(input: GalleryChapterUpdateInput!): GalleryChapter
|
||||
galleryChapterDestroy(id: ID!): Boolean!
|
||||
|
||||
performerCreate(input: PerformerCreateInput!): Performer
|
||||
performerUpdate(input: PerformerUpdateInput!): Performer
|
||||
performerDestroy(input: PerformerDestroyInput!): Boolean!
|
||||
@@ -227,6 +320,16 @@ 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.
|
||||
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.
|
||||
Creates folder hierarchy if needed.
|
||||
"""
|
||||
moveFiles(input: MoveFilesInput!): Boolean!
|
||||
deleteFiles(ids: [ID!]!): Boolean!
|
||||
|
||||
# Saved filters
|
||||
@@ -234,80 +337,107 @@ 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"""
|
||||
migrateHashNaming: ID!
|
||||
|
||||
"""Reload scrapers"""
|
||||
"Migrate generated files for the current hash naming"
|
||||
migrateHashNaming: ID!
|
||||
"Migrates legacy scene screenshot files into the blob storage"
|
||||
migrateSceneScreenshots(input: MigrateSceneScreenshotsInput!): ID!
|
||||
"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"
|
||||
anonymiseDatabase(input: AnonymiseDatabaseInput!): String
|
||||
|
||||
"Optimises the database. Returns the job ID"
|
||||
optimiseDatabase: ID!
|
||||
|
||||
"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
|
||||
|
||||
"""Run batch performer tag task. Returns the job ID."""
|
||||
stashBoxBatchPerformerTag(input: StashBoxBatchPerformerTagInput!): String!
|
||||
"DANGEROUS: Execute an arbitrary SQL statement that returns rows."
|
||||
querySQL(sql: String!, args: [Any]): SQLQueryResult!
|
||||
|
||||
"""Enables DLNA for an optional duration. Has no effect if DLNA is enabled by default"""
|
||||
"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."
|
||||
stashBoxBatchPerformerTag(input: StashBoxBatchTagInput!): String!
|
||||
"Run batch studio tag task. Returns the job ID."
|
||||
stashBoxBatchStudioTag(input: StashBoxBatchTagInput!): String!
|
||||
|
||||
"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!]!
|
||||
|
||||
@@ -1,200 +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"
|
||||
cacheLocation: String!
|
||||
"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
|
||||
# blobs are stored in the filesystem under the configured blobs directory
|
||||
"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
|
||||
"""Whether to calculate MD5 checksums for scene video files"""
|
||||
"Path to blobs - required for filesystem blob storage"
|
||||
blobsPath: String
|
||||
"Where to store blobs"
|
||||
blobsStorage: BlobsStorageType
|
||||
"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
|
||||
"""Max generated transcode size"""
|
||||
"Transcode Hardware Acceleration"
|
||||
transcodeHardwareAcceleration: Boolean
|
||||
"Max generated transcode size"
|
||||
maxTranscodeSize: StreamingResolutionEnum
|
||||
"""Max streaming transcode size"""
|
||||
"Max streaming transcode size"
|
||||
maxStreamingTranscodeSize: StreamingResolutionEnum
|
||||
"""Write image thumbnails to disk when generating on the fly"""
|
||||
|
||||
"""
|
||||
ffmpeg transcode input args - injected before input file
|
||||
These are applied to generated transcodes (previews and transcodes)
|
||||
"""
|
||||
transcodeInputArgs: [String!]
|
||||
"""
|
||||
ffmpeg transcode output args - injected before output file
|
||||
These are applied to generated transcodes (previews and transcodes)
|
||||
"""
|
||||
transcodeOutputArgs: [String!]
|
||||
|
||||
"""
|
||||
ffmpeg stream input args - injected before input file
|
||||
These are applied when live transcoding
|
||||
"""
|
||||
liveTranscodeInputArgs: [String!]
|
||||
"""
|
||||
ffmpeg stream output args - injected before output file
|
||||
These are applied when live transcoding
|
||||
"""
|
||||
liveTranscodeOutputArgs: [String!]
|
||||
|
||||
"whether to include range in generated funscript heatmaps"
|
||||
drawFunscriptHeatmapRange: Boolean
|
||||
|
||||
"Write image thumbnails to disk when generating on the fly"
|
||||
writeImageThumbnails: Boolean
|
||||
"""Username"""
|
||||
"Create Image Clips from Video extensions when Videos are disabled in Library"
|
||||
createImageClipsFromVideos: Boolean
|
||||
"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
|
||||
"""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!
|
||||
"""Whether to calculate MD5 checksums for scene video files"""
|
||||
"Path to blobs - required for filesystem blob storage"
|
||||
blobsPath: String!
|
||||
"Where to store blobs"
|
||||
blobsStorage: BlobsStorageType!
|
||||
"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!
|
||||
"""Max generated transcode size"""
|
||||
"Transcode Hardware Acceleration"
|
||||
transcodeHardwareAcceleration: Boolean!
|
||||
"Max generated transcode size"
|
||||
maxTranscodeSize: StreamingResolutionEnum
|
||||
"""Max streaming transcode size"""
|
||||
"Max streaming transcode size"
|
||||
maxStreamingTranscodeSize: StreamingResolutionEnum
|
||||
"""Write image thumbnails to disk when generating on the fly"""
|
||||
|
||||
"""
|
||||
ffmpeg transcode input args - injected before input file
|
||||
These are applied to generated transcodes (previews and transcodes)
|
||||
"""
|
||||
transcodeInputArgs: [String!]!
|
||||
"""
|
||||
ffmpeg transcode output args - injected before output file
|
||||
These are applied to generated transcodes (previews and transcodes)
|
||||
"""
|
||||
transcodeOutputArgs: [String!]!
|
||||
|
||||
"""
|
||||
ffmpeg stream input args - injected before input file
|
||||
These are applied when live transcoding
|
||||
"""
|
||||
liveTranscodeInputArgs: [String!]!
|
||||
"""
|
||||
ffmpeg stream output args - injected before output file
|
||||
These are applied when live transcoding
|
||||
"""
|
||||
liveTranscodeOutputArgs: [String!]!
|
||||
|
||||
"whether to include range in generated funscript heatmaps"
|
||||
drawFunscriptHeatmapRange: Boolean!
|
||||
|
||||
"Write image thumbnails to disk when generating on the fly"
|
||||
writeImageThumbnails: Boolean!
|
||||
"""API Key"""
|
||||
"Create Image Clips from Video extensions when Videos are disabled in Library"
|
||||
createImageClipsFromVideos: Boolean!
|
||||
"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!
|
||||
"""Array of file regexp to exclude from Video Scans"""
|
||||
"Regex used to identify images as gallery covers"
|
||||
galleryCoverRegex: String!
|
||||
"Array of file regexp to exclude from Video Scans"
|
||||
excludes: [String!]!
|
||||
"""Array of file regexp to exclude from Image Scans"""
|
||||
"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!
|
||||
}
|
||||
|
||||
@@ -202,6 +313,7 @@ input ConfigDisableDropdownCreateInput {
|
||||
performer: Boolean
|
||||
tag: Boolean
|
||||
studio: Boolean
|
||||
movie: Boolean
|
||||
}
|
||||
|
||||
enum ImageLightboxDisplayMode {
|
||||
@@ -234,58 +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 Locales"""
|
||||
"Custom Javascript"
|
||||
javascript: String
|
||||
javascriptEnabled: Boolean
|
||||
|
||||
"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
|
||||
"""True if we should not auto-open a browser window on startup"""
|
||||
"Whether to use Stash Hosted Funscript"
|
||||
useStashHostedFunscript: Boolean
|
||||
"True if we should not auto-open a browser window on startup"
|
||||
noBrowser: Boolean
|
||||
"""True if we should send notifications to the desktop"""
|
||||
"True if we should send notifications to the desktop"
|
||||
notificationsEnabled: Boolean
|
||||
}
|
||||
|
||||
@@ -293,104 +411,116 @@ type ConfigDisableDropdownCreate {
|
||||
performer: Boolean!
|
||||
tag: Boolean!
|
||||
studio: Boolean!
|
||||
movie: Boolean!
|
||||
}
|
||||
|
||||
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 Locales"""
|
||||
"Custom Javascript"
|
||||
javascript: String
|
||||
javascriptEnabled: Boolean
|
||||
|
||||
"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"
|
||||
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"
|
||||
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"
|
||||
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!]!
|
||||
}
|
||||
|
||||
@@ -399,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
|
||||
}
|
||||
|
||||
@@ -412,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!
|
||||
@@ -428,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!
|
||||
|
||||
@@ -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!
|
||||
}
|
||||
|
||||
@@ -1,97 +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
|
||||
|
||||
"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
|
||||
}
|
||||
|
||||
@@ -6,26 +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
|
||||
"4k", FOUR_K
|
||||
"5k", FIVE_K
|
||||
"6k", SIX_K
|
||||
"8k", EIGHT_K
|
||||
"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 {
|
||||
@@ -35,85 +52,130 @@ 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
|
||||
"""
|
||||
endpoint: String
|
||||
stash_id: String
|
||||
modifier: CriterionModifier!
|
||||
}
|
||||
|
||||
input PerformerFilterType {
|
||||
AND: PerformerFilterType
|
||||
OR: PerformerFilterType
|
||||
NOT: PerformerFilterType
|
||||
|
||||
name: StringCriterionInput
|
||||
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
|
||||
"""Filter by measurements"""
|
||||
"Filter by height"
|
||||
height: StringCriterionInput @deprecated(reason: "Use height_cm instead")
|
||||
"Filter by height in cm"
|
||||
height_cm: IntCriterionInput
|
||||
"Filter by measurements"
|
||||
measurements: StringCriterionInput
|
||||
"""Filter by fake tits value"""
|
||||
"Filter by fake tits value"
|
||||
fake_tits: StringCriterionInput
|
||||
"""Filter by career length"""
|
||||
"Filter by penis length value"
|
||||
penis_length: FloatCriterionInput
|
||||
"Filter by ciricumcision"
|
||||
circumcised: CircumcisionCriterionInput
|
||||
"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 StashID"""
|
||||
"Filter by o count"
|
||||
o_counter: IntCriterionInput
|
||||
"Filter by StashID"
|
||||
stash_id: StringCriterionInput
|
||||
"""Filter by rating"""
|
||||
@deprecated(reason: "Use stash_id_endpoint instead")
|
||||
"Filter by StashID"
|
||||
stash_id_endpoint: StashIDCriterionInput
|
||||
"Filter by rating"
|
||||
rating: IntCriterionInput
|
||||
"""Filter by url"""
|
||||
@deprecated(reason: "Use 1-100 range with rating100")
|
||||
# rating expressed as 1-100
|
||||
rating100: IntCriterionInput
|
||||
"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 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"
|
||||
birthdate: DateCriterionInput
|
||||
"Filter by death date"
|
||||
death_date: DateCriterionInput
|
||||
"Filter by creation time"
|
||||
created_at: TimestampCriterionInput
|
||||
"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"
|
||||
created_at: TimestampCriterionInput
|
||||
"Filter by last update time"
|
||||
updated_at: TimestampCriterionInput
|
||||
"Filter by scene date"
|
||||
scene_date: DateCriterionInput
|
||||
"Filter by cscene reation time"
|
||||
scene_created_at: TimestampCriterionInput
|
||||
"Filter by lscene ast update time"
|
||||
scene_updated_at: TimestampCriterionInput
|
||||
}
|
||||
|
||||
input SceneFilterType {
|
||||
@@ -121,83 +183,118 @@ input SceneFilterType {
|
||||
OR: SceneFilterType
|
||||
NOT: SceneFilterType
|
||||
|
||||
id: IntCriterionInput
|
||||
title: StringCriterionInput
|
||||
code: StringCriterionInput
|
||||
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"""
|
||||
phash: StringCriterionInput
|
||||
"""Filter by path"""
|
||||
"Filter by file phash"
|
||||
phash: StringCriterionInput @deprecated(reason: "Use phash_distance instead")
|
||||
"Filter by file phash distance"
|
||||
phash_distance: PhashDistanceCriterionInput
|
||||
"Filter by path"
|
||||
path: StringCriterionInput
|
||||
"""Filter by file count"""
|
||||
"Filter by file count"
|
||||
file_count: IntCriterionInput
|
||||
"""Filter by rating"""
|
||||
"Filter by rating"
|
||||
rating: IntCriterionInput
|
||||
"""Filter by organized"""
|
||||
@deprecated(reason: "Use 1-100 range with rating100")
|
||||
# rating expressed as 1-100
|
||||
rating100: IntCriterionInput
|
||||
"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 duration (in seconds)"""
|
||||
"Filter by video codec"
|
||||
video_codec: StringCriterionInput
|
||||
"Filter by audio codec"
|
||||
audio_codec: StringCriterionInput
|
||||
"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"""
|
||||
"Filter by StashID"
|
||||
stash_id: StringCriterionInput
|
||||
"""Filter by url"""
|
||||
@deprecated(reason: "Use stash_id_endpoint instead")
|
||||
"Filter by StashID"
|
||||
stash_id_endpoint: StashIDCriterionInput
|
||||
"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"
|
||||
resume_time: IntCriterionInput
|
||||
"Filter by play count"
|
||||
play_count: IntCriterionInput
|
||||
"Filter by play duration (in seconds)"
|
||||
play_duration: IntCriterionInput
|
||||
"Filter by date"
|
||||
date: DateCriterionInput
|
||||
"Filter by creation time"
|
||||
created_at: TimestampCriterionInput
|
||||
"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"""
|
||||
"Filter by rating"
|
||||
rating: IntCriterionInput
|
||||
"""Filter to only include movies with this studio"""
|
||||
@deprecated(reason: "Use 1-100 range with rating100")
|
||||
# rating expressed as 1-100
|
||||
rating100: IntCriterionInput
|
||||
"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"
|
||||
date: DateCriterionInput
|
||||
"Filter by creation time"
|
||||
created_at: TimestampCriterionInput
|
||||
"Filter by last update time"
|
||||
updated_at: TimestampCriterionInput
|
||||
}
|
||||
|
||||
input StudioFilterType {
|
||||
@@ -207,26 +304,36 @@ 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"""
|
||||
"Filter by StashID"
|
||||
stash_id: StringCriterionInput
|
||||
"""Filter to only include studios missing this property"""
|
||||
@deprecated(reason: "Use stash_id_endpoint instead")
|
||||
"Filter by StashID"
|
||||
stash_id_endpoint: StashIDCriterionInput
|
||||
"Filter to only include studios missing this property"
|
||||
is_missing: String
|
||||
"""Filter by rating"""
|
||||
"Filter by rating"
|
||||
rating: IntCriterionInput
|
||||
"""Filter by scene count"""
|
||||
@deprecated(reason: "Use 1-100 range with rating100")
|
||||
# rating expressed as 1-100
|
||||
rating100: IntCriterionInput
|
||||
"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"
|
||||
created_at: TimestampCriterionInput
|
||||
"Filter by last update time"
|
||||
updated_at: TimestampCriterionInput
|
||||
}
|
||||
|
||||
input GalleryFilterType {
|
||||
@@ -234,45 +341,57 @@ input GalleryFilterType {
|
||||
OR: GalleryFilterType
|
||||
NOT: GalleryFilterType
|
||||
|
||||
id: IntCriterionInput
|
||||
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"""
|
||||
"Filter by rating"
|
||||
rating: IntCriterionInput
|
||||
"""Filter by organized"""
|
||||
@deprecated(reason: "Use 1-100 range with rating100")
|
||||
# rating expressed as 1-100
|
||||
rating100: IntCriterionInput
|
||||
"Filter by organized"
|
||||
organized: Boolean
|
||||
"""Filter by average image resolution"""
|
||||
"Filter by average image resolution"
|
||||
average_resolution: ResolutionCriterionInput
|
||||
"""Filter to only include galleries with this studio"""
|
||||
"Filter to only include galleries that have chapters. `true` or `false`"
|
||||
has_chapters: String
|
||||
"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"
|
||||
date: DateCriterionInput
|
||||
"Filter by creation time"
|
||||
created_at: TimestampCriterionInput
|
||||
"Filter by last update time"
|
||||
updated_at: TimestampCriterionInput
|
||||
}
|
||||
|
||||
input TagFilterType {
|
||||
@@ -280,44 +399,53 @@ 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 to only include tags missing this property"""
|
||||
"Filter by tag description"
|
||||
description: StringCriterionInput
|
||||
|
||||
"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"
|
||||
created_at: TimestampCriterionInput
|
||||
|
||||
"Filter by last update time"
|
||||
updated_at: TimestampCriterionInput
|
||||
}
|
||||
|
||||
input ImageFilterType {
|
||||
@@ -327,65 +455,78 @@ input ImageFilterType {
|
||||
|
||||
title: StringCriterionInput
|
||||
|
||||
"""Filter by file checksum"""
|
||||
" Filter by image id"
|
||||
id: IntCriterionInput
|
||||
"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"""
|
||||
"Filter by rating"
|
||||
rating: IntCriterionInput
|
||||
"""Filter by organized"""
|
||||
@deprecated(reason: "Use 1-100 range with rating100")
|
||||
# rating expressed as 1-100
|
||||
rating100: IntCriterionInput
|
||||
"Filter by date"
|
||||
date: DateCriterionInput
|
||||
"Filter by url"
|
||||
url: StringCriterionInput
|
||||
"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"
|
||||
created_at: TimestampCriterionInput
|
||||
"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 {
|
||||
@@ -399,9 +540,16 @@ input IntCriterionInput {
|
||||
modifier: CriterionModifier!
|
||||
}
|
||||
|
||||
input FloatCriterionInput {
|
||||
value: Float!
|
||||
value2: Float
|
||||
modifier: CriterionModifier!
|
||||
}
|
||||
|
||||
input MultiCriterionInput {
|
||||
value: [ID!]
|
||||
modifier: CriterionModifier!
|
||||
excludes: [ID!]
|
||||
}
|
||||
|
||||
input GenderCriterionInput {
|
||||
@@ -409,37 +557,61 @@ input GenderCriterionInput {
|
||||
modifier: CriterionModifier!
|
||||
}
|
||||
|
||||
input CircumcisionCriterionInput {
|
||||
value: [CircumisedEnum!]
|
||||
modifier: CriterionModifier!
|
||||
}
|
||||
|
||||
input HierarchicalMultiCriterionInput {
|
||||
value: [ID!]
|
||||
modifier: CriterionModifier!
|
||||
depth: Int
|
||||
excludes: [ID!]
|
||||
}
|
||||
|
||||
input DateCriterionInput {
|
||||
value: String!
|
||||
value2: String
|
||||
modifier: CriterionModifier!
|
||||
}
|
||||
|
||||
input TimestampCriterionInput {
|
||||
value: String!
|
||||
value2: String
|
||||
modifier: CriterionModifier!
|
||||
}
|
||||
|
||||
input PhashDistanceCriterionInput {
|
||||
value: String!
|
||||
modifier: CriterionModifier!
|
||||
distance: Int
|
||||
}
|
||||
|
||||
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!
|
||||
}
|
||||
|
||||
@@ -449,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
|
||||
}
|
||||
|
||||
26
graphql/schema/types/gallery-chapter.graphql
Normal file
26
graphql/schema/types/gallery-chapter.graphql
Normal file
@@ -0,0 +1,26 @@
|
||||
type GalleryChapter {
|
||||
id: ID!
|
||||
gallery: Gallery!
|
||||
title: String!
|
||||
image_index: Int!
|
||||
created_at: Time!
|
||||
updated_at: Time!
|
||||
}
|
||||
|
||||
input GalleryChapterCreateInput {
|
||||
gallery_id: ID!
|
||||
title: String!
|
||||
image_index: Int!
|
||||
}
|
||||
|
||||
input GalleryChapterUpdateInput {
|
||||
id: ID!
|
||||
gallery_id: ID
|
||||
title: String
|
||||
image_index: Int
|
||||
}
|
||||
|
||||
type FindGalleryChaptersResultType {
|
||||
count: Int!
|
||||
chapters: [GalleryChapter!]!
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Gallery type"""
|
||||
"Gallery type"
|
||||
type Gallery {
|
||||
id: ID!
|
||||
checksum: String! @deprecated(reason: "Use files.fingerprints")
|
||||
@@ -7,7 +7,10 @@ type Gallery {
|
||||
url: String
|
||||
date: String
|
||||
details: String
|
||||
rating: Int
|
||||
# rating expressed as 1-5
|
||||
rating: Int @deprecated(reason: "Use 1-100 range with rating100")
|
||||
# rating expressed as 1-100
|
||||
rating100: Int
|
||||
organized: Boolean!
|
||||
created_at: Time!
|
||||
updated_at: Time!
|
||||
@@ -16,14 +19,15 @@ type Gallery {
|
||||
files: [GalleryFile!]!
|
||||
folder: Folder
|
||||
|
||||
chapters: [GalleryChapter!]!
|
||||
scenes: [Scene!]!
|
||||
studio: Studio
|
||||
image_count: Int!
|
||||
tags: [Tag!]!
|
||||
performers: [Performer!]!
|
||||
|
||||
"""The images in the gallery"""
|
||||
images: [Image!]! # Resolver
|
||||
"The images in the gallery"
|
||||
images: [Image!]! @deprecated(reason: "Use findImages")
|
||||
cover: Image
|
||||
}
|
||||
|
||||
@@ -32,7 +36,10 @@ input GalleryCreateInput {
|
||||
url: String
|
||||
date: String
|
||||
details: String
|
||||
rating: Int
|
||||
# rating expressed as 1-5
|
||||
rating: Int @deprecated(reason: "Use 1-100 range with rating100")
|
||||
# rating expressed as 1-100
|
||||
rating100: Int
|
||||
organized: Boolean
|
||||
scene_ids: [ID!]
|
||||
studio_id: ID
|
||||
@@ -47,7 +54,10 @@ input GalleryUpdateInput {
|
||||
url: String
|
||||
date: String
|
||||
details: String
|
||||
rating: Int
|
||||
# rating expressed as 1-5
|
||||
rating: Int @deprecated(reason: "Use 1-100 range with rating100")
|
||||
# rating expressed as 1-100
|
||||
rating100: Int
|
||||
organized: Boolean
|
||||
scene_ids: [ID!]
|
||||
studio_id: ID
|
||||
@@ -63,7 +73,10 @@ input BulkGalleryUpdateInput {
|
||||
url: String
|
||||
date: String
|
||||
details: String
|
||||
rating: Int
|
||||
# rating expressed as 1-5
|
||||
rating: Int @deprecated(reason: "Use 1-100 range with rating100")
|
||||
# rating expressed as 1-100
|
||||
rating100: Int
|
||||
organized: Boolean
|
||||
scene_ids: BulkUpdateIds
|
||||
studio_id: ID
|
||||
@@ -74,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.
|
||||
"""
|
||||
|
||||
@@ -2,19 +2,24 @@ type Image {
|
||||
id: ID!
|
||||
checksum: String @deprecated(reason: "Use files.fingerprints")
|
||||
title: String
|
||||
rating: Int
|
||||
# rating expressed as 1-5
|
||||
rating: Int @deprecated(reason: "Use 1-100 range with rating100")
|
||||
# rating expressed as 1-100
|
||||
rating100: Int
|
||||
url: String
|
||||
date: String
|
||||
o_counter: Int
|
||||
organized: Boolean!
|
||||
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 files.mod_time")
|
||||
files: [ImageFile!]!
|
||||
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!]!
|
||||
@@ -30,6 +35,7 @@ type ImageFileType {
|
||||
|
||||
type ImagePathsType {
|
||||
thumbnail: String # Resolver
|
||||
preview: String # Resolver
|
||||
image: String # Resolver
|
||||
}
|
||||
|
||||
@@ -37,9 +43,14 @@ input ImageUpdateInput {
|
||||
clientMutationId: String
|
||||
id: ID!
|
||||
title: String
|
||||
rating: Int
|
||||
# rating expressed as 1-5
|
||||
rating: Int @deprecated(reason: "Use 1-100 range with rating100")
|
||||
# rating expressed as 1-100
|
||||
rating100: Int
|
||||
organized: Boolean
|
||||
|
||||
url: String
|
||||
date: String
|
||||
|
||||
studio_id: ID
|
||||
performer_ids: [ID!]
|
||||
tag_ids: [ID!]
|
||||
@@ -52,9 +63,14 @@ input BulkImageUpdateInput {
|
||||
clientMutationId: String
|
||||
ids: [ID!]
|
||||
title: String
|
||||
rating: Int
|
||||
# rating expressed as 1-5
|
||||
rating: Int @deprecated(reason: "Use 1-100 range with rating100")
|
||||
# rating expressed as 1-100
|
||||
rating100: Int
|
||||
organized: Boolean
|
||||
|
||||
url: String
|
||||
date: String
|
||||
|
||||
studio_id: ID
|
||||
performer_ids: BulkUpdateIds
|
||||
tag_ids: BulkUpdateIds
|
||||
@@ -75,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!]!
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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!
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
scalar Upload
|
||||
|
||||
input GenerateMetadataInput {
|
||||
covers: Boolean
|
||||
sprites: Boolean
|
||||
previews: Boolean
|
||||
imagePreviews: Boolean
|
||||
@@ -9,34 +10,36 @@ 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
|
||||
}
|
||||
|
||||
type GenerateMetadataOptions {
|
||||
covers: Boolean
|
||||
sprites: Boolean
|
||||
previews: Boolean
|
||||
imagePreviews: Boolean
|
||||
@@ -47,18 +50,19 @@ type GenerateMetadataOptions {
|
||||
transcodes: Boolean
|
||||
phashes: Boolean
|
||||
interactiveHeatmapsSpeeds: Boolean
|
||||
clipPreviews: Boolean
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
@@ -74,84 +78,105 @@ 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 previews during scan"""
|
||||
"Generate covers during scan"
|
||||
scanGenerateCovers: Boolean
|
||||
"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"
|
||||
scanGenerateClipPreviews: Boolean
|
||||
|
||||
"Filter options for the scan"
|
||||
filter: ScanMetaDataFilterInput
|
||||
}
|
||||
|
||||
type ScanMetadataOptions {
|
||||
"""Set name, date, details from metadata (if present)"""
|
||||
useFileMetadata: Boolean!
|
||||
"""Strip file extension from title"""
|
||||
stripFileExtension: Boolean!
|
||||
"""Generate previews during scan"""
|
||||
"Set name, date, details from metadata (if present)"
|
||||
useFileMetadata: Boolean! @deprecated(reason: "Not implemented")
|
||||
"Strip file extension from title"
|
||||
stripFileExtension: Boolean! @deprecated(reason: "Not implemented")
|
||||
"Generate covers during scan"
|
||||
scanGenerateCovers: Boolean!
|
||||
"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"
|
||||
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.
|
||||
"""
|
||||
@@ -161,36 +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"
|
||||
skipMultipleMatches: Boolean
|
||||
"tag to tag skipped multiple matches with"
|
||||
skipMultipleMatchTag: String
|
||||
"defaults to true if not provided"
|
||||
skipSingleNamePerformers: Boolean
|
||||
"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!]
|
||||
}
|
||||
|
||||
@@ -198,30 +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"
|
||||
skipMultipleMatches: Boolean
|
||||
"tag to tag skipped multiple matches with"
|
||||
skipMultipleMatchTag: String
|
||||
"defaults to true if not provided"
|
||||
skipSingleNamePerformers: Boolean
|
||||
"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
|
||||
}
|
||||
|
||||
@@ -263,6 +304,10 @@ input BackupDatabaseInput {
|
||||
download: Boolean
|
||||
}
|
||||
|
||||
input AnonymiseDatabaseInput {
|
||||
download: Boolean
|
||||
}
|
||||
|
||||
enum SystemStatusEnum {
|
||||
SETUP
|
||||
NEEDS_MIGRATION
|
||||
|
||||
11
graphql/schema/types/migration.graphql
Normal file
11
graphql/schema/types/migration.graphql
Normal file
@@ -0,0 +1,11 @@
|
||||
input MigrateSceneScreenshotsInput {
|
||||
# if true, delete screenshot files after migrating
|
||||
deleteFiles: Boolean
|
||||
# if true, overwrite existing covers with the covers from the screenshots directory
|
||||
overwriteExisting: Boolean
|
||||
}
|
||||
|
||||
input MigrateBlobsInput {
|
||||
# if true, delete blob data from old storage system
|
||||
deleteOld: Boolean
|
||||
}
|
||||
@@ -1,12 +1,15 @@
|
||||
type Movie {
|
||||
id: ID!
|
||||
checksum: String!
|
||||
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: Int
|
||||
# rating expressed as 1-5
|
||||
rating: Int @deprecated(reason: "Use 1-100 range with rating100")
|
||||
# rating expressed as 1-100
|
||||
rating100: Int
|
||||
studio: Studio
|
||||
director: String
|
||||
synopsis: String
|
||||
@@ -16,24 +19,27 @@ type Movie {
|
||||
|
||||
front_image_path: String # Resolver
|
||||
back_image_path: String # Resolver
|
||||
scene_count: Int # Resolver
|
||||
scene_count: Int! # Resolver
|
||||
scenes: [Scene!]!
|
||||
}
|
||||
|
||||
input MovieCreateInput {
|
||||
name: String!
|
||||
aliases: String
|
||||
"""Duration in seconds"""
|
||||
"Duration in seconds"
|
||||
duration: Int
|
||||
date: String
|
||||
rating: Int
|
||||
# rating expressed as 1-5
|
||||
rating: Int @deprecated(reason: "Use 1-100 range with rating100")
|
||||
# rating expressed as 1-100
|
||||
rating100: Int
|
||||
studio_id: ID
|
||||
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
|
||||
}
|
||||
|
||||
@@ -43,21 +49,27 @@ input MovieUpdateInput {
|
||||
aliases: String
|
||||
duration: Int
|
||||
date: String
|
||||
rating: Int
|
||||
# rating expressed as 1-5
|
||||
rating: Int @deprecated(reason: "Use 1-100 range with rating100")
|
||||
# rating expressed as 1-100
|
||||
rating100: Int
|
||||
studio_id: ID
|
||||
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
|
||||
}
|
||||
|
||||
input BulkMovieUpdateInput {
|
||||
clientMutationId: String
|
||||
ids: [ID!]
|
||||
rating: Int
|
||||
# rating expressed as 1-5
|
||||
rating: Int @deprecated(reason: "Use 1-100 range with rating100")
|
||||
# rating expressed as 1-100
|
||||
rating100: Int
|
||||
studio_id: ID
|
||||
director: String
|
||||
}
|
||||
|
||||
@@ -7,10 +7,16 @@ enum GenderEnum {
|
||||
NON_BINARY
|
||||
}
|
||||
|
||||
enum CircumisedEnum {
|
||||
CUT
|
||||
UNCUT
|
||||
}
|
||||
|
||||
type Performer {
|
||||
id: ID!
|
||||
checksum: String!
|
||||
name: String
|
||||
checksum: String @deprecated(reason: "Not used")
|
||||
name: String!
|
||||
disambiguation: String
|
||||
url: String
|
||||
gender: GenderEnum
|
||||
twitter: String
|
||||
@@ -19,57 +25,75 @@ type Performer {
|
||||
ethnicity: String
|
||||
country: String
|
||||
eye_color: String
|
||||
height: String
|
||||
height: String @deprecated(reason: "Use height_cm")
|
||||
height_cm: Int
|
||||
measurements: String
|
||||
fake_tits: String
|
||||
penis_length: Float
|
||||
circumcised: CircumisedEnum
|
||||
career_length: String
|
||||
tattoos: String
|
||||
piercings: String
|
||||
aliases: String
|
||||
aliases: String @deprecated(reason: "Use alias_list")
|
||||
alias_list: [String!]!
|
||||
favorite: Boolean!
|
||||
tags: [Tag!]!
|
||||
ignore_auto_tag: Boolean!
|
||||
|
||||
image_path: String # Resolver
|
||||
scene_count: Int # Resolver
|
||||
image_count: Int # Resolver
|
||||
gallery_count: Int # Resolver
|
||||
scene_count: Int! # Resolver
|
||||
image_count: Int! # Resolver
|
||||
gallery_count: Int! # Resolver
|
||||
movie_count: Int! # Resolver
|
||||
performer_count: Int! # Resolver
|
||||
o_counter: Int # Resolver
|
||||
scenes: [Scene!]!
|
||||
stash_ids: [StashID!]!
|
||||
rating: Int
|
||||
# rating expressed as 1-5
|
||||
rating: Int @deprecated(reason: "Use 1-100 range with rating100")
|
||||
# rating expressed as 1-100
|
||||
rating100: Int
|
||||
details: String
|
||||
death_date: String
|
||||
hair_color: String
|
||||
weight: Int
|
||||
created_at: Time!
|
||||
updated_at: Time!
|
||||
movie_count: Int
|
||||
movies: [Movie!]!
|
||||
}
|
||||
|
||||
input PerformerCreateInput {
|
||||
name: String!
|
||||
disambiguation: String
|
||||
url: String
|
||||
gender: GenderEnum
|
||||
birthdate: String
|
||||
ethnicity: String
|
||||
country: String
|
||||
eye_color: String
|
||||
height: String
|
||||
# height must be parsable into an integer
|
||||
height: String @deprecated(reason: "Use height_cm")
|
||||
height_cm: Int
|
||||
measurements: String
|
||||
fake_tits: String
|
||||
penis_length: Float
|
||||
circumcised: CircumisedEnum
|
||||
career_length: String
|
||||
tattoos: String
|
||||
piercings: String
|
||||
aliases: String
|
||||
aliases: String @deprecated(reason: "Use alias_list")
|
||||
alias_list: [String!]
|
||||
twitter: String
|
||||
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: Int
|
||||
# rating expressed as 1-5
|
||||
rating: Int @deprecated(reason: "Use 1-100 range with rating100")
|
||||
# rating expressed as 1-100
|
||||
rating100: Int
|
||||
details: String
|
||||
death_date: String
|
||||
hair_color: String
|
||||
@@ -80,27 +104,36 @@ input PerformerCreateInput {
|
||||
input PerformerUpdateInput {
|
||||
id: ID!
|
||||
name: String
|
||||
disambiguation: String
|
||||
url: String
|
||||
gender: GenderEnum
|
||||
birthdate: String
|
||||
ethnicity: String
|
||||
country: String
|
||||
eye_color: String
|
||||
height: String
|
||||
# height must be parsable into an integer
|
||||
height: String @deprecated(reason: "Use height_cm")
|
||||
height_cm: Int
|
||||
measurements: String
|
||||
fake_tits: String
|
||||
penis_length: Float
|
||||
circumcised: CircumisedEnum
|
||||
career_length: String
|
||||
tattoos: String
|
||||
piercings: String
|
||||
aliases: String
|
||||
aliases: String @deprecated(reason: "Use alias_list")
|
||||
alias_list: [String!]
|
||||
twitter: String
|
||||
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: Int
|
||||
# rating expressed as 1-5
|
||||
rating: Int @deprecated(reason: "Use 1-100 range with rating100")
|
||||
# rating expressed as 1-100
|
||||
rating100: Int
|
||||
details: String
|
||||
death_date: String
|
||||
hair_color: String
|
||||
@@ -108,27 +141,41 @@ input PerformerUpdateInput {
|
||||
ignore_auto_tag: Boolean
|
||||
}
|
||||
|
||||
input BulkUpdateStrings {
|
||||
values: [String!]
|
||||
mode: BulkUpdateIdMode!
|
||||
}
|
||||
|
||||
input BulkPerformerUpdateInput {
|
||||
clientMutationId: String
|
||||
ids: [ID!]
|
||||
disambiguation: String
|
||||
url: String
|
||||
gender: GenderEnum
|
||||
birthdate: String
|
||||
ethnicity: String
|
||||
country: String
|
||||
eye_color: String
|
||||
height: String
|
||||
# height must be parsable into an integer
|
||||
height: String @deprecated(reason: "Use height_cm")
|
||||
height_cm: Int
|
||||
measurements: String
|
||||
fake_tits: String
|
||||
penis_length: Float
|
||||
circumcised: CircumisedEnum
|
||||
career_length: String
|
||||
tattoos: String
|
||||
piercings: String
|
||||
aliases: String
|
||||
aliases: String @deprecated(reason: "Use alias_list")
|
||||
alias_list: BulkUpdateStrings
|
||||
twitter: String
|
||||
instagram: String
|
||||
favorite: Boolean
|
||||
tag_ids: BulkUpdateIds
|
||||
rating: Int
|
||||
# rating expressed as 1-5
|
||||
rating: Int @deprecated(reason: "Use 1-100 range with rating100")
|
||||
# rating expressed as 1-100
|
||||
rating100: Int
|
||||
details: String
|
||||
death_date: String
|
||||
hair_color: String
|
||||
|
||||
@@ -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!]
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
type SceneMarkerTag {
|
||||
tag: Tag!
|
||||
scene_markers: [SceneMarker!]!
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -26,10 +26,10 @@ input SceneMarkerCreateInput {
|
||||
|
||||
input SceneMarkerUpdateInput {
|
||||
id: ID!
|
||||
title: String!
|
||||
seconds: Float!
|
||||
scene_id: ID!
|
||||
primary_tag_id: ID!
|
||||
title: String
|
||||
seconds: Float
|
||||
scene_id: ID
|
||||
primary_tag_id: ID
|
||||
tag_ids: [ID!]
|
||||
}
|
||||
|
||||
@@ -42,4 +42,4 @@ type MarkerStringsResultType {
|
||||
count: Int!
|
||||
id: ID!
|
||||
title: String!
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ type ScenePathsType {
|
||||
stream: String # Resolver
|
||||
webp: String # Resolver
|
||||
vtt: String # Resolver
|
||||
chapters_vtt: String # Resolver
|
||||
chapters_vtt: String @deprecated
|
||||
sprite: String # Resolver
|
||||
funscript: String # Resolver
|
||||
interactive_heatmap: String # Resolver
|
||||
@@ -37,10 +37,16 @@ type Scene {
|
||||
checksum: String @deprecated(reason: "Use files.fingerprints")
|
||||
oshash: String @deprecated(reason: "Use files.fingerprints")
|
||||
title: String
|
||||
code: String
|
||||
details: String
|
||||
url: String
|
||||
director: String
|
||||
url: String @deprecated(reason: "Use urls")
|
||||
urls: [String!]
|
||||
date: String
|
||||
rating: Int
|
||||
# rating expressed as 1-5
|
||||
rating: Int @deprecated(reason: "Use 1-100 range with rating100")
|
||||
# rating expressed as 1-100
|
||||
rating100: Int
|
||||
organized: Boolean!
|
||||
o_counter: Int
|
||||
path: String! @deprecated(reason: "Use files.path")
|
||||
@@ -51,11 +57,18 @@ type Scene {
|
||||
created_at: Time!
|
||||
updated_at: Time!
|
||||
file_mod_time: Time
|
||||
"The last time play count was updated"
|
||||
last_played_at: Time
|
||||
"The time index a scene was left at"
|
||||
resume_time: Float
|
||||
"The total time a scene has spent playing"
|
||||
play_duration: Float
|
||||
"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
|
||||
@@ -64,7 +77,7 @@ type Scene {
|
||||
performers: [Performer!]!
|
||||
stash_ids: [StashID!]!
|
||||
|
||||
"""Return valid stream paths"""
|
||||
"Return valid stream paths"
|
||||
sceneStreams: [SceneStreamEndpoint!]!
|
||||
}
|
||||
|
||||
@@ -73,24 +86,68 @@ input SceneMovieInput {
|
||||
scene_index: Int
|
||||
}
|
||||
|
||||
input SceneUpdateInput {
|
||||
clientMutationId: String
|
||||
id: ID!
|
||||
input SceneCreateInput {
|
||||
title: String
|
||||
code: String
|
||||
details: String
|
||||
url: String
|
||||
director: String
|
||||
url: String @deprecated(reason: "Use urls")
|
||||
urls: [String!]
|
||||
date: String
|
||||
rating: Int
|
||||
# rating expressed as 1-5
|
||||
rating: Int @deprecated(reason: "Use 1-100 range with rating100")
|
||||
# rating expressed as 1-100
|
||||
rating100: Int
|
||||
organized: Boolean
|
||||
studio_id: ID
|
||||
gallery_ids: [ID!]
|
||||
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.
|
||||
"""
|
||||
file_ids: [ID!]
|
||||
}
|
||||
|
||||
input SceneUpdateInput {
|
||||
clientMutationId: String
|
||||
id: ID!
|
||||
title: String
|
||||
code: String
|
||||
details: String
|
||||
director: String
|
||||
url: String @deprecated(reason: "Use urls")
|
||||
urls: [String!]
|
||||
date: String
|
||||
# rating expressed as 1-5
|
||||
rating: Int @deprecated(reason: "Use 1-100 range with rating100")
|
||||
# rating expressed as 1-100
|
||||
rating100: Int
|
||||
o_counter: Int
|
||||
organized: Boolean
|
||||
studio_id: ID
|
||||
gallery_ids: [ID!]
|
||||
performer_ids: [ID!]
|
||||
movies: [SceneMovieInput!]
|
||||
tag_ids: [ID!]
|
||||
"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"
|
||||
resume_time: Float
|
||||
"The total time a scene has spent playing"
|
||||
play_duration: Float
|
||||
"The number ot times a scene has been played"
|
||||
play_count: Int
|
||||
|
||||
primary_file_id: ID
|
||||
}
|
||||
|
||||
@@ -109,16 +166,22 @@ input BulkSceneUpdateInput {
|
||||
clientMutationId: String
|
||||
ids: [ID!]
|
||||
title: String
|
||||
code: String
|
||||
details: String
|
||||
url: String
|
||||
director: String
|
||||
url: String @deprecated(reason: "Use urls")
|
||||
urls: BulkUpdateStrings
|
||||
date: String
|
||||
rating: Int
|
||||
# rating expressed as 1-5
|
||||
rating: Int @deprecated(reason: "Use 1-100 range with rating100")
|
||||
# rating expressed as 1-100
|
||||
rating100: Int
|
||||
organized: Boolean
|
||||
studio_id: ID
|
||||
gallery_ids: BulkUpdateIds
|
||||
performer_ids: BulkUpdateIds
|
||||
tag_ids: BulkUpdateIds
|
||||
movie_ids: BulkUpdateIds
|
||||
movie_ids: BulkUpdateIds
|
||||
}
|
||||
|
||||
input SceneDestroyInput {
|
||||
@@ -135,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
|
||||
}
|
||||
|
||||
@@ -157,10 +220,15 @@ type SceneMovieID {
|
||||
type SceneParserResult {
|
||||
scene: Scene!
|
||||
title: String
|
||||
code: String
|
||||
details: String
|
||||
director: String
|
||||
url: String
|
||||
date: String
|
||||
rating: Int
|
||||
# rating expressed as 1-5
|
||||
rating: Int @deprecated(reason: "Use 1-100 range with rating100")
|
||||
# rating expressed as 1-100
|
||||
rating100: Int
|
||||
studio_id: ID
|
||||
gallery_ids: [ID!]
|
||||
performer_ids: [ID!]
|
||||
@@ -183,3 +251,19 @@ type SceneStreamEndpoint {
|
||||
mime_type: String
|
||||
label: String
|
||||
}
|
||||
|
||||
input AssignSceneFileInput {
|
||||
scene_id: ID!
|
||||
file_id: ID!
|
||||
}
|
||||
|
||||
input SceneMergeInput {
|
||||
"""
|
||||
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
|
||||
values: SceneUpdateInput
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
"""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
|
||||
gender: String
|
||||
url: String
|
||||
twitter: String
|
||||
@@ -14,13 +15,16 @@ type ScrapedPerformer {
|
||||
height: String
|
||||
measurements: String
|
||||
fake_tits: String
|
||||
penis_length: String
|
||||
circumcised: String
|
||||
career_length: String
|
||||
tattoos: String
|
||||
piercings: String
|
||||
# aliases must be comma-delimited to be parsed correctly
|
||||
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
|
||||
@@ -31,9 +35,10 @@ type ScrapedPerformer {
|
||||
}
|
||||
|
||||
input ScrapedPerformerInput {
|
||||
"""Set if performer matched"""
|
||||
"Set if performer matched"
|
||||
stored_id: ID
|
||||
name: String
|
||||
disambiguation: String
|
||||
gender: String
|
||||
url: String
|
||||
twitter: String
|
||||
@@ -45,6 +50,8 @@ input ScrapedPerformerInput {
|
||||
height: String
|
||||
measurements: String
|
||||
fake_tits: String
|
||||
penis_length: String
|
||||
circumcised: String
|
||||
career_length: String
|
||||
tattoos: String
|
||||
piercings: String
|
||||
@@ -57,4 +64,4 @@ input ScrapedPerformerInput {
|
||||
hair_color: String
|
||||
weight: String
|
||||
remote_site_id: String
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,60 +16,63 @@ 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
|
||||
parent: ScrapedStudio
|
||||
image: String
|
||||
|
||||
remote_site_id: String
|
||||
}
|
||||
|
||||
type ScrapedTag {
|
||||
"""Set if tag matched"""
|
||||
"Set if tag matched"
|
||||
stored_id: ID
|
||||
name: String!
|
||||
}
|
||||
|
||||
type ScrapedScene {
|
||||
title: String
|
||||
code: String
|
||||
details: String
|
||||
url: String
|
||||
director: String
|
||||
url: String @deprecated(reason: "use urls")
|
||||
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!]
|
||||
@@ -82,8 +85,11 @@ type ScrapedScene {
|
||||
|
||||
input ScrapedSceneInput {
|
||||
title: String
|
||||
code: String
|
||||
details: String
|
||||
url: String
|
||||
director: String
|
||||
url: String @deprecated(reason: "use urls")
|
||||
urls: [String!]
|
||||
date: String
|
||||
|
||||
# no image, file, duration or relationships
|
||||
@@ -112,84 +118,91 @@ 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"""
|
||||
input ScrapeSingleStudioInput {
|
||||
"""
|
||||
Query can be either a name or a Stash ID
|
||||
"""
|
||||
query: String
|
||||
"""Instructs to query by performer id"""
|
||||
}
|
||||
|
||||
input ScrapeSinglePerformerInput {
|
||||
"Instructs to query by string"
|
||||
query: String
|
||||
"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
|
||||
}
|
||||
|
||||
@@ -204,16 +217,22 @@ type StashBoxFingerprint {
|
||||
duration: Int!
|
||||
}
|
||||
|
||||
"""If neither performer_ids nor performer_names are set, tag all performers"""
|
||||
input StashBoxBatchPerformerTagInput {
|
||||
"Stash endpoint to use for the performer tagging"
|
||||
"If neither ids nor names are set, tag all items"
|
||||
input StashBoxBatchTagInput {
|
||||
"Stash endpoint to use for the tagging"
|
||||
endpoint: Int!
|
||||
"Fields to exclude when executing the performer tagging"
|
||||
"Fields to exclude when executing the tagging"
|
||||
exclude_fields: [String!]
|
||||
"Refresh performers already tagged by StashBox if true. Only tag performers with no StashBox tagging if false"
|
||||
"Refresh items already tagged by StashBox if true. Only tag items with no StashBox tagging if false"
|
||||
refresh: Boolean!
|
||||
"If batch adding studios, should their parent studios also be created?"
|
||||
createParent: Boolean!
|
||||
"If set, only tag these ids"
|
||||
ids: [ID!]
|
||||
"If set, only tag these names"
|
||||
names: [String!]
|
||||
"If set, only tag these performer ids"
|
||||
performer_ids: [ID!]
|
||||
performer_ids: [ID!] @deprecated(reason: "use ids")
|
||||
"If set, only tag these performer names"
|
||||
performer_names: [String!]
|
||||
performer_names: [String!] @deprecated(reason: "use names")
|
||||
}
|
||||
|
||||
20
graphql/schema/types/sql.graphql
Normal file
20
graphql/schema/types/sql.graphql
Normal file
@@ -0,0 +1,20 @@
|
||||
type SQLQueryResult {
|
||||
"The column names, in the order they appear in the result set."
|
||||
columns: [String!]!
|
||||
"The returned rows."
|
||||
rows: [[Any]!]!
|
||||
}
|
||||
|
||||
type SQLExecResult {
|
||||
"""
|
||||
The number of rows affected by the query, usually an UPDATE, INSERT, or DELETE.
|
||||
Not all queries or databases support this feature.
|
||||
"""
|
||||
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.
|
||||
Not all databases support this feature, and the syntax of such statements varies.
|
||||
"""
|
||||
last_insert_id: Int64
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -9,4 +9,8 @@ type StatsResultType {
|
||||
studio_count: Int!
|
||||
movie_count: Int!
|
||||
tag_count: Int!
|
||||
total_o_count: Int!
|
||||
total_play_duration: Float!
|
||||
total_play_count: Int!
|
||||
scenes_played: Int!
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
type Studio {
|
||||
id: ID!
|
||||
checksum: String!
|
||||
name: String!
|
||||
checksum: String! @deprecated(reason: "MD5 hash of name, use name directly")
|
||||
url: String
|
||||
parent_studio: Studio
|
||||
child_studios: [Studio!]!
|
||||
@@ -9,15 +9,19 @@ type Studio {
|
||||
ignore_auto_tag: Boolean!
|
||||
|
||||
image_path: String # Resolver
|
||||
scene_count: Int # Resolver
|
||||
image_count: Int # Resolver
|
||||
gallery_count: Int # Resolver
|
||||
scene_count(depth: Int): Int! # Resolver
|
||||
image_count(depth: Int): Int! # Resolver
|
||||
gallery_count(depth: Int): Int! # Resolver
|
||||
performer_count(depth: Int): Int! # Resolver
|
||||
movie_count(depth: Int): Int! # Resolver
|
||||
stash_ids: [StashID!]!
|
||||
rating: Int
|
||||
# rating expressed as 1-5
|
||||
rating: Int @deprecated(reason: "Use 1-100 range with rating100")
|
||||
# rating expressed as 1-100
|
||||
rating100: Int
|
||||
details: String
|
||||
created_at: Time!
|
||||
updated_at: Time!
|
||||
movie_count: Int
|
||||
movies: [Movie!]!
|
||||
}
|
||||
|
||||
@@ -25,10 +29,13 @@ 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: Int
|
||||
# rating expressed as 1-5
|
||||
rating: Int @deprecated(reason: "Use 1-100 range with rating100")
|
||||
# rating expressed as 1-100
|
||||
rating100: Int
|
||||
details: String
|
||||
aliases: [String!]
|
||||
ignore_auto_tag: Boolean
|
||||
@@ -38,11 +45,14 @@ 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: Int
|
||||
# rating expressed as 1-5
|
||||
rating: Int @deprecated(reason: "Use 1-100 range with rating100")
|
||||
# rating expressed as 1-100
|
||||
rating100: Int
|
||||
details: String
|
||||
aliases: [String!]
|
||||
ignore_auto_tag: Boolean
|
||||
|
||||
@@ -8,12 +8,11 @@ type Tag {
|
||||
updated_at: Time!
|
||||
|
||||
image_path: String # Resolver
|
||||
scene_count: Int # Resolver
|
||||
scene_marker_count: Int # Resolver
|
||||
image_count: Int # Resolver
|
||||
gallery_count: Int # Resolver
|
||||
performer_count: Int
|
||||
|
||||
scene_count(depth: Int): Int! # Resolver
|
||||
scene_marker_count(depth: Int): Int! # Resolver
|
||||
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!]
|
||||
|
||||
@@ -4,7 +4,9 @@ type Version {
|
||||
build_time: String!
|
||||
}
|
||||
|
||||
type ShortVersion {
|
||||
type LatestVersion {
|
||||
version: String!
|
||||
shorthash: String!
|
||||
release_date: String!
|
||||
url: String!
|
||||
}
|
||||
|
||||
@@ -16,6 +16,10 @@ fragment StudioFragment on Studio {
|
||||
urls {
|
||||
...URLFragment
|
||||
}
|
||||
parent {
|
||||
name
|
||||
id
|
||||
}
|
||||
images {
|
||||
...ImageFragment
|
||||
}
|
||||
@@ -94,7 +98,9 @@ fragment FingerprintFragment on Fingerprint {
|
||||
fragment SceneFragment on Scene {
|
||||
id
|
||||
title
|
||||
code
|
||||
details
|
||||
director
|
||||
duration
|
||||
date
|
||||
urls {
|
||||
@@ -129,7 +135,9 @@ query FindScenesByFullFingerprints($fingerprints: [FingerprintQueryInput!]!) {
|
||||
}
|
||||
}
|
||||
|
||||
query FindScenesBySceneFingerprints($fingerprints: [[FingerprintQueryInput!]!]!) {
|
||||
query FindScenesBySceneFingerprints(
|
||||
$fingerprints: [[FingerprintQueryInput!]!]!
|
||||
) {
|
||||
findScenesBySceneFingerprints(fingerprints: $fingerprints) {
|
||||
...SceneFragment
|
||||
}
|
||||
@@ -159,6 +167,12 @@ query FindSceneByID($id: ID!) {
|
||||
}
|
||||
}
|
||||
|
||||
query FindStudio($id: ID, $name: String) {
|
||||
findStudio(id: $id, name: $name) {
|
||||
...StudioFragment
|
||||
}
|
||||
}
|
||||
|
||||
mutation SubmitFingerprint($input: FingerprintSubmission!) {
|
||||
submitFingerprint(input: $input)
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/stashapp/stash/internal/manager"
|
||||
@@ -13,21 +14,19 @@ import (
|
||||
"github.com/stashapp/stash/pkg/session"
|
||||
)
|
||||
|
||||
const loginEndPoint = "/login"
|
||||
|
||||
const (
|
||||
tripwireActivatedErrMsg = "Stash is exposed to the public internet without authentication, and is not serving any more content to protect your privacy. " +
|
||||
"More information and fixes are available at https://github.com/stashapp/stash/wiki/Authentication-Required-When-Accessing-Stash-From-the-Internet"
|
||||
"More information and fixes are available at https://docs.stashapp.cc/networking/authentication-required-when-accessing-stash-from-the-internet"
|
||||
|
||||
externalAccessErrMsg = "You have attempted to access Stash over the internet, and authentication is not enabled. " +
|
||||
"This is extremely dangerous! The whole world can see your your stash page and browse your files! " +
|
||||
"Stash is not answering any other requests to protect your privacy. " +
|
||||
"Please read the log entry or visit https://github.com/stashapp/stash/wiki/Authentication-Required-When-Accessing-Stash-From-the-Internet"
|
||||
"Please read the log entry or visit https://docs.stashapp.cc/networking/authentication-required-when-accessing-stash-from-the-internet"
|
||||
)
|
||||
|
||||
func allowUnauthenticated(r *http.Request) bool {
|
||||
// #2715 - allow access to UI files
|
||||
return strings.HasPrefix(r.URL.Path, loginEndPoint) || r.URL.Path == "/css" || strings.HasPrefix(r.URL.Path, "/assets")
|
||||
return strings.HasPrefix(r.URL.Path, loginEndpoint) || r.URL.Path == logoutEndpoint || r.URL.Path == "/css" || strings.HasPrefix(r.URL.Path, "/assets")
|
||||
}
|
||||
|
||||
func authenticateHandler() func(http.Handler) http.Handler {
|
||||
@@ -35,38 +34,41 @@ func authenticateHandler() func(http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
c := config.GetInstance()
|
||||
|
||||
if !checkSecurityTripwireActivated(c, w) {
|
||||
// error if external access tripwire activated
|
||||
if accessErr := session.CheckExternalAccessTripwire(c); accessErr != nil {
|
||||
http.Error(w, tripwireActivatedErrMsg, http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
||||
userID, err := manager.GetInstance().SessionStore.Authenticate(w, r)
|
||||
if err != nil {
|
||||
if errors.Is(err, session.ErrUnauthorized) {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
_, err = w.Write([]byte(err.Error()))
|
||||
if err != nil {
|
||||
logger.Error(err)
|
||||
}
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
// unauthorized error
|
||||
w.Header().Add("WWW-Authenticate", `FormBased`)
|
||||
w.Header().Add("WWW-Authenticate", "FormBased")
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
if err := session.CheckAllowPublicWithoutAuth(c, r); err != nil {
|
||||
var externalAccess session.ExternalAccessError
|
||||
switch {
|
||||
case errors.As(err, &externalAccess):
|
||||
securityActivateTripwireAccessedFromInternetWithoutAuth(c, externalAccess, w)
|
||||
return
|
||||
default:
|
||||
var accessErr session.ExternalAccessError
|
||||
if errors.As(err, &accessErr) {
|
||||
session.LogExternalAccessError(accessErr)
|
||||
|
||||
err := c.ActivatePublicAccessTripwire(net.IP(accessErr).String())
|
||||
if err != nil {
|
||||
logger.Errorf("Error activating public access tripwire: %v", err)
|
||||
}
|
||||
|
||||
http.Error(w, externalAccessErrMsg, http.StatusForbidden)
|
||||
} else {
|
||||
logger.Errorf("Error checking external access security: %v", err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
ctx := r.Context()
|
||||
@@ -74,23 +76,27 @@ func authenticateHandler() func(http.Handler) http.Handler {
|
||||
if c.HasCredentials() {
|
||||
// authentication is required
|
||||
if userID == "" && !allowUnauthenticated(r) {
|
||||
// authentication was not received, redirect
|
||||
// if graphql was requested, we just return a forbidden error
|
||||
if r.URL.Path == "/graphql" {
|
||||
w.Header().Add("WWW-Authenticate", `FormBased`)
|
||||
// if graphql or a non-webpage was requested, we just return a forbidden error
|
||||
ext := path.Ext(r.URL.Path)
|
||||
if r.URL.Path == gqlEndpoint || (ext != "" && ext != ".html") {
|
||||
w.Header().Add("WWW-Authenticate", "FormBased")
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
prefix := getProxyPrefix(r.Header)
|
||||
prefix := getProxyPrefix(r)
|
||||
|
||||
// otherwise redirect to the login page
|
||||
u := url.URL{
|
||||
Path: prefix + "/login",
|
||||
returnURL := url.URL{
|
||||
Path: prefix + r.URL.Path,
|
||||
RawQuery: r.URL.RawQuery,
|
||||
}
|
||||
q := make(url.Values)
|
||||
q.Set(returnURLParam, returnURL.String())
|
||||
u := url.URL{
|
||||
Path: prefix + loginEndpoint,
|
||||
RawQuery: q.Encode(),
|
||||
}
|
||||
q := u.Query()
|
||||
q.Set(returnURLParam, prefix+r.URL.Path)
|
||||
u.RawQuery = q.Encode()
|
||||
http.Redirect(w, r, u.String(), http.StatusFound)
|
||||
return
|
||||
}
|
||||
@@ -104,31 +110,3 @@ func authenticateHandler() func(http.Handler) http.Handler {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func checkSecurityTripwireActivated(c *config.Instance, w http.ResponseWriter) bool {
|
||||
if accessErr := session.CheckExternalAccessTripwire(c); accessErr != nil {
|
||||
w.WriteHeader(http.StatusForbidden)
|
||||
_, err := w.Write([]byte(tripwireActivatedErrMsg))
|
||||
if err != nil {
|
||||
logger.Error(err)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func securityActivateTripwireAccessedFromInternetWithoutAuth(c *config.Instance, accessErr session.ExternalAccessError, w http.ResponseWriter) {
|
||||
session.LogExternalAccessError(accessErr)
|
||||
|
||||
err := c.ActivatePublicAccessTripwire(net.IP(accessErr).String())
|
||||
if err != nil {
|
||||
logger.Error(err)
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusForbidden)
|
||||
_, err = w.Write([]byte(externalAccessErrMsg))
|
||||
if err != nil {
|
||||
logger.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type byteRange struct {
|
||||
Start int64
|
||||
End *int64
|
||||
RawString string
|
||||
}
|
||||
|
||||
func createByteRange(s string) byteRange {
|
||||
// strip bytes=
|
||||
r := strings.TrimPrefix(s, "bytes=")
|
||||
e := strings.Split(r, "-")
|
||||
|
||||
ret := byteRange{
|
||||
RawString: s,
|
||||
}
|
||||
if len(e) > 0 {
|
||||
ret.Start, _ = strconv.ParseInt(e[0], 10, 64)
|
||||
}
|
||||
if len(e) > 1 && e[1] != "" {
|
||||
end, _ := strconv.ParseInt(e[1], 10, 64)
|
||||
ret.End = &end
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func (r byteRange) toHeaderValue(fileLength int64) string {
|
||||
if r.End == nil {
|
||||
return ""
|
||||
}
|
||||
end := *r.End
|
||||
return "bytes " + strconv.FormatInt(r.Start, 10) + "-" + strconv.FormatInt(end, 10) + "/" + strconv.FormatInt(fileLength, 10)
|
||||
}
|
||||
|
||||
func (r byteRange) apply(bytes []byte) []byte {
|
||||
if r.End == nil {
|
||||
return bytes[r.Start:]
|
||||
}
|
||||
|
||||
end := *r.End + 1
|
||||
if int(end) > len(bytes) {
|
||||
end = int64(len(bytes))
|
||||
}
|
||||
return bytes[r.Start:end]
|
||||
}
|
||||
@@ -2,9 +2,9 @@ package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/99designs/gqlgen/graphql"
|
||||
"github.com/stashapp/stash/pkg/models"
|
||||
@@ -19,19 +19,35 @@ func getArgumentMap(ctx context.Context) map[string]interface{} {
|
||||
}
|
||||
|
||||
func getUpdateInputMap(ctx context.Context) map[string]interface{} {
|
||||
return getNamedUpdateInputMap(ctx, updateInputField)
|
||||
}
|
||||
|
||||
func getNamedUpdateInputMap(ctx context.Context, field string) map[string]interface{} {
|
||||
args := getArgumentMap(ctx)
|
||||
|
||||
input := args[updateInputField]
|
||||
var ret map[string]interface{}
|
||||
if input != nil {
|
||||
ret, _ = input.(map[string]interface{})
|
||||
// field can be qualified
|
||||
fields := strings.Split(field, ".")
|
||||
|
||||
currArgs := args
|
||||
|
||||
for _, f := range fields {
|
||||
v, found := currArgs[f]
|
||||
if !found {
|
||||
currArgs = nil
|
||||
break
|
||||
}
|
||||
|
||||
currArgs, _ = v.(map[string]interface{})
|
||||
if currArgs == nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if ret == nil {
|
||||
ret = make(map[string]interface{})
|
||||
if currArgs != nil {
|
||||
return currArgs
|
||||
}
|
||||
|
||||
return ret
|
||||
return make(map[string]interface{})
|
||||
}
|
||||
|
||||
func getUpdateInputMaps(ctx context.Context) []map[string]interface{} {
|
||||
@@ -75,19 +91,12 @@ func (t changesetTranslator) getFields() []string {
|
||||
return ret
|
||||
}
|
||||
|
||||
func (t changesetTranslator) nullString(value *string, field string) *sql.NullString {
|
||||
if !t.hasField(field) {
|
||||
return nil
|
||||
func (t changesetTranslator) string(value *string, field string) string {
|
||||
if value == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
ret := &sql.NullString{}
|
||||
|
||||
if value != nil {
|
||||
ret.String = *value
|
||||
ret.Valid = true
|
||||
}
|
||||
|
||||
return ret
|
||||
return *value
|
||||
}
|
||||
|
||||
func (t changesetTranslator) optionalString(value *string, field string) models.OptionalString {
|
||||
@@ -98,49 +107,82 @@ func (t changesetTranslator) optionalString(value *string, field string) models.
|
||||
return models.NewOptionalStringPtr(value)
|
||||
}
|
||||
|
||||
func (t changesetTranslator) sqliteDate(value *string, field string) *models.SQLiteDate {
|
||||
func (t changesetTranslator) optionalDate(value *string, field string) (models.OptionalDate, error) {
|
||||
if !t.hasField(field) {
|
||||
return nil
|
||||
return models.OptionalDate{}, nil
|
||||
}
|
||||
|
||||
ret := &models.SQLiteDate{}
|
||||
|
||||
if value != nil {
|
||||
ret.String = *value
|
||||
ret.Valid = true
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func (t changesetTranslator) optionalDate(value *string, field string) models.OptionalDate {
|
||||
if !t.hasField(field) {
|
||||
return models.OptionalDate{}
|
||||
}
|
||||
|
||||
if value == nil {
|
||||
if value == nil || *value == "" {
|
||||
return models.OptionalDate{
|
||||
Set: true,
|
||||
Null: true,
|
||||
}
|
||||
}, nil
|
||||
}
|
||||
|
||||
return models.NewOptionalDate(models.NewDate(*value))
|
||||
date, err := models.ParseDate(*value)
|
||||
if err != nil {
|
||||
return models.OptionalDate{}, err
|
||||
}
|
||||
|
||||
return models.NewOptionalDate(date), nil
|
||||
}
|
||||
|
||||
func (t changesetTranslator) nullInt64(value *int, field string) *sql.NullInt64 {
|
||||
if !t.hasField(field) {
|
||||
return nil
|
||||
func (t changesetTranslator) datePtr(value *string, field string) (*models.Date, error) {
|
||||
if value == nil || *value == "" {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
ret := &sql.NullInt64{}
|
||||
date, err := models.ParseDate(*value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &date, nil
|
||||
}
|
||||
|
||||
if value != nil {
|
||||
ret.Int64 = int64(*value)
|
||||
ret.Valid = true
|
||||
func (t changesetTranslator) intPtrFromString(value *string, field string) (*int, error) {
|
||||
if value == nil || *value == "" {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return ret
|
||||
vv, err := strconv.Atoi(*value)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("converting %v to int: %w", *value, err)
|
||||
}
|
||||
return &vv, nil
|
||||
}
|
||||
|
||||
func (t changesetTranslator) ratingConversionInt(legacyValue *int, rating100Value *int) *int {
|
||||
const (
|
||||
legacyField = "rating"
|
||||
rating100Field = "rating100"
|
||||
)
|
||||
|
||||
legacyRating := t.optionalInt(legacyValue, legacyField)
|
||||
if legacyRating.Set && !(legacyRating.Null) {
|
||||
ret := int(models.Rating5To100(int(legacyRating.Value)))
|
||||
return &ret
|
||||
}
|
||||
|
||||
o := t.optionalInt(rating100Value, rating100Field)
|
||||
if o.Set && !(o.Null) {
|
||||
return &o.Value
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t changesetTranslator) ratingConversionOptional(legacyValue *int, rating100Value *int) models.OptionalInt {
|
||||
const (
|
||||
legacyField = "rating"
|
||||
rating100Field = "rating100"
|
||||
)
|
||||
|
||||
legacyRating := t.optionalInt(legacyValue, legacyField)
|
||||
if legacyRating.Set && !(legacyRating.Null) {
|
||||
legacyRating.Value = int(models.Rating5To100(int(legacyRating.Value)))
|
||||
return legacyRating
|
||||
}
|
||||
return t.optionalInt(rating100Value, rating100Field)
|
||||
}
|
||||
|
||||
func (t changesetTranslator) optionalInt(value *int, field string) models.OptionalInt {
|
||||
@@ -151,21 +193,6 @@ func (t changesetTranslator) optionalInt(value *int, field string) models.Option
|
||||
return models.NewOptionalIntPtr(value)
|
||||
}
|
||||
|
||||
func (t changesetTranslator) nullInt64FromString(value *string, field string) *sql.NullInt64 {
|
||||
if !t.hasField(field) {
|
||||
return nil
|
||||
}
|
||||
|
||||
ret := &sql.NullInt64{}
|
||||
|
||||
if value != nil {
|
||||
ret.Int64, _ = strconv.ParseInt(*value, 10, 64)
|
||||
ret.Valid = true
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func (t changesetTranslator) optionalIntFromString(value *string, field string) (models.OptionalInt, error) {
|
||||
if !t.hasField(field) {
|
||||
return models.OptionalInt{}, nil
|
||||
@@ -185,19 +212,12 @@ func (t changesetTranslator) optionalIntFromString(value *string, field string)
|
||||
return models.NewOptionalInt(vv), nil
|
||||
}
|
||||
|
||||
func (t changesetTranslator) nullBool(value *bool, field string) *sql.NullBool {
|
||||
if !t.hasField(field) {
|
||||
return nil
|
||||
func (t changesetTranslator) bool(value *bool, field string) bool {
|
||||
if value == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
ret := &sql.NullBool{}
|
||||
|
||||
if value != nil {
|
||||
ret.Bool = *value
|
||||
ret.Valid = true
|
||||
}
|
||||
|
||||
return ret
|
||||
return *value
|
||||
}
|
||||
|
||||
func (t changesetTranslator) optionalBool(value *bool, field string) models.OptionalBool {
|
||||
@@ -207,3 +227,11 @@ func (t changesetTranslator) optionalBool(value *bool, field string) models.Opti
|
||||
|
||||
return models.NewOptionalBoolPtr(value)
|
||||
}
|
||||
|
||||
func (t changesetTranslator) optionalFloat64(value *float64, field string) models.OptionalFloat64 {
|
||||
if !t.hasField(field) {
|
||||
return models.OptionalFloat64{}
|
||||
}
|
||||
|
||||
return models.NewOptionalFloat64Ptr(value)
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
|
||||
"golang.org/x/sys/cpu"
|
||||
|
||||
"github.com/stashapp/stash/internal/build"
|
||||
"github.com/stashapp/stash/pkg/logger"
|
||||
)
|
||||
|
||||
@@ -21,11 +22,7 @@ const apiReleases string = "https://api.github.com/repos/stashapp/stash/releases
|
||||
const apiTags string = "https://api.github.com/repos/stashapp/stash/tags"
|
||||
const apiAcceptHeader string = "application/vnd.github.v3+json"
|
||||
const developmentTag string = "latest_develop"
|
||||
const defaultSHLength int = 7 // default length of SHA short hash returned by <git rev-parse --short HEAD>
|
||||
|
||||
// ErrNoVersion indicates that no version information has been embedded in the
|
||||
// stash binary
|
||||
var ErrNoVersion = errors.New("no stash version")
|
||||
const defaultSHLength int = 8 // default length of SHA short hash returned by <git rev-parse --short HEAD>
|
||||
|
||||
var stashReleases = func() map[string]string {
|
||||
return map[string]string{
|
||||
@@ -108,14 +105,26 @@ type githubTagResponse struct {
|
||||
Node_id string
|
||||
}
|
||||
|
||||
type LatestRelease struct {
|
||||
Version string
|
||||
Hash string
|
||||
ShortHash string
|
||||
Date string
|
||||
Url string
|
||||
}
|
||||
|
||||
func makeGithubRequest(ctx context.Context, url string, output interface{}) error {
|
||||
transport := &http.Transport{Proxy: http.ProxyFromEnvironment}
|
||||
|
||||
client := &http.Client{
|
||||
Timeout: 3 * time.Second,
|
||||
Timeout: 3 * time.Second,
|
||||
Transport: transport,
|
||||
}
|
||||
|
||||
req, _ := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
||||
|
||||
req.Header.Add("Accept", apiAcceptHeader) // gh api recommendation , send header with api version
|
||||
logger.Debugf("Github API request: %s", url)
|
||||
response, err := client.Do(req)
|
||||
|
||||
if err != nil {
|
||||
@@ -144,14 +153,16 @@ func makeGithubRequest(ctx context.Context, url string, output interface{}) erro
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetLatestVersion gets latest version (git commit hash) from github API
|
||||
// GetLatestRelease gets latest release information from github API
|
||||
// If running a build from the "master" branch, then the latest full release
|
||||
// is used, otherwise it uses the release that is tagged with "latest_develop"
|
||||
// which is the latest pre-release build.
|
||||
func GetLatestVersion(ctx context.Context, shortHash bool) (latestVersion string, latestRelease string, err error) {
|
||||
func GetLatestRelease(ctx context.Context) (*LatestRelease, error) {
|
||||
arch := runtime.GOARCH
|
||||
|
||||
arch := runtime.GOARCH // https://en.wikipedia.org/wiki/Comparison_of_ARM_cores
|
||||
isARMv7 := cpu.ARM.HasNEON || cpu.ARM.HasVFPv3 || cpu.ARM.HasVFPv3D16 || cpu.ARM.HasVFPv4 // armv6 doesn't support any of these features
|
||||
// https://en.wikipedia.org/wiki/Comparison_of_ARM_cores
|
||||
// armv6 doesn't support any of these features
|
||||
isARMv7 := cpu.ARM.HasNEON || cpu.ARM.HasVFPv3 || cpu.ARM.HasVFPv3D16 || cpu.ARM.HasVFPv4
|
||||
if arch == "arm" && isARMv7 {
|
||||
arch = "armv7"
|
||||
}
|
||||
@@ -159,125 +170,118 @@ func GetLatestVersion(ctx context.Context, shortHash bool) (latestVersion string
|
||||
platform := fmt.Sprintf("%s/%s", runtime.GOOS, arch)
|
||||
wantedRelease := stashReleases()[platform]
|
||||
|
||||
version, _, _ := GetVersion()
|
||||
if version == "" {
|
||||
return "", "", ErrNoVersion
|
||||
}
|
||||
|
||||
// if the version is suffixed with -x-xxxx, then we are running a development build
|
||||
usePreRelease := false
|
||||
re := regexp.MustCompile(`-\d+-g\w+$`)
|
||||
if re.MatchString(version) {
|
||||
usePreRelease = true
|
||||
}
|
||||
|
||||
url := apiReleases
|
||||
if !usePreRelease {
|
||||
// just get the latest full release
|
||||
url += "/latest"
|
||||
} else {
|
||||
if build.IsDevelop() {
|
||||
// get the release tagged with the development tag
|
||||
url += "/tags/" + developmentTag
|
||||
} else {
|
||||
// just get the latest full release
|
||||
url += "/latest"
|
||||
}
|
||||
|
||||
release := githubReleasesResponse{}
|
||||
err = makeGithubRequest(ctx, url, &release)
|
||||
|
||||
var release githubReleasesResponse
|
||||
err := makeGithubRequest(ctx, url, &release)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if release.Prerelease == usePreRelease {
|
||||
latestVersion = getReleaseHash(ctx, release, shortHash, usePreRelease)
|
||||
version := release.Name
|
||||
if release.Prerelease {
|
||||
// find version in prerelease name
|
||||
re := regexp.MustCompile(`v[\w-\.]+-\d+-g[0-9a-f]+`)
|
||||
if match := re.FindString(version); match != "" {
|
||||
version = match
|
||||
}
|
||||
}
|
||||
|
||||
if wantedRelease != "" {
|
||||
for _, asset := range release.Assets {
|
||||
if asset.Name == wantedRelease {
|
||||
latestRelease = asset.Browser_download_url
|
||||
break
|
||||
}
|
||||
latestHash, err := getReleaseHash(ctx, release.Tag_name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var releaseDate string
|
||||
if publishedAt, err := time.Parse(time.RFC3339, release.Published_at); err == nil {
|
||||
releaseDate = publishedAt.Format("2006-01-02")
|
||||
}
|
||||
|
||||
var releaseUrl string
|
||||
if wantedRelease != "" {
|
||||
for _, asset := range release.Assets {
|
||||
if asset.Name == wantedRelease {
|
||||
releaseUrl = asset.Browser_download_url
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if latestVersion == "" {
|
||||
return "", "", fmt.Errorf("no version found for \"%s\"", version)
|
||||
_, githash, _ := build.Version()
|
||||
shLength := len(githash)
|
||||
if shLength == 0 {
|
||||
shLength = defaultSHLength
|
||||
}
|
||||
return latestVersion, latestRelease, nil
|
||||
|
||||
return &LatestRelease{
|
||||
Version: version,
|
||||
Hash: latestHash,
|
||||
ShortHash: latestHash[:shLength],
|
||||
Date: releaseDate,
|
||||
Url: releaseUrl,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func getReleaseHash(ctx context.Context, release githubReleasesResponse, shortHash bool, usePreRelease bool) string {
|
||||
shaLength := len(release.Target_commitish)
|
||||
// the /latest API call doesn't return the hash in target_commitish
|
||||
// also add sanity check in case Target_commitish is not 40 characters
|
||||
if !usePreRelease || shaLength != 40 {
|
||||
return getShaFromTags(ctx, shortHash, release.Tag_name)
|
||||
func getReleaseHash(ctx context.Context, tagName string) (string, error) {
|
||||
// Start with a small page size if not searching for latest_develop
|
||||
perPage := 10
|
||||
if tagName == developmentTag {
|
||||
perPage = 100
|
||||
}
|
||||
|
||||
if shortHash {
|
||||
last := defaultSHLength // default length of git short hash
|
||||
_, gitShort, _ := GetVersion() // retrieve it to check actual length
|
||||
if len(gitShort) > last && len(gitShort) < shaLength { // sometimes short hash is longer
|
||||
last = len(gitShort)
|
||||
// Limit to 5 pages, ie 500 tags - should be plenty
|
||||
for page := 1; page <= 5; {
|
||||
url := fmt.Sprintf("%s?per_page=%d&page=%d", apiTags, perPage, page)
|
||||
tags := []githubTagResponse{}
|
||||
err := makeGithubRequest(ctx, url, &tags)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
for _, tag := range tags {
|
||||
if tag.Name == tagName {
|
||||
if len(tag.Commit.Sha) != 40 {
|
||||
return "", errors.New("invalid Github API response")
|
||||
}
|
||||
return tag.Commit.Sha, nil
|
||||
}
|
||||
}
|
||||
|
||||
if len(tags) == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
// if not found in the first 10, search again on page 1 with the first 100
|
||||
if perPage == 10 {
|
||||
perPage = 100
|
||||
} else {
|
||||
page++
|
||||
}
|
||||
return release.Target_commitish[0:last]
|
||||
}
|
||||
|
||||
return release.Target_commitish
|
||||
return "", errors.New("invalid Github API response")
|
||||
}
|
||||
|
||||
func printLatestVersion(ctx context.Context) {
|
||||
_, githash, _ = GetVersion()
|
||||
latest, _, err := GetLatestVersion(ctx, true)
|
||||
latestRelease, err := GetLatestRelease(ctx)
|
||||
if err != nil {
|
||||
logger.Errorf("Couldn't find latest version: %s", err)
|
||||
logger.Errorf("Couldn't retrieve latest version: %v", err)
|
||||
} else {
|
||||
if githash == latest {
|
||||
logger.Infof("Version: (%s) is already the latest released.", latest)
|
||||
} else {
|
||||
logger.Infof("New version: (%s) available.", latest)
|
||||
_, githash, _ := build.Version()
|
||||
switch {
|
||||
case githash == "":
|
||||
logger.Infof("Latest version: %s (%s)", latestRelease.Version, latestRelease.ShortHash)
|
||||
case githash == latestRelease.ShortHash:
|
||||
logger.Infof("Version %s (%s) is already the latest released", latestRelease.Version, latestRelease.ShortHash)
|
||||
default:
|
||||
logger.Infof("New version available: %s (%s)", latestRelease.Version, latestRelease.ShortHash)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// get sha from the github api tags endpoint
|
||||
// returns the sha1 hash/shorthash or "" if something's wrong
|
||||
func getShaFromTags(ctx context.Context, shortHash bool, name string) string {
|
||||
url := apiTags
|
||||
tags := []githubTagResponse{}
|
||||
err := makeGithubRequest(ctx, url, &tags)
|
||||
|
||||
if err != nil {
|
||||
// If the context is canceled, we don't want to log this as an error
|
||||
// in the path. The function here just gives up and returns "" if
|
||||
// something goes wrong. Hence, log the error at the info-level so
|
||||
// it's still present, but don't treat this as an error.
|
||||
if errors.Is(err, context.Canceled) {
|
||||
logger.Infof("aborting sha request due to context cancellation")
|
||||
} else {
|
||||
logger.Errorf("Github Tags Api: %v", err)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
_, gitShort, _ := GetVersion() // retrieve short hash to check actual length
|
||||
|
||||
for _, tag := range tags {
|
||||
if tag.Name == name {
|
||||
shaLength := len(tag.Commit.Sha)
|
||||
if shaLength != 40 {
|
||||
return ""
|
||||
}
|
||||
if shortHash {
|
||||
last := defaultSHLength // default length of git short hash
|
||||
if len(gitShort) > last && len(gitShort) < shaLength { // sometimes short hash is longer
|
||||
last = len(gitShort)
|
||||
}
|
||||
return tag.Commit.Sha[0:last]
|
||||
}
|
||||
|
||||
return tag.Commit.Sha
|
||||
}
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
42
internal/api/error.go
Normal file
42
internal/api/error.go
Normal file
@@ -0,0 +1,42 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
|
||||
"github.com/99designs/gqlgen/graphql"
|
||||
"github.com/stashapp/stash/pkg/logger"
|
||||
"github.com/vektah/gqlparser/v2/gqlerror"
|
||||
)
|
||||
|
||||
func gqlErrorHandler(ctx context.Context, e error) *gqlerror.Error {
|
||||
if !errors.Is(ctx.Err(), context.Canceled) {
|
||||
// log all errors - for now just log the error message
|
||||
// we can potentially add more context later
|
||||
fc := graphql.GetFieldContext(ctx)
|
||||
if fc != nil {
|
||||
logger.Errorf("%s: %v", fc.Path(), e)
|
||||
|
||||
// log the args in debug level
|
||||
logger.DebugFunc(func() (string, []interface{}) {
|
||||
var args interface{}
|
||||
args = fc.Args
|
||||
|
||||
s, _ := json.Marshal(args)
|
||||
if len(s) > 0 {
|
||||
args = string(s)
|
||||
}
|
||||
|
||||
return "%s: %v", []interface{}{
|
||||
fc.Path(),
|
||||
args,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// we may also want to transform the error message for the response
|
||||
// for now just return the original error
|
||||
return graphql.DefaultErrorPresenter(ctx, e)
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user