diff --git a/.gqlgen.yml b/.gqlgen.yml
index 98fae22..e6c7dff 100644
--- a/.gqlgen.yml
+++ b/.gqlgen.yml
@@ -22,18 +22,9 @@ models:
   Int:
     model: github.com/99designs/gqlgen/graphql.Int64
   Torrent:
-    fields:
-      name:
-        resolver: true
-      files:
-        resolver: true
-      excludedFiles:
-        resolver: true
-      peers:
-        resolver: true
     extraFields:
       T:
-        type: "*git.kmsign.ru/royalcat/tstor/src/host/torrent.Controller"
+        type: "*git.kmsign.ru/royalcat/tstor/src/sources/torrent.Controller"
   TorrentFile:
     extraFields:
       F:
@@ -43,32 +34,37 @@ models:
       F:
         type: "*github.com/anacrolix/torrent.PeerConn"
   SimpleDir:
-    fields:
-      entries:
-        resolver: true
     extraFields:
       Path:
         type: string
       FS:
         type: "git.kmsign.ru/royalcat/tstor/src/vfs.Filesystem"
   TorrentFS:
-    fields:
-      entries:
-        resolver: true
     extraFields:
       FS:
-        type: "*git.kmsign.ru/royalcat/tstor/src/host/torrent.TorrentFS"
+        type: "*git.kmsign.ru/royalcat/tstor/src/sources/torrent.TorrentFS"
   ResolverFS:
-    fields:
-      entries:
-        resolver: true
     extraFields:
       FS:
         type: "*git.kmsign.ru/royalcat/tstor/src/vfs.ResolverFS"
   ArchiveFS:
-    fields:
-      entries:
-        resolver: true
     extraFields:
       FS:
         type: "*git.kmsign.ru/royalcat/tstor/src/vfs.ArchiveFS"
+  TorrentOps:
+    extraFields:
+      InfoHash:
+        type: "string"
+  TorrentPriority:
+    model: "github.com/anacrolix/torrent/types.PiecePriority"
+    enum_values:
+      NONE:
+        value: "github.com/anacrolix/torrent/types.PiecePriorityNone"
+      NORMAL:
+        value: "github.com/anacrolix/torrent/types.PiecePriorityNormal"
+      HIGH:
+        value: "github.com/anacrolix/torrent/types.PiecePriorityHigh"
+      READAHEAD:
+        value: "github.com/anacrolix/torrent/types.PiecePriorityReadahead"
+      NOW:
+        value: "github.com/anacrolix/torrent/types.PiecePriorityNow"
diff --git a/.vscode/launch.json b/.vscode/launch.json
index bc0b8c4..7f0b96d 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -5,14 +5,14 @@
     "version": "0.2.0",
     "configurations": [
         {
-            "name": "Launch file",
+            "name": "Generate GraphQL",
             "type": "go",
             "request": "launch",
             "mode": "debug",
-            "program": "${file}"
+            "program": "${workspaceFolder}/cmd/generate-graphql/main.go",
         },
         {
-            "name": "Launch Package",
+            "name": "TStor",
             "type": "go",
             "request": "launch",
             "mode": "auto",
diff --git a/Dockerfile b/Dockerfile
index 89207ed..4e6bb68 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,4 +1,4 @@
-FROM golang:1.22 as builder
+FROM --platform=$BUILDPLATFORM golang:1.22 as builder
 
 WORKDIR /app
 
@@ -14,7 +14,9 @@ COPY ./templates ./templates
 COPY embed.go embed.go
 
 RUN go generate ./...
-RUN --mount=type=cache,mode=0777,target=/go/pkg/mod CGO_ENABLED=0 go build -tags timetzdata -o /tstor ./cmd/tstor/main.go 
+
+ARG TARGETOS TARGETARCH
+RUN --mount=type=cache,mode=0777,target=/go/pkg/mod CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH go build -tags timetzdata -o /tstor ./cmd/tstor/main.go 
 
 
 FROM scratch
diff --git a/Makefile b/Makefile
index a171a40..fa6d5d4 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 generate-graphql: src/delivery/graphql/generated.go ui/lib/api/schema.graphql
 
-src/delivery/graphql/generated.go: .gqlgen.yml graphql/* graphql/types/* cmd/generate-graphql/*
+src/delivery/graphql/generated.go: .gqlgen.yml cmd/generate-graphql/* $(shell find graphql -type f)
 	go run cmd/generate-graphql/main.go
 
 ui/lib/api/schema.graphql: src/delivery/graphql/* cmd/generate-graphql-schema/*
diff --git a/cmd/generate-graphql/main.go b/cmd/generate-graphql/main.go
index ea2d6aa..52f56c4 100644
--- a/cmd/generate-graphql/main.go
+++ b/cmd/generate-graphql/main.go
@@ -10,6 +10,23 @@ import (
 	"github.com/99designs/gqlgen/codegen/config"
 )
 
+func main() {
+	cfg, err := config.LoadConfigFromDefaultLocations()
+	if err != nil {
+		fmt.Fprintln(os.Stderr, "failed to load config", err.Error())
+		os.Exit(2)
+	}
+
+	err = api.Generate(cfg,
+		api.PrependPlugin(&resolverDirective{}),
+		api.AddPlugin(&fieldDirectiveFix{}),
+	)
+	if err != nil {
+		fmt.Fprintln(os.Stderr, err.Error())
+		os.Exit(3)
+	}
+}
+
 type fieldDirectiveFix struct {
 }
 
@@ -25,9 +42,6 @@ func (fieldDirectiveFix) GenerateCode(cfg *codegen.Data) error {
 				for _, v := range field.TypeReference.Definition.Directives {
 					directiveMap[v.Name]++
 				}
-				// for _, v := range field.Object.Directives {
-				// 	directiveMap[v.Name]++
-				// }
 
 				directive := make([]*codegen.Directive, 0, len(field.Directives))
 				for _, v := range field.Directives {
@@ -48,18 +62,33 @@ func (fieldDirectiveFix) GenerateCode(cfg *codegen.Data) error {
 	return nil
 }
 
-func main() {
-	cfg, err := config.LoadConfigFromDefaultLocations()
-	if err != nil {
-		fmt.Fprintln(os.Stderr, "failed to load config", err.Error())
-		os.Exit(2)
+type resolverDirective struct {
+}
+
+func (resolverDirective) Name() string {
+	return "Resolver directive support"
+}
+
+func (resolverDirective) GenerateCode(cfg *codegen.Data) error {
+	const directiveName = "resolver"
+
+	for _, obj := range cfg.Objects {
+		for _, field := range obj.Fields {
+			if field.FieldDefinition.Directives.ForName(directiveName) != nil {
+				fmt.Printf("Add resolver for field %s{%s}\n", obj.Name, field.Name)
+				field.IsResolver = true
+
+				// TODO
+				// field.FieldDefinition.Directives = removeDirective(field.FieldDefinition.Directives, directiveName)
+			}
+		}
 	}
 
-	err = api.Generate(cfg,
-		api.AddPlugin(&fieldDirectiveFix{}),
-	)
-	if err != nil {
-		fmt.Fprintln(os.Stderr, err.Error())
-		os.Exit(3)
-	}
+	return nil
 }
+
+// func removeDirective(directives ast.DirectiveList, name string) ast.DirectiveList {
+// 	return slices.DeleteFunc(directives, func(directive *ast.Directive) bool {
+// 		return directive.Name == name
+// 	})
+// }
diff --git a/go.mod b/go.mod
index d70e962..34fed80 100644
--- a/go.mod
+++ b/go.mod
@@ -3,13 +3,13 @@ module git.kmsign.ru/royalcat/tstor
 go 1.22.3
 
 require (
-	github.com/99designs/gqlgen v0.17.45
+	github.com/99designs/gqlgen v0.17.49
 	github.com/agoda-com/opentelemetry-go/otelslog v0.1.1
 	github.com/agoda-com/opentelemetry-logs-go v0.5.0
 	github.com/anacrolix/dht/v2 v2.21.1
 	github.com/anacrolix/log v0.15.2
 	github.com/anacrolix/missinggo/v2 v2.7.3
-	github.com/anacrolix/torrent v1.56.0
+	github.com/anacrolix/torrent v1.56.1
 	github.com/billziss-gh/cgofuse v1.5.0
 	github.com/bodgit/sevenzip v1.5.1
 	github.com/cyphar/filepath-securejoin v0.2.5
@@ -43,7 +43,7 @@ require (
 	github.com/samber/slog-zerolog v1.0.0
 	github.com/stretchr/testify v1.9.0
 	github.com/urfave/cli/v2 v2.27.2
-	github.com/vektah/gqlparser/v2 v2.5.11
+	github.com/vektah/gqlparser/v2 v2.5.16
 	github.com/willscott/go-nfs-client v0.0.0-20240104095149-b44639837b00
 	github.com/willscott/memphis v0.0.0-20210922141505-529d4987ab7e
 	go.opentelemetry.io/otel v1.27.0
@@ -54,9 +54,9 @@ require (
 	go.opentelemetry.io/otel/sdk/metric v1.27.0
 	go.opentelemetry.io/otel/trace v1.27.0
 	golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842
-	golang.org/x/net v0.25.0
+	golang.org/x/net v0.26.0
 	golang.org/x/sync v0.7.0
-	golang.org/x/sys v0.20.0
+	golang.org/x/sys v0.21.0
 )
 
 require (
@@ -168,7 +168,7 @@ require (
 	github.com/russross/blackfriday/v2 v2.1.0 // indirect
 	github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46 // indirect
 	github.com/samber/lo v1.39.0 // indirect
-	github.com/sosodev/duration v1.3.0 // indirect
+	github.com/sosodev/duration v1.3.1 // indirect
 	github.com/spaolacci/murmur3 v1.1.0 // indirect
 	github.com/tidwall/btree v1.7.0 // indirect
 	github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
@@ -185,11 +185,11 @@ require (
 	go.opentelemetry.io/proto/otlp v1.2.0 // indirect
 	go4.org v0.0.0-20230225012048-214862532bf5 // indirect
 	golang.org/x/arch v0.8.0 // indirect
-	golang.org/x/crypto v0.23.0 // indirect
-	golang.org/x/mod v0.17.0 // indirect
-	golang.org/x/text v0.15.0 // indirect
+	golang.org/x/crypto v0.24.0 // indirect
+	golang.org/x/mod v0.18.0 // indirect
+	golang.org/x/text v0.16.0 // indirect
 	golang.org/x/time v0.5.0 // indirect
-	golang.org/x/tools v0.21.0 // indirect
+	golang.org/x/tools v0.22.0 // indirect
 	google.golang.org/genproto/googleapis/api v0.0.0-20240520151616-dc85e6b867a5 // indirect
 	google.golang.org/genproto/googleapis/rpc v0.0.0-20240515191416-fc5f0ca64291 // indirect
 	google.golang.org/grpc v1.64.0 // indirect
diff --git a/go.sum b/go.sum
index 32af796..4c30d9b 100644
--- a/go.sum
+++ b/go.sum
@@ -19,8 +19,8 @@ crawshaw.io/sqlite v0.3.2/go.mod h1:igAO5JulrQ1DbdZdtVq48mnZUBAPOeFzer7VhDWNtW4=
 dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
 filippo.io/edwards25519 v1.0.0-rc.1 h1:m0VOOB23frXZvAOK44usCgLWvtsxIoMCTBGJZlpmGfU=
 filippo.io/edwards25519 v1.0.0-rc.1/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns=
-github.com/99designs/gqlgen v0.17.45 h1:bH0AH67vIJo8JKNKPJP+pOPpQhZeuVRQLf53dKIpDik=
-github.com/99designs/gqlgen v0.17.45/go.mod h1:Bas0XQ+Jiu/Xm5E33jC8sES3G+iC2esHBMXcq0fUPs0=
+github.com/99designs/gqlgen v0.17.49 h1:b3hNGexHd33fBSAd4NDT/c3NCcQzcAVkknhN9ym36YQ=
+github.com/99designs/gqlgen v0.17.49/go.mod h1:tC8YFVZMed81x7UJ7ORUwXF4Kn6SXuucFqQBhN8+BU0=
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
 github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE=
@@ -99,8 +99,8 @@ github.com/anacrolix/sync v0.5.1/go.mod h1:BbecHL6jDSExojhNtgTFSBcdGerzNc64tz3DC
 github.com/anacrolix/tagflag v0.0.0-20180109131632-2146c8d41bf0/go.mod h1:1m2U/K6ZT+JZG0+bdMK6qauP49QT4wE5pmhJXOKKCHw=
 github.com/anacrolix/tagflag v1.0.0/go.mod h1:1m2U/K6ZT+JZG0+bdMK6qauP49QT4wE5pmhJXOKKCHw=
 github.com/anacrolix/tagflag v1.1.0/go.mod h1:Scxs9CV10NQatSmbyjqmqmeQNwGzlNe0CMUMIxqHIG8=
-github.com/anacrolix/torrent v1.56.0 h1:g/sM0K/BaWUv4Htu2bblLBhIxGdFZ1MUCoD7lcvemlo=
-github.com/anacrolix/torrent v1.56.0/go.mod h1:5DMHbeIM1TuC5wTQ99XieKKLiYZYz6iB2lyZpKZEr6w=
+github.com/anacrolix/torrent v1.56.1 h1:QeJMOP0NuhpQ5dATsOqEL0vUO85aPMNMGP2FACNt0Eg=
+github.com/anacrolix/torrent v1.56.1/go.mod h1:5DMHbeIM1TuC5wTQ99XieKKLiYZYz6iB2lyZpKZEr6w=
 github.com/anacrolix/upnp v0.1.4 h1:+2t2KA6QOhm/49zeNyeVwDu1ZYS9dB9wfxyVvh/wk7U=
 github.com/anacrolix/upnp v0.1.4/go.mod h1:Qyhbqo69gwNWvEk1xNTXsS5j7hMHef9hdr984+9fIic=
 github.com/anacrolix/utp v0.2.0 h1:65Cdmr6q9WSw2KsM+rtJFu7rqDzLl2bdysf4KlNPcFI=
@@ -582,8 +582,8 @@ github.com/smartystreets/goconvey v0.0.0-20190306220146-200a235640ff/go.mod h1:K
 github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
 github.com/smartystreets/goconvey v1.7.2 h1:9RBaZCeXEQ3UselpuwUQHltGVXvdwm6cv1hgR6gDIPg=
 github.com/smartystreets/goconvey v1.7.2/go.mod h1:Vw0tHAZW6lzCRk3xgdin6fKYcG+G3Pg9vgXWeJpQFMM=
-github.com/sosodev/duration v1.3.0 h1:g3E6mto+hFdA2uZXeNDYff8LYeg7v5D4YKP/Ng/NUkE=
-github.com/sosodev/duration v1.3.0/go.mod h1:RQIBBX0+fMLc/D9+Jb/fwvVmo0eZvDDEERAikUR6SDg=
+github.com/sosodev/duration v1.3.1 h1:qtHBDMQ6lvMQsL15g4aopM4HEfOaYuhWBw3NPTtlqq4=
+github.com/sosodev/duration v1.3.1/go.mod h1:RQIBBX0+fMLc/D9+Jb/fwvVmo0eZvDDEERAikUR6SDg=
 github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
 github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
 github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
@@ -622,8 +622,8 @@ github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6Kllzaw
 github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
 github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
 github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
-github.com/vektah/gqlparser/v2 v2.5.11 h1:JJxLtXIoN7+3x6MBdtIP59TP1RANnY7pXOaDnADQSf8=
-github.com/vektah/gqlparser/v2 v2.5.11/go.mod h1:1rCcfwB2ekJofmluGWXMSEnPMZgbxzwj6FaZ/4OT8Cc=
+github.com/vektah/gqlparser/v2 v2.5.16 h1:1gcmLTvs3JLKXckwCwlUagVn/IlV2bwqle0vJ0vy5p8=
+github.com/vektah/gqlparser/v2 v2.5.16/go.mod h1:1lz1OeCqgQbQepsGxPVywrjdBHW2T08PUS3pJqepRww=
 github.com/warpfork/go-errcat v0.0.0-20180917083543-335044ffc86e h1:FIB2fi7XJGHIdf5rWNsfFQqatIKxutT45G+wNuMQNgs=
 github.com/warpfork/go-errcat v0.0.0-20180917083543-335044ffc86e/go.mod h1:/qe02xr3jvTUz8u/PV0FHGpP8t96OQNP7U9BJMwMLEw=
 github.com/warpfork/go-wish v0.0.0-20200122115046-b9ea61034e4a/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw=
@@ -695,8 +695,8 @@ golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98y
 golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
 golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
 golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
-golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
-golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
+golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI=
+golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -730,8 +730,8 @@ golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
 golang.org/x/mod v0.6.0-dev.0.20211013180041-c96bc1413d57/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
 golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
 golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
-golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
-golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
+golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0=
+golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
 golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -764,8 +764,8 @@ golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
 golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
 golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
 golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
-golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
-golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
+golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
+golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -826,8 +826,8 @@ golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
-golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
+golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
 golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
@@ -850,8 +850,8 @@ golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
 golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
 golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
 golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
-golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
-golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
+golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
+golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
 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.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
@@ -887,8 +887,8 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f
 golang.org/x/tools v0.1.8-0.20211029000441-d6a9af8af023/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
 golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
 golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
-golang.org/x/tools v0.21.0 h1:qc0xYgIbsSDt9EyWz05J5wfa7LOVW0YTLOXrqdLAWIw=
-golang.org/x/tools v0.21.0/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
+golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA=
+golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
diff --git a/graphql/mutation.graphql b/graphql/mutation.graphql
index 83a3a86..9abe03e 100644
--- a/graphql/mutation.graphql
+++ b/graphql/mutation.graphql
@@ -1,26 +1,10 @@
 type Mutation {
-  validateTorrents(filter: TorrentFilter!): Boolean!
-  cleanupTorrents(files: Boolean, dryRun: Boolean!): CleanupResponse!
-  downloadTorrent(infohash: String!, file: String): DownloadTorrentResponse
+  torrentDaemon: TorrentDaemonMutation @resolver
+
   uploadFile(dir: String!, file: Upload!): Boolean!
   dedupeStorage: Int!
 }
 
-input TorrentFilter @oneOf {
-  everything: Boolean
-  infohash: String
-  # pathGlob: String!
-}
-
-type DownloadTorrentResponse {
-  task: Task
-}
-
-type CleanupResponse {
-  count: Int!
-  list: [String!]!
-}
-
 type Task {
   id: ID!
 }
diff --git a/graphql/query.graphql b/graphql/query.graphql
index 47b2a5f..6c7ba45 100644
--- a/graphql/query.graphql
+++ b/graphql/query.graphql
@@ -1,46 +1,5 @@
 type Query {
-  torrents(filter: TorrentsFilter): [Torrent!]!
+  torrentDaemon: TorrentDaemonQuery @resolver
+
   fsEntry(path: String!): FsEntry
 }
-
-input TorrentsFilter {
-  infohash: StringFilter
-  name: StringFilter
-  bytesCompleted: IntFilter
-  bytesMissing: IntFilter
-
-  peersCount: IntFilter
-  downloading: BooleanFilter
-}
-
-input Pagination {
-  offset: Int!
-  limit: Int!
-}
-
-input StringFilter @oneOf {
-  eq: String
-  substr: String
-  in: [String!]
-}
-
-input IntFilter @oneOf {
-  eq: Int
-  gt: Int
-  lt: Int
-  gte: Int
-  lte: Int
-  in: [Int!]
-}
-
-input DateTimeFilter @oneOf {
-  eq: DateTime
-  gt: DateTime
-  lt: DateTime
-  gte: DateTime
-  lte: DateTime
-}
-
-input BooleanFilter @oneOf {
-  eq: Boolean
-}
diff --git a/graphql/schema.graphql b/graphql/schema.graphql
index 21b5cdf..e18fd22 100644
--- a/graphql/schema.graphql
+++ b/graphql/schema.graphql
@@ -1,4 +1,6 @@
 directive @oneOf on INPUT_OBJECT | FIELD_DEFINITION
+directive @resolver on INPUT_FIELD_DEFINITION | FIELD_DEFINITION
+
 directive @stream on FIELD_DEFINITION
 
 scalar DateTime
diff --git a/graphql/sources/torrent_mutation.graphql b/graphql/sources/torrent_mutation.graphql
new file mode 100644
index 0000000..4bf6f77
--- /dev/null
+++ b/graphql/sources/torrent_mutation.graphql
@@ -0,0 +1,18 @@
+type TorrentDaemonMutation {
+  validateTorrent(filter: TorrentFilter!): Boolean! @resolver
+  setTorrentPriority(
+    infohash: String!
+    file: String
+    priority: TorrentPriority!
+  ): Boolean! @resolver
+  cleanup(files: Boolean, dryRun: Boolean!): CleanupResponse! @resolver
+}
+
+type CleanupResponse {
+  count: Int!
+  list: [String!]!
+}
+
+type DownloadTorrentResponse {
+  task: Task
+}
diff --git a/graphql/sources/torrent_query.graphql b/graphql/sources/torrent_query.graphql
new file mode 100644
index 0000000..0bf5335
--- /dev/null
+++ b/graphql/sources/torrent_query.graphql
@@ -0,0 +1,27 @@
+type TorrentDaemonQuery {
+  torrents(filter: TorrentsFilter): [Torrent!]! @resolver
+}
+
+input TorrentsFilter {
+  infohash: StringFilter
+  name: StringFilter
+  bytesCompleted: IntFilter
+  bytesMissing: IntFilter
+  peersCount: IntFilter
+  priority: TorrentPriorityFilter
+}
+
+input TorrentPriorityFilter @oneOf {
+  eq: TorrentPriority
+  gt: TorrentPriority
+  lt: TorrentPriority
+  gte: TorrentPriority
+  lte: TorrentPriority
+  in: [TorrentPriority!]
+}
+
+input TorrentFilter @oneOf {
+  everything: Boolean
+  infohash: String
+  # pathGlob: String!
+}
diff --git a/graphql/types/torrent.graphql b/graphql/sources/torrent_types.graphql
similarity index 55%
rename from graphql/types/torrent.graphql
rename to graphql/sources/torrent_types.graphql
index 1a16327..ecc5723 100644
--- a/graphql/types/torrent.graphql
+++ b/graphql/sources/torrent_types.graphql
@@ -1,15 +1,13 @@
 type Torrent {
-  name: String!
+  name: String! @resolver
   infohash: String!
   bytesCompleted: Int!
   torrentFilePath: String!
   bytesMissing: Int!
-  files: [TorrentFile!]!
-  excludedFiles: [TorrentFile!]!
-  peers: [TorrentPeer!]!
-
-  # if at least one piece of the torrent is request to download and not already downloaded
-  downloading: Boolean!
+  priority: TorrentPriority! @resolver
+  files: [TorrentFile!]! @resolver
+  excludedFiles: [TorrentFile!]! @resolver
+  peers: [TorrentPeer!]! @resolver
 }
 
 type TorrentFile {
@@ -25,3 +23,11 @@ type TorrentPeer {
   port: Int!
   clientName: String!
 }
+
+enum TorrentPriority {
+  NONE
+  NORMAL
+  HIGH
+  READAHEAD
+  NOW
+}
diff --git a/graphql/types/filters.graphql b/graphql/types/filters.graphql
new file mode 100644
index 0000000..f26cc62
--- /dev/null
+++ b/graphql/types/filters.graphql
@@ -0,0 +1,31 @@
+input Pagination {
+  offset: Int!
+  limit: Int!
+}
+
+input StringFilter @oneOf {
+  eq: String
+  substr: String
+  in: [String!]
+}
+
+input IntFilter @oneOf {
+  eq: Int
+  gt: Int
+  lt: Int
+  gte: Int
+  lte: Int
+  in: [Int!]
+}
+
+input DateTimeFilter @oneOf {
+  eq: DateTime
+  gt: DateTime
+  lt: DateTime
+  gte: DateTime
+  lte: DateTime
+}
+
+input BooleanFilter @oneOf {
+  eq: Boolean
+}
diff --git a/graphql/types/fs.graphql b/graphql/types/fs.graphql
index 4174f04..a34da46 100644
--- a/graphql/types/fs.graphql
+++ b/graphql/types/fs.graphql
@@ -14,7 +14,7 @@ interface File implements FsEntry {
 
 type SimpleDir implements Dir & FsEntry {
   name: String!
-  entries: [FsEntry!]!
+  entries: [FsEntry!]! @resolver
 }
 
 type SimpleFile implements File & FsEntry {
@@ -24,12 +24,12 @@ type SimpleFile implements File & FsEntry {
 
 type ResolverFS implements Dir & FsEntry {
   name: String!
-  entries: [FsEntry!]!
+  entries: [FsEntry!]! @resolver
 }
 
 type ArchiveFS implements Dir & FsEntry {
   name: String!
-  entries: [FsEntry!]!
+  entries: [FsEntry!]! @resolver
 
   size: Int!
 }
@@ -37,7 +37,7 @@ type ArchiveFS implements Dir & FsEntry {
 type TorrentFS implements Dir & FsEntry {
   name: String!
   torrent: Torrent!
-  entries: [FsEntry!]!
+  entries: [FsEntry!]! @resolver
 }
 
 type TorrentFileEntry implements File & FsEntry {
diff --git a/pkg/rlog/rlog.go b/pkg/rlog/rlog.go
index 96fa0ba..5f16433 100644
--- a/pkg/rlog/rlog.go
+++ b/pkg/rlog/rlog.go
@@ -34,24 +34,35 @@ func AddHandler(nh slog.Handler) {
 }
 
 type Logger struct {
-	handler   slog.Handler
-	component []string
+	handler     slog.Handler
+	callNesting int
+	component   []string
 }
 
 const functionKey = "function"
 
+const componentKey = "component"
+const componentSep = "."
+
 func (l *Logger) log(ctx context.Context, level slog.Level, msg string, attrs ...slog.Attr) {
 	var pcs [1]uintptr
-	runtime.Callers(3, pcs[:])
+	runtime.Callers(3+l.callNesting, pcs[:])
 	pc := pcs[0]
 	f := runtime.FuncForPC(pc)
-	attrs = append(attrs, slog.String(functionKey, f.Name()))
+	if f != nil {
+		attrs = append(attrs, slog.String(functionKey, f.Name()))
+	}
+
+	if len(l.component) > 0 {
+		attrs = append(attrs, slog.String(componentKey, strings.Join(l.component, componentSep)))
+	}
 
 	r := slog.NewRecord(time.Now(), level, msg, pc)
 	r.AddAttrs(attrs...)
 	if ctx == nil {
 		ctx = context.Background()
 	}
+
 	_ = l.handler.Handle(ctx, r)
 }
 
@@ -71,16 +82,10 @@ func (l *Logger) Error(ctx context.Context, msg string, attrs ...slog.Attr) {
 	l.log(ctx, slog.LevelError, msg, attrs...)
 }
 
-const componentKey = "component"
-const componentSep = "."
-
 func (log *Logger) WithComponent(name string) *Logger {
-	c := append(log.component, name)
 	return &Logger{
-		handler: log.handler.WithAttrs([]slog.Attr{
-			slog.String(componentKey, strings.Join(c, componentSep)),
-		}),
-		component: c,
+		handler:   log.handler,
+		component: append(log.component, name),
 	}
 }
 
@@ -91,23 +96,20 @@ func (l *Logger) With(attrs ...slog.Attr) *Logger {
 	}
 }
 
+func (l *Logger) Nested(callNesting int) *Logger {
+	return &Logger{
+		handler:     l.handler,
+		component:   l.component,
+		callNesting: callNesting,
+	}
+}
+
 // returns a new slog logger with the same attribures as the original logger
 // TODO currently not logging function name
 func (l *Logger) Slog() *slog.Logger {
 	return slog.New(l.handler)
 }
 
-const endpointKey = "endpoint"
-
-func (l *Logger) WithEndpoint(name string) *Logger {
-	return &Logger{
-		handler: l.handler.WithAttrs([]slog.Attr{
-			slog.String(endpointKey, name),
-		}),
-		component: l.component,
-	}
-}
-
 const errKey = "error"
 
 func Error(err error) slog.Attr {
diff --git a/src/delivery/graphql/generated.go b/src/delivery/graphql/generated.go
index 8b8390f..11cd443 100644
--- a/src/delivery/graphql/generated.go
+++ b/src/delivery/graphql/generated.go
@@ -16,6 +16,7 @@ import (
 	"git.kmsign.ru/royalcat/tstor/src/delivery/graphql/model"
 	"github.com/99designs/gqlgen/graphql"
 	"github.com/99designs/gqlgen/graphql/introspection"
+	"github.com/anacrolix/torrent/types"
 	gqlparser "github.com/vektah/gqlparser/v2"
 	"github.com/vektah/gqlparser/v2/ast"
 )
@@ -47,12 +48,15 @@ type ResolverRoot interface {
 	SimpleDir() SimpleDirResolver
 	Subscription() SubscriptionResolver
 	Torrent() TorrentResolver
+	TorrentDaemonMutation() TorrentDaemonMutationResolver
+	TorrentDaemonQuery() TorrentDaemonQueryResolver
 	TorrentFS() TorrentFSResolver
 }
 
 type DirectiveRoot struct {
-	OneOf  func(ctx context.Context, obj interface{}, next graphql.Resolver) (res interface{}, err error)
-	Stream func(ctx context.Context, obj interface{}, next graphql.Resolver) (res interface{}, err error)
+	OneOf    func(ctx context.Context, obj interface{}, next graphql.Resolver) (res interface{}, err error)
+	Resolver func(ctx context.Context, obj interface{}, next graphql.Resolver) (res interface{}, err error)
+	Stream   func(ctx context.Context, obj interface{}, next graphql.Resolver) (res interface{}, err error)
 }
 
 type ComplexityRoot struct {
@@ -72,16 +76,14 @@ type ComplexityRoot struct {
 	}
 
 	Mutation struct {
-		CleanupTorrents  func(childComplexity int, files *bool, dryRun bool) int
-		DedupeStorage    func(childComplexity int) int
-		DownloadTorrent  func(childComplexity int, infohash string, file *string) int
-		UploadFile       func(childComplexity int, dir string, file graphql.Upload) int
-		ValidateTorrents func(childComplexity int, filter model.TorrentFilter) int
+		DedupeStorage func(childComplexity int) int
+		TorrentDaemon func(childComplexity int) int
+		UploadFile    func(childComplexity int, dir string, file graphql.Upload) int
 	}
 
 	Query struct {
-		FsEntry  func(childComplexity int, path string) int
-		Torrents func(childComplexity int, filter *model.TorrentsFilter) int
+		FsEntry       func(childComplexity int, path string) int
+		TorrentDaemon func(childComplexity int) int
 	}
 
 	ResolverFS struct {
@@ -116,15 +118,25 @@ type ComplexityRoot struct {
 	Torrent struct {
 		BytesCompleted  func(childComplexity int) int
 		BytesMissing    func(childComplexity int) int
-		Downloading     func(childComplexity int) int
 		ExcludedFiles   func(childComplexity int) int
 		Files           func(childComplexity int) int
 		Infohash        func(childComplexity int) int
 		Name            func(childComplexity int) int
 		Peers           func(childComplexity int) int
+		Priority        func(childComplexity int) int
 		TorrentFilePath func(childComplexity int) int
 	}
 
+	TorrentDaemonMutation struct {
+		Cleanup            func(childComplexity int, files *bool, dryRun bool) int
+		SetTorrentPriority func(childComplexity int, infohash string, file *string, priority types.PiecePriority) int
+		ValidateTorrent    func(childComplexity int, filter model.TorrentFilter) int
+	}
+
+	TorrentDaemonQuery struct {
+		Torrents func(childComplexity int, filter *model.TorrentsFilter) int
+	}
+
 	TorrentFS struct {
 		Entries func(childComplexity int) int
 		Name    func(childComplexity int) int
@@ -162,14 +174,12 @@ type ArchiveFSResolver interface {
 	Entries(ctx context.Context, obj *model.ArchiveFs) ([]model.FsEntry, error)
 }
 type MutationResolver interface {
-	ValidateTorrents(ctx context.Context, filter model.TorrentFilter) (bool, error)
-	CleanupTorrents(ctx context.Context, files *bool, dryRun bool) (*model.CleanupResponse, error)
-	DownloadTorrent(ctx context.Context, infohash string, file *string) (*model.DownloadTorrentResponse, error)
+	TorrentDaemon(ctx context.Context) (*model.TorrentDaemonMutation, error)
 	UploadFile(ctx context.Context, dir string, file graphql.Upload) (bool, error)
 	DedupeStorage(ctx context.Context) (int64, error)
 }
 type QueryResolver interface {
-	Torrents(ctx context.Context, filter *model.TorrentsFilter) ([]*model.Torrent, error)
+	TorrentDaemon(ctx context.Context) (*model.TorrentDaemonQuery, error)
 	FsEntry(ctx context.Context, path string) (model.FsEntry, error)
 }
 type ResolverFSResolver interface {
@@ -185,10 +195,19 @@ type SubscriptionResolver interface {
 type TorrentResolver interface {
 	Name(ctx context.Context, obj *model.Torrent) (string, error)
 
+	Priority(ctx context.Context, obj *model.Torrent) (types.PiecePriority, error)
 	Files(ctx context.Context, obj *model.Torrent) ([]*model.TorrentFile, error)
 	ExcludedFiles(ctx context.Context, obj *model.Torrent) ([]*model.TorrentFile, error)
 	Peers(ctx context.Context, obj *model.Torrent) ([]*model.TorrentPeer, error)
 }
+type TorrentDaemonMutationResolver interface {
+	ValidateTorrent(ctx context.Context, obj *model.TorrentDaemonMutation, filter model.TorrentFilter) (bool, error)
+	SetTorrentPriority(ctx context.Context, obj *model.TorrentDaemonMutation, infohash string, file *string, priority types.PiecePriority) (bool, error)
+	Cleanup(ctx context.Context, obj *model.TorrentDaemonMutation, files *bool, dryRun bool) (*model.CleanupResponse, error)
+}
+type TorrentDaemonQueryResolver interface {
+	Torrents(ctx context.Context, obj *model.TorrentDaemonQuery, filter *model.TorrentsFilter) ([]*model.Torrent, error)
+}
 type TorrentFSResolver interface {
 	Entries(ctx context.Context, obj *model.TorrentFs) ([]model.FsEntry, error)
 }
@@ -254,18 +273,6 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
 
 		return e.complexity.DownloadTorrentResponse.Task(childComplexity), true
 
-	case "Mutation.cleanupTorrents":
-		if e.complexity.Mutation.CleanupTorrents == nil {
-			break
-		}
-
-		args, err := ec.field_Mutation_cleanupTorrents_args(context.TODO(), rawArgs)
-		if err != nil {
-			return 0, false
-		}
-
-		return e.complexity.Mutation.CleanupTorrents(childComplexity, args["files"].(*bool), args["dryRun"].(bool)), true
-
 	case "Mutation.dedupeStorage":
 		if e.complexity.Mutation.DedupeStorage == nil {
 			break
@@ -273,17 +280,12 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
 
 		return e.complexity.Mutation.DedupeStorage(childComplexity), true
 
-	case "Mutation.downloadTorrent":
-		if e.complexity.Mutation.DownloadTorrent == nil {
+	case "Mutation.torrentDaemon":
+		if e.complexity.Mutation.TorrentDaemon == nil {
 			break
 		}
 
-		args, err := ec.field_Mutation_downloadTorrent_args(context.TODO(), rawArgs)
-		if err != nil {
-			return 0, false
-		}
-
-		return e.complexity.Mutation.DownloadTorrent(childComplexity, args["infohash"].(string), args["file"].(*string)), true
+		return e.complexity.Mutation.TorrentDaemon(childComplexity), true
 
 	case "Mutation.uploadFile":
 		if e.complexity.Mutation.UploadFile == nil {
@@ -297,18 +299,6 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
 
 		return e.complexity.Mutation.UploadFile(childComplexity, args["dir"].(string), args["file"].(graphql.Upload)), true
 
-	case "Mutation.validateTorrents":
-		if e.complexity.Mutation.ValidateTorrents == nil {
-			break
-		}
-
-		args, err := ec.field_Mutation_validateTorrents_args(context.TODO(), rawArgs)
-		if err != nil {
-			return 0, false
-		}
-
-		return e.complexity.Mutation.ValidateTorrents(childComplexity, args["filter"].(model.TorrentFilter)), true
-
 	case "Query.fsEntry":
 		if e.complexity.Query.FsEntry == nil {
 			break
@@ -321,17 +311,12 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
 
 		return e.complexity.Query.FsEntry(childComplexity, args["path"].(string)), true
 
-	case "Query.torrents":
-		if e.complexity.Query.Torrents == nil {
+	case "Query.torrentDaemon":
+		if e.complexity.Query.TorrentDaemon == nil {
 			break
 		}
 
-		args, err := ec.field_Query_torrents_args(context.TODO(), rawArgs)
-		if err != nil {
-			return 0, false
-		}
-
-		return e.complexity.Query.Torrents(childComplexity, args["filter"].(*model.TorrentsFilter)), true
+		return e.complexity.Query.TorrentDaemon(childComplexity), true
 
 	case "ResolverFS.entries":
 		if e.complexity.ResolverFS.Entries == nil {
@@ -429,13 +414,6 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
 
 		return e.complexity.Torrent.BytesMissing(childComplexity), true
 
-	case "Torrent.downloading":
-		if e.complexity.Torrent.Downloading == nil {
-			break
-		}
-
-		return e.complexity.Torrent.Downloading(childComplexity), true
-
 	case "Torrent.excludedFiles":
 		if e.complexity.Torrent.ExcludedFiles == nil {
 			break
@@ -471,6 +449,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
 
 		return e.complexity.Torrent.Peers(childComplexity), true
 
+	case "Torrent.priority":
+		if e.complexity.Torrent.Priority == nil {
+			break
+		}
+
+		return e.complexity.Torrent.Priority(childComplexity), true
+
 	case "Torrent.torrentFilePath":
 		if e.complexity.Torrent.TorrentFilePath == nil {
 			break
@@ -478,6 +463,54 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
 
 		return e.complexity.Torrent.TorrentFilePath(childComplexity), true
 
+	case "TorrentDaemonMutation.cleanup":
+		if e.complexity.TorrentDaemonMutation.Cleanup == nil {
+			break
+		}
+
+		args, err := ec.field_TorrentDaemonMutation_cleanup_args(context.TODO(), rawArgs)
+		if err != nil {
+			return 0, false
+		}
+
+		return e.complexity.TorrentDaemonMutation.Cleanup(childComplexity, args["files"].(*bool), args["dryRun"].(bool)), true
+
+	case "TorrentDaemonMutation.setTorrentPriority":
+		if e.complexity.TorrentDaemonMutation.SetTorrentPriority == nil {
+			break
+		}
+
+		args, err := ec.field_TorrentDaemonMutation_setTorrentPriority_args(context.TODO(), rawArgs)
+		if err != nil {
+			return 0, false
+		}
+
+		return e.complexity.TorrentDaemonMutation.SetTorrentPriority(childComplexity, args["infohash"].(string), args["file"].(*string), args["priority"].(types.PiecePriority)), true
+
+	case "TorrentDaemonMutation.validateTorrent":
+		if e.complexity.TorrentDaemonMutation.ValidateTorrent == nil {
+			break
+		}
+
+		args, err := ec.field_TorrentDaemonMutation_validateTorrent_args(context.TODO(), rawArgs)
+		if err != nil {
+			return 0, false
+		}
+
+		return e.complexity.TorrentDaemonMutation.ValidateTorrent(childComplexity, args["filter"].(model.TorrentFilter)), true
+
+	case "TorrentDaemonQuery.torrents":
+		if e.complexity.TorrentDaemonQuery.Torrents == nil {
+			break
+		}
+
+		args, err := ec.field_TorrentDaemonQuery_torrents_args(context.TODO(), rawArgs)
+		if err != nil {
+			return 0, false
+		}
+
+		return e.complexity.TorrentDaemonQuery.Torrents(childComplexity, args["filter"].(*model.TorrentsFilter)), true
+
 	case "TorrentFS.entries":
 		if e.complexity.TorrentFS.Entries == nil {
 			break
@@ -611,6 +644,7 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler {
 		ec.unmarshalInputPagination,
 		ec.unmarshalInputStringFilter,
 		ec.unmarshalInputTorrentFilter,
+		ec.unmarshalInputTorrentPriorityFilter,
 		ec.unmarshalInputTorrentsFilter,
 	)
 	first := true
@@ -727,48 +761,134 @@ func (ec *executionContext) introspectType(name string) (*introspection.Type, er
 
 var sources = []*ast.Source{
 	{Name: "../../../graphql/mutation.graphql", Input: `type Mutation {
-  validateTorrents(filter: TorrentFilter!): Boolean!
-  cleanupTorrents(files: Boolean, dryRun: Boolean!): CleanupResponse!
-  downloadTorrent(infohash: String!, file: String): DownloadTorrentResponse
+  torrentDaemon: TorrentDaemonMutation @resolver
+
   uploadFile(dir: String!, file: Upload!): Boolean!
   dedupeStorage: Int!
 }
 
-input TorrentFilter @oneOf {
-  everything: Boolean
-  infohash: String
-  # pathGlob: String!
-}
-
-type DownloadTorrentResponse {
-  task: Task
-}
-
-type CleanupResponse {
-  count: Int!
-  list: [String!]!
-}
-
 type Task {
   id: ID!
 }
 `, BuiltIn: false},
 	{Name: "../../../graphql/query.graphql", Input: `type Query {
-  torrents(filter: TorrentsFilter): [Torrent!]!
+  torrentDaemon: TorrentDaemonQuery @resolver
+
   fsEntry(path: String!): FsEntry
 }
+`, BuiltIn: false},
+	{Name: "../../../graphql/schema.graphql", Input: `directive @oneOf on INPUT_OBJECT | FIELD_DEFINITION
+directive @resolver on INPUT_FIELD_DEFINITION | FIELD_DEFINITION
+
+directive @stream on FIELD_DEFINITION
+
+scalar DateTime
+scalar Upload
+
+type Schema {
+  query: Query
+  mutation: Mutation
+}
+`, BuiltIn: false},
+	{Name: "../../../graphql/subscription.graphql", Input: `type Subscription {
+    taskProgress(taskID: ID!): Progress
+    torrentDownloadUpdates: TorrentProgress
+}
+
+
+type TorrentProgress implements Progress {
+    torrent: Torrent!
+    current: Int!
+    total: Int!
+}
+
+interface Progress {
+    current: Int!
+    total: Int!
+}`, BuiltIn: false},
+	{Name: "../../../graphql/sources/torrent_mutation.graphql", Input: `type TorrentDaemonMutation {
+  validateTorrent(filter: TorrentFilter!): Boolean! @resolver
+  setTorrentPriority(
+    infohash: String!
+    file: String
+    priority: TorrentPriority!
+  ): Boolean! @resolver
+  cleanup(files: Boolean, dryRun: Boolean!): CleanupResponse! @resolver
+}
+
+type CleanupResponse {
+  count: Int!
+  list: [String!]!
+}
+
+type DownloadTorrentResponse {
+  task: Task
+}
+`, BuiltIn: false},
+	{Name: "../../../graphql/sources/torrent_query.graphql", Input: `type TorrentDaemonQuery {
+  torrents(filter: TorrentsFilter): [Torrent!]! @resolver
+}
 
 input TorrentsFilter {
   infohash: StringFilter
   name: StringFilter
   bytesCompleted: IntFilter
   bytesMissing: IntFilter
-
   peersCount: IntFilter
-  downloading: BooleanFilter
+  priority: TorrentPriorityFilter
 }
 
-input Pagination {
+input TorrentPriorityFilter @oneOf {
+  eq: TorrentPriority
+  gt: TorrentPriority
+  lt: TorrentPriority
+  gte: TorrentPriority
+  lte: TorrentPriority
+  in: [TorrentPriority!]
+}
+
+input TorrentFilter @oneOf {
+  everything: Boolean
+  infohash: String
+  # pathGlob: String!
+}
+`, BuiltIn: false},
+	{Name: "../../../graphql/sources/torrent_types.graphql", Input: `type Torrent {
+  name: String! @resolver
+  infohash: String!
+  bytesCompleted: Int!
+  torrentFilePath: String!
+  bytesMissing: Int!
+  priority: TorrentPriority! @resolver
+  files: [TorrentFile!]! @resolver
+  excludedFiles: [TorrentFile!]! @resolver
+  peers: [TorrentPeer!]! @resolver
+}
+
+type TorrentFile {
+  filename: String!
+  size: Int!
+  bytesCompleted: Int!
+}
+
+type TorrentPeer {
+  ip: String!
+  downloadRate: Float!
+  discovery: String!
+  port: Int!
+  clientName: String!
+}
+
+enum TorrentPriority {
+  NONE
+  NORMAL
+  HIGH
+  READAHEAD
+  NEXT
+  NOW
+}
+`, BuiltIn: false},
+	{Name: "../../../graphql/types/filters.graphql", Input: `input Pagination {
   offset: Int!
   limit: Int!
 }
@@ -800,33 +920,6 @@ input BooleanFilter @oneOf {
   eq: Boolean
 }
 `, BuiltIn: false},
-	{Name: "../../../graphql/schema.graphql", Input: `directive @oneOf on INPUT_OBJECT | FIELD_DEFINITION
-directive @stream on FIELD_DEFINITION
-
-scalar DateTime
-scalar Upload
-
-type Schema {
-  query: Query
-  mutation: Mutation
-}
-`, BuiltIn: false},
-	{Name: "../../../graphql/subscription.graphql", Input: `type Subscription {
-    taskProgress(taskID: ID!): Progress
-    torrentDownloadUpdates: TorrentProgress
-}
-
-
-type TorrentProgress implements Progress {
-    torrent: Torrent!
-    current: Int!
-    total: Int!
-}
-
-interface Progress {
-    current: Int!
-    total: Int!
-}`, BuiltIn: false},
 	{Name: "../../../graphql/types/fs.graphql", Input: `interface FsEntry {
   name: String!
 }
@@ -843,7 +936,7 @@ interface File implements FsEntry {
 
 type SimpleDir implements Dir & FsEntry {
   name: String!
-  entries: [FsEntry!]!
+  entries: [FsEntry!]! @resolver
 }
 
 type SimpleFile implements File & FsEntry {
@@ -853,12 +946,12 @@ type SimpleFile implements File & FsEntry {
 
 type ResolverFS implements Dir & FsEntry {
   name: String!
-  entries: [FsEntry!]!
+  entries: [FsEntry!]! @resolver
 }
 
 type ArchiveFS implements Dir & FsEntry {
   name: String!
-  entries: [FsEntry!]!
+  entries: [FsEntry!]! @resolver
 
   size: Int!
 }
@@ -866,7 +959,7 @@ type ArchiveFS implements Dir & FsEntry {
 type TorrentFS implements Dir & FsEntry {
   name: String!
   torrent: Torrent!
-  entries: [FsEntry!]!
+  entries: [FsEntry!]! @resolver
 }
 
 type TorrentFileEntry implements File & FsEntry {
@@ -874,34 +967,6 @@ type TorrentFileEntry implements File & FsEntry {
   torrent: Torrent!
   size: Int!
 }
-`, BuiltIn: false},
-	{Name: "../../../graphql/types/torrent.graphql", Input: `type Torrent {
-  name: String!
-  infohash: String!
-  bytesCompleted: Int!
-  torrentFilePath: String!
-  bytesMissing: Int!
-  files: [TorrentFile!]!
-  excludedFiles: [TorrentFile!]!
-  peers: [TorrentPeer!]!
-
-  # if at least one piece of the torrent is request to download and not already downloaded
-  downloading: Boolean!
-}
-
-type TorrentFile {
-  filename: String!
-  size: Int!
-  bytesCompleted: Int!
-}
-
-type TorrentPeer {
-  ip: String!
-  downloadRate: Float!
-  discovery: String!
-  port: Int!
-  clientName: String!
-}
 `, BuiltIn: false},
 }
 var parsedSchema = gqlparser.MustLoadSchema(sources...)
@@ -910,54 +975,6 @@ var parsedSchema = gqlparser.MustLoadSchema(sources...)
 
 // region    ***************************** args.gotpl *****************************
 
-func (ec *executionContext) field_Mutation_cleanupTorrents_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
-	var err error
-	args := map[string]interface{}{}
-	var arg0 *bool
-	if tmp, ok := rawArgs["files"]; ok {
-		ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("files"))
-		arg0, err = ec.unmarshalOBoolean2ᚖbool(ctx, tmp)
-		if err != nil {
-			return nil, err
-		}
-	}
-	args["files"] = arg0
-	var arg1 bool
-	if tmp, ok := rawArgs["dryRun"]; ok {
-		ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("dryRun"))
-		arg1, err = ec.unmarshalNBoolean2bool(ctx, tmp)
-		if err != nil {
-			return nil, err
-		}
-	}
-	args["dryRun"] = arg1
-	return args, nil
-}
-
-func (ec *executionContext) field_Mutation_downloadTorrent_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
-	var err error
-	args := map[string]interface{}{}
-	var arg0 string
-	if tmp, ok := rawArgs["infohash"]; ok {
-		ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("infohash"))
-		arg0, err = ec.unmarshalNString2string(ctx, tmp)
-		if err != nil {
-			return nil, err
-		}
-	}
-	args["infohash"] = arg0
-	var arg1 *string
-	if tmp, ok := rawArgs["file"]; ok {
-		ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("file"))
-		arg1, err = ec.unmarshalOString2ᚖstring(ctx, tmp)
-		if err != nil {
-			return nil, err
-		}
-	}
-	args["file"] = arg1
-	return args, nil
-}
-
 func (ec *executionContext) field_Mutation_uploadFile_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
 	var err error
 	args := map[string]interface{}{}
@@ -982,21 +999,6 @@ func (ec *executionContext) field_Mutation_uploadFile_args(ctx context.Context,
 	return args, nil
 }
 
-func (ec *executionContext) field_Mutation_validateTorrents_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
-	var err error
-	args := map[string]interface{}{}
-	var arg0 model.TorrentFilter
-	if tmp, ok := rawArgs["filter"]; ok {
-		ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("filter"))
-		arg0, err = ec.unmarshalNTorrentFilter2gitᚗkmsignᚗruᚋroyalcatᚋtstorᚋsrcᚋdeliveryᚋgraphqlᚋmodelᚐTorrentFilter(ctx, tmp)
-		if err != nil {
-			return nil, err
-		}
-	}
-	args["filter"] = arg0
-	return args, nil
-}
-
 func (ec *executionContext) field_Query___type_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
 	var err error
 	args := map[string]interface{}{}
@@ -1027,21 +1029,6 @@ func (ec *executionContext) field_Query_fsEntry_args(ctx context.Context, rawArg
 	return args, nil
 }
 
-func (ec *executionContext) field_Query_torrents_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
-	var err error
-	args := map[string]interface{}{}
-	var arg0 *model.TorrentsFilter
-	if tmp, ok := rawArgs["filter"]; ok {
-		ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("filter"))
-		arg0, err = ec.unmarshalOTorrentsFilter2ᚖgitᚗkmsignᚗruᚋroyalcatᚋtstorᚋsrcᚋdeliveryᚋgraphqlᚋmodelᚐTorrentsFilter(ctx, tmp)
-		if err != nil {
-			return nil, err
-		}
-	}
-	args["filter"] = arg0
-	return args, nil
-}
-
 func (ec *executionContext) field_Subscription_taskProgress_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
 	var err error
 	args := map[string]interface{}{}
@@ -1057,6 +1044,93 @@ func (ec *executionContext) field_Subscription_taskProgress_args(ctx context.Con
 	return args, nil
 }
 
+func (ec *executionContext) field_TorrentDaemonMutation_cleanup_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
+	var err error
+	args := map[string]interface{}{}
+	var arg0 *bool
+	if tmp, ok := rawArgs["files"]; ok {
+		ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("files"))
+		arg0, err = ec.unmarshalOBoolean2ᚖbool(ctx, tmp)
+		if err != nil {
+			return nil, err
+		}
+	}
+	args["files"] = arg0
+	var arg1 bool
+	if tmp, ok := rawArgs["dryRun"]; ok {
+		ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("dryRun"))
+		arg1, err = ec.unmarshalNBoolean2bool(ctx, tmp)
+		if err != nil {
+			return nil, err
+		}
+	}
+	args["dryRun"] = arg1
+	return args, nil
+}
+
+func (ec *executionContext) field_TorrentDaemonMutation_setTorrentPriority_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
+	var err error
+	args := map[string]interface{}{}
+	var arg0 string
+	if tmp, ok := rawArgs["infohash"]; ok {
+		ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("infohash"))
+		arg0, err = ec.unmarshalNString2string(ctx, tmp)
+		if err != nil {
+			return nil, err
+		}
+	}
+	args["infohash"] = arg0
+	var arg1 *string
+	if tmp, ok := rawArgs["file"]; ok {
+		ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("file"))
+		arg1, err = ec.unmarshalOString2ᚖstring(ctx, tmp)
+		if err != nil {
+			return nil, err
+		}
+	}
+	args["file"] = arg1
+	var arg2 types.PiecePriority
+	if tmp, ok := rawArgs["priority"]; ok {
+		ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("priority"))
+		arg2, err = ec.unmarshalNTorrentPriority2githubᚗcomᚋanacrolixᚋtorrentᚋtypesᚐPiecePriority(ctx, tmp)
+		if err != nil {
+			return nil, err
+		}
+	}
+	args["priority"] = arg2
+	return args, nil
+}
+
+func (ec *executionContext) field_TorrentDaemonMutation_validateTorrent_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
+	var err error
+	args := map[string]interface{}{}
+	var arg0 model.TorrentFilter
+	if tmp, ok := rawArgs["filter"]; ok {
+		ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("filter"))
+		arg0, err = ec.unmarshalNTorrentFilter2gitᚗkmsignᚗruᚋroyalcatᚋtstorᚋsrcᚋdeliveryᚋgraphqlᚋmodelᚐTorrentFilter(ctx, tmp)
+		if err != nil {
+			return nil, err
+		}
+	}
+	args["filter"] = arg0
+	return args, nil
+}
+
+func (ec *executionContext) field_TorrentDaemonQuery_torrents_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
+	var err error
+	args := map[string]interface{}{}
+	var arg0 *model.TorrentsFilter
+	if tmp, ok := rawArgs["filter"]; ok {
+		ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("filter"))
+		arg0, err = ec.unmarshalOTorrentsFilter2ᚖgitᚗkmsignᚗruᚋroyalcatᚋtstorᚋsrcᚋdeliveryᚋgraphqlᚋmodelᚐTorrentsFilter(ctx, tmp)
+		if err != nil {
+			return nil, err
+		}
+	}
+	args["filter"] = arg0
+	return args, nil
+}
+
 func (ec *executionContext) field___Type_enumValues_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
 	var err error
 	args := map[string]interface{}{}
@@ -1126,7 +1200,7 @@ func (ec *executionContext) _ArchiveFS_name(ctx context.Context, field graphql.C
 	return ec.marshalNString2string(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext_ArchiveFS_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext_ArchiveFS_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "ArchiveFS",
 		Field:      field,
@@ -1152,8 +1226,28 @@ func (ec *executionContext) _ArchiveFS_entries(ctx context.Context, field graphq
 		}
 	}()
 	resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
-		ctx = rctx // use context from middleware stack in children
-		return ec.resolvers.ArchiveFS().Entries(rctx, obj)
+		directive0 := func(rctx context.Context) (interface{}, error) {
+			ctx = rctx // use context from middleware stack in children
+			return ec.resolvers.ArchiveFS().Entries(rctx, obj)
+		}
+		directive1 := func(ctx context.Context) (interface{}, error) {
+			if ec.directives.Resolver == nil {
+				return nil, errors.New("directive resolver is not implemented")
+			}
+			return ec.directives.Resolver(ctx, obj, directive0)
+		}
+
+		tmp, err := directive1(rctx)
+		if err != nil {
+			return nil, graphql.ErrorOnPath(ctx, err)
+		}
+		if tmp == nil {
+			return nil, nil
+		}
+		if data, ok := tmp.([]model.FsEntry); ok {
+			return data, nil
+		}
+		return nil, fmt.Errorf(`unexpected type %T from directive, should be []git.kmsign.ru/royalcat/tstor/src/delivery/graphql/model.FsEntry`, tmp)
 	})
 	if err != nil {
 		ec.Error(ctx, err)
@@ -1170,7 +1264,7 @@ func (ec *executionContext) _ArchiveFS_entries(ctx context.Context, field graphq
 	return ec.marshalNFsEntry2ᚕgitᚗkmsignᚗruᚋroyalcatᚋtstorᚋsrcᚋdeliveryᚋgraphqlᚋmodelᚐFsEntryᚄ(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext_ArchiveFS_entries(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext_ArchiveFS_entries(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "ArchiveFS",
 		Field:      field,
@@ -1214,7 +1308,7 @@ func (ec *executionContext) _ArchiveFS_size(ctx context.Context, field graphql.C
 	return ec.marshalNInt2int64(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext_ArchiveFS_size(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext_ArchiveFS_size(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "ArchiveFS",
 		Field:      field,
@@ -1258,7 +1352,7 @@ func (ec *executionContext) _CleanupResponse_count(ctx context.Context, field gr
 	return ec.marshalNInt2int64(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext_CleanupResponse_count(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext_CleanupResponse_count(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "CleanupResponse",
 		Field:      field,
@@ -1302,7 +1396,7 @@ func (ec *executionContext) _CleanupResponse_list(ctx context.Context, field gra
 	return ec.marshalNString2ᚕstringᚄ(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext_CleanupResponse_list(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext_CleanupResponse_list(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "CleanupResponse",
 		Field:      field,
@@ -1343,7 +1437,7 @@ func (ec *executionContext) _DownloadTorrentResponse_task(ctx context.Context, f
 	return ec.marshalOTask2ᚖgitᚗkmsignᚗruᚋroyalcatᚋtstorᚋsrcᚋdeliveryᚋgraphqlᚋmodelᚐTask(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext_DownloadTorrentResponse_task(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext_DownloadTorrentResponse_task(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "DownloadTorrentResponse",
 		Field:      field,
@@ -1360,8 +1454,8 @@ func (ec *executionContext) fieldContext_DownloadTorrentResponse_task(ctx contex
 	return fc, nil
 }
 
-func (ec *executionContext) _Mutation_validateTorrents(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
-	fc, err := ec.fieldContext_Mutation_validateTorrents(ctx, field)
+func (ec *executionContext) _Mutation_torrentDaemon(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
+	fc, err := ec.fieldContext_Mutation_torrentDaemon(ctx, field)
 	if err != nil {
 		return graphql.Null
 	}
@@ -1373,80 +1467,42 @@ func (ec *executionContext) _Mutation_validateTorrents(ctx context.Context, fiel
 		}
 	}()
 	resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
-		ctx = rctx // use context from middleware stack in children
-		return ec.resolvers.Mutation().ValidateTorrents(rctx, fc.Args["filter"].(model.TorrentFilter))
+		directive0 := func(rctx context.Context) (interface{}, error) {
+			ctx = rctx // use context from middleware stack in children
+			return ec.resolvers.Mutation().TorrentDaemon(rctx)
+		}
+		directive1 := func(ctx context.Context) (interface{}, error) {
+			if ec.directives.Resolver == nil {
+				return nil, errors.New("directive resolver is not implemented")
+			}
+			return ec.directives.Resolver(ctx, nil, directive0)
+		}
+
+		tmp, err := directive1(rctx)
+		if err != nil {
+			return nil, graphql.ErrorOnPath(ctx, err)
+		}
+		if tmp == nil {
+			return nil, nil
+		}
+		if data, ok := tmp.(*model.TorrentDaemonMutation); ok {
+			return data, nil
+		}
+		return nil, fmt.Errorf(`unexpected type %T from directive, should be *git.kmsign.ru/royalcat/tstor/src/delivery/graphql/model.TorrentDaemonMutation`, tmp)
 	})
 	if err != nil {
 		ec.Error(ctx, err)
 		return graphql.Null
 	}
 	if resTmp == nil {
-		if !graphql.HasFieldError(ctx, fc) {
-			ec.Errorf(ctx, "must not be null")
-		}
 		return graphql.Null
 	}
-	res := resTmp.(bool)
+	res := resTmp.(*model.TorrentDaemonMutation)
 	fc.Result = res
-	return ec.marshalNBoolean2bool(ctx, field.Selections, res)
+	return ec.marshalOTorrentDaemonMutation2ᚖgitᚗkmsignᚗruᚋroyalcatᚋtstorᚋsrcᚋdeliveryᚋgraphqlᚋmodelᚐTorrentDaemonMutation(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext_Mutation_validateTorrents(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
-	fc = &graphql.FieldContext{
-		Object:     "Mutation",
-		Field:      field,
-		IsMethod:   true,
-		IsResolver: true,
-		Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
-			return nil, errors.New("field of type Boolean does not have child fields")
-		},
-	}
-	defer func() {
-		if r := recover(); r != nil {
-			err = ec.Recover(ctx, r)
-			ec.Error(ctx, err)
-		}
-	}()
-	ctx = graphql.WithFieldContext(ctx, fc)
-	if fc.Args, err = ec.field_Mutation_validateTorrents_args(ctx, field.ArgumentMap(ec.Variables)); err != nil {
-		ec.Error(ctx, err)
-		return fc, err
-	}
-	return fc, nil
-}
-
-func (ec *executionContext) _Mutation_cleanupTorrents(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
-	fc, err := ec.fieldContext_Mutation_cleanupTorrents(ctx, field)
-	if err != nil {
-		return graphql.Null
-	}
-	ctx = graphql.WithFieldContext(ctx, fc)
-	defer func() {
-		if r := recover(); r != nil {
-			ec.Error(ctx, ec.Recover(ctx, r))
-			ret = graphql.Null
-		}
-	}()
-	resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
-		ctx = rctx // use context from middleware stack in children
-		return ec.resolvers.Mutation().CleanupTorrents(rctx, fc.Args["files"].(*bool), fc.Args["dryRun"].(bool))
-	})
-	if err != nil {
-		ec.Error(ctx, err)
-		return graphql.Null
-	}
-	if resTmp == nil {
-		if !graphql.HasFieldError(ctx, fc) {
-			ec.Errorf(ctx, "must not be null")
-		}
-		return graphql.Null
-	}
-	res := resTmp.(*model.CleanupResponse)
-	fc.Result = res
-	return ec.marshalNCleanupResponse2ᚖgitᚗkmsignᚗruᚋroyalcatᚋtstorᚋsrcᚋdeliveryᚋgraphqlᚋmodelᚐCleanupResponse(ctx, field.Selections, res)
-}
-
-func (ec *executionContext) fieldContext_Mutation_cleanupTorrents(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext_Mutation_torrentDaemon(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "Mutation",
 		Field:      field,
@@ -1454,81 +1510,16 @@ func (ec *executionContext) fieldContext_Mutation_cleanupTorrents(ctx context.Co
 		IsResolver: true,
 		Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
 			switch field.Name {
-			case "count":
-				return ec.fieldContext_CleanupResponse_count(ctx, field)
-			case "list":
-				return ec.fieldContext_CleanupResponse_list(ctx, field)
+			case "validateTorrent":
+				return ec.fieldContext_TorrentDaemonMutation_validateTorrent(ctx, field)
+			case "setTorrentPriority":
+				return ec.fieldContext_TorrentDaemonMutation_setTorrentPriority(ctx, field)
+			case "cleanup":
+				return ec.fieldContext_TorrentDaemonMutation_cleanup(ctx, field)
 			}
-			return nil, fmt.Errorf("no field named %q was found under type CleanupResponse", field.Name)
+			return nil, fmt.Errorf("no field named %q was found under type TorrentDaemonMutation", field.Name)
 		},
 	}
-	defer func() {
-		if r := recover(); r != nil {
-			err = ec.Recover(ctx, r)
-			ec.Error(ctx, err)
-		}
-	}()
-	ctx = graphql.WithFieldContext(ctx, fc)
-	if fc.Args, err = ec.field_Mutation_cleanupTorrents_args(ctx, field.ArgumentMap(ec.Variables)); err != nil {
-		ec.Error(ctx, err)
-		return fc, err
-	}
-	return fc, nil
-}
-
-func (ec *executionContext) _Mutation_downloadTorrent(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
-	fc, err := ec.fieldContext_Mutation_downloadTorrent(ctx, field)
-	if err != nil {
-		return graphql.Null
-	}
-	ctx = graphql.WithFieldContext(ctx, fc)
-	defer func() {
-		if r := recover(); r != nil {
-			ec.Error(ctx, ec.Recover(ctx, r))
-			ret = graphql.Null
-		}
-	}()
-	resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
-		ctx = rctx // use context from middleware stack in children
-		return ec.resolvers.Mutation().DownloadTorrent(rctx, fc.Args["infohash"].(string), fc.Args["file"].(*string))
-	})
-	if err != nil {
-		ec.Error(ctx, err)
-		return graphql.Null
-	}
-	if resTmp == nil {
-		return graphql.Null
-	}
-	res := resTmp.(*model.DownloadTorrentResponse)
-	fc.Result = res
-	return ec.marshalODownloadTorrentResponse2ᚖgitᚗkmsignᚗruᚋroyalcatᚋtstorᚋsrcᚋdeliveryᚋgraphqlᚋmodelᚐDownloadTorrentResponse(ctx, field.Selections, res)
-}
-
-func (ec *executionContext) fieldContext_Mutation_downloadTorrent(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
-	fc = &graphql.FieldContext{
-		Object:     "Mutation",
-		Field:      field,
-		IsMethod:   true,
-		IsResolver: true,
-		Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
-			switch field.Name {
-			case "task":
-				return ec.fieldContext_DownloadTorrentResponse_task(ctx, field)
-			}
-			return nil, fmt.Errorf("no field named %q was found under type DownloadTorrentResponse", field.Name)
-		},
-	}
-	defer func() {
-		if r := recover(); r != nil {
-			err = ec.Recover(ctx, r)
-			ec.Error(ctx, err)
-		}
-	}()
-	ctx = graphql.WithFieldContext(ctx, fc)
-	if fc.Args, err = ec.field_Mutation_downloadTorrent_args(ctx, field.ArgumentMap(ec.Variables)); err != nil {
-		ec.Error(ctx, err)
-		return fc, err
-	}
 	return fc, nil
 }
 
@@ -1618,7 +1609,7 @@ func (ec *executionContext) _Mutation_dedupeStorage(ctx context.Context, field g
 	return ec.marshalNInt2int64(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext_Mutation_dedupeStorage(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext_Mutation_dedupeStorage(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "Mutation",
 		Field:      field,
@@ -1631,8 +1622,8 @@ func (ec *executionContext) fieldContext_Mutation_dedupeStorage(ctx context.Cont
 	return fc, nil
 }
 
-func (ec *executionContext) _Query_torrents(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
-	fc, err := ec.fieldContext_Query_torrents(ctx, field)
+func (ec *executionContext) _Query_torrentDaemon(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
+	fc, err := ec.fieldContext_Query_torrentDaemon(ctx, field)
 	if err != nil {
 		return graphql.Null
 	}
@@ -1644,25 +1635,42 @@ func (ec *executionContext) _Query_torrents(ctx context.Context, field graphql.C
 		}
 	}()
 	resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
-		ctx = rctx // use context from middleware stack in children
-		return ec.resolvers.Query().Torrents(rctx, fc.Args["filter"].(*model.TorrentsFilter))
+		directive0 := func(rctx context.Context) (interface{}, error) {
+			ctx = rctx // use context from middleware stack in children
+			return ec.resolvers.Query().TorrentDaemon(rctx)
+		}
+		directive1 := func(ctx context.Context) (interface{}, error) {
+			if ec.directives.Resolver == nil {
+				return nil, errors.New("directive resolver is not implemented")
+			}
+			return ec.directives.Resolver(ctx, nil, directive0)
+		}
+
+		tmp, err := directive1(rctx)
+		if err != nil {
+			return nil, graphql.ErrorOnPath(ctx, err)
+		}
+		if tmp == nil {
+			return nil, nil
+		}
+		if data, ok := tmp.(*model.TorrentDaemonQuery); ok {
+			return data, nil
+		}
+		return nil, fmt.Errorf(`unexpected type %T from directive, should be *git.kmsign.ru/royalcat/tstor/src/delivery/graphql/model.TorrentDaemonQuery`, tmp)
 	})
 	if err != nil {
 		ec.Error(ctx, err)
 		return graphql.Null
 	}
 	if resTmp == nil {
-		if !graphql.HasFieldError(ctx, fc) {
-			ec.Errorf(ctx, "must not be null")
-		}
 		return graphql.Null
 	}
-	res := resTmp.([]*model.Torrent)
+	res := resTmp.(*model.TorrentDaemonQuery)
 	fc.Result = res
-	return ec.marshalNTorrent2ᚕᚖgitᚗkmsignᚗruᚋroyalcatᚋtstorᚋsrcᚋdeliveryᚋgraphqlᚋmodelᚐTorrentᚄ(ctx, field.Selections, res)
+	return ec.marshalOTorrentDaemonQuery2ᚖgitᚗkmsignᚗruᚋroyalcatᚋtstorᚋsrcᚋdeliveryᚋgraphqlᚋmodelᚐTorrentDaemonQuery(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext_Query_torrents(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext_Query_torrentDaemon(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "Query",
 		Field:      field,
@@ -1670,39 +1678,12 @@ func (ec *executionContext) fieldContext_Query_torrents(ctx context.Context, fie
 		IsResolver: true,
 		Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
 			switch field.Name {
-			case "name":
-				return ec.fieldContext_Torrent_name(ctx, field)
-			case "infohash":
-				return ec.fieldContext_Torrent_infohash(ctx, field)
-			case "bytesCompleted":
-				return ec.fieldContext_Torrent_bytesCompleted(ctx, field)
-			case "torrentFilePath":
-				return ec.fieldContext_Torrent_torrentFilePath(ctx, field)
-			case "bytesMissing":
-				return ec.fieldContext_Torrent_bytesMissing(ctx, field)
-			case "files":
-				return ec.fieldContext_Torrent_files(ctx, field)
-			case "excludedFiles":
-				return ec.fieldContext_Torrent_excludedFiles(ctx, field)
-			case "peers":
-				return ec.fieldContext_Torrent_peers(ctx, field)
-			case "downloading":
-				return ec.fieldContext_Torrent_downloading(ctx, field)
+			case "torrents":
+				return ec.fieldContext_TorrentDaemonQuery_torrents(ctx, field)
 			}
-			return nil, fmt.Errorf("no field named %q was found under type Torrent", field.Name)
+			return nil, fmt.Errorf("no field named %q was found under type TorrentDaemonQuery", field.Name)
 		},
 	}
-	defer func() {
-		if r := recover(); r != nil {
-			err = ec.Recover(ctx, r)
-			ec.Error(ctx, err)
-		}
-	}()
-	ctx = graphql.WithFieldContext(ctx, fc)
-	if fc.Args, err = ec.field_Query_torrents_args(ctx, field.ArgumentMap(ec.Variables)); err != nil {
-		ec.Error(ctx, err)
-		return fc, err
-	}
 	return fc, nil
 }
 
@@ -1860,7 +1841,7 @@ func (ec *executionContext) _Query___schema(ctx context.Context, field graphql.C
 	return ec.marshalO__Schema2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐSchema(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext_Query___schema(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext_Query___schema(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "Query",
 		Field:      field,
@@ -1918,7 +1899,7 @@ func (ec *executionContext) _ResolverFS_name(ctx context.Context, field graphql.
 	return ec.marshalNString2string(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext_ResolverFS_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext_ResolverFS_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "ResolverFS",
 		Field:      field,
@@ -1944,8 +1925,28 @@ func (ec *executionContext) _ResolverFS_entries(ctx context.Context, field graph
 		}
 	}()
 	resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
-		ctx = rctx // use context from middleware stack in children
-		return ec.resolvers.ResolverFS().Entries(rctx, obj)
+		directive0 := func(rctx context.Context) (interface{}, error) {
+			ctx = rctx // use context from middleware stack in children
+			return ec.resolvers.ResolverFS().Entries(rctx, obj)
+		}
+		directive1 := func(ctx context.Context) (interface{}, error) {
+			if ec.directives.Resolver == nil {
+				return nil, errors.New("directive resolver is not implemented")
+			}
+			return ec.directives.Resolver(ctx, obj, directive0)
+		}
+
+		tmp, err := directive1(rctx)
+		if err != nil {
+			return nil, graphql.ErrorOnPath(ctx, err)
+		}
+		if tmp == nil {
+			return nil, nil
+		}
+		if data, ok := tmp.([]model.FsEntry); ok {
+			return data, nil
+		}
+		return nil, fmt.Errorf(`unexpected type %T from directive, should be []git.kmsign.ru/royalcat/tstor/src/delivery/graphql/model.FsEntry`, tmp)
 	})
 	if err != nil {
 		ec.Error(ctx, err)
@@ -1962,7 +1963,7 @@ func (ec *executionContext) _ResolverFS_entries(ctx context.Context, field graph
 	return ec.marshalNFsEntry2ᚕgitᚗkmsignᚗruᚋroyalcatᚋtstorᚋsrcᚋdeliveryᚋgraphqlᚋmodelᚐFsEntryᚄ(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext_ResolverFS_entries(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext_ResolverFS_entries(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "ResolverFS",
 		Field:      field,
@@ -1992,7 +1993,7 @@ func (ec *executionContext) _Schema_query(ctx context.Context, field graphql.Col
 	return ec.marshalOQuery2ᚖgitᚗkmsignᚗruᚋroyalcatᚋtstorᚋsrcᚋdeliveryᚋgraphqlᚋmodelᚐQuery(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext_Schema_query(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext_Schema_query(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "Schema",
 		Field:      field,
@@ -2000,8 +2001,8 @@ func (ec *executionContext) fieldContext_Schema_query(ctx context.Context, field
 		IsResolver: false,
 		Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
 			switch field.Name {
-			case "torrents":
-				return ec.fieldContext_Query_torrents(ctx, field)
+			case "torrentDaemon":
+				return ec.fieldContext_Query_torrentDaemon(ctx, field)
 			case "fsEntry":
 				return ec.fieldContext_Query_fsEntry(ctx, field)
 			case "__schema":
@@ -2032,7 +2033,7 @@ func (ec *executionContext) _Schema_mutation(ctx context.Context, field graphql.
 	return ec.marshalOMutation2ᚖgitᚗkmsignᚗruᚋroyalcatᚋtstorᚋsrcᚋdeliveryᚋgraphqlᚋmodelᚐMutation(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext_Schema_mutation(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext_Schema_mutation(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "Schema",
 		Field:      field,
@@ -2040,12 +2041,8 @@ func (ec *executionContext) fieldContext_Schema_mutation(ctx context.Context, fi
 		IsResolver: false,
 		Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
 			switch field.Name {
-			case "validateTorrents":
-				return ec.fieldContext_Mutation_validateTorrents(ctx, field)
-			case "cleanupTorrents":
-				return ec.fieldContext_Mutation_cleanupTorrents(ctx, field)
-			case "downloadTorrent":
-				return ec.fieldContext_Mutation_downloadTorrent(ctx, field)
+			case "torrentDaemon":
+				return ec.fieldContext_Mutation_torrentDaemon(ctx, field)
 			case "uploadFile":
 				return ec.fieldContext_Mutation_uploadFile(ctx, field)
 			case "dedupeStorage":
@@ -2088,7 +2085,7 @@ func (ec *executionContext) _SimpleDir_name(ctx context.Context, field graphql.C
 	return ec.marshalNString2string(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext_SimpleDir_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext_SimpleDir_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "SimpleDir",
 		Field:      field,
@@ -2114,8 +2111,28 @@ func (ec *executionContext) _SimpleDir_entries(ctx context.Context, field graphq
 		}
 	}()
 	resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
-		ctx = rctx // use context from middleware stack in children
-		return ec.resolvers.SimpleDir().Entries(rctx, obj)
+		directive0 := func(rctx context.Context) (interface{}, error) {
+			ctx = rctx // use context from middleware stack in children
+			return ec.resolvers.SimpleDir().Entries(rctx, obj)
+		}
+		directive1 := func(ctx context.Context) (interface{}, error) {
+			if ec.directives.Resolver == nil {
+				return nil, errors.New("directive resolver is not implemented")
+			}
+			return ec.directives.Resolver(ctx, obj, directive0)
+		}
+
+		tmp, err := directive1(rctx)
+		if err != nil {
+			return nil, graphql.ErrorOnPath(ctx, err)
+		}
+		if tmp == nil {
+			return nil, nil
+		}
+		if data, ok := tmp.([]model.FsEntry); ok {
+			return data, nil
+		}
+		return nil, fmt.Errorf(`unexpected type %T from directive, should be []git.kmsign.ru/royalcat/tstor/src/delivery/graphql/model.FsEntry`, tmp)
 	})
 	if err != nil {
 		ec.Error(ctx, err)
@@ -2132,7 +2149,7 @@ func (ec *executionContext) _SimpleDir_entries(ctx context.Context, field graphq
 	return ec.marshalNFsEntry2ᚕgitᚗkmsignᚗruᚋroyalcatᚋtstorᚋsrcᚋdeliveryᚋgraphqlᚋmodelᚐFsEntryᚄ(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext_SimpleDir_entries(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext_SimpleDir_entries(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "SimpleDir",
 		Field:      field,
@@ -2176,7 +2193,7 @@ func (ec *executionContext) _SimpleFile_name(ctx context.Context, field graphql.
 	return ec.marshalNString2string(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext_SimpleFile_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext_SimpleFile_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "SimpleFile",
 		Field:      field,
@@ -2220,7 +2237,7 @@ func (ec *executionContext) _SimpleFile_size(ctx context.Context, field graphql.
 	return ec.marshalNInt2int64(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext_SimpleFile_size(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext_SimpleFile_size(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "SimpleFile",
 		Field:      field,
@@ -2341,7 +2358,7 @@ func (ec *executionContext) _Subscription_torrentDownloadUpdates(ctx context.Con
 	}
 }
 
-func (ec *executionContext) fieldContext_Subscription_torrentDownloadUpdates(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext_Subscription_torrentDownloadUpdates(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "Subscription",
 		Field:      field,
@@ -2393,7 +2410,7 @@ func (ec *executionContext) _Task_id(ctx context.Context, field graphql.Collecte
 	return ec.marshalNID2string(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext_Task_id(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext_Task_id(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "Task",
 		Field:      field,
@@ -2419,8 +2436,28 @@ func (ec *executionContext) _Torrent_name(ctx context.Context, field graphql.Col
 		}
 	}()
 	resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
-		ctx = rctx // use context from middleware stack in children
-		return ec.resolvers.Torrent().Name(rctx, obj)
+		directive0 := func(rctx context.Context) (interface{}, error) {
+			ctx = rctx // use context from middleware stack in children
+			return ec.resolvers.Torrent().Name(rctx, obj)
+		}
+		directive1 := func(ctx context.Context) (interface{}, error) {
+			if ec.directives.Resolver == nil {
+				return nil, errors.New("directive resolver is not implemented")
+			}
+			return ec.directives.Resolver(ctx, obj, directive0)
+		}
+
+		tmp, err := directive1(rctx)
+		if err != nil {
+			return nil, graphql.ErrorOnPath(ctx, err)
+		}
+		if tmp == nil {
+			return nil, nil
+		}
+		if data, ok := tmp.(string); ok {
+			return data, nil
+		}
+		return nil, fmt.Errorf(`unexpected type %T from directive, should be string`, tmp)
 	})
 	if err != nil {
 		ec.Error(ctx, err)
@@ -2437,7 +2474,7 @@ func (ec *executionContext) _Torrent_name(ctx context.Context, field graphql.Col
 	return ec.marshalNString2string(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext_Torrent_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext_Torrent_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "Torrent",
 		Field:      field,
@@ -2481,7 +2518,7 @@ func (ec *executionContext) _Torrent_infohash(ctx context.Context, field graphql
 	return ec.marshalNString2string(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext_Torrent_infohash(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext_Torrent_infohash(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "Torrent",
 		Field:      field,
@@ -2525,7 +2562,7 @@ func (ec *executionContext) _Torrent_bytesCompleted(ctx context.Context, field g
 	return ec.marshalNInt2int64(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext_Torrent_bytesCompleted(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext_Torrent_bytesCompleted(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "Torrent",
 		Field:      field,
@@ -2569,7 +2606,7 @@ func (ec *executionContext) _Torrent_torrentFilePath(ctx context.Context, field
 	return ec.marshalNString2string(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext_Torrent_torrentFilePath(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext_Torrent_torrentFilePath(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "Torrent",
 		Field:      field,
@@ -2613,7 +2650,7 @@ func (ec *executionContext) _Torrent_bytesMissing(ctx context.Context, field gra
 	return ec.marshalNInt2int64(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext_Torrent_bytesMissing(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext_Torrent_bytesMissing(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "Torrent",
 		Field:      field,
@@ -2626,6 +2663,70 @@ func (ec *executionContext) fieldContext_Torrent_bytesMissing(ctx context.Contex
 	return fc, nil
 }
 
+func (ec *executionContext) _Torrent_priority(ctx context.Context, field graphql.CollectedField, obj *model.Torrent) (ret graphql.Marshaler) {
+	fc, err := ec.fieldContext_Torrent_priority(ctx, field)
+	if err != nil {
+		return graphql.Null
+	}
+	ctx = graphql.WithFieldContext(ctx, fc)
+	defer func() {
+		if r := recover(); r != nil {
+			ec.Error(ctx, ec.Recover(ctx, r))
+			ret = graphql.Null
+		}
+	}()
+	resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+		directive0 := func(rctx context.Context) (interface{}, error) {
+			ctx = rctx // use context from middleware stack in children
+			return ec.resolvers.Torrent().Priority(rctx, obj)
+		}
+		directive1 := func(ctx context.Context) (interface{}, error) {
+			if ec.directives.Resolver == nil {
+				return nil, errors.New("directive resolver is not implemented")
+			}
+			return ec.directives.Resolver(ctx, obj, directive0)
+		}
+
+		tmp, err := directive1(rctx)
+		if err != nil {
+			return nil, graphql.ErrorOnPath(ctx, err)
+		}
+		if tmp == nil {
+			return nil, nil
+		}
+		if data, ok := tmp.(types.PiecePriority); ok {
+			return data, nil
+		}
+		return nil, fmt.Errorf(`unexpected type %T from directive, should be github.com/anacrolix/torrent/types.PiecePriority`, tmp)
+	})
+	if err != nil {
+		ec.Error(ctx, err)
+		return graphql.Null
+	}
+	if resTmp == nil {
+		if !graphql.HasFieldError(ctx, fc) {
+			ec.Errorf(ctx, "must not be null")
+		}
+		return graphql.Null
+	}
+	res := resTmp.(types.PiecePriority)
+	fc.Result = res
+	return ec.marshalNTorrentPriority2githubᚗcomᚋanacrolixᚋtorrentᚋtypesᚐPiecePriority(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext_Torrent_priority(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+	fc = &graphql.FieldContext{
+		Object:     "Torrent",
+		Field:      field,
+		IsMethod:   true,
+		IsResolver: true,
+		Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+			return nil, errors.New("field of type TorrentPriority does not have child fields")
+		},
+	}
+	return fc, nil
+}
+
 func (ec *executionContext) _Torrent_files(ctx context.Context, field graphql.CollectedField, obj *model.Torrent) (ret graphql.Marshaler) {
 	fc, err := ec.fieldContext_Torrent_files(ctx, field)
 	if err != nil {
@@ -2639,8 +2740,28 @@ func (ec *executionContext) _Torrent_files(ctx context.Context, field graphql.Co
 		}
 	}()
 	resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
-		ctx = rctx // use context from middleware stack in children
-		return ec.resolvers.Torrent().Files(rctx, obj)
+		directive0 := func(rctx context.Context) (interface{}, error) {
+			ctx = rctx // use context from middleware stack in children
+			return ec.resolvers.Torrent().Files(rctx, obj)
+		}
+		directive1 := func(ctx context.Context) (interface{}, error) {
+			if ec.directives.Resolver == nil {
+				return nil, errors.New("directive resolver is not implemented")
+			}
+			return ec.directives.Resolver(ctx, obj, directive0)
+		}
+
+		tmp, err := directive1(rctx)
+		if err != nil {
+			return nil, graphql.ErrorOnPath(ctx, err)
+		}
+		if tmp == nil {
+			return nil, nil
+		}
+		if data, ok := tmp.([]*model.TorrentFile); ok {
+			return data, nil
+		}
+		return nil, fmt.Errorf(`unexpected type %T from directive, should be []*git.kmsign.ru/royalcat/tstor/src/delivery/graphql/model.TorrentFile`, tmp)
 	})
 	if err != nil {
 		ec.Error(ctx, err)
@@ -2657,7 +2778,7 @@ func (ec *executionContext) _Torrent_files(ctx context.Context, field graphql.Co
 	return ec.marshalNTorrentFile2ᚕᚖgitᚗkmsignᚗruᚋroyalcatᚋtstorᚋsrcᚋdeliveryᚋgraphqlᚋmodelᚐTorrentFileᚄ(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext_Torrent_files(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext_Torrent_files(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "Torrent",
 		Field:      field,
@@ -2691,8 +2812,28 @@ func (ec *executionContext) _Torrent_excludedFiles(ctx context.Context, field gr
 		}
 	}()
 	resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
-		ctx = rctx // use context from middleware stack in children
-		return ec.resolvers.Torrent().ExcludedFiles(rctx, obj)
+		directive0 := func(rctx context.Context) (interface{}, error) {
+			ctx = rctx // use context from middleware stack in children
+			return ec.resolvers.Torrent().ExcludedFiles(rctx, obj)
+		}
+		directive1 := func(ctx context.Context) (interface{}, error) {
+			if ec.directives.Resolver == nil {
+				return nil, errors.New("directive resolver is not implemented")
+			}
+			return ec.directives.Resolver(ctx, obj, directive0)
+		}
+
+		tmp, err := directive1(rctx)
+		if err != nil {
+			return nil, graphql.ErrorOnPath(ctx, err)
+		}
+		if tmp == nil {
+			return nil, nil
+		}
+		if data, ok := tmp.([]*model.TorrentFile); ok {
+			return data, nil
+		}
+		return nil, fmt.Errorf(`unexpected type %T from directive, should be []*git.kmsign.ru/royalcat/tstor/src/delivery/graphql/model.TorrentFile`, tmp)
 	})
 	if err != nil {
 		ec.Error(ctx, err)
@@ -2709,7 +2850,7 @@ func (ec *executionContext) _Torrent_excludedFiles(ctx context.Context, field gr
 	return ec.marshalNTorrentFile2ᚕᚖgitᚗkmsignᚗruᚋroyalcatᚋtstorᚋsrcᚋdeliveryᚋgraphqlᚋmodelᚐTorrentFileᚄ(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext_Torrent_excludedFiles(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext_Torrent_excludedFiles(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "Torrent",
 		Field:      field,
@@ -2743,8 +2884,28 @@ func (ec *executionContext) _Torrent_peers(ctx context.Context, field graphql.Co
 		}
 	}()
 	resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
-		ctx = rctx // use context from middleware stack in children
-		return ec.resolvers.Torrent().Peers(rctx, obj)
+		directive0 := func(rctx context.Context) (interface{}, error) {
+			ctx = rctx // use context from middleware stack in children
+			return ec.resolvers.Torrent().Peers(rctx, obj)
+		}
+		directive1 := func(ctx context.Context) (interface{}, error) {
+			if ec.directives.Resolver == nil {
+				return nil, errors.New("directive resolver is not implemented")
+			}
+			return ec.directives.Resolver(ctx, obj, directive0)
+		}
+
+		tmp, err := directive1(rctx)
+		if err != nil {
+			return nil, graphql.ErrorOnPath(ctx, err)
+		}
+		if tmp == nil {
+			return nil, nil
+		}
+		if data, ok := tmp.([]*model.TorrentPeer); ok {
+			return data, nil
+		}
+		return nil, fmt.Errorf(`unexpected type %T from directive, should be []*git.kmsign.ru/royalcat/tstor/src/delivery/graphql/model.TorrentPeer`, tmp)
 	})
 	if err != nil {
 		ec.Error(ctx, err)
@@ -2761,7 +2922,7 @@ func (ec *executionContext) _Torrent_peers(ctx context.Context, field graphql.Co
 	return ec.marshalNTorrentPeer2ᚕᚖgitᚗkmsignᚗruᚋroyalcatᚋtstorᚋsrcᚋdeliveryᚋgraphqlᚋmodelᚐTorrentPeerᚄ(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext_Torrent_peers(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext_Torrent_peers(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "Torrent",
 		Field:      field,
@@ -2786,8 +2947,8 @@ func (ec *executionContext) fieldContext_Torrent_peers(ctx context.Context, fiel
 	return fc, nil
 }
 
-func (ec *executionContext) _Torrent_downloading(ctx context.Context, field graphql.CollectedField, obj *model.Torrent) (ret graphql.Marshaler) {
-	fc, err := ec.fieldContext_Torrent_downloading(ctx, field)
+func (ec *executionContext) _TorrentDaemonMutation_validateTorrent(ctx context.Context, field graphql.CollectedField, obj *model.TorrentDaemonMutation) (ret graphql.Marshaler) {
+	fc, err := ec.fieldContext_TorrentDaemonMutation_validateTorrent(ctx, field)
 	if err != nil {
 		return graphql.Null
 	}
@@ -2799,8 +2960,28 @@ func (ec *executionContext) _Torrent_downloading(ctx context.Context, field grap
 		}
 	}()
 	resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
-		ctx = rctx // use context from middleware stack in children
-		return obj.Downloading, nil
+		directive0 := func(rctx context.Context) (interface{}, error) {
+			ctx = rctx // use context from middleware stack in children
+			return ec.resolvers.TorrentDaemonMutation().ValidateTorrent(rctx, obj, fc.Args["filter"].(model.TorrentFilter))
+		}
+		directive1 := func(ctx context.Context) (interface{}, error) {
+			if ec.directives.Resolver == nil {
+				return nil, errors.New("directive resolver is not implemented")
+			}
+			return ec.directives.Resolver(ctx, obj, directive0)
+		}
+
+		tmp, err := directive1(rctx)
+		if err != nil {
+			return nil, graphql.ErrorOnPath(ctx, err)
+		}
+		if tmp == nil {
+			return nil, nil
+		}
+		if data, ok := tmp.(bool); ok {
+			return data, nil
+		}
+		return nil, fmt.Errorf(`unexpected type %T from directive, should be bool`, tmp)
 	})
 	if err != nil {
 		ec.Error(ctx, err)
@@ -2817,16 +2998,278 @@ func (ec *executionContext) _Torrent_downloading(ctx context.Context, field grap
 	return ec.marshalNBoolean2bool(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext_Torrent_downloading(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext_TorrentDaemonMutation_validateTorrent(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
-		Object:     "Torrent",
+		Object:     "TorrentDaemonMutation",
 		Field:      field,
-		IsMethod:   false,
-		IsResolver: false,
+		IsMethod:   true,
+		IsResolver: true,
 		Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
 			return nil, errors.New("field of type Boolean does not have child fields")
 		},
 	}
+	defer func() {
+		if r := recover(); r != nil {
+			err = ec.Recover(ctx, r)
+			ec.Error(ctx, err)
+		}
+	}()
+	ctx = graphql.WithFieldContext(ctx, fc)
+	if fc.Args, err = ec.field_TorrentDaemonMutation_validateTorrent_args(ctx, field.ArgumentMap(ec.Variables)); err != nil {
+		ec.Error(ctx, err)
+		return fc, err
+	}
+	return fc, nil
+}
+
+func (ec *executionContext) _TorrentDaemonMutation_setTorrentPriority(ctx context.Context, field graphql.CollectedField, obj *model.TorrentDaemonMutation) (ret graphql.Marshaler) {
+	fc, err := ec.fieldContext_TorrentDaemonMutation_setTorrentPriority(ctx, field)
+	if err != nil {
+		return graphql.Null
+	}
+	ctx = graphql.WithFieldContext(ctx, fc)
+	defer func() {
+		if r := recover(); r != nil {
+			ec.Error(ctx, ec.Recover(ctx, r))
+			ret = graphql.Null
+		}
+	}()
+	resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+		directive0 := func(rctx context.Context) (interface{}, error) {
+			ctx = rctx // use context from middleware stack in children
+			return ec.resolvers.TorrentDaemonMutation().SetTorrentPriority(rctx, obj, fc.Args["infohash"].(string), fc.Args["file"].(*string), fc.Args["priority"].(types.PiecePriority))
+		}
+		directive1 := func(ctx context.Context) (interface{}, error) {
+			if ec.directives.Resolver == nil {
+				return nil, errors.New("directive resolver is not implemented")
+			}
+			return ec.directives.Resolver(ctx, obj, directive0)
+		}
+
+		tmp, err := directive1(rctx)
+		if err != nil {
+			return nil, graphql.ErrorOnPath(ctx, err)
+		}
+		if tmp == nil {
+			return nil, nil
+		}
+		if data, ok := tmp.(bool); ok {
+			return data, nil
+		}
+		return nil, fmt.Errorf(`unexpected type %T from directive, should be bool`, tmp)
+	})
+	if err != nil {
+		ec.Error(ctx, err)
+		return graphql.Null
+	}
+	if resTmp == nil {
+		if !graphql.HasFieldError(ctx, fc) {
+			ec.Errorf(ctx, "must not be null")
+		}
+		return graphql.Null
+	}
+	res := resTmp.(bool)
+	fc.Result = res
+	return ec.marshalNBoolean2bool(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext_TorrentDaemonMutation_setTorrentPriority(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+	fc = &graphql.FieldContext{
+		Object:     "TorrentDaemonMutation",
+		Field:      field,
+		IsMethod:   true,
+		IsResolver: true,
+		Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+			return nil, errors.New("field of type Boolean does not have child fields")
+		},
+	}
+	defer func() {
+		if r := recover(); r != nil {
+			err = ec.Recover(ctx, r)
+			ec.Error(ctx, err)
+		}
+	}()
+	ctx = graphql.WithFieldContext(ctx, fc)
+	if fc.Args, err = ec.field_TorrentDaemonMutation_setTorrentPriority_args(ctx, field.ArgumentMap(ec.Variables)); err != nil {
+		ec.Error(ctx, err)
+		return fc, err
+	}
+	return fc, nil
+}
+
+func (ec *executionContext) _TorrentDaemonMutation_cleanup(ctx context.Context, field graphql.CollectedField, obj *model.TorrentDaemonMutation) (ret graphql.Marshaler) {
+	fc, err := ec.fieldContext_TorrentDaemonMutation_cleanup(ctx, field)
+	if err != nil {
+		return graphql.Null
+	}
+	ctx = graphql.WithFieldContext(ctx, fc)
+	defer func() {
+		if r := recover(); r != nil {
+			ec.Error(ctx, ec.Recover(ctx, r))
+			ret = graphql.Null
+		}
+	}()
+	resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+		directive0 := func(rctx context.Context) (interface{}, error) {
+			ctx = rctx // use context from middleware stack in children
+			return ec.resolvers.TorrentDaemonMutation().Cleanup(rctx, obj, fc.Args["files"].(*bool), fc.Args["dryRun"].(bool))
+		}
+		directive1 := func(ctx context.Context) (interface{}, error) {
+			if ec.directives.Resolver == nil {
+				return nil, errors.New("directive resolver is not implemented")
+			}
+			return ec.directives.Resolver(ctx, obj, directive0)
+		}
+
+		tmp, err := directive1(rctx)
+		if err != nil {
+			return nil, graphql.ErrorOnPath(ctx, err)
+		}
+		if tmp == nil {
+			return nil, nil
+		}
+		if data, ok := tmp.(*model.CleanupResponse); ok {
+			return data, nil
+		}
+		return nil, fmt.Errorf(`unexpected type %T from directive, should be *git.kmsign.ru/royalcat/tstor/src/delivery/graphql/model.CleanupResponse`, tmp)
+	})
+	if err != nil {
+		ec.Error(ctx, err)
+		return graphql.Null
+	}
+	if resTmp == nil {
+		if !graphql.HasFieldError(ctx, fc) {
+			ec.Errorf(ctx, "must not be null")
+		}
+		return graphql.Null
+	}
+	res := resTmp.(*model.CleanupResponse)
+	fc.Result = res
+	return ec.marshalNCleanupResponse2ᚖgitᚗkmsignᚗruᚋroyalcatᚋtstorᚋsrcᚋdeliveryᚋgraphqlᚋmodelᚐCleanupResponse(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext_TorrentDaemonMutation_cleanup(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+	fc = &graphql.FieldContext{
+		Object:     "TorrentDaemonMutation",
+		Field:      field,
+		IsMethod:   true,
+		IsResolver: true,
+		Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+			switch field.Name {
+			case "count":
+				return ec.fieldContext_CleanupResponse_count(ctx, field)
+			case "list":
+				return ec.fieldContext_CleanupResponse_list(ctx, field)
+			}
+			return nil, fmt.Errorf("no field named %q was found under type CleanupResponse", field.Name)
+		},
+	}
+	defer func() {
+		if r := recover(); r != nil {
+			err = ec.Recover(ctx, r)
+			ec.Error(ctx, err)
+		}
+	}()
+	ctx = graphql.WithFieldContext(ctx, fc)
+	if fc.Args, err = ec.field_TorrentDaemonMutation_cleanup_args(ctx, field.ArgumentMap(ec.Variables)); err != nil {
+		ec.Error(ctx, err)
+		return fc, err
+	}
+	return fc, nil
+}
+
+func (ec *executionContext) _TorrentDaemonQuery_torrents(ctx context.Context, field graphql.CollectedField, obj *model.TorrentDaemonQuery) (ret graphql.Marshaler) {
+	fc, err := ec.fieldContext_TorrentDaemonQuery_torrents(ctx, field)
+	if err != nil {
+		return graphql.Null
+	}
+	ctx = graphql.WithFieldContext(ctx, fc)
+	defer func() {
+		if r := recover(); r != nil {
+			ec.Error(ctx, ec.Recover(ctx, r))
+			ret = graphql.Null
+		}
+	}()
+	resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+		directive0 := func(rctx context.Context) (interface{}, error) {
+			ctx = rctx // use context from middleware stack in children
+			return ec.resolvers.TorrentDaemonQuery().Torrents(rctx, obj, fc.Args["filter"].(*model.TorrentsFilter))
+		}
+		directive1 := func(ctx context.Context) (interface{}, error) {
+			if ec.directives.Resolver == nil {
+				return nil, errors.New("directive resolver is not implemented")
+			}
+			return ec.directives.Resolver(ctx, obj, directive0)
+		}
+
+		tmp, err := directive1(rctx)
+		if err != nil {
+			return nil, graphql.ErrorOnPath(ctx, err)
+		}
+		if tmp == nil {
+			return nil, nil
+		}
+		if data, ok := tmp.([]*model.Torrent); ok {
+			return data, nil
+		}
+		return nil, fmt.Errorf(`unexpected type %T from directive, should be []*git.kmsign.ru/royalcat/tstor/src/delivery/graphql/model.Torrent`, tmp)
+	})
+	if err != nil {
+		ec.Error(ctx, err)
+		return graphql.Null
+	}
+	if resTmp == nil {
+		if !graphql.HasFieldError(ctx, fc) {
+			ec.Errorf(ctx, "must not be null")
+		}
+		return graphql.Null
+	}
+	res := resTmp.([]*model.Torrent)
+	fc.Result = res
+	return ec.marshalNTorrent2ᚕᚖgitᚗkmsignᚗruᚋroyalcatᚋtstorᚋsrcᚋdeliveryᚋgraphqlᚋmodelᚐTorrentᚄ(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext_TorrentDaemonQuery_torrents(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+	fc = &graphql.FieldContext{
+		Object:     "TorrentDaemonQuery",
+		Field:      field,
+		IsMethod:   true,
+		IsResolver: true,
+		Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+			switch field.Name {
+			case "name":
+				return ec.fieldContext_Torrent_name(ctx, field)
+			case "infohash":
+				return ec.fieldContext_Torrent_infohash(ctx, field)
+			case "bytesCompleted":
+				return ec.fieldContext_Torrent_bytesCompleted(ctx, field)
+			case "torrentFilePath":
+				return ec.fieldContext_Torrent_torrentFilePath(ctx, field)
+			case "bytesMissing":
+				return ec.fieldContext_Torrent_bytesMissing(ctx, field)
+			case "priority":
+				return ec.fieldContext_Torrent_priority(ctx, field)
+			case "files":
+				return ec.fieldContext_Torrent_files(ctx, field)
+			case "excludedFiles":
+				return ec.fieldContext_Torrent_excludedFiles(ctx, field)
+			case "peers":
+				return ec.fieldContext_Torrent_peers(ctx, field)
+			}
+			return nil, fmt.Errorf("no field named %q was found under type Torrent", field.Name)
+		},
+	}
+	defer func() {
+		if r := recover(); r != nil {
+			err = ec.Recover(ctx, r)
+			ec.Error(ctx, err)
+		}
+	}()
+	ctx = graphql.WithFieldContext(ctx, fc)
+	if fc.Args, err = ec.field_TorrentDaemonQuery_torrents_args(ctx, field.ArgumentMap(ec.Variables)); err != nil {
+		ec.Error(ctx, err)
+		return fc, err
+	}
 	return fc, nil
 }
 
@@ -2861,7 +3304,7 @@ func (ec *executionContext) _TorrentFS_name(ctx context.Context, field graphql.C
 	return ec.marshalNString2string(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext_TorrentFS_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext_TorrentFS_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "TorrentFS",
 		Field:      field,
@@ -2905,7 +3348,7 @@ func (ec *executionContext) _TorrentFS_torrent(ctx context.Context, field graphq
 	return ec.marshalNTorrent2ᚖgitᚗkmsignᚗruᚋroyalcatᚋtstorᚋsrcᚋdeliveryᚋgraphqlᚋmodelᚐTorrent(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext_TorrentFS_torrent(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext_TorrentFS_torrent(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "TorrentFS",
 		Field:      field,
@@ -2923,14 +3366,14 @@ func (ec *executionContext) fieldContext_TorrentFS_torrent(ctx context.Context,
 				return ec.fieldContext_Torrent_torrentFilePath(ctx, field)
 			case "bytesMissing":
 				return ec.fieldContext_Torrent_bytesMissing(ctx, field)
+			case "priority":
+				return ec.fieldContext_Torrent_priority(ctx, field)
 			case "files":
 				return ec.fieldContext_Torrent_files(ctx, field)
 			case "excludedFiles":
 				return ec.fieldContext_Torrent_excludedFiles(ctx, field)
 			case "peers":
 				return ec.fieldContext_Torrent_peers(ctx, field)
-			case "downloading":
-				return ec.fieldContext_Torrent_downloading(ctx, field)
 			}
 			return nil, fmt.Errorf("no field named %q was found under type Torrent", field.Name)
 		},
@@ -2951,8 +3394,28 @@ func (ec *executionContext) _TorrentFS_entries(ctx context.Context, field graphq
 		}
 	}()
 	resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
-		ctx = rctx // use context from middleware stack in children
-		return ec.resolvers.TorrentFS().Entries(rctx, obj)
+		directive0 := func(rctx context.Context) (interface{}, error) {
+			ctx = rctx // use context from middleware stack in children
+			return ec.resolvers.TorrentFS().Entries(rctx, obj)
+		}
+		directive1 := func(ctx context.Context) (interface{}, error) {
+			if ec.directives.Resolver == nil {
+				return nil, errors.New("directive resolver is not implemented")
+			}
+			return ec.directives.Resolver(ctx, obj, directive0)
+		}
+
+		tmp, err := directive1(rctx)
+		if err != nil {
+			return nil, graphql.ErrorOnPath(ctx, err)
+		}
+		if tmp == nil {
+			return nil, nil
+		}
+		if data, ok := tmp.([]model.FsEntry); ok {
+			return data, nil
+		}
+		return nil, fmt.Errorf(`unexpected type %T from directive, should be []git.kmsign.ru/royalcat/tstor/src/delivery/graphql/model.FsEntry`, tmp)
 	})
 	if err != nil {
 		ec.Error(ctx, err)
@@ -2969,7 +3432,7 @@ func (ec *executionContext) _TorrentFS_entries(ctx context.Context, field graphq
 	return ec.marshalNFsEntry2ᚕgitᚗkmsignᚗruᚋroyalcatᚋtstorᚋsrcᚋdeliveryᚋgraphqlᚋmodelᚐFsEntryᚄ(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext_TorrentFS_entries(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext_TorrentFS_entries(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "TorrentFS",
 		Field:      field,
@@ -3013,7 +3476,7 @@ func (ec *executionContext) _TorrentFile_filename(ctx context.Context, field gra
 	return ec.marshalNString2string(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext_TorrentFile_filename(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext_TorrentFile_filename(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "TorrentFile",
 		Field:      field,
@@ -3057,7 +3520,7 @@ func (ec *executionContext) _TorrentFile_size(ctx context.Context, field graphql
 	return ec.marshalNInt2int64(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext_TorrentFile_size(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext_TorrentFile_size(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "TorrentFile",
 		Field:      field,
@@ -3101,7 +3564,7 @@ func (ec *executionContext) _TorrentFile_bytesCompleted(ctx context.Context, fie
 	return ec.marshalNInt2int64(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext_TorrentFile_bytesCompleted(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext_TorrentFile_bytesCompleted(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "TorrentFile",
 		Field:      field,
@@ -3145,7 +3608,7 @@ func (ec *executionContext) _TorrentFileEntry_name(ctx context.Context, field gr
 	return ec.marshalNString2string(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext_TorrentFileEntry_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext_TorrentFileEntry_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "TorrentFileEntry",
 		Field:      field,
@@ -3189,7 +3652,7 @@ func (ec *executionContext) _TorrentFileEntry_torrent(ctx context.Context, field
 	return ec.marshalNTorrent2ᚖgitᚗkmsignᚗruᚋroyalcatᚋtstorᚋsrcᚋdeliveryᚋgraphqlᚋmodelᚐTorrent(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext_TorrentFileEntry_torrent(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext_TorrentFileEntry_torrent(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "TorrentFileEntry",
 		Field:      field,
@@ -3207,14 +3670,14 @@ func (ec *executionContext) fieldContext_TorrentFileEntry_torrent(ctx context.Co
 				return ec.fieldContext_Torrent_torrentFilePath(ctx, field)
 			case "bytesMissing":
 				return ec.fieldContext_Torrent_bytesMissing(ctx, field)
+			case "priority":
+				return ec.fieldContext_Torrent_priority(ctx, field)
 			case "files":
 				return ec.fieldContext_Torrent_files(ctx, field)
 			case "excludedFiles":
 				return ec.fieldContext_Torrent_excludedFiles(ctx, field)
 			case "peers":
 				return ec.fieldContext_Torrent_peers(ctx, field)
-			case "downloading":
-				return ec.fieldContext_Torrent_downloading(ctx, field)
 			}
 			return nil, fmt.Errorf("no field named %q was found under type Torrent", field.Name)
 		},
@@ -3253,7 +3716,7 @@ func (ec *executionContext) _TorrentFileEntry_size(ctx context.Context, field gr
 	return ec.marshalNInt2int64(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext_TorrentFileEntry_size(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext_TorrentFileEntry_size(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "TorrentFileEntry",
 		Field:      field,
@@ -3297,7 +3760,7 @@ func (ec *executionContext) _TorrentPeer_ip(ctx context.Context, field graphql.C
 	return ec.marshalNString2string(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext_TorrentPeer_ip(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext_TorrentPeer_ip(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "TorrentPeer",
 		Field:      field,
@@ -3341,7 +3804,7 @@ func (ec *executionContext) _TorrentPeer_downloadRate(ctx context.Context, field
 	return ec.marshalNFloat2float64(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext_TorrentPeer_downloadRate(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext_TorrentPeer_downloadRate(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "TorrentPeer",
 		Field:      field,
@@ -3385,7 +3848,7 @@ func (ec *executionContext) _TorrentPeer_discovery(ctx context.Context, field gr
 	return ec.marshalNString2string(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext_TorrentPeer_discovery(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext_TorrentPeer_discovery(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "TorrentPeer",
 		Field:      field,
@@ -3429,7 +3892,7 @@ func (ec *executionContext) _TorrentPeer_port(ctx context.Context, field graphql
 	return ec.marshalNInt2int64(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext_TorrentPeer_port(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext_TorrentPeer_port(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "TorrentPeer",
 		Field:      field,
@@ -3473,7 +3936,7 @@ func (ec *executionContext) _TorrentPeer_clientName(ctx context.Context, field g
 	return ec.marshalNString2string(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext_TorrentPeer_clientName(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext_TorrentPeer_clientName(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "TorrentPeer",
 		Field:      field,
@@ -3517,7 +3980,7 @@ func (ec *executionContext) _TorrentProgress_torrent(ctx context.Context, field
 	return ec.marshalNTorrent2ᚖgitᚗkmsignᚗruᚋroyalcatᚋtstorᚋsrcᚋdeliveryᚋgraphqlᚋmodelᚐTorrent(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext_TorrentProgress_torrent(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext_TorrentProgress_torrent(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "TorrentProgress",
 		Field:      field,
@@ -3535,14 +3998,14 @@ func (ec *executionContext) fieldContext_TorrentProgress_torrent(ctx context.Con
 				return ec.fieldContext_Torrent_torrentFilePath(ctx, field)
 			case "bytesMissing":
 				return ec.fieldContext_Torrent_bytesMissing(ctx, field)
+			case "priority":
+				return ec.fieldContext_Torrent_priority(ctx, field)
 			case "files":
 				return ec.fieldContext_Torrent_files(ctx, field)
 			case "excludedFiles":
 				return ec.fieldContext_Torrent_excludedFiles(ctx, field)
 			case "peers":
 				return ec.fieldContext_Torrent_peers(ctx, field)
-			case "downloading":
-				return ec.fieldContext_Torrent_downloading(ctx, field)
 			}
 			return nil, fmt.Errorf("no field named %q was found under type Torrent", field.Name)
 		},
@@ -3581,7 +4044,7 @@ func (ec *executionContext) _TorrentProgress_current(ctx context.Context, field
 	return ec.marshalNInt2int64(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext_TorrentProgress_current(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext_TorrentProgress_current(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "TorrentProgress",
 		Field:      field,
@@ -3625,7 +4088,7 @@ func (ec *executionContext) _TorrentProgress_total(ctx context.Context, field gr
 	return ec.marshalNInt2int64(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext_TorrentProgress_total(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext_TorrentProgress_total(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "TorrentProgress",
 		Field:      field,
@@ -3669,7 +4132,7 @@ func (ec *executionContext) ___Directive_name(ctx context.Context, field graphql
 	return ec.marshalNString2string(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext___Directive_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext___Directive_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "__Directive",
 		Field:      field,
@@ -3710,7 +4173,7 @@ func (ec *executionContext) ___Directive_description(ctx context.Context, field
 	return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext___Directive_description(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext___Directive_description(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "__Directive",
 		Field:      field,
@@ -3754,7 +4217,7 @@ func (ec *executionContext) ___Directive_locations(ctx context.Context, field gr
 	return ec.marshalN__DirectiveLocation2ᚕstringᚄ(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext___Directive_locations(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext___Directive_locations(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "__Directive",
 		Field:      field,
@@ -3798,7 +4261,7 @@ func (ec *executionContext) ___Directive_args(ctx context.Context, field graphql
 	return ec.marshalN__InputValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValueᚄ(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext___Directive_args(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext___Directive_args(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "__Directive",
 		Field:      field,
@@ -3852,7 +4315,7 @@ func (ec *executionContext) ___Directive_isRepeatable(ctx context.Context, field
 	return ec.marshalNBoolean2bool(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext___Directive_isRepeatable(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext___Directive_isRepeatable(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "__Directive",
 		Field:      field,
@@ -3896,7 +4359,7 @@ func (ec *executionContext) ___EnumValue_name(ctx context.Context, field graphql
 	return ec.marshalNString2string(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext___EnumValue_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext___EnumValue_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "__EnumValue",
 		Field:      field,
@@ -3937,7 +4400,7 @@ func (ec *executionContext) ___EnumValue_description(ctx context.Context, field
 	return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext___EnumValue_description(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext___EnumValue_description(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "__EnumValue",
 		Field:      field,
@@ -3981,7 +4444,7 @@ func (ec *executionContext) ___EnumValue_isDeprecated(ctx context.Context, field
 	return ec.marshalNBoolean2bool(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext___EnumValue_isDeprecated(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext___EnumValue_isDeprecated(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "__EnumValue",
 		Field:      field,
@@ -4022,7 +4485,7 @@ func (ec *executionContext) ___EnumValue_deprecationReason(ctx context.Context,
 	return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext___EnumValue_deprecationReason(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext___EnumValue_deprecationReason(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "__EnumValue",
 		Field:      field,
@@ -4066,7 +4529,7 @@ func (ec *executionContext) ___Field_name(ctx context.Context, field graphql.Col
 	return ec.marshalNString2string(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext___Field_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext___Field_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "__Field",
 		Field:      field,
@@ -4107,7 +4570,7 @@ func (ec *executionContext) ___Field_description(ctx context.Context, field grap
 	return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext___Field_description(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext___Field_description(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "__Field",
 		Field:      field,
@@ -4151,7 +4614,7 @@ func (ec *executionContext) ___Field_args(ctx context.Context, field graphql.Col
 	return ec.marshalN__InputValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValueᚄ(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext___Field_args(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext___Field_args(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "__Field",
 		Field:      field,
@@ -4205,7 +4668,7 @@ func (ec *executionContext) ___Field_type(ctx context.Context, field graphql.Col
 	return ec.marshalN__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext___Field_type(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext___Field_type(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "__Field",
 		Field:      field,
@@ -4271,7 +4734,7 @@ func (ec *executionContext) ___Field_isDeprecated(ctx context.Context, field gra
 	return ec.marshalNBoolean2bool(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext___Field_isDeprecated(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext___Field_isDeprecated(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "__Field",
 		Field:      field,
@@ -4312,7 +4775,7 @@ func (ec *executionContext) ___Field_deprecationReason(ctx context.Context, fiel
 	return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext___Field_deprecationReason(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext___Field_deprecationReason(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "__Field",
 		Field:      field,
@@ -4356,7 +4819,7 @@ func (ec *executionContext) ___InputValue_name(ctx context.Context, field graphq
 	return ec.marshalNString2string(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext___InputValue_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext___InputValue_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "__InputValue",
 		Field:      field,
@@ -4397,7 +4860,7 @@ func (ec *executionContext) ___InputValue_description(ctx context.Context, field
 	return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext___InputValue_description(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext___InputValue_description(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "__InputValue",
 		Field:      field,
@@ -4441,7 +4904,7 @@ func (ec *executionContext) ___InputValue_type(ctx context.Context, field graphq
 	return ec.marshalN__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext___InputValue_type(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext___InputValue_type(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "__InputValue",
 		Field:      field,
@@ -4504,7 +4967,7 @@ func (ec *executionContext) ___InputValue_defaultValue(ctx context.Context, fiel
 	return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext___InputValue_defaultValue(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext___InputValue_defaultValue(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "__InputValue",
 		Field:      field,
@@ -4545,7 +5008,7 @@ func (ec *executionContext) ___Schema_description(ctx context.Context, field gra
 	return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext___Schema_description(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext___Schema_description(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "__Schema",
 		Field:      field,
@@ -4589,7 +5052,7 @@ func (ec *executionContext) ___Schema_types(ctx context.Context, field graphql.C
 	return ec.marshalN__Type2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐTypeᚄ(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext___Schema_types(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext___Schema_types(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "__Schema",
 		Field:      field,
@@ -4655,7 +5118,7 @@ func (ec *executionContext) ___Schema_queryType(ctx context.Context, field graph
 	return ec.marshalN__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext___Schema_queryType(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext___Schema_queryType(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "__Schema",
 		Field:      field,
@@ -4718,7 +5181,7 @@ func (ec *executionContext) ___Schema_mutationType(ctx context.Context, field gr
 	return ec.marshalO__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext___Schema_mutationType(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext___Schema_mutationType(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "__Schema",
 		Field:      field,
@@ -4781,7 +5244,7 @@ func (ec *executionContext) ___Schema_subscriptionType(ctx context.Context, fiel
 	return ec.marshalO__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext___Schema_subscriptionType(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext___Schema_subscriptionType(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "__Schema",
 		Field:      field,
@@ -4847,7 +5310,7 @@ func (ec *executionContext) ___Schema_directives(ctx context.Context, field grap
 	return ec.marshalN__Directive2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐDirectiveᚄ(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext___Schema_directives(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext___Schema_directives(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "__Schema",
 		Field:      field,
@@ -4903,7 +5366,7 @@ func (ec *executionContext) ___Type_kind(ctx context.Context, field graphql.Coll
 	return ec.marshalN__TypeKind2string(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext___Type_kind(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext___Type_kind(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "__Type",
 		Field:      field,
@@ -4944,7 +5407,7 @@ func (ec *executionContext) ___Type_name(ctx context.Context, field graphql.Coll
 	return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext___Type_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext___Type_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "__Type",
 		Field:      field,
@@ -4985,7 +5448,7 @@ func (ec *executionContext) ___Type_description(ctx context.Context, field graph
 	return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext___Type_description(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext___Type_description(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "__Type",
 		Field:      field,
@@ -5092,7 +5555,7 @@ func (ec *executionContext) ___Type_interfaces(ctx context.Context, field graphq
 	return ec.marshalO__Type2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐTypeᚄ(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext___Type_interfaces(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext___Type_interfaces(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "__Type",
 		Field:      field,
@@ -5155,7 +5618,7 @@ func (ec *executionContext) ___Type_possibleTypes(ctx context.Context, field gra
 	return ec.marshalO__Type2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐTypeᚄ(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext___Type_possibleTypes(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext___Type_possibleTypes(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "__Type",
 		Field:      field,
@@ -5280,7 +5743,7 @@ func (ec *executionContext) ___Type_inputFields(ctx context.Context, field graph
 	return ec.marshalO__InputValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValueᚄ(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext___Type_inputFields(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext___Type_inputFields(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "__Type",
 		Field:      field,
@@ -5331,7 +5794,7 @@ func (ec *executionContext) ___Type_ofType(ctx context.Context, field graphql.Co
 	return ec.marshalO__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext___Type_ofType(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext___Type_ofType(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "__Type",
 		Field:      field,
@@ -5394,7 +5857,7 @@ func (ec *executionContext) ___Type_specifiedByURL(ctx context.Context, field gr
 	return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) fieldContext___Type_specifiedByURL(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+func (ec *executionContext) fieldContext___Type_specifiedByURL(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
 	fc = &graphql.FieldContext{
 		Object:     "__Type",
 		Field:      field,
@@ -5919,6 +6382,170 @@ func (ec *executionContext) unmarshalInputTorrentFilter(ctx context.Context, obj
 	return it, nil
 }
 
+func (ec *executionContext) unmarshalInputTorrentPriorityFilter(ctx context.Context, obj interface{}) (model.TorrentPriorityFilter, error) {
+	var it model.TorrentPriorityFilter
+	asMap := map[string]interface{}{}
+	for k, v := range obj.(map[string]interface{}) {
+		asMap[k] = v
+	}
+
+	fieldsInOrder := [...]string{"eq", "gt", "lt", "gte", "lte", "in"}
+	for _, k := range fieldsInOrder {
+		v, ok := asMap[k]
+		if !ok {
+			continue
+		}
+		switch k {
+		case "eq":
+			ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("eq"))
+			directive0 := func(ctx context.Context) (interface{}, error) {
+				return ec.unmarshalOTorrentPriority2ᚖgithubᚗcomᚋanacrolixᚋtorrentᚋtypesᚐPiecePriority(ctx, v)
+			}
+			directive1 := func(ctx context.Context) (interface{}, error) {
+				if ec.directives.OneOf == nil {
+					return nil, errors.New("directive oneOf is not implemented")
+				}
+				return ec.directives.OneOf(ctx, obj, directive0)
+			}
+
+			tmp, err := directive1(ctx)
+			if err != nil {
+				return it, graphql.ErrorOnPath(ctx, err)
+			}
+			if data, ok := tmp.(*types.PiecePriority); ok {
+				it.Eq = data
+			} else if tmp == nil {
+				it.Eq = nil
+			} else {
+				err := fmt.Errorf(`unexpected type %T from directive, should be *github.com/anacrolix/torrent/types.PiecePriority`, tmp)
+				return it, graphql.ErrorOnPath(ctx, err)
+			}
+		case "gt":
+			ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("gt"))
+			directive0 := func(ctx context.Context) (interface{}, error) {
+				return ec.unmarshalOTorrentPriority2ᚖgithubᚗcomᚋanacrolixᚋtorrentᚋtypesᚐPiecePriority(ctx, v)
+			}
+			directive1 := func(ctx context.Context) (interface{}, error) {
+				if ec.directives.OneOf == nil {
+					return nil, errors.New("directive oneOf is not implemented")
+				}
+				return ec.directives.OneOf(ctx, obj, directive0)
+			}
+
+			tmp, err := directive1(ctx)
+			if err != nil {
+				return it, graphql.ErrorOnPath(ctx, err)
+			}
+			if data, ok := tmp.(*types.PiecePriority); ok {
+				it.Gt = data
+			} else if tmp == nil {
+				it.Gt = nil
+			} else {
+				err := fmt.Errorf(`unexpected type %T from directive, should be *github.com/anacrolix/torrent/types.PiecePriority`, tmp)
+				return it, graphql.ErrorOnPath(ctx, err)
+			}
+		case "lt":
+			ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("lt"))
+			directive0 := func(ctx context.Context) (interface{}, error) {
+				return ec.unmarshalOTorrentPriority2ᚖgithubᚗcomᚋanacrolixᚋtorrentᚋtypesᚐPiecePriority(ctx, v)
+			}
+			directive1 := func(ctx context.Context) (interface{}, error) {
+				if ec.directives.OneOf == nil {
+					return nil, errors.New("directive oneOf is not implemented")
+				}
+				return ec.directives.OneOf(ctx, obj, directive0)
+			}
+
+			tmp, err := directive1(ctx)
+			if err != nil {
+				return it, graphql.ErrorOnPath(ctx, err)
+			}
+			if data, ok := tmp.(*types.PiecePriority); ok {
+				it.Lt = data
+			} else if tmp == nil {
+				it.Lt = nil
+			} else {
+				err := fmt.Errorf(`unexpected type %T from directive, should be *github.com/anacrolix/torrent/types.PiecePriority`, tmp)
+				return it, graphql.ErrorOnPath(ctx, err)
+			}
+		case "gte":
+			ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("gte"))
+			directive0 := func(ctx context.Context) (interface{}, error) {
+				return ec.unmarshalOTorrentPriority2ᚖgithubᚗcomᚋanacrolixᚋtorrentᚋtypesᚐPiecePriority(ctx, v)
+			}
+			directive1 := func(ctx context.Context) (interface{}, error) {
+				if ec.directives.OneOf == nil {
+					return nil, errors.New("directive oneOf is not implemented")
+				}
+				return ec.directives.OneOf(ctx, obj, directive0)
+			}
+
+			tmp, err := directive1(ctx)
+			if err != nil {
+				return it, graphql.ErrorOnPath(ctx, err)
+			}
+			if data, ok := tmp.(*types.PiecePriority); ok {
+				it.Gte = data
+			} else if tmp == nil {
+				it.Gte = nil
+			} else {
+				err := fmt.Errorf(`unexpected type %T from directive, should be *github.com/anacrolix/torrent/types.PiecePriority`, tmp)
+				return it, graphql.ErrorOnPath(ctx, err)
+			}
+		case "lte":
+			ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("lte"))
+			directive0 := func(ctx context.Context) (interface{}, error) {
+				return ec.unmarshalOTorrentPriority2ᚖgithubᚗcomᚋanacrolixᚋtorrentᚋtypesᚐPiecePriority(ctx, v)
+			}
+			directive1 := func(ctx context.Context) (interface{}, error) {
+				if ec.directives.OneOf == nil {
+					return nil, errors.New("directive oneOf is not implemented")
+				}
+				return ec.directives.OneOf(ctx, obj, directive0)
+			}
+
+			tmp, err := directive1(ctx)
+			if err != nil {
+				return it, graphql.ErrorOnPath(ctx, err)
+			}
+			if data, ok := tmp.(*types.PiecePriority); ok {
+				it.Lte = data
+			} else if tmp == nil {
+				it.Lte = nil
+			} else {
+				err := fmt.Errorf(`unexpected type %T from directive, should be *github.com/anacrolix/torrent/types.PiecePriority`, tmp)
+				return it, graphql.ErrorOnPath(ctx, err)
+			}
+		case "in":
+			ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("in"))
+			directive0 := func(ctx context.Context) (interface{}, error) {
+				return ec.unmarshalOTorrentPriority2ᚕgithubᚗcomᚋanacrolixᚋtorrentᚋtypesᚐPiecePriorityᚄ(ctx, v)
+			}
+			directive1 := func(ctx context.Context) (interface{}, error) {
+				if ec.directives.OneOf == nil {
+					return nil, errors.New("directive oneOf is not implemented")
+				}
+				return ec.directives.OneOf(ctx, obj, directive0)
+			}
+
+			tmp, err := directive1(ctx)
+			if err != nil {
+				return it, graphql.ErrorOnPath(ctx, err)
+			}
+			if data, ok := tmp.([]types.PiecePriority); ok {
+				it.In = data
+			} else if tmp == nil {
+				it.In = nil
+			} else {
+				err := fmt.Errorf(`unexpected type %T from directive, should be []github.com/anacrolix/torrent/types.PiecePriority`, tmp)
+				return it, graphql.ErrorOnPath(ctx, err)
+			}
+		}
+	}
+
+	return it, nil
+}
+
 func (ec *executionContext) unmarshalInputTorrentsFilter(ctx context.Context, obj interface{}) (model.TorrentsFilter, error) {
 	var it model.TorrentsFilter
 	asMap := map[string]interface{}{}
@@ -5926,7 +6553,7 @@ func (ec *executionContext) unmarshalInputTorrentsFilter(ctx context.Context, ob
 		asMap[k] = v
 	}
 
-	fieldsInOrder := [...]string{"infohash", "name", "bytesCompleted", "bytesMissing", "peersCount", "downloading"}
+	fieldsInOrder := [...]string{"infohash", "name", "bytesCompleted", "bytesMissing", "peersCount", "priority"}
 	for _, k := range fieldsInOrder {
 		v, ok := asMap[k]
 		if !ok {
@@ -5968,13 +6595,13 @@ func (ec *executionContext) unmarshalInputTorrentsFilter(ctx context.Context, ob
 				return it, err
 			}
 			it.PeersCount = data
-		case "downloading":
-			ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("downloading"))
-			data, err := ec.unmarshalOBooleanFilter2ᚖgitᚗkmsignᚗruᚋroyalcatᚋtstorᚋsrcᚋdeliveryᚋgraphqlᚋmodelᚐBooleanFilter(ctx, v)
+		case "priority":
+			ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("priority"))
+			data, err := ec.unmarshalOTorrentPriorityFilter2ᚖgitᚗkmsignᚗruᚋroyalcatᚋtstorᚋsrcᚋdeliveryᚋgraphqlᚋmodelᚐTorrentPriorityFilter(ctx, v)
 			if err != nil {
 				return it, err
 			}
-			it.Downloading = data
+			it.Priority = data
 		}
 	}
 
@@ -6305,23 +6932,9 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet)
 		switch field.Name {
 		case "__typename":
 			out.Values[i] = graphql.MarshalString("Mutation")
-		case "validateTorrents":
+		case "torrentDaemon":
 			out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) {
-				return ec._Mutation_validateTorrents(ctx, field)
-			})
-			if out.Values[i] == graphql.Null {
-				out.Invalids++
-			}
-		case "cleanupTorrents":
-			out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) {
-				return ec._Mutation_cleanupTorrents(ctx, field)
-			})
-			if out.Values[i] == graphql.Null {
-				out.Invalids++
-			}
-		case "downloadTorrent":
-			out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) {
-				return ec._Mutation_downloadTorrent(ctx, field)
+				return ec._Mutation_torrentDaemon(ctx, field)
 			})
 		case "uploadFile":
 			out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) {
@@ -6379,19 +6992,16 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr
 		switch field.Name {
 		case "__typename":
 			out.Values[i] = graphql.MarshalString("Query")
-		case "torrents":
+		case "torrentDaemon":
 			field := field
 
-			innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) {
+			innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) {
 				defer func() {
 					if r := recover(); r != nil {
 						ec.Error(ctx, ec.Recover(ctx, r))
 					}
 				}()
-				res = ec._Query_torrents(ctx, field)
-				if res == graphql.Null {
-					atomic.AddUint32(&fs.Invalids, 1)
-				}
+				res = ec._Query_torrentDaemon(ctx, field)
 				return res
 			}
 
@@ -6404,7 +7014,7 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr
 		case "fsEntry":
 			field := field
 
-			innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) {
+			innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) {
 				defer func() {
 					if r := recover(); r != nil {
 						ec.Error(ctx, ec.Recover(ctx, r))
@@ -6811,6 +7421,42 @@ func (ec *executionContext) _Torrent(ctx context.Context, sel ast.SelectionSet,
 			if out.Values[i] == graphql.Null {
 				atomic.AddUint32(&out.Invalids, 1)
 			}
+		case "priority":
+			field := field
+
+			innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) {
+				defer func() {
+					if r := recover(); r != nil {
+						ec.Error(ctx, ec.Recover(ctx, r))
+					}
+				}()
+				res = ec._Torrent_priority(ctx, field, obj)
+				if res == graphql.Null {
+					atomic.AddUint32(&fs.Invalids, 1)
+				}
+				return res
+			}
+
+			if field.Deferrable != nil {
+				dfs, ok := deferred[field.Deferrable.Label]
+				di := 0
+				if ok {
+					dfs.AddField(field)
+					di = len(dfs.Values) - 1
+				} else {
+					dfs = graphql.NewFieldSet([]graphql.CollectedField{field})
+					deferred[field.Deferrable.Label] = dfs
+				}
+				dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler {
+					return innerFunc(ctx, dfs)
+				})
+
+				// don't run the out.Concurrently() call below
+				out.Values[i] = graphql.Null
+				continue
+			}
+
+			out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) })
 		case "files":
 			field := field
 
@@ -6919,11 +7565,218 @@ func (ec *executionContext) _Torrent(ctx context.Context, sel ast.SelectionSet,
 			}
 
 			out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) })
-		case "downloading":
-			out.Values[i] = ec._Torrent_downloading(ctx, field, obj)
-			if out.Values[i] == graphql.Null {
-				atomic.AddUint32(&out.Invalids, 1)
+		default:
+			panic("unknown field " + strconv.Quote(field.Name))
+		}
+	}
+	out.Dispatch(ctx)
+	if out.Invalids > 0 {
+		return graphql.Null
+	}
+
+	atomic.AddInt32(&ec.deferred, int32(len(deferred)))
+
+	for label, dfs := range deferred {
+		ec.processDeferredGroup(graphql.DeferredGroup{
+			Label:    label,
+			Path:     graphql.GetPath(ctx),
+			FieldSet: dfs,
+			Context:  ctx,
+		})
+	}
+
+	return out
+}
+
+var torrentDaemonMutationImplementors = []string{"TorrentDaemonMutation"}
+
+func (ec *executionContext) _TorrentDaemonMutation(ctx context.Context, sel ast.SelectionSet, obj *model.TorrentDaemonMutation) graphql.Marshaler {
+	fields := graphql.CollectFields(ec.OperationContext, sel, torrentDaemonMutationImplementors)
+
+	out := graphql.NewFieldSet(fields)
+	deferred := make(map[string]*graphql.FieldSet)
+	for i, field := range fields {
+		switch field.Name {
+		case "__typename":
+			out.Values[i] = graphql.MarshalString("TorrentDaemonMutation")
+		case "validateTorrent":
+			field := field
+
+			innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) {
+				defer func() {
+					if r := recover(); r != nil {
+						ec.Error(ctx, ec.Recover(ctx, r))
+					}
+				}()
+				res = ec._TorrentDaemonMutation_validateTorrent(ctx, field, obj)
+				if res == graphql.Null {
+					atomic.AddUint32(&fs.Invalids, 1)
+				}
+				return res
 			}
+
+			if field.Deferrable != nil {
+				dfs, ok := deferred[field.Deferrable.Label]
+				di := 0
+				if ok {
+					dfs.AddField(field)
+					di = len(dfs.Values) - 1
+				} else {
+					dfs = graphql.NewFieldSet([]graphql.CollectedField{field})
+					deferred[field.Deferrable.Label] = dfs
+				}
+				dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler {
+					return innerFunc(ctx, dfs)
+				})
+
+				// don't run the out.Concurrently() call below
+				out.Values[i] = graphql.Null
+				continue
+			}
+
+			out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) })
+		case "setTorrentPriority":
+			field := field
+
+			innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) {
+				defer func() {
+					if r := recover(); r != nil {
+						ec.Error(ctx, ec.Recover(ctx, r))
+					}
+				}()
+				res = ec._TorrentDaemonMutation_setTorrentPriority(ctx, field, obj)
+				if res == graphql.Null {
+					atomic.AddUint32(&fs.Invalids, 1)
+				}
+				return res
+			}
+
+			if field.Deferrable != nil {
+				dfs, ok := deferred[field.Deferrable.Label]
+				di := 0
+				if ok {
+					dfs.AddField(field)
+					di = len(dfs.Values) - 1
+				} else {
+					dfs = graphql.NewFieldSet([]graphql.CollectedField{field})
+					deferred[field.Deferrable.Label] = dfs
+				}
+				dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler {
+					return innerFunc(ctx, dfs)
+				})
+
+				// don't run the out.Concurrently() call below
+				out.Values[i] = graphql.Null
+				continue
+			}
+
+			out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) })
+		case "cleanup":
+			field := field
+
+			innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) {
+				defer func() {
+					if r := recover(); r != nil {
+						ec.Error(ctx, ec.Recover(ctx, r))
+					}
+				}()
+				res = ec._TorrentDaemonMutation_cleanup(ctx, field, obj)
+				if res == graphql.Null {
+					atomic.AddUint32(&fs.Invalids, 1)
+				}
+				return res
+			}
+
+			if field.Deferrable != nil {
+				dfs, ok := deferred[field.Deferrable.Label]
+				di := 0
+				if ok {
+					dfs.AddField(field)
+					di = len(dfs.Values) - 1
+				} else {
+					dfs = graphql.NewFieldSet([]graphql.CollectedField{field})
+					deferred[field.Deferrable.Label] = dfs
+				}
+				dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler {
+					return innerFunc(ctx, dfs)
+				})
+
+				// don't run the out.Concurrently() call below
+				out.Values[i] = graphql.Null
+				continue
+			}
+
+			out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) })
+		default:
+			panic("unknown field " + strconv.Quote(field.Name))
+		}
+	}
+	out.Dispatch(ctx)
+	if out.Invalids > 0 {
+		return graphql.Null
+	}
+
+	atomic.AddInt32(&ec.deferred, int32(len(deferred)))
+
+	for label, dfs := range deferred {
+		ec.processDeferredGroup(graphql.DeferredGroup{
+			Label:    label,
+			Path:     graphql.GetPath(ctx),
+			FieldSet: dfs,
+			Context:  ctx,
+		})
+	}
+
+	return out
+}
+
+var torrentDaemonQueryImplementors = []string{"TorrentDaemonQuery"}
+
+func (ec *executionContext) _TorrentDaemonQuery(ctx context.Context, sel ast.SelectionSet, obj *model.TorrentDaemonQuery) graphql.Marshaler {
+	fields := graphql.CollectFields(ec.OperationContext, sel, torrentDaemonQueryImplementors)
+
+	out := graphql.NewFieldSet(fields)
+	deferred := make(map[string]*graphql.FieldSet)
+	for i, field := range fields {
+		switch field.Name {
+		case "__typename":
+			out.Values[i] = graphql.MarshalString("TorrentDaemonQuery")
+		case "torrents":
+			field := field
+
+			innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) {
+				defer func() {
+					if r := recover(); r != nil {
+						ec.Error(ctx, ec.Recover(ctx, r))
+					}
+				}()
+				res = ec._TorrentDaemonQuery_torrents(ctx, field, obj)
+				if res == graphql.Null {
+					atomic.AddUint32(&fs.Invalids, 1)
+				}
+				return res
+			}
+
+			if field.Deferrable != nil {
+				dfs, ok := deferred[field.Deferrable.Label]
+				di := 0
+				if ok {
+					dfs.AddField(field)
+					di = len(dfs.Values) - 1
+				} else {
+					dfs = graphql.NewFieldSet([]graphql.CollectedField{field})
+					deferred[field.Deferrable.Label] = dfs
+				}
+				dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler {
+					return innerFunc(ctx, dfs)
+				})
+
+				// don't run the out.Concurrently() call below
+				out.Values[i] = graphql.Null
+				continue
+			}
+
+			out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) })
 		default:
 			panic("unknown field " + strconv.Quote(field.Name))
 		}
@@ -7574,10 +8427,6 @@ func (ec *executionContext) marshalNBoolean2bool(ctx context.Context, sel ast.Se
 	return res
 }
 
-func (ec *executionContext) marshalNCleanupResponse2gitᚗkmsignᚗruᚋroyalcatᚋtstorᚋsrcᚋdeliveryᚋgraphqlᚋmodelᚐCleanupResponse(ctx context.Context, sel ast.SelectionSet, v model.CleanupResponse) graphql.Marshaler {
-	return ec._CleanupResponse(ctx, sel, &v)
-}
-
 func (ec *executionContext) marshalNCleanupResponse2ᚖgitᚗkmsignᚗruᚋroyalcatᚋtstorᚋsrcᚋdeliveryᚋgraphqlᚋmodelᚐCleanupResponse(ctx context.Context, sel ast.SelectionSet, v *model.CleanupResponse) graphql.Marshaler {
 	if v == nil {
 		if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
@@ -7901,6 +8750,41 @@ func (ec *executionContext) marshalNTorrentPeer2ᚖgitᚗkmsignᚗruᚋroyalcat
 	return ec._TorrentPeer(ctx, sel, v)
 }
 
+func (ec *executionContext) unmarshalNTorrentPriority2githubᚗcomᚋanacrolixᚋtorrentᚋtypesᚐPiecePriority(ctx context.Context, v interface{}) (types.PiecePriority, error) {
+	tmp, err := graphql.UnmarshalString(v)
+	res := unmarshalNTorrentPriority2githubᚗcomᚋanacrolixᚋtorrentᚋtypesᚐPiecePriority[tmp]
+	return res, graphql.ErrorOnPath(ctx, err)
+}
+
+func (ec *executionContext) marshalNTorrentPriority2githubᚗcomᚋanacrolixᚋtorrentᚋtypesᚐPiecePriority(ctx context.Context, sel ast.SelectionSet, v types.PiecePriority) graphql.Marshaler {
+	res := graphql.MarshalString(marshalNTorrentPriority2githubᚗcomᚋanacrolixᚋtorrentᚋtypesᚐPiecePriority[v])
+	if res == graphql.Null {
+		if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
+			ec.Errorf(ctx, "the requested element is null which the schema does not allow")
+		}
+	}
+	return res
+}
+
+var (
+	unmarshalNTorrentPriority2githubᚗcomᚋanacrolixᚋtorrentᚋtypesᚐPiecePriority = map[string]types.PiecePriority{
+		"NONE":      types.PiecePriorityNone,
+		"NORMAL":    types.PiecePriorityNormal,
+		"HIGH":      types.PiecePriorityHigh,
+		"READAHEAD": types.PiecePriorityReadahead,
+		"NEXT":      types.PiecePriorityNext,
+		"NOW":       types.PiecePriorityNow,
+	}
+	marshalNTorrentPriority2githubᚗcomᚋanacrolixᚋtorrentᚋtypesᚐPiecePriority = map[types.PiecePriority]string{
+		types.PiecePriorityNone:      "NONE",
+		types.PiecePriorityNormal:    "NORMAL",
+		types.PiecePriorityHigh:      "HIGH",
+		types.PiecePriorityReadahead: "READAHEAD",
+		types.PiecePriorityNext:      "NEXT",
+		types.PiecePriorityNow:       "NOW",
+	}
+)
+
 func (ec *executionContext) unmarshalNUpload2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚐUpload(ctx context.Context, v interface{}) (graphql.Upload, error) {
 	res, err := graphql.UnmarshalUpload(v)
 	return res, graphql.ErrorOnPath(ctx, err)
@@ -8195,14 +9079,6 @@ func (ec *executionContext) marshalOBoolean2ᚖbool(ctx context.Context, sel ast
 	return res
 }
 
-func (ec *executionContext) unmarshalOBooleanFilter2ᚖgitᚗkmsignᚗruᚋroyalcatᚋtstorᚋsrcᚋdeliveryᚋgraphqlᚋmodelᚐBooleanFilter(ctx context.Context, v interface{}) (*model.BooleanFilter, error) {
-	if v == nil {
-		return nil, nil
-	}
-	res, err := ec.unmarshalInputBooleanFilter(ctx, v)
-	return &res, graphql.ErrorOnPath(ctx, err)
-}
-
 func (ec *executionContext) unmarshalODateTime2ᚖtimeᚐTime(ctx context.Context, v interface{}) (*time.Time, error) {
 	if v == nil {
 		return nil, nil
@@ -8219,13 +9095,6 @@ func (ec *executionContext) marshalODateTime2ᚖtimeᚐTime(ctx context.Context,
 	return res
 }
 
-func (ec *executionContext) marshalODownloadTorrentResponse2ᚖgitᚗkmsignᚗruᚋroyalcatᚋtstorᚋsrcᚋdeliveryᚋgraphqlᚋmodelᚐDownloadTorrentResponse(ctx context.Context, sel ast.SelectionSet, v *model.DownloadTorrentResponse) graphql.Marshaler {
-	if v == nil {
-		return graphql.Null
-	}
-	return ec._DownloadTorrentResponse(ctx, sel, v)
-}
-
 func (ec *executionContext) marshalOFsEntry2gitᚗkmsignᚗruᚋroyalcatᚋtstorᚋsrcᚋdeliveryᚋgraphqlᚋmodelᚐFsEntry(ctx context.Context, sel ast.SelectionSet, v model.FsEntry) graphql.Marshaler {
 	if v == nil {
 		return graphql.Null
@@ -8385,6 +9254,150 @@ func (ec *executionContext) marshalOTask2ᚖgitᚗkmsignᚗruᚋroyalcatᚋtstor
 	return ec._Task(ctx, sel, v)
 }
 
+func (ec *executionContext) marshalOTorrentDaemonMutation2ᚖgitᚗkmsignᚗruᚋroyalcatᚋtstorᚋsrcᚋdeliveryᚋgraphqlᚋmodelᚐTorrentDaemonMutation(ctx context.Context, sel ast.SelectionSet, v *model.TorrentDaemonMutation) graphql.Marshaler {
+	if v == nil {
+		return graphql.Null
+	}
+	return ec._TorrentDaemonMutation(ctx, sel, v)
+}
+
+func (ec *executionContext) marshalOTorrentDaemonQuery2ᚖgitᚗkmsignᚗruᚋroyalcatᚋtstorᚋsrcᚋdeliveryᚋgraphqlᚋmodelᚐTorrentDaemonQuery(ctx context.Context, sel ast.SelectionSet, v *model.TorrentDaemonQuery) graphql.Marshaler {
+	if v == nil {
+		return graphql.Null
+	}
+	return ec._TorrentDaemonQuery(ctx, sel, v)
+}
+
+func (ec *executionContext) unmarshalOTorrentPriority2ᚕgithubᚗcomᚋanacrolixᚋtorrentᚋtypesᚐPiecePriorityᚄ(ctx context.Context, v interface{}) ([]types.PiecePriority, error) {
+	if v == nil {
+		return nil, nil
+	}
+	var vSlice []interface{}
+	if v != nil {
+		vSlice = graphql.CoerceList(v)
+	}
+	var err error
+	res := make([]types.PiecePriority, len(vSlice))
+	for i := range vSlice {
+		ctx := graphql.WithPathContext(ctx, graphql.NewPathWithIndex(i))
+		res[i], err = ec.unmarshalNTorrentPriority2githubᚗcomᚋanacrolixᚋtorrentᚋtypesᚐPiecePriority(ctx, vSlice[i])
+		if err != nil {
+			return nil, err
+		}
+	}
+	return res, nil
+}
+
+func (ec *executionContext) marshalOTorrentPriority2ᚕgithubᚗcomᚋanacrolixᚋtorrentᚋtypesᚐPiecePriorityᚄ(ctx context.Context, sel ast.SelectionSet, v []types.PiecePriority) graphql.Marshaler {
+	if v == nil {
+		return graphql.Null
+	}
+	ret := make(graphql.Array, len(v))
+	var wg sync.WaitGroup
+	isLen1 := len(v) == 1
+	if !isLen1 {
+		wg.Add(len(v))
+	}
+	for i := range v {
+		i := i
+		fc := &graphql.FieldContext{
+			Index:  &i,
+			Result: &v[i],
+		}
+		ctx := graphql.WithFieldContext(ctx, fc)
+		f := func(i int) {
+			defer func() {
+				if r := recover(); r != nil {
+					ec.Error(ctx, ec.Recover(ctx, r))
+					ret = nil
+				}
+			}()
+			if !isLen1 {
+				defer wg.Done()
+			}
+			ret[i] = ec.marshalNTorrentPriority2githubᚗcomᚋanacrolixᚋtorrentᚋtypesᚐPiecePriority(ctx, sel, v[i])
+		}
+		if isLen1 {
+			f(i)
+		} else {
+			go f(i)
+		}
+
+	}
+	wg.Wait()
+
+	for _, e := range ret {
+		if e == graphql.Null {
+			return graphql.Null
+		}
+	}
+
+	return ret
+}
+
+var (
+	unmarshalOTorrentPriority2ᚕgithubᚗcomᚋanacrolixᚋtorrentᚋtypesᚐPiecePriorityᚄ = map[string]types.PiecePriority{
+		"NONE":      types.PiecePriorityNone,
+		"NORMAL":    types.PiecePriorityNormal,
+		"HIGH":      types.PiecePriorityHigh,
+		"READAHEAD": types.PiecePriorityReadahead,
+		"NEXT":      types.PiecePriorityNext,
+		"NOW":       types.PiecePriorityNow,
+	}
+	marshalOTorrentPriority2ᚕgithubᚗcomᚋanacrolixᚋtorrentᚋtypesᚐPiecePriorityᚄ = map[types.PiecePriority]string{
+		types.PiecePriorityNone:      "NONE",
+		types.PiecePriorityNormal:    "NORMAL",
+		types.PiecePriorityHigh:      "HIGH",
+		types.PiecePriorityReadahead: "READAHEAD",
+		types.PiecePriorityNext:      "NEXT",
+		types.PiecePriorityNow:       "NOW",
+	}
+)
+
+func (ec *executionContext) unmarshalOTorrentPriority2ᚖgithubᚗcomᚋanacrolixᚋtorrentᚋtypesᚐPiecePriority(ctx context.Context, v interface{}) (*types.PiecePriority, error) {
+	if v == nil {
+		return nil, nil
+	}
+	tmp, err := graphql.UnmarshalString(v)
+	res := unmarshalOTorrentPriority2ᚖgithubᚗcomᚋanacrolixᚋtorrentᚋtypesᚐPiecePriority[tmp]
+	return &res, graphql.ErrorOnPath(ctx, err)
+}
+
+func (ec *executionContext) marshalOTorrentPriority2ᚖgithubᚗcomᚋanacrolixᚋtorrentᚋtypesᚐPiecePriority(ctx context.Context, sel ast.SelectionSet, v *types.PiecePriority) graphql.Marshaler {
+	if v == nil {
+		return graphql.Null
+	}
+	res := graphql.MarshalString(marshalOTorrentPriority2ᚖgithubᚗcomᚋanacrolixᚋtorrentᚋtypesᚐPiecePriority[*v])
+	return res
+}
+
+var (
+	unmarshalOTorrentPriority2ᚖgithubᚗcomᚋanacrolixᚋtorrentᚋtypesᚐPiecePriority = map[string]types.PiecePriority{
+		"NONE":      types.PiecePriorityNone,
+		"NORMAL":    types.PiecePriorityNormal,
+		"HIGH":      types.PiecePriorityHigh,
+		"READAHEAD": types.PiecePriorityReadahead,
+		"NEXT":      types.PiecePriorityNext,
+		"NOW":       types.PiecePriorityNow,
+	}
+	marshalOTorrentPriority2ᚖgithubᚗcomᚋanacrolixᚋtorrentᚋtypesᚐPiecePriority = map[types.PiecePriority]string{
+		types.PiecePriorityNone:      "NONE",
+		types.PiecePriorityNormal:    "NORMAL",
+		types.PiecePriorityHigh:      "HIGH",
+		types.PiecePriorityReadahead: "READAHEAD",
+		types.PiecePriorityNext:      "NEXT",
+		types.PiecePriorityNow:       "NOW",
+	}
+)
+
+func (ec *executionContext) unmarshalOTorrentPriorityFilter2ᚖgitᚗkmsignᚗruᚋroyalcatᚋtstorᚋsrcᚋdeliveryᚋgraphqlᚋmodelᚐTorrentPriorityFilter(ctx context.Context, v interface{}) (*model.TorrentPriorityFilter, error) {
+	if v == nil {
+		return nil, nil
+	}
+	res, err := ec.unmarshalInputTorrentPriorityFilter(ctx, v)
+	return &res, graphql.ErrorOnPath(ctx, err)
+}
+
 func (ec *executionContext) marshalOTorrentProgress2ᚖgitᚗkmsignᚗruᚋroyalcatᚋtstorᚋsrcᚋdeliveryᚋgraphqlᚋmodelᚐTorrentProgress(ctx context.Context, sel ast.SelectionSet, v *model.TorrentProgress) graphql.Marshaler {
 	if v == nil {
 		return graphql.Null
diff --git a/src/delivery/graphql/model/filter.go b/src/delivery/graphql/model/filter.go
index 834d2ef..3df1931 100644
--- a/src/delivery/graphql/model/filter.go
+++ b/src/delivery/graphql/model/filter.go
@@ -3,6 +3,8 @@ package model
 import (
 	"slices"
 	"strings"
+
+	"github.com/anacrolix/torrent/types"
 )
 
 type Filter[T any] interface {
@@ -52,3 +54,23 @@ func (f *BooleanFilter) Include(v bool) bool {
 
 	return true
 }
+
+func (f *TorrentPriorityFilter) Include(v types.PiecePriority) bool {
+	if f == nil {
+		return true
+	} else if f.Eq != nil {
+		return v == *f.Eq
+	} else if f.Gt != nil {
+		return v > *f.Gt
+	} else if f.Gte != nil {
+		return v >= *f.Gte
+	} else if f.Lt != nil {
+		return v < *f.Lt
+	} else if f.Lte != nil {
+		return v <= *f.Lte
+	} else if f.In != nil {
+		return slices.Contains(f.In, v)
+	}
+
+	return true
+}
diff --git a/src/delivery/graphql/model/mappers.go b/src/delivery/graphql/model/mappers.go
index 93d2651..2ebfba5 100644
--- a/src/delivery/graphql/model/mappers.go
+++ b/src/delivery/graphql/model/mappers.go
@@ -29,24 +29,11 @@ func MapPeerSource(source atorrent.PeerSource) string {
 }
 
 func MapTorrent(ctx context.Context, t *torrent.Controller) (*Torrent, error) {
-	downloading := false
-	files, err := t.Files(ctx)
-	if err != nil {
-		return nil, err
-	}
-	for _, file := range files {
-		if file.Priority() > atorrent.PiecePriorityNone && file.BytesCompleted() < file.Length() {
-			downloading = true
-			break
-		}
-	}
-
 	return &Torrent{
 		Infohash:       t.InfoHash(),
 		Name:           t.Name(),
 		BytesCompleted: t.BytesCompleted(),
 		BytesMissing:   t.BytesMissing(),
 		T:              t,
-		Downloading:    downloading,
 	}, nil
 }
diff --git a/src/delivery/graphql/model/models_gen.go b/src/delivery/graphql/model/models_gen.go
index 7a2aeb2..3efd284 100644
--- a/src/delivery/graphql/model/models_gen.go
+++ b/src/delivery/graphql/model/models_gen.go
@@ -8,6 +8,7 @@ import (
 	"git.kmsign.ru/royalcat/tstor/src/sources/torrent"
 	"git.kmsign.ru/royalcat/tstor/src/vfs"
 	torrent1 "github.com/anacrolix/torrent"
+	"github.com/anacrolix/torrent/types"
 )
 
 type Dir interface {
@@ -176,13 +177,23 @@ type Torrent struct {
 	BytesCompleted  int64               `json:"bytesCompleted"`
 	TorrentFilePath string              `json:"torrentFilePath"`
 	BytesMissing    int64               `json:"bytesMissing"`
+	Priority        types.PiecePriority `json:"priority"`
 	Files           []*TorrentFile      `json:"files"`
 	ExcludedFiles   []*TorrentFile      `json:"excludedFiles"`
 	Peers           []*TorrentPeer      `json:"peers"`
-	Downloading     bool                `json:"downloading"`
 	T               *torrent.Controller `json:"-"`
 }
 
+type TorrentDaemonMutation struct {
+	ValidateTorrent    bool             `json:"validateTorrent"`
+	SetTorrentPriority bool             `json:"setTorrentPriority"`
+	Cleanup            *CleanupResponse `json:"cleanup"`
+}
+
+type TorrentDaemonQuery struct {
+	Torrents []*Torrent `json:"torrents"`
+}
+
 type TorrentFs struct {
 	Name    string             `json:"name"`
 	Torrent *Torrent           `json:"torrent"`
@@ -238,6 +249,15 @@ type TorrentPeer struct {
 	F            *torrent1.PeerConn `json:"-"`
 }
 
+type TorrentPriorityFilter struct {
+	Eq  *types.PiecePriority  `json:"eq,omitempty"`
+	Gt  *types.PiecePriority  `json:"gt,omitempty"`
+	Lt  *types.PiecePriority  `json:"lt,omitempty"`
+	Gte *types.PiecePriority  `json:"gte,omitempty"`
+	Lte *types.PiecePriority  `json:"lte,omitempty"`
+	In  []types.PiecePriority `json:"in,omitempty"`
+}
+
 type TorrentProgress struct {
 	Torrent *Torrent `json:"torrent"`
 	Current int64    `json:"current"`
@@ -249,10 +269,10 @@ func (this TorrentProgress) GetCurrent() int64 { return this.Current }
 func (this TorrentProgress) GetTotal() int64   { return this.Total }
 
 type TorrentsFilter struct {
-	Infohash       *StringFilter  `json:"infohash,omitempty"`
-	Name           *StringFilter  `json:"name,omitempty"`
-	BytesCompleted *IntFilter     `json:"bytesCompleted,omitempty"`
-	BytesMissing   *IntFilter     `json:"bytesMissing,omitempty"`
-	PeersCount     *IntFilter     `json:"peersCount,omitempty"`
-	Downloading    *BooleanFilter `json:"downloading,omitempty"`
+	Infohash       *StringFilter          `json:"infohash,omitempty"`
+	Name           *StringFilter          `json:"name,omitempty"`
+	BytesCompleted *IntFilter             `json:"bytesCompleted,omitempty"`
+	BytesMissing   *IntFilter             `json:"bytesMissing,omitempty"`
+	PeersCount     *IntFilter             `json:"peersCount,omitempty"`
+	Priority       *TorrentPriorityFilter `json:"priority,omitempty"`
 }
diff --git a/src/delivery/graphql/resolver/fs.resolvers.go b/src/delivery/graphql/resolver/fs.resolvers.go
index 3e180b0..4c79912 100644
--- a/src/delivery/graphql/resolver/fs.resolvers.go
+++ b/src/delivery/graphql/resolver/fs.resolvers.go
@@ -2,7 +2,7 @@ package resolver
 
 // This file will be automatically regenerated based on the schema, any resolver implementations
 // will be copied through when generating and any unknown code will be moved to the end.
-// Code generated by github.com/99designs/gqlgen version v0.17.45
+// Code generated by github.com/99designs/gqlgen version v0.17.49
 
 import (
 	"context"
diff --git a/src/delivery/graphql/resolver/mutation.resolvers.go b/src/delivery/graphql/resolver/mutation.resolvers.go
index f6e3af2..dae361d 100644
--- a/src/delivery/graphql/resolver/mutation.resolvers.go
+++ b/src/delivery/graphql/resolver/mutation.resolvers.go
@@ -2,7 +2,7 @@ package resolver
 
 // This file will be automatically regenerated based on the schema, any resolver implementations
 // will be copied through when generating and any unknown code will be moved to the end.
-// Code generated by github.com/99designs/gqlgen version v0.17.45
+// Code generated by github.com/99designs/gqlgen version v0.17.49
 
 import (
 	"context"
@@ -11,84 +11,14 @@ import (
 	"os"
 	pathlib "path"
 
-	"git.kmsign.ru/royalcat/tstor/pkg/uuid"
 	graph "git.kmsign.ru/royalcat/tstor/src/delivery/graphql"
 	"git.kmsign.ru/royalcat/tstor/src/delivery/graphql/model"
-	"git.kmsign.ru/royalcat/tstor/src/sources/torrent"
 	"github.com/99designs/gqlgen/graphql"
-	aih "github.com/anacrolix/torrent/types/infohash"
 )
 
-// ValidateTorrents is the resolver for the validateTorrents field.
-func (r *mutationResolver) ValidateTorrents(ctx context.Context, filter model.TorrentFilter) (bool, error) {
-	if filter.Infohash != nil {
-		t, err := r.Resolver.Service.GetTorrent(*filter.Infohash)
-		if err != nil {
-			return false, err
-		}
-		if t == nil {
-			return false, nil
-		}
-
-		t.ValidateTorrent(ctx)
-		return true, nil
-	}
-
-	if filter.Everything != nil && *filter.Everything {
-		torrents, err := r.Resolver.Service.ListTorrents(ctx)
-		if err != nil {
-			return false, err
-		}
-		for _, v := range torrents {
-			if err := v.ValidateTorrent(ctx); err != nil {
-				return false, err
-			}
-		}
-		return true, nil
-	}
-
-	return false, nil
-}
-
-// CleanupTorrents is the resolver for the cleanupTorrents field.
-func (r *mutationResolver) CleanupTorrents(ctx context.Context, files *bool, dryRun bool) (*model.CleanupResponse, error) {
-	torrents, err := r.Service.ListTorrents(ctx)
-	if err != nil {
-		return nil, err
-	}
-
-	if files != nil && *files {
-		r, err := r.Service.Storage.CleanupFiles(ctx, torrents, dryRun)
-		return &model.CleanupResponse{
-			Count: int64(len(r)),
-			List:  r,
-		}, err
-	} else {
-		r, err := r.Service.Storage.CleanupDirs(ctx, torrents, dryRun)
-		return &model.CleanupResponse{
-			Count: int64(len(r)),
-			List:  r,
-		}, err
-	}
-}
-
-// DownloadTorrent is the resolver for the downloadTorrent field.
-func (r *mutationResolver) DownloadTorrent(ctx context.Context, infohash string, file *string) (*model.DownloadTorrentResponse, error) {
-	f := ""
-	if file != nil {
-		f = *file
-	}
-
-	err := r.Service.Download(ctx, &torrent.DownloadTask{
-		ID:       uuid.New(),
-		InfoHash: aih.FromHexString(infohash),
-		File:     f,
-	})
-	if err != nil {
-		return nil, err
-	}
-
-	return &model.DownloadTorrentResponse{}, nil
+// TorrentDaemon is the resolver for the torrentDaemon field.
+func (r *mutationResolver) TorrentDaemon(ctx context.Context) (*model.TorrentDaemonMutation, error) {
+	return &model.TorrentDaemonMutation{}, nil
 }
 
 // UploadFile is the resolver for the uploadFile field.
diff --git a/src/delivery/graphql/resolver/query.resolvers.go b/src/delivery/graphql/resolver/query.resolvers.go
index 8d8d01f..686969e 100644
--- a/src/delivery/graphql/resolver/query.resolvers.go
+++ b/src/delivery/graphql/resolver/query.resolvers.go
@@ -2,89 +2,18 @@ package resolver
 
 // This file will be automatically regenerated based on the schema, any resolver implementations
 // will be copied through when generating and any unknown code will be moved to the end.
-// Code generated by github.com/99designs/gqlgen version v0.17.45
+// Code generated by github.com/99designs/gqlgen version v0.17.49
 
 import (
 	"context"
-	"slices"
-	"strings"
 
 	graph "git.kmsign.ru/royalcat/tstor/src/delivery/graphql"
 	"git.kmsign.ru/royalcat/tstor/src/delivery/graphql/model"
-	"git.kmsign.ru/royalcat/tstor/src/sources/torrent"
 )
 
-// Torrents is the resolver for the torrents field.
-func (r *queryResolver) Torrents(ctx context.Context, filter *model.TorrentsFilter) ([]*model.Torrent, error) {
-	torrents, err := r.Service.ListTorrents(ctx)
-	if err != nil {
-		return nil, err
-	}
-
-	filterFuncs := []func(torrent *model.Torrent) bool{}
-
-	if filter != nil {
-		if filter.BytesCompleted != nil {
-			filterFuncs = append(filterFuncs, func(torrent *model.Torrent) bool {
-				return filter.BytesCompleted.Include(torrent.BytesCompleted)
-			})
-		}
-		if filter.BytesMissing != nil {
-			filterFuncs = append(filterFuncs, func(torrent *model.Torrent) bool {
-				return filter.BytesMissing.Include(torrent.BytesMissing)
-			})
-		}
-		if filter.PeersCount != nil {
-			filterFuncs = append(filterFuncs, func(torrent *model.Torrent) bool {
-				return filter.PeersCount.Include(
-					int64(len(torrent.T.Torrent().PeerConns())),
-				)
-			})
-		}
-		if filter.Infohash != nil {
-			filterFuncs = append(filterFuncs, func(torrent *model.Torrent) bool {
-				return filter.Infohash.Include(
-					torrent.Infohash,
-				)
-			})
-		}
-
-		if filter.Downloading != nil {
-			filterFuncs = append(filterFuncs, func(torrent *model.Torrent) bool {
-				return filter.Downloading.Include(
-					torrent.Downloading,
-				)
-			})
-		}
-	}
-
-	filterFunc := func(torrent *model.Torrent) bool {
-		for _, f := range filterFuncs {
-			if !f(torrent) {
-				return false
-			}
-		}
-		return true
-	}
-
-	tr := []*model.Torrent{}
-	for _, t := range torrents {
-		d, err := model.MapTorrent(ctx, t)
-		if err != nil {
-			return nil, err
-		}
-
-		if !filterFunc(d) {
-			continue
-		}
-		tr = append(tr, d)
-	}
-
-	slices.SortStableFunc(torrents, func(t1, t2 *torrent.Controller) int {
-		return strings.Compare(t1.Name(), t2.Name())
-	})
-
-	return tr, nil
+// TorrentDaemon is the resolver for the torrentDaemon field.
+func (r *queryResolver) TorrentDaemon(ctx context.Context) (*model.TorrentDaemonQuery, error) {
+	return &model.TorrentDaemonQuery{}, nil
 }
 
 // FsEntry is the resolver for the fsEntry field.
diff --git a/src/delivery/graphql/resolver/subscription.resolvers.go b/src/delivery/graphql/resolver/subscription.resolvers.go
index f5eb19e..af5a31d 100644
--- a/src/delivery/graphql/resolver/subscription.resolvers.go
+++ b/src/delivery/graphql/resolver/subscription.resolvers.go
@@ -2,7 +2,7 @@ package resolver
 
 // This file will be automatically regenerated based on the schema, any resolver implementations
 // will be copied through when generating and any unknown code will be moved to the end.
-// Code generated by github.com/99designs/gqlgen version v0.17.45
+// Code generated by github.com/99designs/gqlgen version v0.17.49
 
 import (
 	"context"
diff --git a/src/delivery/graphql/resolver/torrent_mutation.resolvers.go b/src/delivery/graphql/resolver/torrent_mutation.resolvers.go
new file mode 100644
index 0000000..0f4bd8f
--- /dev/null
+++ b/src/delivery/graphql/resolver/torrent_mutation.resolvers.go
@@ -0,0 +1,90 @@
+package resolver
+
+// This file will be automatically regenerated based on the schema, any resolver implementations
+// will be copied through when generating and any unknown code will be moved to the end.
+// Code generated by github.com/99designs/gqlgen version v0.17.49
+
+import (
+	"context"
+
+	graph "git.kmsign.ru/royalcat/tstor/src/delivery/graphql"
+	"git.kmsign.ru/royalcat/tstor/src/delivery/graphql/model"
+	"github.com/anacrolix/torrent/types"
+)
+
+// ValidateTorrent is the resolver for the validateTorrent field.
+func (r *torrentDaemonMutationResolver) ValidateTorrent(ctx context.Context, obj *model.TorrentDaemonMutation, filter model.TorrentFilter) (bool, error) {
+	if filter.Infohash != nil {
+		t, err := r.Resolver.Service.GetTorrent(*filter.Infohash)
+		if err != nil {
+			return false, err
+		}
+		if t == nil {
+			return false, nil
+		}
+
+		t.ValidateTorrent(ctx)
+		return true, nil
+	}
+
+	if filter.Everything != nil && *filter.Everything {
+		torrents, err := r.Resolver.Service.ListTorrents(ctx)
+		if err != nil {
+			return false, err
+		}
+		for _, v := range torrents {
+			if err := v.ValidateTorrent(ctx); err != nil {
+				return false, err
+			}
+		}
+		return true, nil
+	}
+
+	return false, nil
+}
+
+// SetTorrentPriority is the resolver for the setTorrentPriority field.
+func (r *torrentDaemonMutationResolver) SetTorrentPriority(ctx context.Context, obj *model.TorrentDaemonMutation, infohash string, file *string, priority types.PiecePriority) (bool, error) {
+	t, err := r.Resolver.Service.GetTorrent(infohash)
+	if err != nil {
+		return false, err
+	}
+	if t == nil {
+		return false, nil
+	}
+
+	err = t.SetPriority(ctx, file, priority)
+	if err != nil {
+		return false, err
+	}
+	return true, nil
+}
+
+// Cleanup is the resolver for the cleanup field.
+func (r *torrentDaemonMutationResolver) Cleanup(ctx context.Context, obj *model.TorrentDaemonMutation, files *bool, dryRun bool) (*model.CleanupResponse, error) {
+	torrents, err := r.Service.ListTorrents(ctx)
+	if err != nil {
+		return nil, err
+	}
+
+	if files != nil && *files {
+		r, err := r.Service.Storage.CleanupFiles(ctx, torrents, dryRun)
+		return &model.CleanupResponse{
+			Count: int64(len(r)),
+			List:  r,
+		}, err
+	} else {
+		r, err := r.Service.Storage.CleanupDirs(ctx, torrents, dryRun)
+		return &model.CleanupResponse{
+			Count: int64(len(r)),
+			List:  r,
+		}, err
+	}
+}
+
+// TorrentDaemonMutation returns graph.TorrentDaemonMutationResolver implementation.
+func (r *Resolver) TorrentDaemonMutation() graph.TorrentDaemonMutationResolver {
+	return &torrentDaemonMutationResolver{r}
+}
+
+type torrentDaemonMutationResolver struct{ *Resolver }
diff --git a/src/delivery/graphql/resolver/torrent_query.resolvers.go b/src/delivery/graphql/resolver/torrent_query.resolvers.go
new file mode 100644
index 0000000..3661a7f
--- /dev/null
+++ b/src/delivery/graphql/resolver/torrent_query.resolvers.go
@@ -0,0 +1,94 @@
+package resolver
+
+// This file will be automatically regenerated based on the schema, any resolver implementations
+// will be copied through when generating and any unknown code will be moved to the end.
+// Code generated by github.com/99designs/gqlgen version v0.17.49
+
+import (
+	"context"
+	"slices"
+	"strings"
+
+	graph "git.kmsign.ru/royalcat/tstor/src/delivery/graphql"
+	"git.kmsign.ru/royalcat/tstor/src/delivery/graphql/model"
+	"git.kmsign.ru/royalcat/tstor/src/sources/torrent"
+)
+
+// Torrents is the resolver for the torrents field.
+func (r *torrentDaemonQueryResolver) Torrents(ctx context.Context, obj *model.TorrentDaemonQuery, filter *model.TorrentsFilter) ([]*model.Torrent, error) {
+	torrents, err := r.Service.ListTorrents(ctx)
+	if err != nil {
+		return nil, err
+	}
+
+	filterFuncs := []func(torrent *model.Torrent) bool{}
+
+	if filter != nil {
+		if filter.BytesCompleted != nil {
+			filterFuncs = append(filterFuncs, func(torrent *model.Torrent) bool {
+				return filter.BytesCompleted.Include(torrent.BytesCompleted)
+			})
+		}
+		if filter.BytesMissing != nil {
+			filterFuncs = append(filterFuncs, func(torrent *model.Torrent) bool {
+				return filter.BytesMissing.Include(torrent.BytesMissing)
+			})
+		}
+		if filter.PeersCount != nil {
+			filterFuncs = append(filterFuncs, func(torrent *model.Torrent) bool {
+				return filter.PeersCount.Include(
+					int64(len(torrent.T.Torrent().PeerConns())),
+				)
+			})
+		}
+		if filter.Infohash != nil {
+			filterFuncs = append(filterFuncs, func(torrent *model.Torrent) bool {
+				return filter.Infohash.Include(
+					torrent.Infohash,
+				)
+			})
+		}
+		if filter.Priority != nil {
+			filterFuncs = append(filterFuncs, func(torrent *model.Torrent) bool {
+				return filter.Priority.Include(
+					torrent.Priority,
+				)
+			})
+		}
+	}
+
+	filterFunc := func(torrent *model.Torrent) bool {
+		for _, f := range filterFuncs {
+			if !f(torrent) {
+				return false
+			}
+		}
+		return true
+	}
+
+	tr := []*model.Torrent{}
+	for _, t := range torrents {
+		d, err := model.MapTorrent(ctx, t)
+		if err != nil {
+			return nil, err
+		}
+
+		if !filterFunc(d) {
+			continue
+		}
+		tr = append(tr, d)
+	}
+
+	slices.SortStableFunc(torrents, func(t1, t2 *torrent.Controller) int {
+		return strings.Compare(t1.Name(), t2.Name())
+	})
+
+	return tr, nil
+}
+
+// TorrentDaemonQuery returns graph.TorrentDaemonQueryResolver implementation.
+func (r *Resolver) TorrentDaemonQuery() graph.TorrentDaemonQueryResolver {
+	return &torrentDaemonQueryResolver{r}
+}
+
+type torrentDaemonQueryResolver struct{ *Resolver }
diff --git a/src/delivery/graphql/resolver/torrent.resolvers.go b/src/delivery/graphql/resolver/torrent_types.resolvers.go
similarity index 90%
rename from src/delivery/graphql/resolver/torrent.resolvers.go
rename to src/delivery/graphql/resolver/torrent_types.resolvers.go
index dab9b3b..90f0dff 100644
--- a/src/delivery/graphql/resolver/torrent.resolvers.go
+++ b/src/delivery/graphql/resolver/torrent_types.resolvers.go
@@ -2,13 +2,14 @@ package resolver
 
 // This file will be automatically regenerated based on the schema, any resolver implementations
 // will be copied through when generating and any unknown code will be moved to the end.
-// Code generated by github.com/99designs/gqlgen version v0.17.45
+// Code generated by github.com/99designs/gqlgen version v0.17.49
 
 import (
 	"context"
 
 	graph "git.kmsign.ru/royalcat/tstor/src/delivery/graphql"
 	"git.kmsign.ru/royalcat/tstor/src/delivery/graphql/model"
+	"github.com/anacrolix/torrent/types"
 )
 
 // Name is the resolver for the name field.
@@ -16,6 +17,11 @@ func (r *torrentResolver) Name(ctx context.Context, obj *model.Torrent) (string,
 	return obj.T.Name(), nil
 }
 
+// Priority is the resolver for the priority field.
+func (r *torrentResolver) Priority(ctx context.Context, obj *model.Torrent) (types.PiecePriority, error) {
+	return obj.T.Priority(ctx, nil)
+}
+
 // Files is the resolver for the files field.
 func (r *torrentResolver) Files(ctx context.Context, obj *model.Torrent) ([]*model.TorrentFile, error) {
 	out := []*model.TorrentFile{}
diff --git a/src/delivery/router.go b/src/delivery/router.go
index d6c108d..cfb526b 100644
--- a/src/delivery/router.go
+++ b/src/delivery/router.go
@@ -18,13 +18,19 @@ import (
 	"github.com/ravilushqa/otelgqlgen"
 )
 
+func noopDirective(ctx context.Context, obj interface{}, next graphql.Resolver) (res interface{}, err error) {
+	return next(ctx)
+}
+
 func GraphQLHandler(service *torrent.Daemon, vfs vfs.Filesystem) http.Handler {
 	graphqlHandler := handler.NewDefaultServer(
 		graph.NewExecutableSchema(
 			graph.Config{
 				Resolvers: &resolver.Resolver{Service: service, VFS: vfs},
 				Directives: graph.DirectiveRoot{
-					OneOf: graph.OneOf,
+					OneOf:    graph.OneOf,
+					Resolver: noopDirective,
+					Stream:   noopDirective,
 				},
 			},
 		),
diff --git a/src/log/badger.go b/src/log/badger.go
index ca57c37..52f59c0 100644
--- a/src/log/badger.go
+++ b/src/log/badger.go
@@ -1,8 +1,8 @@
 package log
 
 import (
+	"context"
 	"fmt"
-	"log/slog"
 	"strings"
 
 	"git.kmsign.ru/royalcat/tstor/pkg/rlog"
@@ -11,14 +11,14 @@ import (
 
 func BadgerLogger(name ...string) badger.Logger {
 	return &badgerLogger{
-		L: rlog.Component(append(name, "badger")...).Slog(),
+		L: rlog.Component(append([]string{"badger"}, name...)...).Nested(2),
 	}
 }
 
 var _ badger.Logger = (*badgerLogger)(nil)
 
 type badgerLogger struct {
-	L *slog.Logger
+	L *rlog.Logger
 }
 
 func fmtBadgerLog(m string, f ...any) string {
@@ -26,17 +26,21 @@ func fmtBadgerLog(m string, f ...any) string {
 }
 
 func (l *badgerLogger) Errorf(m string, f ...interface{}) {
-	l.L.Error(fmtBadgerLog(m, f...))
+	ctx := context.Background()
+	l.L.Error(ctx, fmtBadgerLog(m, f...))
 }
 
 func (l *badgerLogger) Warningf(m string, f ...interface{}) {
-	l.L.Warn(fmtBadgerLog(m, f...))
+	ctx := context.Background()
+	l.L.Warn(ctx, fmtBadgerLog(m, f...))
 }
 
 func (l *badgerLogger) Infof(m string, f ...interface{}) {
-	l.L.Info(fmtBadgerLog(m, f...))
+	ctx := context.Background()
+	l.L.Info(ctx, fmtBadgerLog(m, f...))
 }
 
 func (l *badgerLogger) Debugf(m string, f ...interface{}) {
-	l.L.Debug(fmtBadgerLog(m, f...))
+	ctx := context.Background()
+	l.L.Debug(ctx, fmtBadgerLog(m, f...))
 }
diff --git a/src/sources/torrent/controller.go b/src/sources/torrent/controller.go
index b90c32f..0bf1b13 100644
--- a/src/sources/torrent/controller.go
+++ b/src/sources/torrent/controller.go
@@ -111,6 +111,21 @@ func (s *Controller) Files(ctx context.Context) ([]*torrent.File, error) {
 	return files, nil
 }
 
+func (s *Controller) GetFile(ctx context.Context, file string) (*torrent.File, error) {
+	files, err := s.Files(ctx)
+	if err != nil {
+		return nil, err
+	}
+
+	for _, v := range files {
+		if v.Path() == file {
+			return v, nil
+		}
+	}
+
+	return nil, nil
+}
+
 func Map[T, U any](ts []T, f func(T) U) []U {
 	us := make([]U, len(ts))
 	for i := range ts {
@@ -166,18 +181,79 @@ func (s *Controller) ValidateTorrent(ctx context.Context) error {
 	return nil
 }
 
-func (c *Controller) SetFilePriority(ctx context.Context, file *torrent.File, priority types.PiecePriority) error {
-	log := c.log.With(slog.String("file", file.Path()), slog.Int("priority", int(priority)))
-	log.Info(ctx, "set pritority for file")
+func (c *Controller) SetPriority(ctx context.Context, filePath *string, priority types.PiecePriority) error {
+	log := c.log.With(slog.Int("priority", int(priority)))
 
+	if filePath != nil {
+		file, err := c.GetFile(ctx, *filePath)
+		if err != nil {
+			return err
+		}
+		if file == nil {
+			log.Error(ctx, "file not found")
+			return nil
+		}
+
+		return c.setFilePriority(ctx, file, priority)
+	}
+
+	for _, f := range c.t.Files() {
+		err := c.setFilePriority(ctx, f, priority)
+		if err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
+const defaultPriority = types.PiecePriorityNone
+
+func (c *Controller) Priority(ctx context.Context, filePath *string) (types.PiecePriority, error) {
+	if filePath == nil {
+		prio := defaultPriority
+		err := c.fileProperties.Range(ctx, func(filePath string, v FileProperties) error {
+			if filePath == "" {
+				return nil
+			}
+
+			if v.Priority > prio {
+				prio = v.Priority
+			}
+			return nil
+		})
+		if err == kv.ErrKeyNotFound {
+			err = nil
+		}
+
+		return prio, err
+	}
+
+	props, err := c.fileProperties.Get(ctx, *filePath)
+	if err != nil {
+		if err == kv.ErrKeyNotFound {
+			return defaultPriority, nil
+		}
+		return 0, err
+	}
+
+	return props.Priority, nil
+}
+func (c *Controller) setFilePriority(ctx context.Context, file *torrent.File, priority types.PiecePriority) error {
 	err := c.fileProperties.Edit(ctx, file.Path(), func(ctx context.Context, v FileProperties) (FileProperties, error) {
 		v.Priority = priority
 		return v, nil
 	})
 	if err != nil {
+		if err == kv.ErrKeyNotFound {
+			err := c.fileProperties.Set(ctx, file.Path(), FileProperties{Priority: priority})
+			if err != nil {
+				return err
+			}
+		}
+
 		return err
 	}
-
 	file.SetPriority(priority)
 	return nil
 }
@@ -204,7 +280,6 @@ func (c *Controller) initializeTorrentPriories(ctx context.Context) error {
 		}
 
 		file.SetPriority(props.Priority)
-
 	}
 
 	log.Info(ctx, "torrent initialization complete", slog.String("infohash", c.InfoHash()), slog.String("torrent_name", c.Name()))
diff --git a/src/sources/torrent/piece_completion.go b/src/sources/torrent/piece_completion.go
index 55709ab..01a3d4d 100644
--- a/src/sources/torrent/piece_completion.go
+++ b/src/sources/torrent/piece_completion.go
@@ -43,21 +43,26 @@ func newPieceCompletion(dir string) (storage.PieceCompletion, error) {
 	return &badgerPieceCompletion{db}, nil
 }
 
+const delimeter rune = 0x1F
+
 func pkToBytes(pk metainfo.PieceKey) []byte {
-	key := make([]byte, len(pk.InfoHash.Bytes()))
-	copy(key, pk.InfoHash.Bytes())
-	binary.BigEndian.AppendUint32(key, uint32(pk.Index))
+	key := make([]byte, 0, len(pk.InfoHash.Bytes())+1+4)
+	key = append(key, pk.InfoHash.Bytes()...)
+	key = append(key, byte(delimeter))
+	key = binary.BigEndian.AppendUint32(key, uint32(pk.Index))
 	return key
 }
 
 func (k *badgerPieceCompletion) Get(pk metainfo.PieceKey) (storage.Completion, error) {
 	completion := storage.Completion{
-		Ok: true,
+		Complete: false,
+		Ok:       false,
 	}
 	err := k.db.View(func(tx *badger.Txn) error {
 		item, err := tx.Get(pkToBytes(pk))
 		if err != nil {
 			if err == badger.ErrKeyNotFound {
+				completion.Complete = false
 				completion.Ok = false
 				return nil
 			}
@@ -71,11 +76,12 @@ func (k *badgerPieceCompletion) Get(pk metainfo.PieceKey) (storage.Completion, e
 		}
 		compl := PieceCompletionState(valCopy[0])
 
-		completion.Ok = true
 		switch compl {
 		case PieceComplete:
+			completion.Ok = true
 			completion.Complete = true
 		case PieceNotComplete:
+			completion.Ok = true
 			completion.Complete = false
 		}
 
diff --git a/src/sources/torrent/setup.go b/src/sources/torrent/setup.go
index 667176a..4e5d057 100644
--- a/src/sources/torrent/setup.go
+++ b/src/sources/torrent/setup.go
@@ -14,6 +14,12 @@ func setupStorage(cfg config.TorrentClient) (*fileStorage, storage.PieceCompleti
 	if err := os.MkdirAll(pcp, 0744); err != nil {
 		return nil, nil, fmt.Errorf("error creating piece completion folder: %w", err)
 	}
+
+	// pc, err := storage.NewBoltPieceCompletion(pcp)
+	// if err != nil {
+	// 	return nil, nil, err
+	// }
+
 	pc, err := newPieceCompletion(pcp)
 	if err != nil {
 		return nil, nil, fmt.Errorf("error creating servers piece completion: %w", err)
diff --git a/src/sources/torrent/storage_open.go b/src/sources/torrent/storage_open.go
index 3941696..84b3055 100644
--- a/src/sources/torrent/storage_open.go
+++ b/src/sources/torrent/storage_open.go
@@ -4,7 +4,6 @@ import (
 	"context"
 	"errors"
 	"fmt"
-	"io/fs"
 	"log/slog"
 	"os"
 	"path/filepath"
@@ -22,34 +21,38 @@ import (
 // OpenTorrent implements storage.ClientImplCloser.
 func (me *fileStorage) OpenTorrent(info *metainfo.Info, infoHash infohash.T) (storage.TorrentImpl, error) {
 	ctx := context.Background()
-	log := me.log
+	log := me.log.With(slog.String("infohash", infoHash.HexString()))
 
-	dir := torrentDir(me.baseDir, infoHash)
-	legacyDir := filepath.Join(me.baseDir, info.Name)
+	// dir := torrentDir(me.baseDir, infoHash)
+	// legacyDir := filepath.Join(me.baseDir, info.Name)
 
-	log = log.With(slog.String("legacy_dir", legacyDir), slog.String("dir", dir))
-	if _, err := os.Stat(legacyDir); err == nil {
-		log.Warn(ctx, "legacy torrent dir found, renaming", slog.String("dir", dir))
-		err = os.Rename(legacyDir, dir)
-		if err != nil {
-			return storage.TorrentImpl{}, fmt.Errorf("error renaming legacy torrent dir: %w", err)
-		}
+	// log = log.With(slog.String("legacy_dir", legacyDir), slog.String("dir", dir))
+	// if _, err := os.Stat(legacyDir); err == nil {
+	// 	log.Warn(ctx, "legacy torrent dir found, renaming", slog.String("dir", dir))
+	// 	err = os.Rename(legacyDir, dir)
+	// 	if err != nil {
+	// 		return storage.TorrentImpl{}, fmt.Errorf("error renaming legacy torrent dir: %w", err)
+	// 	}
+	// }
+
+	// if _, err := os.Stat(dir); errors.Is(err, fs.ErrNotExist) {
+	// 	log.Info(ctx, "new torrent, trying copy files from existing")
+	// 	dups := me.dupIndex.Includes(infoHash, info.Files)
+
+	// 	for _, dup := range dups {
+	// 		err := me.copyDup(ctx, infoHash, dup)
+	// 		if err != nil {
+	// 			log.Error(ctx, "error copying file", slog.String("file", dup.fileinfo.DisplayPath(info)), rlog.Error(err))
+	// 		}
+	// 	}
+
+	// }
+
+	impl, err := me.client.OpenTorrent(info, infoHash)
+	if err != nil {
+		log.Error(ctx, "error opening torrent", rlog.Error(err))
 	}
-
-	if _, err := os.Stat(dir); errors.Is(err, fs.ErrNotExist) {
-		log.Info(ctx, "new torrent, trying copy files from existing")
-		dups := me.dupIndex.Includes(infoHash, info.Files)
-
-		for _, dup := range dups {
-			err := me.copyDup(ctx, infoHash, dup)
-			if err != nil {
-				log.Error(ctx, "error copying file", slog.String("file", dup.fileinfo.DisplayPath(info)), rlog.Error(err))
-			}
-		}
-
-	}
-
-	return me.client.OpenTorrent(info, infoHash)
+	return impl, err
 }
 
 func (me *fileStorage) copyDup(ctx context.Context, infoHash infohash.T, dup dupInfo) error {
diff --git a/ui/lib/api/schema.graphql b/ui/lib/api/schema.graphql
index 2098c19..7ba6433 100644
--- a/ui/lib/api/schema.graphql
+++ b/ui/lib/api/schema.graphql
@@ -1,8 +1,9 @@
 directive @oneOf on INPUT_OBJECT | FIELD_DEFINITION
+directive @resolver on INPUT_FIELD_DEFINITION | FIELD_DEFINITION
 directive @stream on FIELD_DEFINITION
 type ArchiveFS implements Dir & FsEntry {
 	name: String!
-	entries: [FsEntry!]!
+	entries: [FsEntry!]! @resolver
 	size: Int!
 }
 input BooleanFilter @oneOf {
@@ -43,9 +44,7 @@ input IntFilter @oneOf {
 	in: [Int!]
 }
 type Mutation {
-	validateTorrents(filter: TorrentFilter!): Boolean!
-	cleanupTorrents(files: Boolean, dryRun: Boolean!): CleanupResponse!
-	downloadTorrent(infohash: String!, file: String): DownloadTorrentResponse
+	torrentDaemon: TorrentDaemonMutation @resolver
 	uploadFile(dir: String!, file: Upload!): Boolean!
 	dedupeStorage: Int!
 }
@@ -58,12 +57,12 @@ interface Progress {
 	total: Int!
 }
 type Query {
-	torrents(filter: TorrentsFilter): [Torrent!]!
+	torrentDaemon: TorrentDaemonQuery @resolver
 	fsEntry(path: String!): FsEntry
 }
 type ResolverFS implements Dir & FsEntry {
 	name: String!
-	entries: [FsEntry!]!
+	entries: [FsEntry!]! @resolver
 }
 type Schema {
 	query: Query
@@ -71,7 +70,7 @@ type Schema {
 }
 type SimpleDir implements Dir & FsEntry {
 	name: String!
-	entries: [FsEntry!]!
+	entries: [FsEntry!]! @resolver
 }
 type SimpleFile implements File & FsEntry {
 	name: String!
@@ -90,20 +89,28 @@ type Task {
 	id: ID!
 }
 type Torrent {
-	name: String!
+	name: String! @resolver
 	infohash: String!
 	bytesCompleted: Int!
 	torrentFilePath: String!
 	bytesMissing: Int!
-	files: [TorrentFile!]!
-	excludedFiles: [TorrentFile!]!
-	peers: [TorrentPeer!]!
-	downloading: Boolean!
+	priority: TorrentPriority! @resolver
+	files: [TorrentFile!]! @resolver
+	excludedFiles: [TorrentFile!]! @resolver
+	peers: [TorrentPeer!]! @resolver
+}
+type TorrentDaemonMutation {
+	validateTorrent(filter: TorrentFilter!): Boolean! @resolver
+	setTorrentPriority(infohash: String!, file: String, priority: TorrentPriority!): Boolean! @resolver
+	cleanup(files: Boolean, dryRun: Boolean!): CleanupResponse! @resolver
+}
+type TorrentDaemonQuery {
+	torrents(filter: TorrentsFilter): [Torrent!]! @resolver
 }
 type TorrentFS implements Dir & FsEntry {
 	name: String!
 	torrent: Torrent!
-	entries: [FsEntry!]!
+	entries: [FsEntry!]! @resolver
 }
 type TorrentFile {
 	filename: String!
@@ -126,6 +133,22 @@ type TorrentPeer {
 	port: Int!
 	clientName: String!
 }
+enum TorrentPriority {
+	NONE
+	NORMAL
+	HIGH
+	READAHEAD
+	NEXT
+	NOW
+}
+input TorrentPriorityFilter @oneOf {
+	eq: TorrentPriority
+	gt: TorrentPriority
+	lt: TorrentPriority
+	gte: TorrentPriority
+	lte: TorrentPriority
+	in: [TorrentPriority!]
+}
 type TorrentProgress implements Progress {
 	torrent: Torrent!
 	current: Int!
@@ -137,6 +160,6 @@ input TorrentsFilter {
 	bytesCompleted: IntFilter
 	bytesMissing: IntFilter
 	peersCount: IntFilter
-	downloading: BooleanFilter
+	priority: TorrentPriorityFilter
 }
 scalar Upload