This commit is contained in:
parent
98ee1dc6f1
commit
585f317478
61 changed files with 6616 additions and 791 deletions
|
@ -27,11 +27,11 @@ models:
|
||||||
Torrent:
|
Torrent:
|
||||||
extraFields:
|
extraFields:
|
||||||
T:
|
T:
|
||||||
type: "*git.kmsign.ru/royalcat/tstor/src/daemons/torrent.Controller"
|
type: "*git.kmsign.ru/royalcat/tstor/daemons/torrent.Controller"
|
||||||
TorrentFile:
|
TorrentFile:
|
||||||
extraFields:
|
extraFields:
|
||||||
F:
|
F:
|
||||||
type: "*git.kmsign.ru/royalcat/tstor/src/daemons/torrent.FileController"
|
type: "*git.kmsign.ru/royalcat/tstor/daemons/torrent.FileController"
|
||||||
TorrentPeer:
|
TorrentPeer:
|
||||||
extraFields:
|
extraFields:
|
||||||
F:
|
F:
|
||||||
|
@ -45,7 +45,7 @@ models:
|
||||||
TorrentFS:
|
TorrentFS:
|
||||||
extraFields:
|
extraFields:
|
||||||
FS:
|
FS:
|
||||||
type: "*git.kmsign.ru/royalcat/tstor/src/daemons/torrent.TorrentFS"
|
type: "*git.kmsign.ru/royalcat/tstor/daemons/torrent.TorrentFS"
|
||||||
ResolverFS:
|
ResolverFS:
|
||||||
extraFields:
|
extraFields:
|
||||||
FS:
|
FS:
|
||||||
|
|
|
@ -6,6 +6,7 @@ COPY go.mod ./
|
||||||
COPY go.sum ./
|
COPY go.sum ./
|
||||||
RUN --mount=type=cache,mode=0777,target=/go/pkg/mod go mod download all
|
RUN --mount=type=cache,mode=0777,target=/go/pkg/mod go mod download all
|
||||||
|
|
||||||
|
COPY ./daemons ./daemons
|
||||||
COPY ./pkg ./pkg
|
COPY ./pkg ./pkg
|
||||||
COPY ./src ./src
|
COPY ./src ./src
|
||||||
COPY ./cmd ./cmd
|
COPY ./cmd ./cmd
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/fs"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
|
|
||||||
"net"
|
"net"
|
||||||
|
@ -13,13 +14,13 @@ import (
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
|
"git.kmsign.ru/royalcat/tstor/daemons/qbittorrent"
|
||||||
|
"git.kmsign.ru/royalcat/tstor/daemons/ytdlp"
|
||||||
"git.kmsign.ru/royalcat/tstor/pkg/ctxbilly"
|
"git.kmsign.ru/royalcat/tstor/pkg/ctxbilly"
|
||||||
wnfs "git.kmsign.ru/royalcat/tstor/pkg/go-nfs"
|
wnfs "git.kmsign.ru/royalcat/tstor/pkg/go-nfs"
|
||||||
"git.kmsign.ru/royalcat/tstor/pkg/rlog"
|
"git.kmsign.ru/royalcat/tstor/pkg/rlog"
|
||||||
"git.kmsign.ru/royalcat/tstor/src/config"
|
"git.kmsign.ru/royalcat/tstor/src/config"
|
||||||
"git.kmsign.ru/royalcat/tstor/src/daemons"
|
"git.kmsign.ru/royalcat/tstor/src/daemons"
|
||||||
"git.kmsign.ru/royalcat/tstor/src/daemons/qbittorrent"
|
|
||||||
"git.kmsign.ru/royalcat/tstor/src/daemons/ytdlp"
|
|
||||||
"git.kmsign.ru/royalcat/tstor/src/delivery"
|
"git.kmsign.ru/royalcat/tstor/src/delivery"
|
||||||
"git.kmsign.ru/royalcat/tstor/src/telemetry"
|
"git.kmsign.ru/royalcat/tstor/src/telemetry"
|
||||||
"git.kmsign.ru/royalcat/tstor/src/vfs"
|
"git.kmsign.ru/royalcat/tstor/src/vfs"
|
||||||
|
@ -118,6 +119,10 @@ func run(configPath string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vfs.Walk(ctx, sfs, "/", func(path string, info fs.FileInfo, err error) error {
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
if conf.Mounts.Fuse.Enabled {
|
if conf.Mounts.Fuse.Enabled {
|
||||||
mh := fuse.NewHandler(conf.Mounts.Fuse.AllowOther, conf.Mounts.Fuse.Path)
|
mh := fuse.NewHandler(conf.Mounts.Fuse.AllowOther, conf.Mounts.Fuse.Path)
|
||||||
err := mh.Mount(sfs)
|
err := mh.Mount(sfs)
|
||||||
|
|
6
daemons/kemono/client.cfg.yaml
Normal file
6
daemons/kemono/client.cfg.yaml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
# yaml-language-server: $schema=https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/HEAD/configuration-schema.json
|
||||||
|
package: client
|
||||||
|
output: client/client.gen.go
|
||||||
|
generate:
|
||||||
|
models: true
|
||||||
|
client: true
|
3176
daemons/kemono/client/client.gen.go
Normal file
3176
daemons/kemono/client/client.gen.go
Normal file
File diff suppressed because it is too large
Load diff
21
daemons/kemono/client/models.go
Normal file
21
daemons/kemono/client/models.go
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Timestamp struct {
|
||||||
|
Time time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Timestamp) UnmarshalJSON(b []byte) error {
|
||||||
|
var timestamp float64
|
||||||
|
err := json.Unmarshal(b, ×tamp)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Time = time.Unix(int64(timestamp), int64((timestamp-float64(int64(timestamp)))*1e9))
|
||||||
|
return nil
|
||||||
|
}
|
2079
daemons/kemono/client/spec.json
Normal file
2079
daemons/kemono/client/spec.json
Normal file
File diff suppressed because it is too large
Load diff
42
daemons/kemono/daemon.go
Normal file
42
daemons/kemono/daemon.go
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
package kemono
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"git.kmsign.ru/royalcat/tstor/daemons/kemono/client"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Daemon struct {
|
||||||
|
client client.ClientWithResponsesInterface
|
||||||
|
}
|
||||||
|
|
||||||
|
type creator struct {
|
||||||
|
Service string
|
||||||
|
CreatorID string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDaemon(server string) (*Daemon, error) {
|
||||||
|
cl, err := client.NewClientWithResponses(server)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Daemon{
|
||||||
|
client: cl,
|
||||||
|
}, nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Daemon) scrapCreator(ctx context.Context, creator creator) error {
|
||||||
|
resp, err := d.client.GetServiceUserCreatorIdWithResponse(ctx, creator.Service, creator.CreatorID, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, post := range *resp.JSON200 {
|
||||||
|
fmt.Println(post)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
22
daemons/kemono/daemon_test.go
Normal file
22
daemons/kemono/daemon_test.go
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
package kemono_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"git.kmsign.ru/royalcat/tstor/daemons/kemono"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestScrapCreator(t *testing.T) {
|
||||||
|
k := kemono.NewKemono("https://coomer.su/")
|
||||||
|
ctx := context.Background()
|
||||||
|
posts, err := k.FetchPosts(ctx, "onlyfans", "bigtittygothegg")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, post := range posts {
|
||||||
|
fmt.Println(post)
|
||||||
|
}
|
||||||
|
}
|
69
daemons/kemono/fetch.go
Normal file
69
daemons/kemono/fetch.go
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
package kemono
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/carlmjohnson/requests"
|
||||||
|
)
|
||||||
|
|
||||||
|
// FetchCreators fetch Creator list
|
||||||
|
func (k *kemono) FetchCreators() (creators []Creator, err error) {
|
||||||
|
// k.log.Print("fetching creator list...")
|
||||||
|
// url := fmt.Sprintf("https://%s/api/v1/creators", k.Site)
|
||||||
|
// resp, err := k.Downloader.Get(url)
|
||||||
|
// if err != nil {
|
||||||
|
// return nil, fmt.Errorf("fetch creator list error: %s", err)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// reader, err := handleCompressedHTTPResponse(resp)
|
||||||
|
// if err != nil {
|
||||||
|
// return nil, err
|
||||||
|
// }
|
||||||
|
|
||||||
|
// data, err := ioutil.ReadAll(reader)
|
||||||
|
// if err != nil {
|
||||||
|
// return nil, fmt.Errorf("fetch creator list error: %s", err)
|
||||||
|
// }
|
||||||
|
// err = json.Unmarshal(data, &creators)
|
||||||
|
// if err != nil {
|
||||||
|
// return nil, fmt.Errorf("unmarshal creator list error: %s", err)
|
||||||
|
// }
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// FetchPosts fetch post list
|
||||||
|
func (k *kemono) FetchPosts(ctx context.Context, service, id string) (posts []Post, err error) {
|
||||||
|
const perUnit = 50
|
||||||
|
page := 0
|
||||||
|
|
||||||
|
for {
|
||||||
|
k.log.Printf("fetching post list page %d...", page)
|
||||||
|
var ps []json.RawMessage
|
||||||
|
err = requests.URL(k.Site).
|
||||||
|
Pathf("/api/v1/%s/user/%s", service, id).
|
||||||
|
ParamInt("o", page*perUnit).
|
||||||
|
Client(k.client).
|
||||||
|
CheckStatus(200).
|
||||||
|
ToJSON(&ps).
|
||||||
|
Fetch(ctx)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(ps) == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, raw := range ps {
|
||||||
|
var p Post
|
||||||
|
err := json.Unmarshal(raw, &p)
|
||||||
|
if err != nil {
|
||||||
|
return posts, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return posts, nil
|
||||||
|
}
|
32
daemons/kemono/go.mod
Normal file
32
daemons/kemono/go.mod
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
module git.kmsign.ru/royalcat/tstor/daemons/kemono
|
||||||
|
|
||||||
|
go 1.23.3
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/oapi-codegen/oapi-codegen/v2 v2.4.1
|
||||||
|
github.com/oapi-codegen/runtime v1.1.1
|
||||||
|
github.com/spf13/cast v1.7.0
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect
|
||||||
|
github.com/carlmjohnson/requests v0.24.2 // indirect
|
||||||
|
github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // indirect
|
||||||
|
github.com/getkin/kin-openapi v0.127.0 // indirect
|
||||||
|
github.com/go-openapi/jsonpointer v0.21.0 // indirect
|
||||||
|
github.com/go-openapi/swag v0.23.0 // indirect
|
||||||
|
github.com/google/uuid v1.5.0 // indirect
|
||||||
|
github.com/invopop/yaml v0.3.1 // indirect
|
||||||
|
github.com/josharian/intern v1.0.0 // indirect
|
||||||
|
github.com/mailru/easyjson v0.7.7 // indirect
|
||||||
|
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
|
||||||
|
github.com/perimeterx/marshmallow v1.1.5 // indirect
|
||||||
|
github.com/speakeasy-api/openapi-overlay v0.9.0 // indirect
|
||||||
|
github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect
|
||||||
|
golang.org/x/mod v0.17.0 // indirect
|
||||||
|
golang.org/x/net v0.27.0 // indirect
|
||||||
|
golang.org/x/text v0.18.0 // indirect
|
||||||
|
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
|
||||||
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
|
)
|
189
daemons/kemono/go.sum
Normal file
189
daemons/kemono/go.sum
Normal file
|
@ -0,0 +1,189 @@
|
||||||
|
github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk=
|
||||||
|
github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ=
|
||||||
|
github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP2+08jFMw88y4klk=
|
||||||
|
github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w=
|
||||||
|
github.com/carlmjohnson/requests v0.24.2 h1:JDakhAmTIKL/qL/1P7Kkc2INGBJIkIFP6xUeUmPzLso=
|
||||||
|
github.com/carlmjohnson/requests v0.24.2/go.mod h1:duYA/jDnyZ6f3xbcF5PpZ9N8clgopubP2nK5i6MVMhU=
|
||||||
|
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||||
|
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||||
|
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/dprotaso/go-yit v0.0.0-20191028211022-135eb7262960/go.mod h1:9HQzr9D/0PGwMEbC3d5AB7oi67+h4TsQqItC1GVYG58=
|
||||||
|
github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 h1:PRxIJD8XjimM5aTknUK9w6DHLDox2r2M3DI4i2pnd3w=
|
||||||
|
github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936/go.mod h1:ttYvX5qlB+mlV1okblJqcSMtR4c52UKxDiX9GRBS8+Q=
|
||||||
|
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
||||||
|
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||||
|
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||||
|
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||||
|
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||||
|
github.com/getkin/kin-openapi v0.127.0 h1:Mghqi3Dhryf3F8vR370nN67pAERW+3a95vomb3MAREY=
|
||||||
|
github.com/getkin/kin-openapi v0.127.0/go.mod h1:OZrfXzUfGrNbsKj+xmFBx6E5c6yH3At/tAKSc2UszXM=
|
||||||
|
github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
|
||||||
|
github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
|
||||||
|
github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
|
||||||
|
github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
|
||||||
|
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||||
|
github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM=
|
||||||
|
github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
|
||||||
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||||
|
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||||
|
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||||
|
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||||
|
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||||
|
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
|
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
|
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||||
|
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
|
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||||
|
github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU=
|
||||||
|
github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||||
|
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||||
|
github.com/invopop/yaml v0.3.1 h1:f0+ZpmhfBSS4MhG+4HYseMdJhoeeopbSKbq5Rpeelso=
|
||||||
|
github.com/invopop/yaml v0.3.1/go.mod h1:PMOp3nn4/12yEZUFfmOuNHJsZToEEOwoWsT+D81KkeA=
|
||||||
|
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||||
|
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||||
|
github.com/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d/go.mod h1:2PavIy+JPciBPrBUjwbNvtwB6RQlve+hkpll6QSNmOE=
|
||||||
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
|
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||||
|
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||||
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
|
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
||||||
|
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||||
|
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw=
|
||||||
|
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
|
||||||
|
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||||
|
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
||||||
|
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
||||||
|
github.com/oapi-codegen/oapi-codegen/v2 v2.4.1 h1:ykgG34472DWey7TSjd8vIfNykXgjOgYJZoQbKfEeY/Q=
|
||||||
|
github.com/oapi-codegen/oapi-codegen/v2 v2.4.1/go.mod h1:N5+lY1tiTDV3V1BeHtOxeWXHoPVeApvsvjJqegfoaz8=
|
||||||
|
github.com/oapi-codegen/runtime v1.1.1 h1:EXLHh0DXIJnWhdRPN2w4MXAzFyE4CskzhNLUmtpMYro=
|
||||||
|
github.com/oapi-codegen/runtime v1.1.1/go.mod h1:SK9X900oXmPWilYR5/WKPzt3Kqxn/uS/+lbpREv+eCg=
|
||||||
|
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
|
github.com/onsi/ginkgo v1.10.2/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
|
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
||||||
|
github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
|
||||||
|
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
|
||||||
|
github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
|
||||||
|
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||||
|
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||||
|
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||||
|
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
|
||||||
|
github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro=
|
||||||
|
github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE=
|
||||||
|
github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg=
|
||||||
|
github.com/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX50IvK2s=
|
||||||
|
github.com/perimeterx/marshmallow v1.1.5/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
|
||||||
|
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
|
||||||
|
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
|
||||||
|
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||||
|
github.com/speakeasy-api/openapi-overlay v0.9.0 h1:Wrz6NO02cNlLzx1fB093lBlYxSI54VRhy1aSutx0PQg=
|
||||||
|
github.com/speakeasy-api/openapi-overlay v0.9.0/go.mod h1:f5FloQrHA7MsxYg9djzMD5h6dxrHjVVByWKh7an8TRc=
|
||||||
|
github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w=
|
||||||
|
github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
|
||||||
|
github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
|
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||||
|
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||||
|
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
|
github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
|
||||||
|
github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
||||||
|
github.com/vmware-labs/yaml-jsonpath v0.3.2 h1:/5QKeCBGdsInyDCyVNLbXyilb61MXGi9NP674f9Hobk=
|
||||||
|
github.com/vmware-labs/yaml-jsonpath v0.3.2/go.mod h1:U6whw1z03QyqgWdgXxvVnQ90zN1BWz5V+51Ewf8k+rQ=
|
||||||
|
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
|
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
|
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/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||||
|
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
|
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
|
||||||
|
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||||
|
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.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys=
|
||||||
|
golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
|
||||||
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
|
||||||
|
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
|
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
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/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/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
|
golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
|
||||||
|
golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||||
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
|
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg=
|
||||||
|
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||||
|
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=
|
||||||
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||||
|
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||||
|
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||||
|
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||||
|
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||||
|
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||||
|
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||||
|
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||||
|
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||||
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||||
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||||
|
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||||
|
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20191026110619-0b21df46bc1d/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
436
daemons/kemono/kemono.go
Normal file
436
daemons/kemono/kemono.go
Normal file
|
@ -0,0 +1,436 @@
|
||||||
|
package kemono
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Downloader interface {
|
||||||
|
Download(<-chan FileWithIndex, Creator, Post) <-chan error
|
||||||
|
Get(url string) (resp *http.Response, err error)
|
||||||
|
WriteContent(Creator, Post, string) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type Log interface {
|
||||||
|
Printf(format string, v ...interface{})
|
||||||
|
Print(s string)
|
||||||
|
}
|
||||||
|
|
||||||
|
type DefaultLog struct {
|
||||||
|
log *log.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DefaultLog) Printf(format string, v ...interface{}) {
|
||||||
|
d.log.Printf(format, v...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DefaultLog) Print(s string) {
|
||||||
|
d.log.Print(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filter return true for continue, false for skip
|
||||||
|
|
||||||
|
type CreatorFilter func(i int, post Creator) bool
|
||||||
|
|
||||||
|
type PostFilter func(i int, post Post) bool
|
||||||
|
|
||||||
|
type AttachmentFilter func(i int, attachment File) bool
|
||||||
|
|
||||||
|
type Option func(*kemono)
|
||||||
|
|
||||||
|
type kemono struct {
|
||||||
|
// kemono or coomer ...
|
||||||
|
Site string
|
||||||
|
//download Banner
|
||||||
|
Banner bool
|
||||||
|
// All Creator
|
||||||
|
creators []Creator
|
||||||
|
|
||||||
|
// Creator filter
|
||||||
|
creatorFilters []CreatorFilter
|
||||||
|
|
||||||
|
// Post filter map[creator(<service>:<id>)][]PostFilter
|
||||||
|
postFilters map[string][]PostFilter
|
||||||
|
|
||||||
|
// Attachment filter map[creator(<service>:<id>)][]AttachmentFilter
|
||||||
|
attachmentFilters map[string][]AttachmentFilter
|
||||||
|
|
||||||
|
// Select a specific creator
|
||||||
|
// If not specified, all creators will be selected
|
||||||
|
users []Creator
|
||||||
|
|
||||||
|
client *http.Client
|
||||||
|
|
||||||
|
log Log
|
||||||
|
|
||||||
|
retry int
|
||||||
|
|
||||||
|
retryInterval time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewKemono(site string) *kemono {
|
||||||
|
k := &kemono{
|
||||||
|
Site: site,
|
||||||
|
Banner: true,
|
||||||
|
postFilters: make(map[string][]PostFilter),
|
||||||
|
attachmentFilters: make(map[string][]AttachmentFilter),
|
||||||
|
retry: 3,
|
||||||
|
retryInterval: 5 * time.Second,
|
||||||
|
}
|
||||||
|
if k.log == nil {
|
||||||
|
k.log = &DefaultLog{log: log.New(os.Stdout, "", log.LstdFlags)}
|
||||||
|
}
|
||||||
|
return k
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithDomain Set Site
|
||||||
|
// func WithDomain(web string) Option {
|
||||||
|
// return func(k *kemono) {
|
||||||
|
// k.Site = web
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// func WithBanner(banner bool) Option {
|
||||||
|
// return func(k *kemono) {
|
||||||
|
// k.Banner = banner
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Custom the creator list
|
||||||
|
// func WithCreators(creators []Creator) Option {
|
||||||
|
// return func(k *kemono) {
|
||||||
|
// k.creators = creators
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// WithUsers Select a specific creator, if not specified, all creators will be selected
|
||||||
|
// func WithUsers(user ...Creator) Option {
|
||||||
|
// return func(k *kemono) {
|
||||||
|
// for _, u := range user {
|
||||||
|
// exist := false
|
||||||
|
// for _, c := range k.users {
|
||||||
|
// if c.Service == u.Service && c.Id == u.Id {
|
||||||
|
// exist = true
|
||||||
|
// break
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// if !exist {
|
||||||
|
// k.users = append(k.users, u)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// WithUsersPair Select a specific creator, if not specified, all creators will be selected
|
||||||
|
// func WithUsersPair(serviceIdPairs ...string) Option {
|
||||||
|
// return func(k *kemono) {
|
||||||
|
// if len(serviceIdPairs)%2 != 0 {
|
||||||
|
// k.log.Printf("serviceIdPairs length must be even")
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// for i := 0; i < len(serviceIdPairs); i += 2 {
|
||||||
|
// exist := false
|
||||||
|
// for _, c := range k.users {
|
||||||
|
// if c.Service == serviceIdPairs[i] && c.Id == serviceIdPairs[i+1] {
|
||||||
|
// exist = true
|
||||||
|
// break
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// if !exist {
|
||||||
|
// k.users = append(k.users, NewCreator(serviceIdPairs[i], serviceIdPairs[i+1]))
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// SetLog set log
|
||||||
|
func SetLog(log Log) Option {
|
||||||
|
return func(k *kemono) {
|
||||||
|
k.log = log
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// // SetRetry set retry
|
||||||
|
// func SetRetry(retry int) Option {
|
||||||
|
// return func(k *kemono) {
|
||||||
|
// k.retry = retry
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // SetRetryInterval set retry interval
|
||||||
|
// func SetRetryInterval(retryInterval time.Duration) Option {
|
||||||
|
// return func(k *kemono) {
|
||||||
|
// k.retryInterval = retryInterval
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // WithCreatorFilter Creator filter
|
||||||
|
// func WithCreatorFilter(filter ...CreatorFilter) Option {
|
||||||
|
// return func(k *kemono) {
|
||||||
|
// k.addCreatorFilter(filter...)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // WithPostFilter Post filter
|
||||||
|
// func WithPostFilter(filter ...PostFilter) Option {
|
||||||
|
// return func(k *kemono) {
|
||||||
|
// k.addPostFilter(filter...)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// func WithUserPostFilter(creator Creator, filter ...PostFilter) Option {
|
||||||
|
// return func(k *kemono) {
|
||||||
|
// k.addUserPostFilter(creator.PairString(), filter...)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // WithAttachmentFilter Attachment filter
|
||||||
|
// func WithAttachmentFilter(filter ...AttachmentFilter) Option {
|
||||||
|
// return func(k *kemono) {
|
||||||
|
// k.addAttachmentFilter(filter...)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// func WithUserAttachmentFilter(creator Creator, filter ...AttachmentFilter) Option {
|
||||||
|
// return func(k *kemono) {
|
||||||
|
// k.addUserAttachmentFilter(creator.PairString(), filter...)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Start fetch and download
|
||||||
|
// func (k *kemono) Start() error {
|
||||||
|
// // initialize the creators
|
||||||
|
// if len(k.creators) == 0 {
|
||||||
|
// // fetch creators from kemono
|
||||||
|
// cs, err := k.FetchCreators()
|
||||||
|
// if err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
// k.creators = cs
|
||||||
|
// }
|
||||||
|
|
||||||
|
// //find creators
|
||||||
|
// if len(k.users) != 0 {
|
||||||
|
// var creators []Creator
|
||||||
|
// for _, user := range k.users {
|
||||||
|
// c, ok := FindCreator(k.creators, user.Id, user.Service)
|
||||||
|
// if !ok {
|
||||||
|
// k.log.Printf("Creator %s:%s not found", user.Service, user.Id)
|
||||||
|
// continue
|
||||||
|
// }
|
||||||
|
// creators = append(creators, c)
|
||||||
|
// }
|
||||||
|
// k.users = creators
|
||||||
|
// } else {
|
||||||
|
// k.users = k.creators
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Filter selected creators
|
||||||
|
// k.users = k.FilterCreators(k.users)
|
||||||
|
|
||||||
|
// // start download
|
||||||
|
// k.log.Printf("Start download %d creators", len(k.users))
|
||||||
|
// for _, creator := range k.users {
|
||||||
|
// // fetch posts
|
||||||
|
// posts, err := k.FetchPosts(creator.Service, creator.Id)
|
||||||
|
// if err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
// // filter posts
|
||||||
|
// posts = k.FilterPosts(posts)
|
||||||
|
|
||||||
|
// // filter attachments
|
||||||
|
// for i, post := range posts {
|
||||||
|
// // download banner if banner is true or file is not image
|
||||||
|
// if (k.Banner || !isImage(filepath.Ext(post.File.Name))) && post.File.Path != "" {
|
||||||
|
// res := make([]File, len(post.Attachments)+1)
|
||||||
|
// copy(res[1:], post.Attachments)
|
||||||
|
// res[0] = post.File
|
||||||
|
// post.Attachments = res
|
||||||
|
// }
|
||||||
|
// posts[i].Attachments = k.FilterAttachments(fmt.Sprintf("%s:%s", post.Service, post.User), post.Attachments)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // download posts
|
||||||
|
// err = k.DownloadPosts(creator, posts)
|
||||||
|
// if err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return nil
|
||||||
|
// }
|
||||||
|
|
||||||
|
// func (k *kemono) addCreatorFilter(filter ...CreatorFilter) {
|
||||||
|
// k.creatorFilters = append(k.creatorFilters, filter...)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// func (k *kemono) addPostFilter(filter ...PostFilter) {
|
||||||
|
// k.postFilters["*"] = append(k.postFilters["*"], filter...)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// func (k *kemono) addUserPostFilter(user string, filter ...PostFilter) {
|
||||||
|
// k.postFilters[user] = append(k.postFilters[user], filter...)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// func (k *kemono) addAttachmentFilter(filter ...AttachmentFilter) {
|
||||||
|
// k.attachmentFilters["*"] = append(k.attachmentFilters["*"], filter...)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// func (k *kemono) addUserAttachmentFilter(user string, filter ...AttachmentFilter) {
|
||||||
|
// k.attachmentFilters[user] = append(k.attachmentFilters[user], filter...)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// func (k *kemono) filterCreator(i int, creator Creator) bool {
|
||||||
|
// for _, filter := range k.creatorFilters {
|
||||||
|
// if !filter(i, creator) {
|
||||||
|
// return false
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return true
|
||||||
|
// }
|
||||||
|
|
||||||
|
// func (k *kemono) filterPost(i int, post Post) bool {
|
||||||
|
// for _, filter := range k.postFilters["*"] {
|
||||||
|
// if !filter(i, post) {
|
||||||
|
// return false
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// for _, filter := range k.postFilters[fmt.Sprintf("%s:%s", post.Service, post.User)] {
|
||||||
|
// if !filter(i, post) {
|
||||||
|
// return false
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return true
|
||||||
|
// }
|
||||||
|
|
||||||
|
// func (k *kemono) filterAttachment(user string, i int, attachment File) bool {
|
||||||
|
// for _, filter := range k.attachmentFilters["*"] {
|
||||||
|
// if !filter(i, attachment) {
|
||||||
|
// return false
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// for _, filter := range k.attachmentFilters[user] {
|
||||||
|
// if !filter(i, attachment) {
|
||||||
|
// return false
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return true
|
||||||
|
// }
|
||||||
|
|
||||||
|
// func (k *kemono) FilterCreators(creators []Creator) []Creator {
|
||||||
|
// var filteredCreators []Creator
|
||||||
|
// for i, creator := range creators {
|
||||||
|
// if k.filterCreator(i, creator) {
|
||||||
|
// filteredCreators = append(filteredCreators, creator)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return filteredCreators
|
||||||
|
// }
|
||||||
|
|
||||||
|
// func (k *kemono) FilterPosts(posts []Post) []Post {
|
||||||
|
// var filteredPosts []Post
|
||||||
|
// for i, post := range posts {
|
||||||
|
// if k.filterPost(i, post) {
|
||||||
|
// filteredPosts = append(filteredPosts, post)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return filteredPosts
|
||||||
|
// }
|
||||||
|
|
||||||
|
// func (k *kemono) FilterAttachments(user string, attachments []File) []File {
|
||||||
|
// var filteredAttachments []File
|
||||||
|
// for i, attachment := range attachments {
|
||||||
|
// if k.filterAttachment(user, i, attachment) {
|
||||||
|
// filteredAttachments = append(filteredAttachments, attachment)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return filteredAttachments
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // ReleaseDateFilter A Post filter that filters posts with release date
|
||||||
|
// func ReleaseDateFilter(from, to time.Time) PostFilter {
|
||||||
|
// return func(i int, post Post) bool {
|
||||||
|
// return post.Published.After(from) && post.Published.Before(to)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // ReleaseDateAfterFilter A Post filter that filters posts with release date after
|
||||||
|
// func ReleaseDateAfterFilter(from time.Time) PostFilter {
|
||||||
|
// return func(i int, post Post) bool {
|
||||||
|
// return post.Published.After(from)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // ReleaseDateBeforeFilter A Post filter that filters posts with release date before
|
||||||
|
// func ReleaseDateBeforeFilter(to time.Time) PostFilter {
|
||||||
|
// return func(i int, post Post) bool {
|
||||||
|
// return post.Published.Before(to)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // EditDateFilter A Post filter that filters posts with edit date
|
||||||
|
// func EditDateFilter(from, to time.Time) PostFilter {
|
||||||
|
// return func(i int, post Post) bool {
|
||||||
|
// return post.Edited.After(from) && post.Edited.Before(to)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // EditDateAfterFilter A Post filter that filters posts with edit date after
|
||||||
|
// func EditDateAfterFilter(from time.Time) PostFilter {
|
||||||
|
// return func(i int, post Post) bool {
|
||||||
|
// return post.Edited.After(from)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // EditDateBeforeFilter A Post filter that filters posts with edit date before
|
||||||
|
// func EditDateBeforeFilter(to time.Time) PostFilter {
|
||||||
|
// return func(i int, post Post) bool {
|
||||||
|
// return post.Edited.Before(to)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// func IdFilter(ids ...string) PostFilter {
|
||||||
|
// return func(i int, post Post) bool {
|
||||||
|
// for _, id := range ids {
|
||||||
|
// if id == post.Id {
|
||||||
|
// return true
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return false
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // NumbFilter A Post filter that filters posts with a specific number
|
||||||
|
// func NumbFilter(f func(i int) bool) PostFilter {
|
||||||
|
// return func(i int, post Post) bool {
|
||||||
|
// return f(i)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // ExtensionFilter A attachmentFilter filter that filters attachments with a specific extension
|
||||||
|
// func ExtensionFilter(extension ...string) AttachmentFilter {
|
||||||
|
// return func(i int, attachment File) bool {
|
||||||
|
// ext := filepath.Ext(attachment.Name)
|
||||||
|
// for _, e := range extension {
|
||||||
|
// if ext == e {
|
||||||
|
// return true
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return false
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // ExtensionExcludeFilter A attachmentFilter filter that filters attachments without a specific extension
|
||||||
|
// func ExtensionExcludeFilter(extension ...string) AttachmentFilter {
|
||||||
|
// return func(i int, attachment File) bool {
|
||||||
|
// ext := filepath.Ext(attachment.Name)
|
||||||
|
// for _, e := range extension {
|
||||||
|
// if ext == e {
|
||||||
|
// return false
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return true
|
||||||
|
// }
|
||||||
|
// }
|
10
daemons/kemono/tools.go
Normal file
10
daemons/kemono/tools.go
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
//go:build tools
|
||||||
|
// +build tools
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen@latest -config client.cfg.yaml client/spec.json
|
201
daemons/kemono/types.go
Normal file
201
daemons/kemono/types.go
Normal file
|
@ -0,0 +1,201 @@
|
||||||
|
package kemono
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
"path/filepath"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/spf13/cast"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Timestamp struct {
|
||||||
|
Time time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Timestamp) UnmarshalJSON(b []byte) error {
|
||||||
|
var timestamp float64
|
||||||
|
err := json.Unmarshal(b, ×tamp)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Time = time.Unix(int64(timestamp), int64((timestamp-float64(int64(timestamp)))*1e9))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type Creator struct {
|
||||||
|
Favorited int `json:"favorited"`
|
||||||
|
Id string `json:"id"`
|
||||||
|
Indexed Timestamp `json:"indexed"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Service string `json:"service"`
|
||||||
|
Updated Timestamp `json:"updated"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetID get creator id
|
||||||
|
func (c Creator) GetID() string {
|
||||||
|
return c.Id
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetService get creator Service
|
||||||
|
func (c Creator) GetService() string {
|
||||||
|
return c.Service
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Creator) PairString() string {
|
||||||
|
return fmt.Sprintf("%s:%s", c.Service, c.Id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCreator(service, id string) Creator {
|
||||||
|
return Creator{
|
||||||
|
Service: service,
|
||||||
|
Id: id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindCreator Get the Creator by ID and Service
|
||||||
|
func FindCreator(creators []Creator, id, service string) (Creator, bool) {
|
||||||
|
for _, creator := range creators {
|
||||||
|
if creator.Id == id && creator.Service == service {
|
||||||
|
return creator, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Creator{}, false
|
||||||
|
}
|
||||||
|
|
||||||
|
type File struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Path string `json:"path"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetURL return the url
|
||||||
|
func (f File) GetURL() string {
|
||||||
|
ext := filepath.Ext(f.Name)
|
||||||
|
name := f.Name[:len(f.Name)-len(ext)]
|
||||||
|
return fmt.Sprintf("%s?f=%s%s", f.Path, url.QueryEscape(name), ext)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetHash get hash from file path
|
||||||
|
func (f File) GetHash() (string, error) {
|
||||||
|
return SplitHash(f.Path)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f File) Index(n int) FileWithIndex {
|
||||||
|
return FileWithIndex{
|
||||||
|
Index: n,
|
||||||
|
File: f,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type FileWithIndex struct {
|
||||||
|
Index int
|
||||||
|
File
|
||||||
|
}
|
||||||
|
|
||||||
|
type Post struct {
|
||||||
|
ID string `json:"id,omitempty"`
|
||||||
|
Added time.Time `json:"added,omitempty"`
|
||||||
|
Attachments []Attachment `json:"attachments,omitempty"`
|
||||||
|
Author Author `json:"author,omitempty"`
|
||||||
|
Channel string `json:"channel,omitempty"`
|
||||||
|
Content string `json:"content,omitempty"`
|
||||||
|
Edited time.Time `json:"edited,omitempty"`
|
||||||
|
Embeds []any `json:"embeds,omitempty"`
|
||||||
|
Mentions []any `json:"mentions,omitempty"`
|
||||||
|
Published time.Time `json:"published,omitempty"`
|
||||||
|
Server string `json:"server,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Attachment struct {
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
Path string `json:"path,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Author struct {
|
||||||
|
ID string `json:"id,omitempty"`
|
||||||
|
Avatar string `json:"avatar,omitempty"`
|
||||||
|
Discriminator string `json:"discriminator,omitempty"`
|
||||||
|
PublicFlags int64 `json:"public_flags,omitempty"`
|
||||||
|
Username string `json:"username,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Post) UnmarshalJSON(data []byte) error {
|
||||||
|
var pr struct {
|
||||||
|
Added string `json:"added"`
|
||||||
|
Attachments []File `json:"attachments"`
|
||||||
|
Content string `json:"content"`
|
||||||
|
Edited string `json:"edited"`
|
||||||
|
Embed interface{} `json:"embed"`
|
||||||
|
File File `json:"file"`
|
||||||
|
Id string `json:"id"`
|
||||||
|
Published string `json:"published"`
|
||||||
|
Service string `json:"service"`
|
||||||
|
SharedFile bool `json:"shared_file"`
|
||||||
|
Title string `json:"title"`
|
||||||
|
User string `json:"user"`
|
||||||
|
}
|
||||||
|
err := json.Unmarshal(data, &pr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
|
||||||
|
p.Added, err = cast.StringToDate(pr.Added)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("parse added time error: %s", err)
|
||||||
|
}
|
||||||
|
p.Edited, err = cast.StringToDate(pr.Edited)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("parse edited time error: %s", err)
|
||||||
|
}
|
||||||
|
p.Published, err = cast.StringToDate(pr.Published)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("parse published time error: %s", err)
|
||||||
|
}
|
||||||
|
p.ID = pr.Id
|
||||||
|
p.Service = pr.Service
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// User a creator according to the service and id
|
||||||
|
type User struct {
|
||||||
|
Service string `json:"service"`
|
||||||
|
Id string `json:"id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetID get user id
|
||||||
|
func (u User) GetID() string {
|
||||||
|
return u.Id
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetService get user Service
|
||||||
|
func (u User) GetService() string {
|
||||||
|
return u.Service
|
||||||
|
}
|
||||||
|
|
||||||
|
type FavoriteCreator struct {
|
||||||
|
FavedSeq int `json:"faved_seq"`
|
||||||
|
Id string `json:"id"`
|
||||||
|
Index string `json:"index"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Service string `json:"service"`
|
||||||
|
Update string `json:"update"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var SiteMap = map[string]string{
|
||||||
|
"patreon": "kemono",
|
||||||
|
"fanbox": "kemono",
|
||||||
|
"gumroad": "kemono",
|
||||||
|
"subscribestar": "kemono",
|
||||||
|
"dlsite": "kemono",
|
||||||
|
"discord": "kemono",
|
||||||
|
"fantia": "kemono",
|
||||||
|
"boosty": "kemono",
|
||||||
|
"afdian": "kemono",
|
||||||
|
"onlyfans": "coomer",
|
||||||
|
"fansly": "coomer",
|
||||||
|
}
|
25
daemons/kemono/utils.go
Normal file
25
daemons/kemono/utils.go
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
package kemono
|
||||||
|
|
||||||
|
import (
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func isImage(ext string) bool {
|
||||||
|
switch ext {
|
||||||
|
case ".apng", ".avif", ".bmp", ".gif", ".ico", ".cur", ".jpg", ".jpeg", ".jfif", ".pjpeg", ".pjp", ".png", ".svg", ".tif", ".tiff", ".webp", ".jpe":
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func SplitHash(str string) (string, error) {
|
||||||
|
parts := strings.Split(str, "/")
|
||||||
|
if len(parts) < 4 {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
ext := filepath.Ext(parts[3])
|
||||||
|
name := parts[3][:len(parts[3])-len(ext)]
|
||||||
|
return name, nil
|
||||||
|
}
|
|
@ -12,7 +12,7 @@ import (
|
||||||
"git.kmsign.ru/royalcat/tstor/pkg/rlog"
|
"git.kmsign.ru/royalcat/tstor/pkg/rlog"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (d *Daemon) Cleanup(ctx context.Context, dryRun bool) ([]string, error) {
|
func (d *Daemon) Cleanup(ctx context.Context, run bool) ([]string, error) {
|
||||||
d.log.Info(ctx, "cleanup started")
|
d.log.Info(ctx, "cleanup started")
|
||||||
|
|
||||||
torrentInfos, err := d.client.qb.Torrent().GetTorrents(ctx, &qbittorrent.TorrentOption{})
|
torrentInfos, err := d.client.qb.Torrent().GetTorrents(ctx, &qbittorrent.TorrentOption{})
|
||||||
|
@ -37,7 +37,7 @@ func (d *Daemon) Cleanup(ctx context.Context, dryRun bool) ([]string, error) {
|
||||||
slog.Any("infohashes", torrentToDelete),
|
slog.Any("infohashes", torrentToDelete),
|
||||||
)
|
)
|
||||||
|
|
||||||
if dryRun {
|
if !run {
|
||||||
d.log.Info(ctx, "dry run, skipping deletion")
|
d.log.Info(ctx, "dry run, skipping deletion")
|
||||||
return torrentToDelete, nil
|
return torrentToDelete, nil
|
||||||
}
|
}
|
|
@ -26,7 +26,7 @@ import (
|
||||||
"go.opentelemetry.io/otel"
|
"go.opentelemetry.io/otel"
|
||||||
)
|
)
|
||||||
|
|
||||||
var trace = otel.Tracer("git.kmsign.ru/royalcat/tstor/src/daemons/qbittorrent")
|
var trace = otel.Tracer("git.kmsign.ru/royalcat/tstor/daemons/qbittorrent")
|
||||||
|
|
||||||
type Daemon struct {
|
type Daemon struct {
|
||||||
proc *os.Process
|
proc *os.Process
|
||||||
|
@ -231,6 +231,9 @@ func (d *Daemon) syncTorrentState(ctx context.Context, file vfs.File, ih metainf
|
||||||
if err == nil {
|
if err == nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
if errors.Is(err, context.DeadlineExceeded) {
|
||||||
|
return err
|
||||||
|
}
|
||||||
log.Error(ctx, "waiting for torrent to be added", rlog.Error(err))
|
log.Error(ctx, "waiting for torrent to be added", rlog.Error(err))
|
||||||
time.Sleep(time.Millisecond * 15)
|
time.Sleep(time.Millisecond * 15)
|
||||||
}
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
type QBitTorrentDaemonMutation {
|
type QBitTorrentDaemonMutation {
|
||||||
cleanup(dryRun: Boolean!): QBitCleanupResponse! @resolver
|
cleanup(run: Boolean!): QBitCleanupResponse! @resolver
|
||||||
}
|
}
|
||||||
|
|
||||||
type QBitCleanupResponse {
|
type QBitCleanupResponse {
|
||||||
|
|
|
@ -3,8 +3,8 @@ package daemons
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"git.kmsign.ru/royalcat/tstor/src/daemons/qbittorrent"
|
"git.kmsign.ru/royalcat/tstor/daemons/qbittorrent"
|
||||||
"git.kmsign.ru/royalcat/tstor/src/daemons/ytdlp"
|
"git.kmsign.ru/royalcat/tstor/daemons/ytdlp"
|
||||||
"git.kmsign.ru/royalcat/tstor/src/vfs"
|
"git.kmsign.ru/royalcat/tstor/src/vfs"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -3,7 +3,7 @@ package model
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"git.kmsign.ru/royalcat/tstor/src/daemons/torrent"
|
"git.kmsign.ru/royalcat/tstor/daemons/torrent"
|
||||||
"git.kmsign.ru/royalcat/tstor/src/vfs"
|
"git.kmsign.ru/royalcat/tstor/src/vfs"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ package model
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"git.kmsign.ru/royalcat/tstor/src/daemons/torrent"
|
"git.kmsign.ru/royalcat/tstor/daemons/torrent"
|
||||||
atorrent "github.com/anacrolix/torrent"
|
atorrent "github.com/anacrolix/torrent"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ package model
|
||||||
import (
|
import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.kmsign.ru/royalcat/tstor/src/daemons/torrent"
|
"git.kmsign.ru/royalcat/tstor/daemons/torrent"
|
||||||
"git.kmsign.ru/royalcat/tstor/src/vfs"
|
"git.kmsign.ru/royalcat/tstor/src/vfs"
|
||||||
torrent1 "github.com/anacrolix/torrent"
|
torrent1 "github.com/anacrolix/torrent"
|
||||||
"github.com/anacrolix/torrent/types"
|
"github.com/anacrolix/torrent/types"
|
||||||
|
|
|
@ -12,8 +12,8 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// Cleanup is the resolver for the cleanup field.
|
// Cleanup is the resolver for the cleanup field.
|
||||||
func (r *qBitTorrentDaemonMutationResolver) Cleanup(ctx context.Context, obj *model.QBitTorrentDaemonMutation, dryRun bool) (*model.QBitCleanupResponse, error) {
|
func (r *qBitTorrentDaemonMutationResolver) Cleanup(ctx context.Context, obj *model.QBitTorrentDaemonMutation, run bool) (*model.QBitCleanupResponse, error) {
|
||||||
hahses, err := r.QBitTorrentDaemon.Cleanup(ctx, dryRun)
|
hahses, err := r.QBitTorrentDaemon.Cleanup(ctx, run)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
package resolver
|
package resolver
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"git.kmsign.ru/royalcat/tstor/src/daemons/qbittorrent"
|
"git.kmsign.ru/royalcat/tstor/daemons/qbittorrent"
|
||||||
"git.kmsign.ru/royalcat/tstor/src/daemons/torrent"
|
"git.kmsign.ru/royalcat/tstor/daemons/torrent"
|
||||||
"git.kmsign.ru/royalcat/tstor/src/vfs"
|
"git.kmsign.ru/royalcat/tstor/src/vfs"
|
||||||
"github.com/go-git/go-billy/v5"
|
"github.com/go-git/go-billy/v5"
|
||||||
)
|
)
|
||||||
|
|
|
@ -10,7 +10,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.kmsign.ru/royalcat/tstor/src/daemons/torrent"
|
"git.kmsign.ru/royalcat/tstor/daemons/torrent"
|
||||||
graph "git.kmsign.ru/royalcat/tstor/src/delivery/graphql"
|
graph "git.kmsign.ru/royalcat/tstor/src/delivery/graphql"
|
||||||
"git.kmsign.ru/royalcat/tstor/src/delivery/graphql/model"
|
"git.kmsign.ru/royalcat/tstor/src/delivery/graphql/model"
|
||||||
tinfohash "github.com/anacrolix/torrent/types/infohash"
|
tinfohash "github.com/anacrolix/torrent/types/infohash"
|
||||||
|
|
|
@ -5,10 +5,10 @@ import (
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"git.kmsign.ru/royalcat/tstor/daemons/qbittorrent"
|
||||||
|
"git.kmsign.ru/royalcat/tstor/daemons/torrent"
|
||||||
"git.kmsign.ru/royalcat/tstor/pkg/rlog"
|
"git.kmsign.ru/royalcat/tstor/pkg/rlog"
|
||||||
"git.kmsign.ru/royalcat/tstor/src/config"
|
"git.kmsign.ru/royalcat/tstor/src/config"
|
||||||
"git.kmsign.ru/royalcat/tstor/src/daemons/qbittorrent"
|
|
||||||
"git.kmsign.ru/royalcat/tstor/src/daemons/torrent"
|
|
||||||
"git.kmsign.ru/royalcat/tstor/src/vfs"
|
"git.kmsign.ru/royalcat/tstor/src/vfs"
|
||||||
echopprof "github.com/labstack/echo-contrib/pprof"
|
echopprof "github.com/labstack/echo-contrib/pprof"
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
|
|
|
@ -4,8 +4,8 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"git.kmsign.ru/royalcat/tstor/src/daemons/qbittorrent"
|
"git.kmsign.ru/royalcat/tstor/daemons/qbittorrent"
|
||||||
"git.kmsign.ru/royalcat/tstor/src/daemons/torrent"
|
"git.kmsign.ru/royalcat/tstor/daemons/torrent"
|
||||||
graph "git.kmsign.ru/royalcat/tstor/src/delivery/graphql"
|
graph "git.kmsign.ru/royalcat/tstor/src/delivery/graphql"
|
||||||
"git.kmsign.ru/royalcat/tstor/src/delivery/graphql/resolver"
|
"git.kmsign.ru/royalcat/tstor/src/delivery/graphql/resolver"
|
||||||
"git.kmsign.ru/royalcat/tstor/src/vfs"
|
"git.kmsign.ru/royalcat/tstor/src/vfs"
|
||||||
|
|
|
@ -57,8 +57,12 @@ interface Progress {
|
||||||
current: Int!
|
current: Int!
|
||||||
total: Int!
|
total: Int!
|
||||||
}
|
}
|
||||||
|
type QBitCleanupResponse {
|
||||||
|
count: Int!
|
||||||
|
hashes: [String!]!
|
||||||
|
}
|
||||||
type QBitTorrentDaemonMutation {
|
type QBitTorrentDaemonMutation {
|
||||||
cleanup(dryRun: Boolean!): Int! @resolver
|
cleanup(run: Boolean!): QBitCleanupResponse! @resolver
|
||||||
}
|
}
|
||||||
type QBitTorrentDaemonQuery {
|
type QBitTorrentDaemonQuery {
|
||||||
torrents: [QTorrent!]! @resolver
|
torrents: [QTorrent!]! @resolver
|
||||||
|
|
Loading…
Reference in a new issue