diff --git a/.gqlgen.yml b/.gqlgen.yml index 521a6cf..06e5f7c 100644 --- a/.gqlgen.yml +++ b/.gqlgen.yml @@ -27,11 +27,11 @@ models: Torrent: extraFields: T: - type: "*git.kmsign.ru/royalcat/tstor/src/daemons/torrent.Controller" + type: "*git.kmsign.ru/royalcat/tstor/daemons/torrent.Controller" TorrentFile: extraFields: F: - type: "*git.kmsign.ru/royalcat/tstor/src/daemons/torrent.FileController" + type: "*git.kmsign.ru/royalcat/tstor/daemons/torrent.FileController" TorrentPeer: extraFields: F: @@ -45,7 +45,7 @@ models: TorrentFS: extraFields: FS: - type: "*git.kmsign.ru/royalcat/tstor/src/daemons/torrent.TorrentFS" + type: "*git.kmsign.ru/royalcat/tstor/daemons/torrent.TorrentFS" ResolverFS: extraFields: FS: diff --git a/Dockerfile b/Dockerfile index 054e197..707f524 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,6 +6,7 @@ COPY go.mod ./ COPY go.sum ./ RUN --mount=type=cache,mode=0777,target=/go/pkg/mod go mod download all +COPY ./daemons ./daemons COPY ./pkg ./pkg COPY ./src ./src COPY ./cmd ./cmd diff --git a/cmd/tstor/main.go b/cmd/tstor/main.go index 58fec83..5d6ff4a 100644 --- a/cmd/tstor/main.go +++ b/cmd/tstor/main.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "io/fs" "log/slog" "net" @@ -13,13 +14,13 @@ import ( "os/signal" "syscall" + "git.kmsign.ru/royalcat/tstor/daemons/qbittorrent" + "git.kmsign.ru/royalcat/tstor/daemons/ytdlp" "git.kmsign.ru/royalcat/tstor/pkg/ctxbilly" wnfs "git.kmsign.ru/royalcat/tstor/pkg/go-nfs" "git.kmsign.ru/royalcat/tstor/pkg/rlog" "git.kmsign.ru/royalcat/tstor/src/config" "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/telemetry" "git.kmsign.ru/royalcat/tstor/src/vfs" @@ -118,6 +119,10 @@ func run(configPath string) error { return err } + vfs.Walk(ctx, sfs, "/", func(path string, info fs.FileInfo, err error) error { + return nil + }) + if conf.Mounts.Fuse.Enabled { mh := fuse.NewHandler(conf.Mounts.Fuse.AllowOther, conf.Mounts.Fuse.Path) err := mh.Mount(sfs) diff --git a/daemons/kemono/client.cfg.yaml b/daemons/kemono/client.cfg.yaml new file mode 100644 index 0000000..5bdc4d6 --- /dev/null +++ b/daemons/kemono/client.cfg.yaml @@ -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 diff --git a/daemons/kemono/client/client.gen.go b/daemons/kemono/client/client.gen.go new file mode 100644 index 0000000..6db212b --- /dev/null +++ b/daemons/kemono/client/client.gen.go @@ -0,0 +1,3176 @@ +// Package client provides primitives to interact with the openapi HTTP API. +// +// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.4.1 DO NOT EDIT. +package client + +import ( + "context" + "encoding/json" + "fmt" + "io" + "net/http" + "net/url" + "strings" + "time" + + "github.com/oapi-codegen/runtime" +) + +const ( + CookieAuthScopes = "cookieAuth.Scopes" +) + +// Defines values for GetAccountFavoritesParamsType. +const ( + Artist GetAccountFavoritesParamsType = "artist" + Post GetAccountFavoritesParamsType = "post" +) + +// GetAccountFavoritesParams defines parameters for GetAccountFavorites. +type GetAccountFavoritesParams struct { + // Type Type of favorites to list (post or creator (artist) ) + Type *GetAccountFavoritesParamsType `form:"type,omitempty" json:"type,omitempty"` +} + +// GetAccountFavoritesParamsType defines parameters for GetAccountFavorites. +type GetAccountFavoritesParamsType string + +// GetDiscordChannelChannelIdParams defines parameters for GetDiscordChannelChannelId. +type GetDiscordChannelChannelIdParams struct { + // O Result offset, stepping of 150 is enforced + O *int `form:"o,omitempty" json:"o,omitempty"` +} + +// GetPostsParams defines parameters for GetPosts. +type GetPostsParams struct { + // Q Search query + Q *string `form:"q,omitempty" json:"q,omitempty"` + + // O Result offset, stepping of 50 is enforced + O *int `form:"o,omitempty" json:"o,omitempty"` +} + +// GetServiceUserCreatorIdParams defines parameters for GetServiceUserCreatorId. +type GetServiceUserCreatorIdParams struct { + // Q Search query + Q *string `form:"q,omitempty" json:"q,omitempty"` + + // O Result offset, stepping of 50 is enforced + O *int `form:"o,omitempty" json:"o,omitempty"` +} + +// RequestEditorFn is the function signature for the RequestEditor callback function +type RequestEditorFn func(ctx context.Context, req *http.Request) error + +// Doer performs HTTP requests. +// +// The standard http.Client implements this interface. +type HttpRequestDoer interface { + Do(req *http.Request) (*http.Response, error) +} + +// Client which conforms to the OpenAPI3 specification for this service. +type Client struct { + // The endpoint of the server conforming to this interface, with scheme, + // https://api.deepmap.com for example. This can contain a path relative + // to the server, such as https://api.deepmap.com/dev-test, and all the + // paths in the swagger spec will be appended to the server. + Server string + + // Doer for performing requests, typically a *http.Client with any + // customized settings, such as certificate chains. + Client HttpRequestDoer + + // A list of callbacks for modifying requests which are generated before sending over + // the network. + RequestEditors []RequestEditorFn +} + +// ClientOption allows setting custom parameters during construction +type ClientOption func(*Client) error + +// Creates a new Client, with reasonable defaults +func NewClient(server string, opts ...ClientOption) (*Client, error) { + // create a client with sane default values + client := Client{ + Server: server, + } + // mutate client and add all optional params + for _, o := range opts { + if err := o(&client); err != nil { + return nil, err + } + } + // ensure the server URL always has a trailing slash + if !strings.HasSuffix(client.Server, "/") { + client.Server += "/" + } + // create httpClient, if not already present + if client.Client == nil { + client.Client = &http.Client{} + } + return &client, nil +} + +// WithHTTPClient allows overriding the default Doer, which is +// automatically created using http.Client. This is useful for tests. +func WithHTTPClient(doer HttpRequestDoer) ClientOption { + return func(c *Client) error { + c.Client = doer + return nil + } +} + +// WithRequestEditorFn allows setting up a callback function, which will be +// called right before sending the request. This can be used to mutate the request. +func WithRequestEditorFn(fn RequestEditorFn) ClientOption { + return func(c *Client) error { + c.RequestEditors = append(c.RequestEditors, fn) + return nil + } +} + +// The interface specification for the client above. +type ClientInterface interface { + // GetAccountFavorites request + GetAccountFavorites(ctx context.Context, params *GetAccountFavoritesParams, reqEditors ...RequestEditorFn) (*http.Response, error) + + // GetAppVersion request + GetAppVersion(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) + + // GetCreatorsTxt request + GetCreatorsTxt(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) + + // GetDiscordChannelLookupDiscordServer request + GetDiscordChannelLookupDiscordServer(ctx context.Context, discordServer string, reqEditors ...RequestEditorFn) (*http.Response, error) + + // GetDiscordChannelChannelId request + GetDiscordChannelChannelId(ctx context.Context, channelId string, params *GetDiscordChannelChannelIdParams, reqEditors ...RequestEditorFn) (*http.Response, error) + + // DeleteFavoritesCreatorServiceCreatorId request + DeleteFavoritesCreatorServiceCreatorId(ctx context.Context, service string, creatorId string, reqEditors ...RequestEditorFn) (*http.Response, error) + + // PostFavoritesCreatorServiceCreatorId request + PostFavoritesCreatorServiceCreatorId(ctx context.Context, service string, creatorId string, reqEditors ...RequestEditorFn) (*http.Response, error) + + // DeleteFavoritesPostServiceCreatorIdPostId request + DeleteFavoritesPostServiceCreatorIdPostId(ctx context.Context, service string, creatorId string, postId string, reqEditors ...RequestEditorFn) (*http.Response, error) + + // PostFavoritesPostServiceCreatorIdPostId request + PostFavoritesPostServiceCreatorIdPostId(ctx context.Context, service string, creatorId string, postId string, reqEditors ...RequestEditorFn) (*http.Response, error) + + // GetPosts request + GetPosts(ctx context.Context, params *GetPostsParams, reqEditors ...RequestEditorFn) (*http.Response, error) + + // GetSearchHashFileHash request + GetSearchHashFileHash(ctx context.Context, fileHash string, reqEditors ...RequestEditorFn) (*http.Response, error) + + // GetServiceUserCreatorId request + GetServiceUserCreatorId(ctx context.Context, service string, creatorId string, params *GetServiceUserCreatorIdParams, reqEditors ...RequestEditorFn) (*http.Response, error) + + // GetServiceUserCreatorIdAnnouncements request + GetServiceUserCreatorIdAnnouncements(ctx context.Context, service string, creatorId string, reqEditors ...RequestEditorFn) (*http.Response, error) + + // GetServiceUserCreatorIdFancards request + GetServiceUserCreatorIdFancards(ctx context.Context, service string, creatorId string, reqEditors ...RequestEditorFn) (*http.Response, error) + + // GetServiceUserCreatorIdLinks request + GetServiceUserCreatorIdLinks(ctx context.Context, service string, creatorId string, reqEditors ...RequestEditorFn) (*http.Response, error) + + // GetServiceUserCreatorIdPostPostId request + GetServiceUserCreatorIdPostPostId(ctx context.Context, service string, creatorId string, postId string, reqEditors ...RequestEditorFn) (*http.Response, error) + + // GetServiceUserCreatorIdPostPostIdComments request + GetServiceUserCreatorIdPostPostIdComments(ctx context.Context, service string, creatorId string, postId string, reqEditors ...RequestEditorFn) (*http.Response, error) + + // GetServiceUserCreatorIdPostPostIdRevisions request + GetServiceUserCreatorIdPostPostIdRevisions(ctx context.Context, service string, creatorId string, postId string, reqEditors ...RequestEditorFn) (*http.Response, error) + + // GetServiceUserCreatorIdPostPostFlag request + GetServiceUserCreatorIdPostPostFlag(ctx context.Context, service string, creatorId string, post string, reqEditors ...RequestEditorFn) (*http.Response, error) + + // PostServiceUserCreatorIdPostPostFlag request + PostServiceUserCreatorIdPostPostFlag(ctx context.Context, service string, creatorId string, post string, reqEditors ...RequestEditorFn) (*http.Response, error) + + // GetServiceUserCreatorIdProfile request + GetServiceUserCreatorIdProfile(ctx context.Context, service string, creatorId string, reqEditors ...RequestEditorFn) (*http.Response, error) +} + +func (c *Client) GetAccountFavorites(ctx context.Context, params *GetAccountFavoritesParams, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewGetAccountFavoritesRequest(c.Server, params) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) GetAppVersion(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewGetAppVersionRequest(c.Server) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) GetCreatorsTxt(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewGetCreatorsTxtRequest(c.Server) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) GetDiscordChannelLookupDiscordServer(ctx context.Context, discordServer string, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewGetDiscordChannelLookupDiscordServerRequest(c.Server, discordServer) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) GetDiscordChannelChannelId(ctx context.Context, channelId string, params *GetDiscordChannelChannelIdParams, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewGetDiscordChannelChannelIdRequest(c.Server, channelId, params) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) DeleteFavoritesCreatorServiceCreatorId(ctx context.Context, service string, creatorId string, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewDeleteFavoritesCreatorServiceCreatorIdRequest(c.Server, service, creatorId) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) PostFavoritesCreatorServiceCreatorId(ctx context.Context, service string, creatorId string, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewPostFavoritesCreatorServiceCreatorIdRequest(c.Server, service, creatorId) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) DeleteFavoritesPostServiceCreatorIdPostId(ctx context.Context, service string, creatorId string, postId string, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewDeleteFavoritesPostServiceCreatorIdPostIdRequest(c.Server, service, creatorId, postId) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) PostFavoritesPostServiceCreatorIdPostId(ctx context.Context, service string, creatorId string, postId string, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewPostFavoritesPostServiceCreatorIdPostIdRequest(c.Server, service, creatorId, postId) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) GetPosts(ctx context.Context, params *GetPostsParams, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewGetPostsRequest(c.Server, params) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) GetSearchHashFileHash(ctx context.Context, fileHash string, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewGetSearchHashFileHashRequest(c.Server, fileHash) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) GetServiceUserCreatorId(ctx context.Context, service string, creatorId string, params *GetServiceUserCreatorIdParams, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewGetServiceUserCreatorIdRequest(c.Server, service, creatorId, params) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) GetServiceUserCreatorIdAnnouncements(ctx context.Context, service string, creatorId string, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewGetServiceUserCreatorIdAnnouncementsRequest(c.Server, service, creatorId) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) GetServiceUserCreatorIdFancards(ctx context.Context, service string, creatorId string, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewGetServiceUserCreatorIdFancardsRequest(c.Server, service, creatorId) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) GetServiceUserCreatorIdLinks(ctx context.Context, service string, creatorId string, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewGetServiceUserCreatorIdLinksRequest(c.Server, service, creatorId) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) GetServiceUserCreatorIdPostPostId(ctx context.Context, service string, creatorId string, postId string, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewGetServiceUserCreatorIdPostPostIdRequest(c.Server, service, creatorId, postId) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) GetServiceUserCreatorIdPostPostIdComments(ctx context.Context, service string, creatorId string, postId string, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewGetServiceUserCreatorIdPostPostIdCommentsRequest(c.Server, service, creatorId, postId) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) GetServiceUserCreatorIdPostPostIdRevisions(ctx context.Context, service string, creatorId string, postId string, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewGetServiceUserCreatorIdPostPostIdRevisionsRequest(c.Server, service, creatorId, postId) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) GetServiceUserCreatorIdPostPostFlag(ctx context.Context, service string, creatorId string, post string, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewGetServiceUserCreatorIdPostPostFlagRequest(c.Server, service, creatorId, post) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) PostServiceUserCreatorIdPostPostFlag(ctx context.Context, service string, creatorId string, post string, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewPostServiceUserCreatorIdPostPostFlagRequest(c.Server, service, creatorId, post) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) GetServiceUserCreatorIdProfile(ctx context.Context, service string, creatorId string, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewGetServiceUserCreatorIdProfileRequest(c.Server, service, creatorId) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +// NewGetAccountFavoritesRequest generates requests for GetAccountFavorites +func NewGetAccountFavoritesRequest(server string, params *GetAccountFavoritesParams) (*http.Request, error) { + var err error + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/account/favorites") + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + if params != nil { + queryValues := queryURL.Query() + + if params.Type != nil { + + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "type", runtime.ParamLocationQuery, *params.Type); err != nil { + return nil, err + } else if parsed, err := url.ParseQuery(queryFrag); err != nil { + return nil, err + } else { + for k, v := range parsed { + for _, v2 := range v { + queryValues.Add(k, v2) + } + } + } + + } + + queryURL.RawQuery = queryValues.Encode() + } + + req, err := http.NewRequest("GET", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + +// NewGetAppVersionRequest generates requests for GetAppVersion +func NewGetAppVersionRequest(server string) (*http.Request, error) { + var err error + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/app_version") + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("GET", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + +// NewGetCreatorsTxtRequest generates requests for GetCreatorsTxt +func NewGetCreatorsTxtRequest(server string) (*http.Request, error) { + var err error + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/creators.txt") + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("GET", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + +// NewGetDiscordChannelLookupDiscordServerRequest generates requests for GetDiscordChannelLookupDiscordServer +func NewGetDiscordChannelLookupDiscordServerRequest(server string, discordServer string) (*http.Request, error) { + var err error + + var pathParam0 string + + pathParam0, err = runtime.StyleParamWithLocation("simple", false, "discord_server", runtime.ParamLocationPath, discordServer) + if err != nil { + return nil, err + } + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/discord/channel/lookup/%s", pathParam0) + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("GET", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + +// NewGetDiscordChannelChannelIdRequest generates requests for GetDiscordChannelChannelId +func NewGetDiscordChannelChannelIdRequest(server string, channelId string, params *GetDiscordChannelChannelIdParams) (*http.Request, error) { + var err error + + var pathParam0 string + + pathParam0, err = runtime.StyleParamWithLocation("simple", false, "channel_id", runtime.ParamLocationPath, channelId) + if err != nil { + return nil, err + } + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/discord/channel/%s", pathParam0) + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + if params != nil { + queryValues := queryURL.Query() + + if params.O != nil { + + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "o", runtime.ParamLocationQuery, *params.O); err != nil { + return nil, err + } else if parsed, err := url.ParseQuery(queryFrag); err != nil { + return nil, err + } else { + for k, v := range parsed { + for _, v2 := range v { + queryValues.Add(k, v2) + } + } + } + + } + + queryURL.RawQuery = queryValues.Encode() + } + + req, err := http.NewRequest("GET", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + +// NewDeleteFavoritesCreatorServiceCreatorIdRequest generates requests for DeleteFavoritesCreatorServiceCreatorId +func NewDeleteFavoritesCreatorServiceCreatorIdRequest(server string, service string, creatorId string) (*http.Request, error) { + var err error + + var pathParam0 string + + pathParam0, err = runtime.StyleParamWithLocation("simple", false, "service", runtime.ParamLocationPath, service) + if err != nil { + return nil, err + } + + var pathParam1 string + + pathParam1, err = runtime.StyleParamWithLocation("simple", false, "creator_id", runtime.ParamLocationPath, creatorId) + if err != nil { + return nil, err + } + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/favorites/creator/%s/%s", pathParam0, pathParam1) + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("DELETE", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + +// NewPostFavoritesCreatorServiceCreatorIdRequest generates requests for PostFavoritesCreatorServiceCreatorId +func NewPostFavoritesCreatorServiceCreatorIdRequest(server string, service string, creatorId string) (*http.Request, error) { + var err error + + var pathParam0 string + + pathParam0, err = runtime.StyleParamWithLocation("simple", false, "service", runtime.ParamLocationPath, service) + if err != nil { + return nil, err + } + + var pathParam1 string + + pathParam1, err = runtime.StyleParamWithLocation("simple", false, "creator_id", runtime.ParamLocationPath, creatorId) + if err != nil { + return nil, err + } + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/favorites/creator/%s/%s", pathParam0, pathParam1) + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("POST", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + +// NewDeleteFavoritesPostServiceCreatorIdPostIdRequest generates requests for DeleteFavoritesPostServiceCreatorIdPostId +func NewDeleteFavoritesPostServiceCreatorIdPostIdRequest(server string, service string, creatorId string, postId string) (*http.Request, error) { + var err error + + var pathParam0 string + + pathParam0, err = runtime.StyleParamWithLocation("simple", false, "service", runtime.ParamLocationPath, service) + if err != nil { + return nil, err + } + + var pathParam1 string + + pathParam1, err = runtime.StyleParamWithLocation("simple", false, "creator_id", runtime.ParamLocationPath, creatorId) + if err != nil { + return nil, err + } + + var pathParam2 string + + pathParam2, err = runtime.StyleParamWithLocation("simple", false, "post_id", runtime.ParamLocationPath, postId) + if err != nil { + return nil, err + } + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/favorites/post/%s/%s/%s", pathParam0, pathParam1, pathParam2) + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("DELETE", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + +// NewPostFavoritesPostServiceCreatorIdPostIdRequest generates requests for PostFavoritesPostServiceCreatorIdPostId +func NewPostFavoritesPostServiceCreatorIdPostIdRequest(server string, service string, creatorId string, postId string) (*http.Request, error) { + var err error + + var pathParam0 string + + pathParam0, err = runtime.StyleParamWithLocation("simple", false, "service", runtime.ParamLocationPath, service) + if err != nil { + return nil, err + } + + var pathParam1 string + + pathParam1, err = runtime.StyleParamWithLocation("simple", false, "creator_id", runtime.ParamLocationPath, creatorId) + if err != nil { + return nil, err + } + + var pathParam2 string + + pathParam2, err = runtime.StyleParamWithLocation("simple", false, "post_id", runtime.ParamLocationPath, postId) + if err != nil { + return nil, err + } + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/favorites/post/%s/%s/%s", pathParam0, pathParam1, pathParam2) + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("POST", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + +// NewGetPostsRequest generates requests for GetPosts +func NewGetPostsRequest(server string, params *GetPostsParams) (*http.Request, error) { + var err error + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/posts") + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + if params != nil { + queryValues := queryURL.Query() + + if params.Q != nil { + + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "q", runtime.ParamLocationQuery, *params.Q); err != nil { + return nil, err + } else if parsed, err := url.ParseQuery(queryFrag); err != nil { + return nil, err + } else { + for k, v := range parsed { + for _, v2 := range v { + queryValues.Add(k, v2) + } + } + } + + } + + if params.O != nil { + + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "o", runtime.ParamLocationQuery, *params.O); err != nil { + return nil, err + } else if parsed, err := url.ParseQuery(queryFrag); err != nil { + return nil, err + } else { + for k, v := range parsed { + for _, v2 := range v { + queryValues.Add(k, v2) + } + } + } + + } + + queryURL.RawQuery = queryValues.Encode() + } + + req, err := http.NewRequest("GET", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + +// NewGetSearchHashFileHashRequest generates requests for GetSearchHashFileHash +func NewGetSearchHashFileHashRequest(server string, fileHash string) (*http.Request, error) { + var err error + + var pathParam0 string + + pathParam0, err = runtime.StyleParamWithLocation("simple", false, "file_hash", runtime.ParamLocationPath, fileHash) + if err != nil { + return nil, err + } + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/search_hash/%s", pathParam0) + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("GET", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + +// NewGetServiceUserCreatorIdRequest generates requests for GetServiceUserCreatorId +func NewGetServiceUserCreatorIdRequest(server string, service string, creatorId string, params *GetServiceUserCreatorIdParams) (*http.Request, error) { + var err error + + var pathParam0 string + + pathParam0, err = runtime.StyleParamWithLocation("simple", false, "service", runtime.ParamLocationPath, service) + if err != nil { + return nil, err + } + + var pathParam1 string + + pathParam1, err = runtime.StyleParamWithLocation("simple", false, "creator_id", runtime.ParamLocationPath, creatorId) + if err != nil { + return nil, err + } + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/%s/user/%s", pathParam0, pathParam1) + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + if params != nil { + queryValues := queryURL.Query() + + if params.Q != nil { + + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "q", runtime.ParamLocationQuery, *params.Q); err != nil { + return nil, err + } else if parsed, err := url.ParseQuery(queryFrag); err != nil { + return nil, err + } else { + for k, v := range parsed { + for _, v2 := range v { + queryValues.Add(k, v2) + } + } + } + + } + + if params.O != nil { + + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "o", runtime.ParamLocationQuery, *params.O); err != nil { + return nil, err + } else if parsed, err := url.ParseQuery(queryFrag); err != nil { + return nil, err + } else { + for k, v := range parsed { + for _, v2 := range v { + queryValues.Add(k, v2) + } + } + } + + } + + queryURL.RawQuery = queryValues.Encode() + } + + req, err := http.NewRequest("GET", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + +// NewGetServiceUserCreatorIdAnnouncementsRequest generates requests for GetServiceUserCreatorIdAnnouncements +func NewGetServiceUserCreatorIdAnnouncementsRequest(server string, service string, creatorId string) (*http.Request, error) { + var err error + + var pathParam0 string + + pathParam0, err = runtime.StyleParamWithLocation("simple", false, "service", runtime.ParamLocationPath, service) + if err != nil { + return nil, err + } + + var pathParam1 string + + pathParam1, err = runtime.StyleParamWithLocation("simple", false, "creator_id", runtime.ParamLocationPath, creatorId) + if err != nil { + return nil, err + } + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/%s/user/%s/announcements", pathParam0, pathParam1) + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("GET", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + +// NewGetServiceUserCreatorIdFancardsRequest generates requests for GetServiceUserCreatorIdFancards +func NewGetServiceUserCreatorIdFancardsRequest(server string, service string, creatorId string) (*http.Request, error) { + var err error + + var pathParam0 string + + pathParam0, err = runtime.StyleParamWithLocation("simple", false, "service", runtime.ParamLocationPath, service) + if err != nil { + return nil, err + } + + var pathParam1 string + + pathParam1, err = runtime.StyleParamWithLocation("simple", false, "creator_id", runtime.ParamLocationPath, creatorId) + if err != nil { + return nil, err + } + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/%s/user/%s/fancards", pathParam0, pathParam1) + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("GET", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + +// NewGetServiceUserCreatorIdLinksRequest generates requests for GetServiceUserCreatorIdLinks +func NewGetServiceUserCreatorIdLinksRequest(server string, service string, creatorId string) (*http.Request, error) { + var err error + + var pathParam0 string + + pathParam0, err = runtime.StyleParamWithLocation("simple", false, "service", runtime.ParamLocationPath, service) + if err != nil { + return nil, err + } + + var pathParam1 string + + pathParam1, err = runtime.StyleParamWithLocation("simple", false, "creator_id", runtime.ParamLocationPath, creatorId) + if err != nil { + return nil, err + } + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/%s/user/%s/links", pathParam0, pathParam1) + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("GET", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + +// NewGetServiceUserCreatorIdPostPostIdRequest generates requests for GetServiceUserCreatorIdPostPostId +func NewGetServiceUserCreatorIdPostPostIdRequest(server string, service string, creatorId string, postId string) (*http.Request, error) { + var err error + + var pathParam0 string + + pathParam0, err = runtime.StyleParamWithLocation("simple", false, "service", runtime.ParamLocationPath, service) + if err != nil { + return nil, err + } + + var pathParam1 string + + pathParam1, err = runtime.StyleParamWithLocation("simple", false, "creator_id", runtime.ParamLocationPath, creatorId) + if err != nil { + return nil, err + } + + var pathParam2 string + + pathParam2, err = runtime.StyleParamWithLocation("simple", false, "post_id", runtime.ParamLocationPath, postId) + if err != nil { + return nil, err + } + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/%s/user/%s/post/%s", pathParam0, pathParam1, pathParam2) + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("GET", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + +// NewGetServiceUserCreatorIdPostPostIdCommentsRequest generates requests for GetServiceUserCreatorIdPostPostIdComments +func NewGetServiceUserCreatorIdPostPostIdCommentsRequest(server string, service string, creatorId string, postId string) (*http.Request, error) { + var err error + + var pathParam0 string + + pathParam0, err = runtime.StyleParamWithLocation("simple", false, "service", runtime.ParamLocationPath, service) + if err != nil { + return nil, err + } + + var pathParam1 string + + pathParam1, err = runtime.StyleParamWithLocation("simple", false, "creator_id", runtime.ParamLocationPath, creatorId) + if err != nil { + return nil, err + } + + var pathParam2 string + + pathParam2, err = runtime.StyleParamWithLocation("simple", false, "post_id", runtime.ParamLocationPath, postId) + if err != nil { + return nil, err + } + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/%s/user/%s/post/%s/comments", pathParam0, pathParam1, pathParam2) + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("GET", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + +// NewGetServiceUserCreatorIdPostPostIdRevisionsRequest generates requests for GetServiceUserCreatorIdPostPostIdRevisions +func NewGetServiceUserCreatorIdPostPostIdRevisionsRequest(server string, service string, creatorId string, postId string) (*http.Request, error) { + var err error + + var pathParam0 string + + pathParam0, err = runtime.StyleParamWithLocation("simple", false, "service", runtime.ParamLocationPath, service) + if err != nil { + return nil, err + } + + var pathParam1 string + + pathParam1, err = runtime.StyleParamWithLocation("simple", false, "creator_id", runtime.ParamLocationPath, creatorId) + if err != nil { + return nil, err + } + + var pathParam2 string + + pathParam2, err = runtime.StyleParamWithLocation("simple", false, "post_id", runtime.ParamLocationPath, postId) + if err != nil { + return nil, err + } + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/%s/user/%s/post/%s/revisions", pathParam0, pathParam1, pathParam2) + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("GET", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + +// NewGetServiceUserCreatorIdPostPostFlagRequest generates requests for GetServiceUserCreatorIdPostPostFlag +func NewGetServiceUserCreatorIdPostPostFlagRequest(server string, service string, creatorId string, post string) (*http.Request, error) { + var err error + + var pathParam0 string + + pathParam0, err = runtime.StyleParamWithLocation("simple", false, "service", runtime.ParamLocationPath, service) + if err != nil { + return nil, err + } + + var pathParam1 string + + pathParam1, err = runtime.StyleParamWithLocation("simple", false, "creator_id", runtime.ParamLocationPath, creatorId) + if err != nil { + return nil, err + } + + var pathParam2 string + + pathParam2, err = runtime.StyleParamWithLocation("simple", false, "post", runtime.ParamLocationPath, post) + if err != nil { + return nil, err + } + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/%s/user/%s/post/%s/flag", pathParam0, pathParam1, pathParam2) + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("GET", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + +// NewPostServiceUserCreatorIdPostPostFlagRequest generates requests for PostServiceUserCreatorIdPostPostFlag +func NewPostServiceUserCreatorIdPostPostFlagRequest(server string, service string, creatorId string, post string) (*http.Request, error) { + var err error + + var pathParam0 string + + pathParam0, err = runtime.StyleParamWithLocation("simple", false, "service", runtime.ParamLocationPath, service) + if err != nil { + return nil, err + } + + var pathParam1 string + + pathParam1, err = runtime.StyleParamWithLocation("simple", false, "creator_id", runtime.ParamLocationPath, creatorId) + if err != nil { + return nil, err + } + + var pathParam2 string + + pathParam2, err = runtime.StyleParamWithLocation("simple", false, "post", runtime.ParamLocationPath, post) + if err != nil { + return nil, err + } + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/%s/user/%s/post/%s/flag", pathParam0, pathParam1, pathParam2) + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("POST", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + +// NewGetServiceUserCreatorIdProfileRequest generates requests for GetServiceUserCreatorIdProfile +func NewGetServiceUserCreatorIdProfileRequest(server string, service string, creatorId string) (*http.Request, error) { + var err error + + var pathParam0 string + + pathParam0, err = runtime.StyleParamWithLocation("simple", false, "service", runtime.ParamLocationPath, service) + if err != nil { + return nil, err + } + + var pathParam1 string + + pathParam1, err = runtime.StyleParamWithLocation("simple", false, "creator_id", runtime.ParamLocationPath, creatorId) + if err != nil { + return nil, err + } + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/%s/user/%s/profile", pathParam0, pathParam1) + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("GET", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + +func (c *Client) applyEditors(ctx context.Context, req *http.Request, additionalEditors []RequestEditorFn) error { + for _, r := range c.RequestEditors { + if err := r(ctx, req); err != nil { + return err + } + } + for _, r := range additionalEditors { + if err := r(ctx, req); err != nil { + return err + } + } + return nil +} + +// ClientWithResponses builds on ClientInterface to offer response payloads +type ClientWithResponses struct { + ClientInterface +} + +// NewClientWithResponses creates a new ClientWithResponses, which wraps +// Client with return type handling +func NewClientWithResponses(server string, opts ...ClientOption) (*ClientWithResponses, error) { + client, err := NewClient(server, opts...) + if err != nil { + return nil, err + } + return &ClientWithResponses{client}, nil +} + +// WithBaseURL overrides the baseURL. +func WithBaseURL(baseURL string) ClientOption { + return func(c *Client) error { + newBaseURL, err := url.Parse(baseURL) + if err != nil { + return err + } + c.Server = newBaseURL.String() + return nil + } +} + +// ClientWithResponsesInterface is the interface specification for the client with responses above. +type ClientWithResponsesInterface interface { + // GetAccountFavoritesWithResponse request + GetAccountFavoritesWithResponse(ctx context.Context, params *GetAccountFavoritesParams, reqEditors ...RequestEditorFn) (*GetAccountFavoritesResponse, error) + + // GetAppVersionWithResponse request + GetAppVersionWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetAppVersionResponse, error) + + // GetCreatorsTxtWithResponse request + GetCreatorsTxtWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetCreatorsTxtResponse, error) + + // GetDiscordChannelLookupDiscordServerWithResponse request + GetDiscordChannelLookupDiscordServerWithResponse(ctx context.Context, discordServer string, reqEditors ...RequestEditorFn) (*GetDiscordChannelLookupDiscordServerResponse, error) + + // GetDiscordChannelChannelIdWithResponse request + GetDiscordChannelChannelIdWithResponse(ctx context.Context, channelId string, params *GetDiscordChannelChannelIdParams, reqEditors ...RequestEditorFn) (*GetDiscordChannelChannelIdResponse, error) + + // DeleteFavoritesCreatorServiceCreatorIdWithResponse request + DeleteFavoritesCreatorServiceCreatorIdWithResponse(ctx context.Context, service string, creatorId string, reqEditors ...RequestEditorFn) (*DeleteFavoritesCreatorServiceCreatorIdResponse, error) + + // PostFavoritesCreatorServiceCreatorIdWithResponse request + PostFavoritesCreatorServiceCreatorIdWithResponse(ctx context.Context, service string, creatorId string, reqEditors ...RequestEditorFn) (*PostFavoritesCreatorServiceCreatorIdResponse, error) + + // DeleteFavoritesPostServiceCreatorIdPostIdWithResponse request + DeleteFavoritesPostServiceCreatorIdPostIdWithResponse(ctx context.Context, service string, creatorId string, postId string, reqEditors ...RequestEditorFn) (*DeleteFavoritesPostServiceCreatorIdPostIdResponse, error) + + // PostFavoritesPostServiceCreatorIdPostIdWithResponse request + PostFavoritesPostServiceCreatorIdPostIdWithResponse(ctx context.Context, service string, creatorId string, postId string, reqEditors ...RequestEditorFn) (*PostFavoritesPostServiceCreatorIdPostIdResponse, error) + + // GetPostsWithResponse request + GetPostsWithResponse(ctx context.Context, params *GetPostsParams, reqEditors ...RequestEditorFn) (*GetPostsResponse, error) + + // GetSearchHashFileHashWithResponse request + GetSearchHashFileHashWithResponse(ctx context.Context, fileHash string, reqEditors ...RequestEditorFn) (*GetSearchHashFileHashResponse, error) + + // GetServiceUserCreatorIdWithResponse request + GetServiceUserCreatorIdWithResponse(ctx context.Context, service string, creatorId string, params *GetServiceUserCreatorIdParams, reqEditors ...RequestEditorFn) (*GetServiceUserCreatorIdResponse, error) + + // GetServiceUserCreatorIdAnnouncementsWithResponse request + GetServiceUserCreatorIdAnnouncementsWithResponse(ctx context.Context, service string, creatorId string, reqEditors ...RequestEditorFn) (*GetServiceUserCreatorIdAnnouncementsResponse, error) + + // GetServiceUserCreatorIdFancardsWithResponse request + GetServiceUserCreatorIdFancardsWithResponse(ctx context.Context, service string, creatorId string, reqEditors ...RequestEditorFn) (*GetServiceUserCreatorIdFancardsResponse, error) + + // GetServiceUserCreatorIdLinksWithResponse request + GetServiceUserCreatorIdLinksWithResponse(ctx context.Context, service string, creatorId string, reqEditors ...RequestEditorFn) (*GetServiceUserCreatorIdLinksResponse, error) + + // GetServiceUserCreatorIdPostPostIdWithResponse request + GetServiceUserCreatorIdPostPostIdWithResponse(ctx context.Context, service string, creatorId string, postId string, reqEditors ...RequestEditorFn) (*GetServiceUserCreatorIdPostPostIdResponse, error) + + // GetServiceUserCreatorIdPostPostIdCommentsWithResponse request + GetServiceUserCreatorIdPostPostIdCommentsWithResponse(ctx context.Context, service string, creatorId string, postId string, reqEditors ...RequestEditorFn) (*GetServiceUserCreatorIdPostPostIdCommentsResponse, error) + + // GetServiceUserCreatorIdPostPostIdRevisionsWithResponse request + GetServiceUserCreatorIdPostPostIdRevisionsWithResponse(ctx context.Context, service string, creatorId string, postId string, reqEditors ...RequestEditorFn) (*GetServiceUserCreatorIdPostPostIdRevisionsResponse, error) + + // GetServiceUserCreatorIdPostPostFlagWithResponse request + GetServiceUserCreatorIdPostPostFlagWithResponse(ctx context.Context, service string, creatorId string, post string, reqEditors ...RequestEditorFn) (*GetServiceUserCreatorIdPostPostFlagResponse, error) + + // PostServiceUserCreatorIdPostPostFlagWithResponse request + PostServiceUserCreatorIdPostPostFlagWithResponse(ctx context.Context, service string, creatorId string, post string, reqEditors ...RequestEditorFn) (*PostServiceUserCreatorIdPostPostFlagResponse, error) + + // GetServiceUserCreatorIdProfileWithResponse request + GetServiceUserCreatorIdProfileWithResponse(ctx context.Context, service string, creatorId string, reqEditors ...RequestEditorFn) (*GetServiceUserCreatorIdProfileResponse, error) +} + +type GetAccountFavoritesResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *[]struct { + // FavedSeq The sequence number of the favorite + FavedSeq *int `json:"faved_seq,omitempty"` + + // Id The ID of the favorite (post or creator) + Id *string `json:"id,omitempty"` + + // Indexed Timestamp when the creator was indexed isoformat + Indexed *string `json:"indexed,omitempty"` + + // LastImported Timestamp when the creator was last imported + LastImported *string `json:"last_imported,omitempty"` + + // Name The name of the creator + Name *string `json:"name,omitempty"` + + // Service The service where the creator is located + Service *string `json:"service,omitempty"` + + // Updated Timestamp when the creator was last updated + Updated *string `json:"updated,omitempty"` + } +} + +// Status returns HTTPResponse.Status +func (r GetAccountFavoritesResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r GetAccountFavoritesResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type GetAppVersionResponse struct { + Body []byte + HTTPResponse *http.Response +} + +// Status returns HTTPResponse.Status +func (r GetAppVersionResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r GetAppVersionResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type GetCreatorsTxtResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *[]struct { + // Favorited The number of times this creator has been favorited + Favorited *int `json:"favorited,omitempty"` + + // Id The ID of the creator + Id *string `json:"id,omitempty"` + + // Indexed Timestamp when the creator was indexed, Unix time as integer + Indexed *float32 `json:"indexed,omitempty"` + + // Name The name of the creator + Name *string `json:"name,omitempty"` + + // Service The service for the creator + Service *string `json:"service,omitempty"` + + // Updated Timestamp when the creator was last updated, Unix time as integer + Updated *float32 `json:"updated,omitempty"` + } +} + +// Status returns HTTPResponse.Status +func (r GetCreatorsTxtResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r GetCreatorsTxtResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type GetDiscordChannelLookupDiscordServerResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *[]struct { + Id *string `json:"id,omitempty"` + Name *string `json:"name,omitempty"` + } +} + +// Status returns HTTPResponse.Status +func (r GetDiscordChannelLookupDiscordServerResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r GetDiscordChannelLookupDiscordServerResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type GetDiscordChannelChannelIdResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *[]struct { + Added *time.Time `json:"added,omitempty"` + Attachments *[]struct { + Name *string `json:"name,omitempty"` + Path *string `json:"path,omitempty"` + } `json:"attachments,omitempty"` + Author *struct { + Avatar *string `json:"avatar,omitempty"` + Discriminator *string `json:"discriminator,omitempty"` + Id *string `json:"id,omitempty"` + PublicFlags *int `json:"public_flags,omitempty"` + Username *string `json:"username,omitempty"` + } `json:"author,omitempty"` + Channel *string `json:"channel,omitempty"` + Content *string `json:"content,omitempty"` + Edited *time.Time `json:"edited,omitempty"` + Embeds *[]interface{} `json:"embeds,omitempty"` + Id *string `json:"id,omitempty"` + Mentions *[]interface{} `json:"mentions,omitempty"` + Published *time.Time `json:"published,omitempty"` + Server *string `json:"server,omitempty"` + } +} + +// Status returns HTTPResponse.Status +func (r GetDiscordChannelChannelIdResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r GetDiscordChannelChannelIdResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type DeleteFavoritesCreatorServiceCreatorIdResponse struct { + Body []byte + HTTPResponse *http.Response +} + +// Status returns HTTPResponse.Status +func (r DeleteFavoritesCreatorServiceCreatorIdResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r DeleteFavoritesCreatorServiceCreatorIdResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type PostFavoritesCreatorServiceCreatorIdResponse struct { + Body []byte + HTTPResponse *http.Response +} + +// Status returns HTTPResponse.Status +func (r PostFavoritesCreatorServiceCreatorIdResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r PostFavoritesCreatorServiceCreatorIdResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type DeleteFavoritesPostServiceCreatorIdPostIdResponse struct { + Body []byte + HTTPResponse *http.Response +} + +// Status returns HTTPResponse.Status +func (r DeleteFavoritesPostServiceCreatorIdPostIdResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r DeleteFavoritesPostServiceCreatorIdPostIdResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type PostFavoritesPostServiceCreatorIdPostIdResponse struct { + Body []byte + HTTPResponse *http.Response +} + +// Status returns HTTPResponse.Status +func (r PostFavoritesPostServiceCreatorIdPostIdResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r PostFavoritesPostServiceCreatorIdPostIdResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type GetPostsResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *[]struct { + Added *time.Time `json:"added,omitempty"` + Attachments *[]struct { + Name *string `json:"name,omitempty"` + Path *string `json:"path,omitempty"` + } `json:"attachments,omitempty"` + Content *string `json:"content,omitempty"` + Edited *time.Time `json:"edited,omitempty"` + Embed *map[string]interface{} `json:"embed,omitempty"` + File *struct { + Name *string `json:"name,omitempty"` + Path *string `json:"path,omitempty"` + } `json:"file,omitempty"` + Id *string `json:"id,omitempty"` + Published *time.Time `json:"published,omitempty"` + Service *string `json:"service,omitempty"` + SharedFile *bool `json:"shared_file,omitempty"` + Title *string `json:"title,omitempty"` + User *string `json:"user,omitempty"` + } +} + +// Status returns HTTPResponse.Status +func (r GetPostsResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r GetPostsResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type GetSearchHashFileHashResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *struct { + Added *time.Time `json:"added,omitempty"` + Ctime *time.Time `json:"ctime,omitempty"` + DiscordPosts *[]struct { + Attachments *[]struct { + Name *string `json:"name,omitempty"` + Path *string `json:"path,omitempty"` + } `json:"attachments,omitempty"` + Channel *string `json:"channel,omitempty"` + Embeds *[]interface{} `json:"embeds,omitempty"` + FileId *int `json:"file_id,omitempty"` + Id *string `json:"id,omitempty"` + Mentions *[]interface{} `json:"mentions,omitempty"` + Published *time.Time `json:"published,omitempty"` + Server *string `json:"server,omitempty"` + Substring *string `json:"substring,omitempty"` + } `json:"discord_posts,omitempty"` + Ext *string `json:"ext,omitempty"` + Hash *string `json:"hash,omitempty"` + Id *int `json:"id,omitempty"` + Ihash *string `json:"ihash,omitempty"` + Mime *string `json:"mime,omitempty"` + Mtime *time.Time `json:"mtime,omitempty"` + Posts *[]struct { + Attachments *[]struct { + Name *string `json:"name,omitempty"` + Path *string `json:"path,omitempty"` + } `json:"attachments,omitempty"` + File *struct { + Name *string `json:"name,omitempty"` + Path *string `json:"path,omitempty"` + } `json:"file,omitempty"` + FileId *int `json:"file_id,omitempty"` + Id *string `json:"id,omitempty"` + Published *time.Time `json:"published,omitempty"` + Service *string `json:"service,omitempty"` + Substring *string `json:"substring,omitempty"` + Title *string `json:"title,omitempty"` + User *string `json:"user,omitempty"` + } `json:"posts,omitempty"` + Size *int `json:"size,omitempty"` + } +} + +// Status returns HTTPResponse.Status +func (r GetSearchHashFileHashResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r GetSearchHashFileHashResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type GetServiceUserCreatorIdResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *[]struct { + Added *time.Time `json:"added,omitempty"` + Attachments *[]struct { + Name *string `json:"name,omitempty"` + Path *string `json:"path,omitempty"` + } `json:"attachments,omitempty"` + Content *string `json:"content,omitempty"` + Edited *time.Time `json:"edited,omitempty"` + Embed *map[string]interface{} `json:"embed,omitempty"` + File *struct { + Name *string `json:"name,omitempty"` + Path *string `json:"path,omitempty"` + } `json:"file,omitempty"` + Id *string `json:"id,omitempty"` + Published *time.Time `json:"published,omitempty"` + Service *string `json:"service,omitempty"` + SharedFile *bool `json:"shared_file,omitempty"` + Title *string `json:"title,omitempty"` + User *string `json:"user,omitempty"` + } + JSON404 *struct { + // Error The error message + Error *GetServiceUserCreatorId404Error `json:"error,omitempty"` + } +} +type GetServiceUserCreatorId404Error string + +// Status returns HTTPResponse.Status +func (r GetServiceUserCreatorIdResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r GetServiceUserCreatorIdResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type GetServiceUserCreatorIdAnnouncementsResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *[]struct { + // Added isoformat UTC + Added *time.Time `json:"added,omitempty"` + Content *string `json:"content,omitempty"` + + // Hash sha256 + Hash *string `json:"hash,omitempty"` + Service *string `json:"service,omitempty"` + UserId *string `json:"user_id,omitempty"` + } +} + +// Status returns HTTPResponse.Status +func (r GetServiceUserCreatorIdAnnouncementsResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r GetServiceUserCreatorIdAnnouncementsResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type GetServiceUserCreatorIdFancardsResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *[]struct { + Added *time.Time `json:"added,omitempty"` + Ctime *time.Time `json:"ctime,omitempty"` + Ext *string `json:"ext,omitempty"` + FileId *int `json:"file_id,omitempty"` + Hash *string `json:"hash,omitempty"` + Id *int `json:"id,omitempty"` + Ihash *string `json:"ihash,omitempty"` + Mime *string `json:"mime,omitempty"` + Mtime *time.Time `json:"mtime,omitempty"` + Size *int `json:"size,omitempty"` + UserId *string `json:"user_id,omitempty"` + } +} + +// Status returns HTTPResponse.Status +func (r GetServiceUserCreatorIdFancardsResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r GetServiceUserCreatorIdFancardsResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type GetServiceUserCreatorIdLinksResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *[]struct { + // Id The ID of the creator + Id *string `json:"id,omitempty"` + + // Indexed The time the creator was last indexed + Indexed *time.Time `json:"indexed,omitempty"` + + // Name The creator's display name + Name *string `json:"name,omitempty"` + + // PublicId The public ID of the creator + PublicId *string `json:"public_id"` + + // Service The service where the creator is located + Service *string `json:"service,omitempty"` + + // Updated The time the creator was last updated + Updated *time.Time `json:"updated,omitempty"` + } + JSON404 *struct { + // Error The error message + Error *GetServiceUserCreatorIdLinks404Error `json:"error,omitempty"` + } +} +type GetServiceUserCreatorIdLinks404Error string + +// Status returns HTTPResponse.Status +func (r GetServiceUserCreatorIdLinksResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r GetServiceUserCreatorIdLinksResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type GetServiceUserCreatorIdPostPostIdResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *struct { + Added *time.Time `json:"added,omitempty"` + Attachments *[]struct { + Name *string `json:"name,omitempty"` + Path *string `json:"path,omitempty"` + } `json:"attachments,omitempty"` + Content *string `json:"content,omitempty"` + Edited *time.Time `json:"edited,omitempty"` + Embed *map[string]interface{} `json:"embed,omitempty"` + File *struct { + Name *string `json:"name,omitempty"` + Path *string `json:"path,omitempty"` + } `json:"file,omitempty"` + Id *string `json:"id,omitempty"` + Next *string `json:"next,omitempty"` + Prev *string `json:"prev,omitempty"` + Published *time.Time `json:"published,omitempty"` + Service *string `json:"service,omitempty"` + SharedFile *bool `json:"shared_file,omitempty"` + Title *string `json:"title,omitempty"` + User *string `json:"user,omitempty"` + } +} + +// Status returns HTTPResponse.Status +func (r GetServiceUserCreatorIdPostPostIdResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r GetServiceUserCreatorIdPostPostIdResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type GetServiceUserCreatorIdPostPostIdCommentsResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *[]struct { + Commenter *string `json:"commenter,omitempty"` + Content *string `json:"content,omitempty"` + Id *string `json:"id,omitempty"` + ParentId *string `json:"parent_id"` + Published *time.Time `json:"published,omitempty"` + Revisions *[]struct { + Added *time.Time `json:"added,omitempty"` + Content *string `json:"content,omitempty"` + Id *int `json:"id,omitempty"` + } `json:"revisions,omitempty"` + } +} + +// Status returns HTTPResponse.Status +func (r GetServiceUserCreatorIdPostPostIdCommentsResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r GetServiceUserCreatorIdPostPostIdCommentsResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type GetServiceUserCreatorIdPostPostIdRevisionsResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *[]struct { + Added *time.Time `json:"added,omitempty"` + Attachments *[]struct { + Name *string `json:"name,omitempty"` + Path *string `json:"path,omitempty"` + } `json:"attachments,omitempty"` + Content *string `json:"content,omitempty"` + Edited *time.Time `json:"edited,omitempty"` + Embed *map[string]interface{} `json:"embed,omitempty"` + File *struct { + Name *string `json:"name,omitempty"` + Path *string `json:"path,omitempty"` + } `json:"file,omitempty"` + Id *string `json:"id,omitempty"` + Published *time.Time `json:"published,omitempty"` + RevisionId *int `json:"revision_id,omitempty"` + Service *string `json:"service,omitempty"` + SharedFile *bool `json:"shared_file,omitempty"` + Title *string `json:"title,omitempty"` + User *string `json:"user,omitempty"` + } +} + +// Status returns HTTPResponse.Status +func (r GetServiceUserCreatorIdPostPostIdRevisionsResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r GetServiceUserCreatorIdPostPostIdRevisionsResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type GetServiceUserCreatorIdPostPostFlagResponse struct { + Body []byte + HTTPResponse *http.Response +} + +// Status returns HTTPResponse.Status +func (r GetServiceUserCreatorIdPostPostFlagResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r GetServiceUserCreatorIdPostPostFlagResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type PostServiceUserCreatorIdPostPostFlagResponse struct { + Body []byte + HTTPResponse *http.Response +} + +// Status returns HTTPResponse.Status +func (r PostServiceUserCreatorIdPostPostFlagResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r PostServiceUserCreatorIdPostPostFlagResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type GetServiceUserCreatorIdProfileResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *struct { + // Id The ID of the creator + Id *string `json:"id,omitempty"` + + // Indexed The time the creator was last indexed + Indexed *time.Time `json:"indexed,omitempty"` + + // Name The creator's display name + Name *string `json:"name,omitempty"` + + // PublicId The public ID of the creator + PublicId *string `json:"public_id"` + + // Service The service where the creator is located + Service *string `json:"service,omitempty"` + + // Updated The time the creator was last updated + Updated *time.Time `json:"updated,omitempty"` + } + JSON404 *struct { + // Error The error message + Error *GetServiceUserCreatorIdProfile404Error `json:"error,omitempty"` + } +} +type GetServiceUserCreatorIdProfile404Error string + +// Status returns HTTPResponse.Status +func (r GetServiceUserCreatorIdProfileResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r GetServiceUserCreatorIdProfileResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +// GetAccountFavoritesWithResponse request returning *GetAccountFavoritesResponse +func (c *ClientWithResponses) GetAccountFavoritesWithResponse(ctx context.Context, params *GetAccountFavoritesParams, reqEditors ...RequestEditorFn) (*GetAccountFavoritesResponse, error) { + rsp, err := c.GetAccountFavorites(ctx, params, reqEditors...) + if err != nil { + return nil, err + } + return ParseGetAccountFavoritesResponse(rsp) +} + +// GetAppVersionWithResponse request returning *GetAppVersionResponse +func (c *ClientWithResponses) GetAppVersionWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetAppVersionResponse, error) { + rsp, err := c.GetAppVersion(ctx, reqEditors...) + if err != nil { + return nil, err + } + return ParseGetAppVersionResponse(rsp) +} + +// GetCreatorsTxtWithResponse request returning *GetCreatorsTxtResponse +func (c *ClientWithResponses) GetCreatorsTxtWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetCreatorsTxtResponse, error) { + rsp, err := c.GetCreatorsTxt(ctx, reqEditors...) + if err != nil { + return nil, err + } + return ParseGetCreatorsTxtResponse(rsp) +} + +// GetDiscordChannelLookupDiscordServerWithResponse request returning *GetDiscordChannelLookupDiscordServerResponse +func (c *ClientWithResponses) GetDiscordChannelLookupDiscordServerWithResponse(ctx context.Context, discordServer string, reqEditors ...RequestEditorFn) (*GetDiscordChannelLookupDiscordServerResponse, error) { + rsp, err := c.GetDiscordChannelLookupDiscordServer(ctx, discordServer, reqEditors...) + if err != nil { + return nil, err + } + return ParseGetDiscordChannelLookupDiscordServerResponse(rsp) +} + +// GetDiscordChannelChannelIdWithResponse request returning *GetDiscordChannelChannelIdResponse +func (c *ClientWithResponses) GetDiscordChannelChannelIdWithResponse(ctx context.Context, channelId string, params *GetDiscordChannelChannelIdParams, reqEditors ...RequestEditorFn) (*GetDiscordChannelChannelIdResponse, error) { + rsp, err := c.GetDiscordChannelChannelId(ctx, channelId, params, reqEditors...) + if err != nil { + return nil, err + } + return ParseGetDiscordChannelChannelIdResponse(rsp) +} + +// DeleteFavoritesCreatorServiceCreatorIdWithResponse request returning *DeleteFavoritesCreatorServiceCreatorIdResponse +func (c *ClientWithResponses) DeleteFavoritesCreatorServiceCreatorIdWithResponse(ctx context.Context, service string, creatorId string, reqEditors ...RequestEditorFn) (*DeleteFavoritesCreatorServiceCreatorIdResponse, error) { + rsp, err := c.DeleteFavoritesCreatorServiceCreatorId(ctx, service, creatorId, reqEditors...) + if err != nil { + return nil, err + } + return ParseDeleteFavoritesCreatorServiceCreatorIdResponse(rsp) +} + +// PostFavoritesCreatorServiceCreatorIdWithResponse request returning *PostFavoritesCreatorServiceCreatorIdResponse +func (c *ClientWithResponses) PostFavoritesCreatorServiceCreatorIdWithResponse(ctx context.Context, service string, creatorId string, reqEditors ...RequestEditorFn) (*PostFavoritesCreatorServiceCreatorIdResponse, error) { + rsp, err := c.PostFavoritesCreatorServiceCreatorId(ctx, service, creatorId, reqEditors...) + if err != nil { + return nil, err + } + return ParsePostFavoritesCreatorServiceCreatorIdResponse(rsp) +} + +// DeleteFavoritesPostServiceCreatorIdPostIdWithResponse request returning *DeleteFavoritesPostServiceCreatorIdPostIdResponse +func (c *ClientWithResponses) DeleteFavoritesPostServiceCreatorIdPostIdWithResponse(ctx context.Context, service string, creatorId string, postId string, reqEditors ...RequestEditorFn) (*DeleteFavoritesPostServiceCreatorIdPostIdResponse, error) { + rsp, err := c.DeleteFavoritesPostServiceCreatorIdPostId(ctx, service, creatorId, postId, reqEditors...) + if err != nil { + return nil, err + } + return ParseDeleteFavoritesPostServiceCreatorIdPostIdResponse(rsp) +} + +// PostFavoritesPostServiceCreatorIdPostIdWithResponse request returning *PostFavoritesPostServiceCreatorIdPostIdResponse +func (c *ClientWithResponses) PostFavoritesPostServiceCreatorIdPostIdWithResponse(ctx context.Context, service string, creatorId string, postId string, reqEditors ...RequestEditorFn) (*PostFavoritesPostServiceCreatorIdPostIdResponse, error) { + rsp, err := c.PostFavoritesPostServiceCreatorIdPostId(ctx, service, creatorId, postId, reqEditors...) + if err != nil { + return nil, err + } + return ParsePostFavoritesPostServiceCreatorIdPostIdResponse(rsp) +} + +// GetPostsWithResponse request returning *GetPostsResponse +func (c *ClientWithResponses) GetPostsWithResponse(ctx context.Context, params *GetPostsParams, reqEditors ...RequestEditorFn) (*GetPostsResponse, error) { + rsp, err := c.GetPosts(ctx, params, reqEditors...) + if err != nil { + return nil, err + } + return ParseGetPostsResponse(rsp) +} + +// GetSearchHashFileHashWithResponse request returning *GetSearchHashFileHashResponse +func (c *ClientWithResponses) GetSearchHashFileHashWithResponse(ctx context.Context, fileHash string, reqEditors ...RequestEditorFn) (*GetSearchHashFileHashResponse, error) { + rsp, err := c.GetSearchHashFileHash(ctx, fileHash, reqEditors...) + if err != nil { + return nil, err + } + return ParseGetSearchHashFileHashResponse(rsp) +} + +// GetServiceUserCreatorIdWithResponse request returning *GetServiceUserCreatorIdResponse +func (c *ClientWithResponses) GetServiceUserCreatorIdWithResponse(ctx context.Context, service string, creatorId string, params *GetServiceUserCreatorIdParams, reqEditors ...RequestEditorFn) (*GetServiceUserCreatorIdResponse, error) { + rsp, err := c.GetServiceUserCreatorId(ctx, service, creatorId, params, reqEditors...) + if err != nil { + return nil, err + } + return ParseGetServiceUserCreatorIdResponse(rsp) +} + +// GetServiceUserCreatorIdAnnouncementsWithResponse request returning *GetServiceUserCreatorIdAnnouncementsResponse +func (c *ClientWithResponses) GetServiceUserCreatorIdAnnouncementsWithResponse(ctx context.Context, service string, creatorId string, reqEditors ...RequestEditorFn) (*GetServiceUserCreatorIdAnnouncementsResponse, error) { + rsp, err := c.GetServiceUserCreatorIdAnnouncements(ctx, service, creatorId, reqEditors...) + if err != nil { + return nil, err + } + return ParseGetServiceUserCreatorIdAnnouncementsResponse(rsp) +} + +// GetServiceUserCreatorIdFancardsWithResponse request returning *GetServiceUserCreatorIdFancardsResponse +func (c *ClientWithResponses) GetServiceUserCreatorIdFancardsWithResponse(ctx context.Context, service string, creatorId string, reqEditors ...RequestEditorFn) (*GetServiceUserCreatorIdFancardsResponse, error) { + rsp, err := c.GetServiceUserCreatorIdFancards(ctx, service, creatorId, reqEditors...) + if err != nil { + return nil, err + } + return ParseGetServiceUserCreatorIdFancardsResponse(rsp) +} + +// GetServiceUserCreatorIdLinksWithResponse request returning *GetServiceUserCreatorIdLinksResponse +func (c *ClientWithResponses) GetServiceUserCreatorIdLinksWithResponse(ctx context.Context, service string, creatorId string, reqEditors ...RequestEditorFn) (*GetServiceUserCreatorIdLinksResponse, error) { + rsp, err := c.GetServiceUserCreatorIdLinks(ctx, service, creatorId, reqEditors...) + if err != nil { + return nil, err + } + return ParseGetServiceUserCreatorIdLinksResponse(rsp) +} + +// GetServiceUserCreatorIdPostPostIdWithResponse request returning *GetServiceUserCreatorIdPostPostIdResponse +func (c *ClientWithResponses) GetServiceUserCreatorIdPostPostIdWithResponse(ctx context.Context, service string, creatorId string, postId string, reqEditors ...RequestEditorFn) (*GetServiceUserCreatorIdPostPostIdResponse, error) { + rsp, err := c.GetServiceUserCreatorIdPostPostId(ctx, service, creatorId, postId, reqEditors...) + if err != nil { + return nil, err + } + return ParseGetServiceUserCreatorIdPostPostIdResponse(rsp) +} + +// GetServiceUserCreatorIdPostPostIdCommentsWithResponse request returning *GetServiceUserCreatorIdPostPostIdCommentsResponse +func (c *ClientWithResponses) GetServiceUserCreatorIdPostPostIdCommentsWithResponse(ctx context.Context, service string, creatorId string, postId string, reqEditors ...RequestEditorFn) (*GetServiceUserCreatorIdPostPostIdCommentsResponse, error) { + rsp, err := c.GetServiceUserCreatorIdPostPostIdComments(ctx, service, creatorId, postId, reqEditors...) + if err != nil { + return nil, err + } + return ParseGetServiceUserCreatorIdPostPostIdCommentsResponse(rsp) +} + +// GetServiceUserCreatorIdPostPostIdRevisionsWithResponse request returning *GetServiceUserCreatorIdPostPostIdRevisionsResponse +func (c *ClientWithResponses) GetServiceUserCreatorIdPostPostIdRevisionsWithResponse(ctx context.Context, service string, creatorId string, postId string, reqEditors ...RequestEditorFn) (*GetServiceUserCreatorIdPostPostIdRevisionsResponse, error) { + rsp, err := c.GetServiceUserCreatorIdPostPostIdRevisions(ctx, service, creatorId, postId, reqEditors...) + if err != nil { + return nil, err + } + return ParseGetServiceUserCreatorIdPostPostIdRevisionsResponse(rsp) +} + +// GetServiceUserCreatorIdPostPostFlagWithResponse request returning *GetServiceUserCreatorIdPostPostFlagResponse +func (c *ClientWithResponses) GetServiceUserCreatorIdPostPostFlagWithResponse(ctx context.Context, service string, creatorId string, post string, reqEditors ...RequestEditorFn) (*GetServiceUserCreatorIdPostPostFlagResponse, error) { + rsp, err := c.GetServiceUserCreatorIdPostPostFlag(ctx, service, creatorId, post, reqEditors...) + if err != nil { + return nil, err + } + return ParseGetServiceUserCreatorIdPostPostFlagResponse(rsp) +} + +// PostServiceUserCreatorIdPostPostFlagWithResponse request returning *PostServiceUserCreatorIdPostPostFlagResponse +func (c *ClientWithResponses) PostServiceUserCreatorIdPostPostFlagWithResponse(ctx context.Context, service string, creatorId string, post string, reqEditors ...RequestEditorFn) (*PostServiceUserCreatorIdPostPostFlagResponse, error) { + rsp, err := c.PostServiceUserCreatorIdPostPostFlag(ctx, service, creatorId, post, reqEditors...) + if err != nil { + return nil, err + } + return ParsePostServiceUserCreatorIdPostPostFlagResponse(rsp) +} + +// GetServiceUserCreatorIdProfileWithResponse request returning *GetServiceUserCreatorIdProfileResponse +func (c *ClientWithResponses) GetServiceUserCreatorIdProfileWithResponse(ctx context.Context, service string, creatorId string, reqEditors ...RequestEditorFn) (*GetServiceUserCreatorIdProfileResponse, error) { + rsp, err := c.GetServiceUserCreatorIdProfile(ctx, service, creatorId, reqEditors...) + if err != nil { + return nil, err + } + return ParseGetServiceUserCreatorIdProfileResponse(rsp) +} + +// ParseGetAccountFavoritesResponse parses an HTTP response from a GetAccountFavoritesWithResponse call +func ParseGetAccountFavoritesResponse(rsp *http.Response) (*GetAccountFavoritesResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &GetAccountFavoritesResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest []struct { + // FavedSeq The sequence number of the favorite + FavedSeq *int `json:"faved_seq,omitempty"` + + // Id The ID of the favorite (post or creator) + Id *string `json:"id,omitempty"` + + // Indexed Timestamp when the creator was indexed isoformat + Indexed *string `json:"indexed,omitempty"` + + // LastImported Timestamp when the creator was last imported + LastImported *string `json:"last_imported,omitempty"` + + // Name The name of the creator + Name *string `json:"name,omitempty"` + + // Service The service where the creator is located + Service *string `json:"service,omitempty"` + + // Updated Timestamp when the creator was last updated + Updated *string `json:"updated,omitempty"` + } + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + } + + return response, nil +} + +// ParseGetAppVersionResponse parses an HTTP response from a GetAppVersionWithResponse call +func ParseGetAppVersionResponse(rsp *http.Response) (*GetAppVersionResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &GetAppVersionResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + return response, nil +} + +// ParseGetCreatorsTxtResponse parses an HTTP response from a GetCreatorsTxtWithResponse call +func ParseGetCreatorsTxtResponse(rsp *http.Response) (*GetCreatorsTxtResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &GetCreatorsTxtResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest []struct { + // Favorited The number of times this creator has been favorited + Favorited *int `json:"favorited,omitempty"` + + // Id The ID of the creator + Id *string `json:"id,omitempty"` + + // Indexed Timestamp when the creator was indexed, Unix time as integer + Indexed *float32 `json:"indexed,omitempty"` + + // Name The name of the creator + Name *string `json:"name,omitempty"` + + // Service The service for the creator + Service *string `json:"service,omitempty"` + + // Updated Timestamp when the creator was last updated, Unix time as integer + Updated *float32 `json:"updated,omitempty"` + } + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + } + + return response, nil +} + +// ParseGetDiscordChannelLookupDiscordServerResponse parses an HTTP response from a GetDiscordChannelLookupDiscordServerWithResponse call +func ParseGetDiscordChannelLookupDiscordServerResponse(rsp *http.Response) (*GetDiscordChannelLookupDiscordServerResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &GetDiscordChannelLookupDiscordServerResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest []struct { + Id *string `json:"id,omitempty"` + Name *string `json:"name,omitempty"` + } + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + } + + return response, nil +} + +// ParseGetDiscordChannelChannelIdResponse parses an HTTP response from a GetDiscordChannelChannelIdWithResponse call +func ParseGetDiscordChannelChannelIdResponse(rsp *http.Response) (*GetDiscordChannelChannelIdResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &GetDiscordChannelChannelIdResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest []struct { + Added *time.Time `json:"added,omitempty"` + Attachments *[]struct { + Name *string `json:"name,omitempty"` + Path *string `json:"path,omitempty"` + } `json:"attachments,omitempty"` + Author *struct { + Avatar *string `json:"avatar,omitempty"` + Discriminator *string `json:"discriminator,omitempty"` + Id *string `json:"id,omitempty"` + PublicFlags *int `json:"public_flags,omitempty"` + Username *string `json:"username,omitempty"` + } `json:"author,omitempty"` + Channel *string `json:"channel,omitempty"` + Content *string `json:"content,omitempty"` + Edited *time.Time `json:"edited,omitempty"` + Embeds *[]interface{} `json:"embeds,omitempty"` + Id *string `json:"id,omitempty"` + Mentions *[]interface{} `json:"mentions,omitempty"` + Published *time.Time `json:"published,omitempty"` + Server *string `json:"server,omitempty"` + } + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + } + + return response, nil +} + +// ParseDeleteFavoritesCreatorServiceCreatorIdResponse parses an HTTP response from a DeleteFavoritesCreatorServiceCreatorIdWithResponse call +func ParseDeleteFavoritesCreatorServiceCreatorIdResponse(rsp *http.Response) (*DeleteFavoritesCreatorServiceCreatorIdResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &DeleteFavoritesCreatorServiceCreatorIdResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + return response, nil +} + +// ParsePostFavoritesCreatorServiceCreatorIdResponse parses an HTTP response from a PostFavoritesCreatorServiceCreatorIdWithResponse call +func ParsePostFavoritesCreatorServiceCreatorIdResponse(rsp *http.Response) (*PostFavoritesCreatorServiceCreatorIdResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &PostFavoritesCreatorServiceCreatorIdResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + return response, nil +} + +// ParseDeleteFavoritesPostServiceCreatorIdPostIdResponse parses an HTTP response from a DeleteFavoritesPostServiceCreatorIdPostIdWithResponse call +func ParseDeleteFavoritesPostServiceCreatorIdPostIdResponse(rsp *http.Response) (*DeleteFavoritesPostServiceCreatorIdPostIdResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &DeleteFavoritesPostServiceCreatorIdPostIdResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + return response, nil +} + +// ParsePostFavoritesPostServiceCreatorIdPostIdResponse parses an HTTP response from a PostFavoritesPostServiceCreatorIdPostIdWithResponse call +func ParsePostFavoritesPostServiceCreatorIdPostIdResponse(rsp *http.Response) (*PostFavoritesPostServiceCreatorIdPostIdResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &PostFavoritesPostServiceCreatorIdPostIdResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + return response, nil +} + +// ParseGetPostsResponse parses an HTTP response from a GetPostsWithResponse call +func ParseGetPostsResponse(rsp *http.Response) (*GetPostsResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &GetPostsResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest []struct { + Added *time.Time `json:"added,omitempty"` + Attachments *[]struct { + Name *string `json:"name,omitempty"` + Path *string `json:"path,omitempty"` + } `json:"attachments,omitempty"` + Content *string `json:"content,omitempty"` + Edited *time.Time `json:"edited,omitempty"` + Embed *map[string]interface{} `json:"embed,omitempty"` + File *struct { + Name *string `json:"name,omitempty"` + Path *string `json:"path,omitempty"` + } `json:"file,omitempty"` + Id *string `json:"id,omitempty"` + Published *time.Time `json:"published,omitempty"` + Service *string `json:"service,omitempty"` + SharedFile *bool `json:"shared_file,omitempty"` + Title *string `json:"title,omitempty"` + User *string `json:"user,omitempty"` + } + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + } + + return response, nil +} + +// ParseGetSearchHashFileHashResponse parses an HTTP response from a GetSearchHashFileHashWithResponse call +func ParseGetSearchHashFileHashResponse(rsp *http.Response) (*GetSearchHashFileHashResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &GetSearchHashFileHashResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest struct { + Added *time.Time `json:"added,omitempty"` + Ctime *time.Time `json:"ctime,omitempty"` + DiscordPosts *[]struct { + Attachments *[]struct { + Name *string `json:"name,omitempty"` + Path *string `json:"path,omitempty"` + } `json:"attachments,omitempty"` + Channel *string `json:"channel,omitempty"` + Embeds *[]interface{} `json:"embeds,omitempty"` + FileId *int `json:"file_id,omitempty"` + Id *string `json:"id,omitempty"` + Mentions *[]interface{} `json:"mentions,omitempty"` + Published *time.Time `json:"published,omitempty"` + Server *string `json:"server,omitempty"` + Substring *string `json:"substring,omitempty"` + } `json:"discord_posts,omitempty"` + Ext *string `json:"ext,omitempty"` + Hash *string `json:"hash,omitempty"` + Id *int `json:"id,omitempty"` + Ihash *string `json:"ihash,omitempty"` + Mime *string `json:"mime,omitempty"` + Mtime *time.Time `json:"mtime,omitempty"` + Posts *[]struct { + Attachments *[]struct { + Name *string `json:"name,omitempty"` + Path *string `json:"path,omitempty"` + } `json:"attachments,omitempty"` + File *struct { + Name *string `json:"name,omitempty"` + Path *string `json:"path,omitempty"` + } `json:"file,omitempty"` + FileId *int `json:"file_id,omitempty"` + Id *string `json:"id,omitempty"` + Published *time.Time `json:"published,omitempty"` + Service *string `json:"service,omitempty"` + Substring *string `json:"substring,omitempty"` + Title *string `json:"title,omitempty"` + User *string `json:"user,omitempty"` + } `json:"posts,omitempty"` + Size *int `json:"size,omitempty"` + } + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + } + + return response, nil +} + +// ParseGetServiceUserCreatorIdResponse parses an HTTP response from a GetServiceUserCreatorIdWithResponse call +func ParseGetServiceUserCreatorIdResponse(rsp *http.Response) (*GetServiceUserCreatorIdResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &GetServiceUserCreatorIdResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest []struct { + Added *time.Time `json:"added,omitempty"` + Attachments *[]struct { + Name *string `json:"name,omitempty"` + Path *string `json:"path,omitempty"` + } `json:"attachments,omitempty"` + Content *string `json:"content,omitempty"` + Edited *time.Time `json:"edited,omitempty"` + Embed *map[string]interface{} `json:"embed,omitempty"` + File *struct { + Name *string `json:"name,omitempty"` + Path *string `json:"path,omitempty"` + } `json:"file,omitempty"` + Id *string `json:"id,omitempty"` + Published *time.Time `json:"published,omitempty"` + Service *string `json:"service,omitempty"` + SharedFile *bool `json:"shared_file,omitempty"` + Title *string `json:"title,omitempty"` + User *string `json:"user,omitempty"` + } + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404: + var dest struct { + // Error The error message + Error *GetServiceUserCreatorId404Error `json:"error,omitempty"` + } + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON404 = &dest + + } + + return response, nil +} + +// ParseGetServiceUserCreatorIdAnnouncementsResponse parses an HTTP response from a GetServiceUserCreatorIdAnnouncementsWithResponse call +func ParseGetServiceUserCreatorIdAnnouncementsResponse(rsp *http.Response) (*GetServiceUserCreatorIdAnnouncementsResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &GetServiceUserCreatorIdAnnouncementsResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest []struct { + // Added isoformat UTC + Added *time.Time `json:"added,omitempty"` + Content *string `json:"content,omitempty"` + + // Hash sha256 + Hash *string `json:"hash,omitempty"` + Service *string `json:"service,omitempty"` + UserId *string `json:"user_id,omitempty"` + } + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + } + + return response, nil +} + +// ParseGetServiceUserCreatorIdFancardsResponse parses an HTTP response from a GetServiceUserCreatorIdFancardsWithResponse call +func ParseGetServiceUserCreatorIdFancardsResponse(rsp *http.Response) (*GetServiceUserCreatorIdFancardsResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &GetServiceUserCreatorIdFancardsResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest []struct { + Added *time.Time `json:"added,omitempty"` + Ctime *time.Time `json:"ctime,omitempty"` + Ext *string `json:"ext,omitempty"` + FileId *int `json:"file_id,omitempty"` + Hash *string `json:"hash,omitempty"` + Id *int `json:"id,omitempty"` + Ihash *string `json:"ihash,omitempty"` + Mime *string `json:"mime,omitempty"` + Mtime *time.Time `json:"mtime,omitempty"` + Size *int `json:"size,omitempty"` + UserId *string `json:"user_id,omitempty"` + } + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + } + + return response, nil +} + +// ParseGetServiceUserCreatorIdLinksResponse parses an HTTP response from a GetServiceUserCreatorIdLinksWithResponse call +func ParseGetServiceUserCreatorIdLinksResponse(rsp *http.Response) (*GetServiceUserCreatorIdLinksResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &GetServiceUserCreatorIdLinksResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest []struct { + // Id The ID of the creator + Id *string `json:"id,omitempty"` + + // Indexed The time the creator was last indexed + Indexed *time.Time `json:"indexed,omitempty"` + + // Name The creator's display name + Name *string `json:"name,omitempty"` + + // PublicId The public ID of the creator + PublicId *string `json:"public_id"` + + // Service The service where the creator is located + Service *string `json:"service,omitempty"` + + // Updated The time the creator was last updated + Updated *time.Time `json:"updated,omitempty"` + } + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404: + var dest struct { + // Error The error message + Error *GetServiceUserCreatorIdLinks404Error `json:"error,omitempty"` + } + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON404 = &dest + + } + + return response, nil +} + +// ParseGetServiceUserCreatorIdPostPostIdResponse parses an HTTP response from a GetServiceUserCreatorIdPostPostIdWithResponse call +func ParseGetServiceUserCreatorIdPostPostIdResponse(rsp *http.Response) (*GetServiceUserCreatorIdPostPostIdResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &GetServiceUserCreatorIdPostPostIdResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest struct { + Added *time.Time `json:"added,omitempty"` + Attachments *[]struct { + Name *string `json:"name,omitempty"` + Path *string `json:"path,omitempty"` + } `json:"attachments,omitempty"` + Content *string `json:"content,omitempty"` + Edited *time.Time `json:"edited,omitempty"` + Embed *map[string]interface{} `json:"embed,omitempty"` + File *struct { + Name *string `json:"name,omitempty"` + Path *string `json:"path,omitempty"` + } `json:"file,omitempty"` + Id *string `json:"id,omitempty"` + Next *string `json:"next,omitempty"` + Prev *string `json:"prev,omitempty"` + Published *time.Time `json:"published,omitempty"` + Service *string `json:"service,omitempty"` + SharedFile *bool `json:"shared_file,omitempty"` + Title *string `json:"title,omitempty"` + User *string `json:"user,omitempty"` + } + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + } + + return response, nil +} + +// ParseGetServiceUserCreatorIdPostPostIdCommentsResponse parses an HTTP response from a GetServiceUserCreatorIdPostPostIdCommentsWithResponse call +func ParseGetServiceUserCreatorIdPostPostIdCommentsResponse(rsp *http.Response) (*GetServiceUserCreatorIdPostPostIdCommentsResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &GetServiceUserCreatorIdPostPostIdCommentsResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest []struct { + Commenter *string `json:"commenter,omitempty"` + Content *string `json:"content,omitempty"` + Id *string `json:"id,omitempty"` + ParentId *string `json:"parent_id"` + Published *time.Time `json:"published,omitempty"` + Revisions *[]struct { + Added *time.Time `json:"added,omitempty"` + Content *string `json:"content,omitempty"` + Id *int `json:"id,omitempty"` + } `json:"revisions,omitempty"` + } + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + } + + return response, nil +} + +// ParseGetServiceUserCreatorIdPostPostIdRevisionsResponse parses an HTTP response from a GetServiceUserCreatorIdPostPostIdRevisionsWithResponse call +func ParseGetServiceUserCreatorIdPostPostIdRevisionsResponse(rsp *http.Response) (*GetServiceUserCreatorIdPostPostIdRevisionsResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &GetServiceUserCreatorIdPostPostIdRevisionsResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest []struct { + Added *time.Time `json:"added,omitempty"` + Attachments *[]struct { + Name *string `json:"name,omitempty"` + Path *string `json:"path,omitempty"` + } `json:"attachments,omitempty"` + Content *string `json:"content,omitempty"` + Edited *time.Time `json:"edited,omitempty"` + Embed *map[string]interface{} `json:"embed,omitempty"` + File *struct { + Name *string `json:"name,omitempty"` + Path *string `json:"path,omitempty"` + } `json:"file,omitempty"` + Id *string `json:"id,omitempty"` + Published *time.Time `json:"published,omitempty"` + RevisionId *int `json:"revision_id,omitempty"` + Service *string `json:"service,omitempty"` + SharedFile *bool `json:"shared_file,omitempty"` + Title *string `json:"title,omitempty"` + User *string `json:"user,omitempty"` + } + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + } + + return response, nil +} + +// ParseGetServiceUserCreatorIdPostPostFlagResponse parses an HTTP response from a GetServiceUserCreatorIdPostPostFlagWithResponse call +func ParseGetServiceUserCreatorIdPostPostFlagResponse(rsp *http.Response) (*GetServiceUserCreatorIdPostPostFlagResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &GetServiceUserCreatorIdPostPostFlagResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + return response, nil +} + +// ParsePostServiceUserCreatorIdPostPostFlagResponse parses an HTTP response from a PostServiceUserCreatorIdPostPostFlagWithResponse call +func ParsePostServiceUserCreatorIdPostPostFlagResponse(rsp *http.Response) (*PostServiceUserCreatorIdPostPostFlagResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &PostServiceUserCreatorIdPostPostFlagResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + return response, nil +} + +// ParseGetServiceUserCreatorIdProfileResponse parses an HTTP response from a GetServiceUserCreatorIdProfileWithResponse call +func ParseGetServiceUserCreatorIdProfileResponse(rsp *http.Response) (*GetServiceUserCreatorIdProfileResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &GetServiceUserCreatorIdProfileResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest struct { + // Id The ID of the creator + Id *string `json:"id,omitempty"` + + // Indexed The time the creator was last indexed + Indexed *time.Time `json:"indexed,omitempty"` + + // Name The creator's display name + Name *string `json:"name,omitempty"` + + // PublicId The public ID of the creator + PublicId *string `json:"public_id"` + + // Service The service where the creator is located + Service *string `json:"service,omitempty"` + + // Updated The time the creator was last updated + Updated *time.Time `json:"updated,omitempty"` + } + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404: + var dest struct { + // Error The error message + Error *GetServiceUserCreatorIdProfile404Error `json:"error,omitempty"` + } + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON404 = &dest + + } + + return response, nil +} diff --git a/daemons/kemono/client/models.go b/daemons/kemono/client/models.go new file mode 100644 index 0000000..090e952 --- /dev/null +++ b/daemons/kemono/client/models.go @@ -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 +} diff --git a/daemons/kemono/client/spec.json b/daemons/kemono/client/spec.json new file mode 100644 index 0000000..6e35fdf --- /dev/null +++ b/daemons/kemono/client/spec.json @@ -0,0 +1,2079 @@ +{ + "openapi": "3.0.1", + "info": { + "title": "Kemono API", + "version": "1.0.0" + }, + "contact": { + "email": "contact@kemono.party" + }, + "servers": [ + { + "url": "https://kemono.su/api/v1" + }, + { + "url": "https://coomer.su/api/v1" + } + ], + "tags": [ + { + "name": "Posts", + "description": "Version one" + }, + { + "name": "Creators" + }, + { + "name": "Comments" + }, + { + "name": "Post Flagging", + "description": "Flag post for re-import" + }, + { + "name": "Discord" + }, + { + "name": "Favorites" + }, + { + "name": "File Search" + }, + { + "name": "Misc" + } + ], + "paths": { + "/creators.txt": { + "get": { + "tags": [ + "Posts" + ], + "summary": "List All Creators", + "description": "List all creators with details. I blame DDG for .txt.", + "responses": { + "200": { + "description": "List of all creators", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "favorited": { + "type": "integer", + "description": "The number of times this creator has been favorited" + }, + "id": { + "type": "string", + "description": "The ID of the creator" + }, + "indexed": { + "type": "number", + "description": "Timestamp when the creator was indexed, Unix time as integer" + }, + "name": { + "type": "string", + "description": "The name of the creator" + }, + "service": { + "type": "string", + "description": "The service for the creator" + }, + "updated": { + "type": "number", + "description": "Timestamp when the creator was last updated, Unix time as integer" + } + } + } + }, + "example": [ + { + "favorited": 1, + "id": "21101760", + "indexed": 1672534800, + "name": "RAIGYO", + "service": "fanbox", + "updated": 1672534800 + } + ] + } + } + } + } + } + }, + "/posts": { + "get": { + "tags": [ + "Posts" + ], + "summary": "List recent posts", + "description": "List of recently imported posts", + "parameters": [ + { + "name": "q", + "in": "query", + "description": "Search query", + "schema": { + "type": "string", + "minLength": 3 + } + }, + { + "name": "o", + "in": "query", + "description": "Result offset, stepping of 50 is enforced", + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "List of recently added posts", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "user": { + "type": "string" + }, + "service": { + "type": "string" + }, + "title": { + "type": "string" + }, + "content": { + "type": "string" + }, + "embed": { + "type": "object" + }, + "shared_file": { + "type": "boolean" + }, + "added": { + "type": "string", + "format": "date-time" + }, + "published": { + "type": "string", + "format": "date-time" + }, + "edited": { + "type": "string", + "format": "date-time" + }, + "file": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "path": { + "type": "string" + } + } + }, + "attachments": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "path": { + "type": "string" + } + } + } + } + } + } + }, + "example": [ + { + "id": "1836570", + "user": "6570768", + "service": "fanbox", + "title": "今日はFANBOXを始まりました!", + "content": "

みなさんこんにちは、影おじです。

先週のように、FANBOXを始まりに決定しました!

そしてFANBOXの更新内容について、アンケートのみなさん

ありがとうございました!


では更新内容の詳しいことはこちらです↓

毎回の絵、元も差分がありませんの場合、ボナスとして差分イラストを支援者の皆様にプレゼント。

もとも差分があれば、ボナスとしてヌード差分イラストを支援者の皆様にプレゼント。


これから、仕事以外の時間、できる限り勤勉な更新したいと思います!

どうぞよろしくお願いいたします!

", + "embed": {}, + "shared_file": false, + "added": "2021-03-30T18:00:05.973913", + "published": "2021-01-24T17:54:38", + "edited": "2021-01-24T18:46:15", + "file": { + "name": "a99d9674-5490-400e-acca-4bed99590699.jpg", + "path": "/5c/98/5c984d1f62f0990a0891d8fa359aecdff6ac1e26ac165ba7bb7f31cc99e7a674.jpg" + }, + "attachments": [] + }, + { + "id": "1836649", + "user": "6570768", + "service": "fanbox", + "title": "忍ちゃん 脇コキ差分", + "content": "", + "embed": {}, + "shared_file": false, + "added": "2021-03-30T17:59:57.815397", + "published": "2021-01-24T18:23:12", + "edited": "2023-01-04T14:45:19", + "file": { + "name": "4c5615f9-be74-4fa7-b88d-168fd37a2824.jpg", + "path": "/d0/3c/d03c893927521536646619f5fb33426aa4b82dc12869865d6d666932755d9acd.jpg" + }, + "attachments": [ + { + "name": "9cc982e4-1d94-4a1a-ac62-3dddd29f881c.png", + "path": "/d7/4d/d74d1727f2c3fcf7a7cc2d244d677d93b4cc562a56904765e4e708523b34fb4c.png" + }, + { + "name": "ab0e17d7-52e5-42c2-925b-5cfdb451df0c.png", + "path": "/1b/67/1b677a8c0525e386bf2b2f013e36e29e4033feb2308798e4e5e3780da6c0e815.png" + } + ] + } + ] + } + } + } + } + } + }, + "/{service}/user/{creator_id}/profile": { + "get": { + "summary": "Get a creator", + "tags": [ + "Creators" + ], + "parameters": [ + { + "name": "service", + "in": "path", + "description": "The service where the creator is located", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "creator_id", + "in": "path", + "description": "The ID of the creator", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Creator details retrieved successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "The ID of the creator" + }, + "public_id": { + "type": "string", + "nullable": true, + "description": "The public ID of the creator" + }, + "service": { + "type": "string", + "description": "The service where the creator is located" + }, + "name": { + "type": "string", + "description": "The creator's display name" + }, + "indexed": { + "type": "string", + "format": "date-time", + "description": "The time the creator was last indexed" + }, + "updated": { + "type": "string", + "format": "date-time", + "description": "The time the creator was last updated" + } + } + } + } + } + }, + "404": { + "description": "The creator could not be found", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "error": { + "type": "string", + "description": "The error message", + "enum": [ + "Creator not found." + ] + } + } + } + } + } + } + } + } + }, + "/{service}/user/{creator_id}": { + "get": { + "summary": "Get a list of creator posts", + "tags": [ + "Posts" + ], + "parameters": [ + { + "name": "service", + "in": "path", + "description": "The service where the post is located", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "creator_id", + "in": "path", + "description": "The ID of the creator", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "q", + "in": "query", + "description": "Search query", + "schema": { + "type": "string", + "minLength": 3 + } + }, + { + "name": "o", + "in": "query", + "description": "Result offset, stepping of 50 is enforced", + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "Post details retrieved successfully", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "user": { + "type": "string" + }, + "service": { + "type": "string" + }, + "title": { + "type": "string" + }, + "content": { + "type": "string" + }, + "embed": { + "type": "object" + }, + "shared_file": { + "type": "boolean" + }, + "added": { + "type": "string", + "format": "date-time" + }, + "published": { + "type": "string", + "format": "date-time" + }, + "edited": { + "type": "string", + "format": "date-time" + }, + "file": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "path": { + "type": "string" + } + } + }, + "attachments": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "path": { + "type": "string" + } + } + } + } + } + } + }, + "example": [ + { + "id": "1836570", + "user": "6570768", + "service": "fanbox", + "title": "今日はFANBOXを始まりました!", + "content": "

みなさんこんにちは、影おじです。

先週のように、FANBOXを始まりに決定しました!

そしてFANBOXの更新内容について、アンケートのみなさん

ありがとうございました!


では更新内容の詳しいことはこちらです↓

毎回の絵、元も差分がありませんの場合、ボナスとして差分イラストを支援者の皆様にプレゼント。

もとも差分があれば、ボナスとしてヌード差分イラストを支援者の皆様にプレゼント。


これから、仕事以外の時間、できる限り勤勉な更新したいと思います!

どうぞよろしくお願いいたします!

", + "embed": {}, + "shared_file": false, + "added": "2021-03-30T18:00:05.973913", + "published": "2021-01-24T17:54:38", + "edited": "2021-01-24T18:46:15", + "file": { + "name": "a99d9674-5490-400e-acca-4bed99590699.jpg", + "path": "/5c/98/5c984d1f62f0990a0891d8fa359aecdff6ac1e26ac165ba7bb7f31cc99e7a674.jpg" + }, + "attachments": [] + }, + { + "id": "1836649", + "user": "6570768", + "service": "fanbox", + "title": "忍ちゃん 脇コキ差分", + "content": "", + "embed": {}, + "shared_file": false, + "added": "2021-03-30T17:59:57.815397", + "published": "2021-01-24T18:23:12", + "edited": "2023-01-04T14:45:19", + "file": { + "name": "4c5615f9-be74-4fa7-b88d-168fd37a2824.jpg", + "path": "/d0/3c/d03c893927521536646619f5fb33426aa4b82dc12869865d6d666932755d9acd.jpg" + }, + "attachments": [ + { + "name": "9cc982e4-1d94-4a1a-ac62-3dddd29f881c.png", + "path": "/d7/4d/d74d1727f2c3fcf7a7cc2d244d677d93b4cc562a56904765e4e708523b34fb4c.png" + }, + { + "name": "ab0e17d7-52e5-42c2-925b-5cfdb451df0c.png", + "path": "/1b/67/1b677a8c0525e386bf2b2f013e36e29e4033feb2308798e4e5e3780da6c0e815.png" + } + ] + } + ] + } + } + }, + "400": { + "description": "Offset provided which is not a multiple of 50" + }, + "404": { + "description": "The creator could not be found", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "error": { + "type": "string", + "description": "The error message", + "enum": [ + "Creator not found." + ] + } + } + } + } + } + } + } + } + }, + "/{service}/user/{creator_id}/announcements": { + "get": { + "summary": "Get creator announcements", + "tags": [ + "Posts" + ], + "parameters": [ + { + "name": "service", + "in": "path", + "required": true, + "description": "The service name", + "schema": { + "type": "string" + } + }, + { + "name": "creator_id", + "in": "path", + "required": true, + "description": "The creator's ID", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "service": { + "type": "string" + }, + "user_id": { + "type": "string" + }, + "hash": { + "type": "string", + "description": "sha256" + }, + "content": { + "type": "string" + }, + "added": { + "type": "string", + "format": "date-time", + "description": "isoformat UTC" + } + } + } + }, + "example": [ + { + "service": "patreon", + "user_id": "8693043", + "hash": "820b7397c7f75efb13c4a8aa5d4aacfbb200749f3e1cec16e9f2951d158be8c2", + "content": "Hey guys, thank you so much for your support, that means a lot to me!", + "added": "2023-01-31T05:16:15.462035" + } + ] + } + } + }, + "404": { + "description": "Artist not found" + } + } + } + }, + "/{service}/user/{creator_id}/fancards": { + "get": { + "summary": "Get fancards by creator, fanbox only", + "tags": [ + "Posts" + ], + "parameters": [ + { + "name": "service", + "in": "path", + "required": true, + "description": "The service name, has to be \"fanbox\"", + "schema": { + "type": "string" + } + }, + { + "name": "creator_id", + "in": "path", + "required": true, + "description": "The creator's ID", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "user_id": { + "type": "string" + }, + "file_id": { + "type": "integer" + }, + "hash": { + "type": "string" + }, + "mtime": { + "type": "string", + "format": "date-time" + }, + "ctime": { + "type": "string", + "format": "date-time" + }, + "mime": { + "type": "string" + }, + "ext": { + "type": "string" + }, + "added": { + "type": "string", + "format": "date-time" + }, + "size": { + "type": "integer" + }, + "ihash": { + "type": "string" + } + } + } + }, + "example": [ + { + "id": 108058645, + "user_id": "3316400", + "file_id": 108058645, + "hash": "727bf3f0d774a98c80cf6c76c3fb0e049522b88eb7f02c8d3fc59bae20439fcf", + "mtime": "2023-05-23T15:09:43.941195", + "ctime": "2023-05-23T15:09:43.941195", + "mime": "image/jpeg", + "ext": ".jpg", + "added": "2023-05-23T15:09:43.960578", + "size": 339710, + "ihash": null + }, + { + "id": 103286760, + "user_id": "3316400", + "file_id": 103286760, + "hash": "8b0d0f1be38efab9306b32c7b14b74ddd92a2513026c859a280fe737980a467d", + "mtime": "2023-04-26T14:16:53.205183", + "ctime": "2023-04-26T14:16:53.205183", + "mime": "image/jpeg", + "ext": ".jpg", + "added": "2023-04-26T14:16:53.289143", + "size": 339764, + "ihash": null + } + ] + } + } + }, + "404": { + "description": "Artist not found" + } + } + } + }, + "/{service}/user/{creator_id}/links": { + "get": { + "summary": "Get a creator's linked accounts", + "tags": [ + "Creators" + ], + "parameters": [ + { + "name": "service", + "in": "path", + "description": "The service where the creator is located", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "creator_id", + "in": "path", + "description": "The ID of the creator", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Linked accounts retrieved successfully", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "The ID of the creator" + }, + "public_id": { + "type": "string", + "nullable": true, + "description": "The public ID of the creator" + }, + "service": { + "type": "string", + "description": "The service where the creator is located" + }, + "name": { + "type": "string", + "description": "The creator's display name" + }, + "indexed": { + "type": "string", + "format": "date-time", + "description": "The time the creator was last indexed" + }, + "updated": { + "type": "string", + "format": "date-time", + "description": "The time the creator was last updated" + } + } + } + } + } + } + }, + "404": { + "description": "The creator could not be found", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "error": { + "type": "string", + "description": "The error message", + "enum": [ + "Creator not found." + ] + } + } + } + } + } + } + } + } + }, + "/{service}/user/{creator_id}/post/{post_id}": { + "get": { + "summary": "Get a specific post", + "tags": [ + "Posts" + ], + "parameters": [ + { + "name": "service", + "in": "path", + "required": true, + "description": "The service name", + "schema": { + "type": "string" + } + }, + { + "name": "creator_id", + "in": "path", + "required": true, + "description": "The creator's ID", + "schema": { + "type": "string" + } + }, + { + "name": "post_id", + "in": "path", + "required": true, + "description": "The post ID", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "user": { + "type": "string" + }, + "service": { + "type": "string" + }, + "title": { + "type": "string" + }, + "content": { + "type": "string" + }, + "embed": { + "type": "object" + }, + "shared_file": { + "type": "boolean" + }, + "added": { + "type": "string", + "format": "date-time" + }, + "published": { + "type": "string", + "format": "date-time" + }, + "edited": { + "type": "string", + "format": "date-time" + }, + "file": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "path": { + "type": "string" + } + } + }, + "attachments": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "path": { + "type": "string" + } + } + } + }, + "next": { + "type": "string" + }, + "prev": { + "type": "string" + } + } + }, + "example": { + "id": "1836570", + "user": "6570768", + "service": "fanbox", + "title": "今日はFANBOXを始まりました!", + "content": "

みなさんこんにちは、影おじです。

先週のように、FANBOXを始まりに決定しました!

そしてFANBOXの更新内容について、アンケートのみなさん

ありがとうございました!


では更新内容の詳しいことはこちらです↓

毎回の絵、元も差分がありませんの場合、ボナスとして差分イラストを支援者の皆様にプレゼント。

もとも差分があれば、ボナスとしてヌード差分イラストを支援者の皆様にプレゼント。


これから、仕事以外の時間、できる限り勤勉な更新したいと思います!

どうぞよろしくお願いいたします!

", + "embed": {}, + "shared_file": false, + "added": "2021-03-30T18:00:05.973913", + "published": "2021-01-24T17:54:38", + "edited": "2021-01-24T18:46:15", + "file": { + "name": "a99d9674-5490-400e-acca-4bed99590699.jpg", + "path": "/5c/98/5c984d1f62f0990a0891d8fa359aecdff6ac1e26ac165ba7bb7f31cc99e7a674.jpg" + }, + "attachments": [], + "next": null, + "prev": "1836649" + } + } + } + }, + "404": { + "description": "Post not found" + } + } + } + }, + "/discord/channel/{channel_id}": { + "get": { + "tags": [ + "Discord" + ], + "summary": "Get Discord channel posts by offset", + "parameters": [ + { + "name": "channel_id", + "in": "path", + "description": "ID of the Discord channel", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "o", + "in": "query", + "description": "Result offset, stepping of 150 is enforced", + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "Discord channel found", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "author": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "avatar": { + "type": "string" + }, + "username": { + "type": "string" + }, + "public_flags": { + "type": "integer" + }, + "discriminator": { + "type": "string" + } + } + }, + "server": { + "type": "string" + }, + "channel": { + "type": "string" + }, + "content": { + "type": "string" + }, + "added": { + "type": "string", + "format": "date-time" + }, + "published": { + "type": "string", + "format": "date-time" + }, + "edited": { + "type": "string", + "format": "date-time" + }, + "embeds": { + "type": "array", + "items": {} + }, + "mentions": { + "type": "array", + "items": {} + }, + "attachments": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "path": { + "type": "string" + } + } + } + } + } + } + }, + "example": [ + { + "id": "942909658610413578", + "author": { + "id": "421590382300889088", + "avatar": "0956f3dc18eba7da9daedc4e50fb96d0", + "username": "Merry", + "public_flags": 0, + "discriminator": "7849" + }, + "server": "455285536341491714", + "channel": "455287420959850496", + "content": "@everyone Happy Valentine’s Day! 💜✨", + "added": "2022-02-15T01:26:12.708959", + "published": "2022-02-14T22:26:21.027000", + "edited": null, + "embeds": [], + "mentions": [], + "attachments": [] + }, + { + "id": "942909571947712594", + "author": { + "id": "421590382300889088", + "avatar": "0956f3dc18eba7da9daedc4e50fb96d0", + "username": "Merry", + "public_flags": 0, + "discriminator": "7849" + }, + "server": "455285536341491714", + "channel": "455287420959850496", + "content": "", + "added": "2022-02-15T01:26:13.006228", + "published": "2022-02-14T22:26:00.365000", + "edited": null, + "embeds": [], + "mentions": [], + "attachments": [ + { + "name": "sofa_03.png", + "path": "/3b/4e/3b4ed5aabdd85b26fbbc3ee9b0e5649df69167efe26b5abc24cc2a1159f446d4.png" + } + ] + } + ] + } + } + }, + "404": { + "description": "Discord channel not found" + } + } + } + }, + "/discord/channel/lookup/{discord_server}": { + "get": { + "tags": [ + "Discord" + ], + "summary": "Lookup Discord channels", + "parameters": [ + { + "name": "discord_server", + "in": "path", + "description": "Discord Server ID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Discord channels found", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + } + } + } + }, + "example": [ + { + "id": "455285536341491716", + "name": "news" + }, + { + "id": "455287420959850496", + "name": "nyarla-lewds" + } + ] + } + } + }, + "404": { + "description": "Discord server not found" + } + } + } + }, + "/account/favorites": { + "get": { + "tags": [ + "Favorites" + ], + "security": [ + { + "cookieAuth": [] + } + ], + "summary": "List Account Favorites", + "description": "List account favorites (posts or creators) for the authenticated user (cookie session)", + "parameters": [ + { + "name": "type", + "in": "query", + "description": "Type of favorites to list (post or creator (artist) )", + "schema": { + "type": "string", + "enum": [ + "post", + "artist" + ] + } + } + ], + "responses": { + "200": { + "description": "List of account favorites", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "faved_seq": { + "type": "integer", + "description": "The sequence number of the favorite" + }, + "id": { + "type": "string", + "description": "The ID of the favorite (post or creator)" + }, + "indexed": { + "type": "string", + "description": "Timestamp when the creator was indexed isoformat" + }, + "last_imported": { + "type": "string", + "description": "Timestamp when the creator was last imported" + }, + "name": { + "type": "string", + "description": "The name of the creator" + }, + "service": { + "type": "string", + "description": "The service where the creator is located" + }, + "updated": { + "type": "string", + "description": "Timestamp when the creator was last updated" + } + } + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/401" + } + } + } + }, + "/favorites/post/{service}/{creator_id}/{post_id}": { + "post": { + "tags": [ + "Favorites" + ], + "security": [ + { + "cookieAuth": [] + } + ], + "summary": "Add Favorite Post", + "description": "Add a post to the user's favorite posts", + "parameters": [ + { + "name": "service", + "in": "path", + "description": "Service of the post", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "creator_id", + "in": "path", + "description": "The ID of the creator", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "post_id", + "in": "path", + "description": "The ID of the post", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Favorite post added successfully", + "content": {} + }, + "302": { + "description": "Redirect to login if not authenticated", + "content": {} + }, + "401": { + "$ref": "#/components/responses/401" + } + } + }, + "delete": { + "tags": [ + "Favorites" + ], + "security": [ + { + "cookieAuth": [] + } + ], + "summary": "Remove Favorite Post", + "description": "Remove a post from the user's favorite posts", + "parameters": [ + { + "name": "service", + "in": "path", + "description": "The service where the post is located", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "creator_id", + "in": "path", + "description": "The ID of the creator", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "post_id", + "in": "path", + "description": "The ID of the post", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Unfavorite post removed successfully", + "content": {} + }, + "302": { + "description": "Redirect to login if not authenticated", + "content": {} + }, + "401": { + "$ref": "#/components/responses/401" + } + } + } + }, + "/favorites/creator/{service}/{creator_id}": { + "post": { + "tags": [ + "Favorites" + ], + "security": [ + { + "cookieAuth": [] + } + ], + "summary": "Add Favorite creator", + "description": "Add an creator to the user's favorite creators", + "parameters": [ + { + "name": "service", + "in": "path", + "description": "The service where the creator is located", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "creator_id", + "in": "path", + "description": "The ID of the creator", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Favorite creator added successfully", + "content": {} + }, + "302": { + "description": "Redirect to login if not authenticated", + "content": {} + }, + "401": { + "$ref": "#/components/responses/401" + } + } + }, + "delete": { + "tags": [ + "Favorites" + ], + "security": [ + { + "cookieAuth": [] + } + ], + "summary": "Remove Favorite Creator", + "description": "Remove an creator from the user's favorite creators", + "parameters": [ + { + "name": "service", + "in": "path", + "description": "The service where the creator is located", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "creator_id", + "in": "path", + "description": "The ID of the creator", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Favorite creator removed successfully", + "content": {} + }, + "302": { + "description": "Redirect to login if not authenticated", + "content": {} + }, + "401": { + "$ref": "#/components/responses/401" + } + } + } + }, + "/search_hash/{file_hash}": { + "get": { + "tags": [ + "File Search" + ], + "summary": "Lookup file by hash", + "parameters": [ + { + "name": "file_hash", + "in": "path", + "required": true, + "description": "SHA-2 / SHA-256", + "schema": { + "type": "string", + "format": "hex", + "minLength": 64, + "maxLength": 64 + } + } + ], + "responses": { + "200": { + "description": "File found", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "hash": { + "type": "string" + }, + "mtime": { + "type": "string", + "format": "date-time" + }, + "ctime": { + "type": "string", + "format": "date-time" + }, + "mime": { + "type": "string" + }, + "ext": { + "type": "string" + }, + "added": { + "type": "string", + "format": "date-time" + }, + "size": { + "type": "integer" + }, + "ihash": { + "type": "string" + }, + "posts": { + "type": "array", + "items": { + "type": "object", + "properties": { + "file_id": { + "type": "integer" + }, + "id": { + "type": "string" + }, + "user": { + "type": "string" + }, + "service": { + "type": "string" + }, + "title": { + "type": "string" + }, + "substring": { + "type": "string" + }, + "published": { + "type": "string", + "format": "date-time" + }, + "file": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "path": { + "type": "string" + } + } + }, + "attachments": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "path": { + "type": "string" + } + } + } + } + } + } + }, + "discord_posts": { + "type": "array", + "items": { + "type": "object", + "properties": { + "file_id": { + "type": "integer" + }, + "id": { + "type": "string" + }, + "server": { + "type": "string" + }, + "channel": { + "type": "string" + }, + "substring": { + "type": "string" + }, + "published": { + "type": "string", + "format": "date-time" + }, + "embeds": { + "type": "array", + "items": {} + }, + "mentions": { + "type": "array", + "items": {} + }, + "attachments": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "path": { + "type": "string" + } + } + } + } + } + } + } + } + }, + "example": { + "id": 40694581, + "hash": "b926020cf035af45a1351e0a7e2c983ebcc93b4c751998321a6593a98277cdeb", + "mtime": "2021-12-04T07:16:09.385539", + "ctime": "2021-12-04T07:16:09.385539", + "mime": "image/png", + "ext": ".png", + "added": "2021-12-04T07:16:09.443016", + "size": 10869921, + "ihash": null, + "posts": [ + { + "file_id": 108400151, + "id": "5956097", + "user": "21101760", + "service": "fanbox", + "title": "Loli Bae", + "substring": "Thank you for your continued support!\nいつも支援ありがとうご", + "published": "2023-05-14T00:00:00", + "file": { + "name": "8f183dac-470d-4587-9657-23efe8890a7b.jpg", + "path": "/e5/1f/e51fc831dfdac7a21cc650ad46af59340e35e2a051aed8c1e65633592f4dc11c.jpg" + }, + "attachments": [ + { + "name": "b644eb9c-cffa-400e-9bd6-40cccb2331ba.png", + "path": "/5e/b3/5eb3197668ac23bd7c473d3c750334eb206b060c610e4ac5fa1a9370fd1314d9.png" + }, + { + "name": "17f295ba-a9f2-4034-aafc-bf74904ec144.png", + "path": "/88/ad/88ad2ba77c89e4d7a9dbe1f9531ba3e3077a82aee2b61efa29fda122ebe1b516.png" + } + ] + } + ], + "discord_posts": [ + { + "file_id": 40694581, + "id": "769704201495904286", + "server": "455285536341491714", + "channel": "769703874356445216", + "substring": "", + "published": "2020-10-24T23:29:42.049", + "embeds": [], + "mentions": [], + "attachments": [ + { + "name": "3.png", + "path": "/b9/26/b926020cf035af45a1351e0a7e2c983ebcc93b4c751998321a6593a98277cdeb.png" + } + ] + } + ] + } + } + } + }, + "404": { + "description": "File not found" + } + } + } + }, + "/{service}/user/{creator_id}/post/{post}/flag": { + "post": { + "tags": [ + "Post Flagging" + ], + "summary": "Flag a post", + "parameters": [ + { + "name": "service", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "creator_id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "post", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "201": { + "description": "Flagged successfully", + "content": {} + }, + "409": { + "description": "Already flagged", + "content": {} + } + } + }, + "get": { + "tags": [ + "Post Flagging" + ], + "summary": "Check if a Post is flagged", + "description": "Check if a Post is flagged", + "parameters": [ + { + "name": "service", + "in": "path", + "description": "The service where the post is located", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "creator_id", + "in": "path", + "description": "The creator of the post", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "post", + "in": "path", + "description": "The ID of the post to flag", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "The post is flagged", + "content": {} + }, + "404": { + "description": "The post has no flag", + "content": {} + } + } + } + }, + "/{service}/user/{creator_id}/post/{post_id}/revisions": { + "get": { + "tags": [ + "Posts" + ], + "summary": "List a Post's Revisions", + "description": "List revisions of a specific post by service, creator_id, and post_id", + "parameters": [ + { + "name": "service", + "in": "path", + "description": "The service where the post is located", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "creator_id", + "in": "path", + "description": "The ID of the creator", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "post_id", + "in": "path", + "description": "The ID of the post", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "List of post revisions", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "revision_id": { + "type": "integer" + }, + "id": { + "type": "string" + }, + "user": { + "type": "string" + }, + "service": { + "type": "string" + }, + "title": { + "type": "string" + }, + "content": { + "type": "string" + }, + "embed": { + "type": "object" + }, + "shared_file": { + "type": "boolean" + }, + "added": { + "type": "string", + "format": "date-time" + }, + "published": { + "type": "string", + "format": "date-time" + }, + "edited": { + "type": "string", + "format": "date-time" + }, + "file": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "path": { + "type": "string" + } + } + }, + "attachments": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "path": { + "type": "string" + } + } + } + } + } + } + }, + "example": [ + { + "revision_id": 8059287, + "id": "1836570", + "user": "6570768", + "service": "fanbox", + "title": "今日はFANBOXを始まりました!", + "content": "

みなさんこんにちは、影おじです。

先週のように、FANBOXを始まりに決定しました!

そしてFANBOXの更新内容について、アンケートのみなさん

ありがとうございました!


では更新内容の詳しいことはこちらです↓

毎回の絵、元も差分がありませんの場合、ボナスとして差分イラストを支援者の皆様にプレゼント。

もとも差分があれば、ボナスとしてヌード差分イラストを支援者の皆様にプレゼント。


これから、仕事以外の時間、できる限り勤勉な更新したいと思います!

どうぞよろしくお願いいたします!

", + "embed": {}, + "shared_file": false, + "added": "2023-09-19T13:19:57.416086", + "published": "2021-01-24T17:54:38", + "edited": "2021-01-24T18:46:15", + "file": { + "name": "8c2be0fd-a130-4afb-9314-80f2501d94f7.jpg", + "path": "/5c/98/5c984d1f62f0990a0891d8fa359aecdff6ac1e26ac165ba7bb7f31cc99e7a674.jpg" + }, + "attachments": [ + { + "name": "attachment1.jpg", + "path": "/attachments/attachment1.jpg" + }, + { + "name": "attachment2.jpg", + "path": "/attachments/attachment2.jpg" + } + ] + }, + { + "revision_id": 6770513, + "id": "1836570", + "user": "6570768", + "service": "fanbox", + "title": "今日はFANBOXを始まりました!", + "content": "

みなさんこんにちは、影おじです。

先週のように、FANBOXを始まりに決定しました!

そしてFANBOXの更新内容について、アンケートのみなさん

ありがとうございました!


では更新内容の詳しいことはこちらです↓

毎回の絵、元も差分がありませんの場合、ボナスとして差分イラストを支援者の皆様にプレゼント。

もとも差分があれば、ボナスとしてヌード差分イラストを支援者の皆様にプレゼント。


これから、仕事以外の時間、できる限り勤勉な更新したいと思います!

どうぞよろしくお願いいたします!

", + "embed": {}, + "shared_file": false, + "added": "2023-07-28T23:51:25.477291", + "published": "2021-01-24T17:54:38", + "edited": "2021-01-24T18:46:15", + "file": { + "name": "0d133e49-a2d4-4733-9044-dd57e25b1fce.jpg", + "path": "/5c/98/5c984d1f62f0990a0891d8fa359aecdff6ac1e26ac165ba7bb7f31cc99e7a674.jpg" + }, + "attachments": [ + { + "name": "attachment3.jpg", + "path": "/attachments/attachment3.jpg" + }, + { + "name": "attachment4.jpg", + "path": "/attachments/attachment4.jpg" + } + ] + } + ] + } + } + }, + "404": { + "description": "Post not found" + } + } + } + }, + "/{service}/user/{creator_id}/post/{post_id}/comments": { + "get": { + "tags": [ + "Comments" + ], + "summary": "List a post's comments", + "description": "List comments for a specific post by service, creator_id, and post_id.", + "parameters": [ + { + "name": "service", + "in": "path", + "description": "The post's service.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "creator_id", + "in": "path", + "description": "The service ID of the post's creator.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "post_id", + "in": "path", + "description": "The service ID of the post.", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "List of post comments.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "parent_id": { + "type": "string", + "nullable": true + }, + "commenter": { + "type": "string" + }, + "content": { + "type": "string" + }, + "published": { + "type": "string", + "format": "date-time" + }, + "revisions": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "content": { + "type": "string" + }, + "added": { + "type": "string", + "format": "date-time" + } + } + } + } + } + } + }, + "example": [ + { + "id": "121508687", + "parent_id": null, + "commenter": "84534108", + "content": "YOU DREW MORE YAYYYY", + "published": "2023-11-05T20:17:47.635000", + "revisions": [ + { + "id": 1, + "content": "YOU DREW MORE YAYYYY2222222", + "added": "2023-11-14T03:09:12.275975" + } + ] + } + ] + } + } + }, + "404": { + "description": "No comments found." + } + } + } + }, + "/app_version": { + "get": { + "tags": [ + "Misc" + ], + "summary": "Git Commit Hash", + "description": "Show current App commit hash", + "responses": { + "200": { + "description": "Commit Hash", + "content": { + "text/plain": { + "schema": { + "type": "string", + "format": "hex", + "minLength": 40, + "maxLength": 40, + "example": "3b9cd5fab1d35316436968fe85c90ff2de0cdca0" + } + } + } + } + } + } + } + }, + "components": { + "securitySchemes": { + "cookieAuth": { + "description": "Session key that can be found in cookies after a successful login", + "type": "apiKey", + "in": "cookie", + "name": "session" + } + }, + "responses": { + "401": { + "description": "Unauthorized", + "content": {} + } + } + } +} \ No newline at end of file diff --git a/daemons/kemono/daemon.go b/daemons/kemono/daemon.go new file mode 100644 index 0000000..66a1343 --- /dev/null +++ b/daemons/kemono/daemon.go @@ -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 +} diff --git a/daemons/kemono/daemon_test.go b/daemons/kemono/daemon_test.go new file mode 100644 index 0000000..8c418ae --- /dev/null +++ b/daemons/kemono/daemon_test.go @@ -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) + } +} diff --git a/daemons/kemono/fetch.go b/daemons/kemono/fetch.go new file mode 100644 index 0000000..672dbd8 --- /dev/null +++ b/daemons/kemono/fetch.go @@ -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 +} diff --git a/daemons/kemono/go.mod b/daemons/kemono/go.mod new file mode 100644 index 0000000..ac8b47f --- /dev/null +++ b/daemons/kemono/go.mod @@ -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 +) diff --git a/daemons/kemono/go.sum b/daemons/kemono/go.sum new file mode 100644 index 0000000..1c19d33 --- /dev/null +++ b/daemons/kemono/go.sum @@ -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= diff --git a/daemons/kemono/kemono.go b/daemons/kemono/kemono.go new file mode 100644 index 0000000..ecb313a --- /dev/null +++ b/daemons/kemono/kemono.go @@ -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(:)][]PostFilter + postFilters map[string][]PostFilter + + // Attachment filter map[creator(:)][]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 +// } +// } diff --git a/daemons/kemono/tools.go b/daemons/kemono/tools.go new file mode 100644 index 0000000..5d27f64 --- /dev/null +++ b/daemons/kemono/tools.go @@ -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 diff --git a/daemons/kemono/types.go b/daemons/kemono/types.go new file mode 100644 index 0000000..c1cc4da --- /dev/null +++ b/daemons/kemono/types.go @@ -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", +} diff --git a/daemons/kemono/utils.go b/daemons/kemono/utils.go new file mode 100644 index 0000000..f892e6c --- /dev/null +++ b/daemons/kemono/utils.go @@ -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 +} diff --git a/src/daemons/qbittorrent/api.go b/daemons/qbittorrent/api.go similarity index 100% rename from src/daemons/qbittorrent/api.go rename to daemons/qbittorrent/api.go diff --git a/src/daemons/qbittorrent/cleanup.go b/daemons/qbittorrent/cleanup.go similarity index 95% rename from src/daemons/qbittorrent/cleanup.go rename to daemons/qbittorrent/cleanup.go index 21a32d4..c8b08c9 100644 --- a/src/daemons/qbittorrent/cleanup.go +++ b/daemons/qbittorrent/cleanup.go @@ -12,7 +12,7 @@ import ( "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") 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), ) - if dryRun { + if !run { d.log.Info(ctx, "dry run, skipping deletion") return torrentToDelete, nil } diff --git a/src/daemons/qbittorrent/client.go b/daemons/qbittorrent/client.go similarity index 100% rename from src/daemons/qbittorrent/client.go rename to daemons/qbittorrent/client.go diff --git a/src/daemons/qbittorrent/daemon.go b/daemons/qbittorrent/daemon.go similarity index 97% rename from src/daemons/qbittorrent/daemon.go rename to daemons/qbittorrent/daemon.go index 143752c..cd53747 100644 --- a/src/daemons/qbittorrent/daemon.go +++ b/daemons/qbittorrent/daemon.go @@ -26,7 +26,7 @@ import ( "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 { proc *os.Process @@ -231,6 +231,9 @@ func (d *Daemon) syncTorrentState(ctx context.Context, file vfs.File, ih metainf if err == nil { break } + if errors.Is(err, context.DeadlineExceeded) { + return err + } log.Error(ctx, "waiting for torrent to be added", rlog.Error(err)) time.Sleep(time.Millisecond * 15) } diff --git a/src/daemons/qbittorrent/fs.go b/daemons/qbittorrent/fs.go similarity index 100% rename from src/daemons/qbittorrent/fs.go rename to daemons/qbittorrent/fs.go diff --git a/src/daemons/qbittorrent/install.go b/daemons/qbittorrent/install.go similarity index 100% rename from src/daemons/qbittorrent/install.go rename to daemons/qbittorrent/install.go diff --git a/src/daemons/qbittorrent/install_test.go b/daemons/qbittorrent/install_test.go similarity index 100% rename from src/daemons/qbittorrent/install_test.go rename to daemons/qbittorrent/install_test.go diff --git a/src/daemons/torrent/client.go b/daemons/torrent/client.go similarity index 100% rename from src/daemons/torrent/client.go rename to daemons/torrent/client.go diff --git a/src/daemons/torrent/controller.go b/daemons/torrent/controller.go similarity index 100% rename from src/daemons/torrent/controller.go rename to daemons/torrent/controller.go diff --git a/src/daemons/torrent/daemon.go b/daemons/torrent/daemon.go similarity index 100% rename from src/daemons/torrent/daemon.go rename to daemons/torrent/daemon.go diff --git a/src/daemons/torrent/daemon_load.go b/daemons/torrent/daemon_load.go similarity index 100% rename from src/daemons/torrent/daemon_load.go rename to daemons/torrent/daemon_load.go diff --git a/src/daemons/torrent/daemon_stats.go b/daemons/torrent/daemon_stats.go similarity index 100% rename from src/daemons/torrent/daemon_stats.go rename to daemons/torrent/daemon_stats.go diff --git a/src/daemons/torrent/dht_fileitem_store.go b/daemons/torrent/dht_fileitem_store.go similarity index 100% rename from src/daemons/torrent/dht_fileitem_store.go rename to daemons/torrent/dht_fileitem_store.go diff --git a/src/daemons/torrent/dup_cache.go b/daemons/torrent/dup_cache.go similarity index 100% rename from src/daemons/torrent/dup_cache.go rename to daemons/torrent/dup_cache.go diff --git a/src/daemons/torrent/file_controller.go b/daemons/torrent/file_controller.go similarity index 100% rename from src/daemons/torrent/file_controller.go rename to daemons/torrent/file_controller.go diff --git a/src/daemons/torrent/fs.go b/daemons/torrent/fs.go similarity index 100% rename from src/daemons/torrent/fs.go rename to daemons/torrent/fs.go diff --git a/src/daemons/torrent/fs_test.go b/daemons/torrent/fs_test.go similarity index 100% rename from src/daemons/torrent/fs_test.go rename to daemons/torrent/fs_test.go diff --git a/src/daemons/torrent/infobytes.go b/daemons/torrent/infobytes.go similarity index 100% rename from src/daemons/torrent/infobytes.go rename to daemons/torrent/infobytes.go diff --git a/src/daemons/torrent/metrics.go b/daemons/torrent/metrics.go similarity index 100% rename from src/daemons/torrent/metrics.go rename to daemons/torrent/metrics.go diff --git a/src/daemons/torrent/peer_store.go b/daemons/torrent/peer_store.go similarity index 100% rename from src/daemons/torrent/peer_store.go rename to daemons/torrent/peer_store.go diff --git a/src/daemons/torrent/piece_completion.go b/daemons/torrent/piece_completion.go similarity index 100% rename from src/daemons/torrent/piece_completion.go rename to daemons/torrent/piece_completion.go diff --git a/src/daemons/torrent/piece_completion_test.go b/daemons/torrent/piece_completion_test.go similarity index 100% rename from src/daemons/torrent/piece_completion_test.go rename to daemons/torrent/piece_completion_test.go diff --git a/src/daemons/torrent/queue.go b/daemons/torrent/queue.go similarity index 100% rename from src/daemons/torrent/queue.go rename to daemons/torrent/queue.go diff --git a/src/daemons/torrent/setup.go b/daemons/torrent/setup.go similarity index 100% rename from src/daemons/torrent/setup.go rename to daemons/torrent/setup.go diff --git a/src/daemons/torrent/stats.go b/daemons/torrent/stats.go similarity index 100% rename from src/daemons/torrent/stats.go rename to daemons/torrent/stats.go diff --git a/src/daemons/torrent/storage.go b/daemons/torrent/storage.go similarity index 100% rename from src/daemons/torrent/storage.go rename to daemons/torrent/storage.go diff --git a/src/daemons/torrent/storage_dedupe.go b/daemons/torrent/storage_dedupe.go similarity index 100% rename from src/daemons/torrent/storage_dedupe.go rename to daemons/torrent/storage_dedupe.go diff --git a/src/daemons/torrent/storage_open.go b/daemons/torrent/storage_open.go similarity index 100% rename from src/daemons/torrent/storage_open.go rename to daemons/torrent/storage_open.go diff --git a/src/daemons/ytdlp/controller.go b/daemons/ytdlp/controller.go similarity index 100% rename from src/daemons/ytdlp/controller.go rename to daemons/ytdlp/controller.go diff --git a/src/daemons/ytdlp/daemon.go b/daemons/ytdlp/daemon.go similarity index 100% rename from src/daemons/ytdlp/daemon.go rename to daemons/ytdlp/daemon.go diff --git a/src/daemons/ytdlp/fs.go b/daemons/ytdlp/fs.go similarity index 100% rename from src/daemons/ytdlp/fs.go rename to daemons/ytdlp/fs.go diff --git a/src/daemons/ytdlp/tasks.go b/daemons/ytdlp/tasks.go similarity index 100% rename from src/daemons/ytdlp/tasks.go rename to daemons/ytdlp/tasks.go diff --git a/src/daemons/ytdlp/ytdlp.go b/daemons/ytdlp/ytdlp.go similarity index 100% rename from src/daemons/ytdlp/ytdlp.go rename to daemons/ytdlp/ytdlp.go diff --git a/graphql/sources/qbittorrent_mutation.graphql b/graphql/sources/qbittorrent_mutation.graphql index c5d5809..aba4408 100644 --- a/graphql/sources/qbittorrent_mutation.graphql +++ b/graphql/sources/qbittorrent_mutation.graphql @@ -1,5 +1,5 @@ type QBitTorrentDaemonMutation { - cleanup(dryRun: Boolean!): QBitCleanupResponse! @resolver + cleanup(run: Boolean!): QBitCleanupResponse! @resolver } type QBitCleanupResponse { diff --git a/src/daemons/storage.go b/src/daemons/storage.go index df121f8..b67dc7f 100644 --- a/src/daemons/storage.go +++ b/src/daemons/storage.go @@ -3,8 +3,8 @@ package daemons import ( "context" - "git.kmsign.ru/royalcat/tstor/src/daemons/qbittorrent" - "git.kmsign.ru/royalcat/tstor/src/daemons/ytdlp" + "git.kmsign.ru/royalcat/tstor/daemons/qbittorrent" + "git.kmsign.ru/royalcat/tstor/daemons/ytdlp" "git.kmsign.ru/royalcat/tstor/src/vfs" ) diff --git a/src/delivery/graphql/generated.go b/src/delivery/graphql/generated.go index 501cf2b..47b1936 100644 --- a/src/delivery/graphql/generated.go +++ b/src/delivery/graphql/generated.go @@ -41,20 +41,9 @@ type Config struct { } type ResolverRoot interface { - ArchiveFS() ArchiveFSResolver Mutation() MutationResolver - QBitTorrentDaemonMutation() QBitTorrentDaemonMutationResolver - QBitTorrentDaemonQuery() QBitTorrentDaemonQueryResolver - QTorrent() QTorrentResolver Query() QueryResolver - ResolverFS() ResolverFSResolver - SimpleDir() SimpleDirResolver Subscription() SubscriptionResolver - Torrent() TorrentResolver - TorrentDaemonMutation() TorrentDaemonMutationResolver - TorrentDaemonQuery() TorrentDaemonQueryResolver - TorrentFS() TorrentFSResolver - TorrentFile() TorrentFileResolver } type DirectiveRoot struct { @@ -92,7 +81,7 @@ type ComplexityRoot struct { } QBitTorrentDaemonMutation struct { - Cleanup func(childComplexity int, dryRun bool) int + Cleanup func(childComplexity int, run bool) int } QBitTorrentDaemonQuery struct { @@ -223,62 +212,21 @@ type ComplexityRoot struct { } } -type ArchiveFSResolver interface { - Entries(ctx context.Context, obj *model.ArchiveFs) ([]model.FsEntry, error) -} type MutationResolver interface { TorrentDaemon(ctx context.Context) (*model.TorrentDaemonMutation, error) QbitTorrentDaemon(ctx context.Context) (*model.QBitTorrentDaemonMutation, error) UploadFile(ctx context.Context, dir string, file graphql.Upload) (bool, error) DedupeStorage(ctx context.Context) (int64, error) } -type QBitTorrentDaemonMutationResolver interface { - Cleanup(ctx context.Context, obj *model.QBitTorrentDaemonMutation, dryRun bool) (*model.QBitCleanupResponse, error) -} -type QBitTorrentDaemonQueryResolver interface { - Torrents(ctx context.Context, obj *model.QBitTorrentDaemonQuery) ([]*model.QTorrent, error) -} -type QTorrentResolver interface { - SourceFiles(ctx context.Context, obj *model.QTorrent) ([]string, error) -} type QueryResolver interface { TorrentDaemon(ctx context.Context) (*model.TorrentDaemonQuery, error) QbitTorrentDaemon(ctx context.Context) (*model.QBitTorrentDaemonQuery, error) FsEntry(ctx context.Context, path string) (model.FsEntry, error) } -type ResolverFSResolver interface { - Entries(ctx context.Context, obj *model.ResolverFs) ([]model.FsEntry, error) -} -type SimpleDirResolver interface { - Entries(ctx context.Context, obj *model.SimpleDir) ([]model.FsEntry, error) -} type SubscriptionResolver interface { TaskProgress(ctx context.Context, taskID string) (<-chan model.Progress, error) TorrentDownloadUpdates(ctx context.Context) (<-chan *model.TorrentProgress, error) } -type TorrentResolver interface { - Name(ctx context.Context, obj *model.Torrent) (string, 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) - ClientStats(ctx context.Context, obj *model.TorrentDaemonQuery) (*model.TorrentClientStats, error) - StatsHistory(ctx context.Context, obj *model.TorrentDaemonQuery, since time.Time, infohash *string) ([]*model.TorrentStats, error) -} -type TorrentFSResolver interface { - Entries(ctx context.Context, obj *model.TorrentFs) ([]model.FsEntry, error) -} -type TorrentFileResolver interface { - Priority(ctx context.Context, obj *model.TorrentFile) (types.PiecePriority, error) -} type executableSchema struct { schema *ast.Schema @@ -398,7 +346,7 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return 0, false } - return e.complexity.QBitTorrentDaemonMutation.Cleanup(childComplexity, args["dryRun"].(bool)), true + return e.complexity.QBitTorrentDaemonMutation.Cleanup(childComplexity, args["run"].(bool)), true case "QBitTorrentDaemonQuery.torrents": if e.complexity.QBitTorrentDaemonQuery.Torrents == nil { @@ -1105,7 +1053,7 @@ interface Progress { total: Int! }`, BuiltIn: false}, {Name: "../../../graphql/sources/qbittorrent_mutation.graphql", Input: `type QBitTorrentDaemonMutation { - cleanup(dryRun: Boolean!): QBitCleanupResponse! @resolver + cleanup(run: Boolean!): QBitCleanupResponse! @resolver } type QBitCleanupResponse { @@ -1384,28 +1332,28 @@ func (ec *executionContext) field_Mutation_uploadFile_argsFile( func (ec *executionContext) field_QBitTorrentDaemonMutation_cleanup_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} - arg0, err := ec.field_QBitTorrentDaemonMutation_cleanup_argsDryRun(ctx, rawArgs) + arg0, err := ec.field_QBitTorrentDaemonMutation_cleanup_argsRun(ctx, rawArgs) if err != nil { return nil, err } - args["dryRun"] = arg0 + args["run"] = arg0 return args, nil } -func (ec *executionContext) field_QBitTorrentDaemonMutation_cleanup_argsDryRun( +func (ec *executionContext) field_QBitTorrentDaemonMutation_cleanup_argsRun( ctx context.Context, rawArgs map[string]interface{}, ) (bool, error) { // We won't call the directive if the argument is null. // Set call_argument_directives_with_null to true to call directives // even if the argument is null. - _, ok := rawArgs["dryRun"] + _, ok := rawArgs["run"] if !ok { var zeroVal bool return zeroVal, nil } - ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("dryRun")) - if tmp, ok := rawArgs["dryRun"]; ok { + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("run")) + if tmp, ok := rawArgs["run"]; ok { return ec.unmarshalNBoolean2bool(ctx, tmp) } @@ -1908,7 +1856,7 @@ func (ec *executionContext) _ArchiveFS_entries(ctx context.Context, field graphq 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.ArchiveFS().Entries(rctx, obj) + return obj.Entries, nil } directive1 := func(ctx context.Context) (interface{}, error) { @@ -1950,8 +1898,8 @@ func (ec *executionContext) fieldContext_ArchiveFS_entries(_ context.Context, fi fc = &graphql.FieldContext{ Object: "ArchiveFS", Field: field, - IsMethod: true, - IsResolver: true, + IsMethod: false, + IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("FieldContext.Child cannot be called on type INTERFACE") }, @@ -2476,7 +2424,7 @@ func (ec *executionContext) _QBitTorrentDaemonMutation_cleanup(ctx context.Conte 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.QBitTorrentDaemonMutation().Cleanup(rctx, obj, fc.Args["dryRun"].(bool)) + return obj.Cleanup, nil } directive1 := func(ctx context.Context) (interface{}, error) { @@ -2518,8 +2466,8 @@ func (ec *executionContext) fieldContext_QBitTorrentDaemonMutation_cleanup(ctx c fc = &graphql.FieldContext{ Object: "QBitTorrentDaemonMutation", Field: field, - IsMethod: true, - IsResolver: true, + IsMethod: false, + IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "count": @@ -2559,7 +2507,7 @@ func (ec *executionContext) _QBitTorrentDaemonQuery_torrents(ctx context.Context 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.QBitTorrentDaemonQuery().Torrents(rctx, obj) + return obj.Torrents, nil } directive1 := func(ctx context.Context) (interface{}, error) { @@ -2601,8 +2549,8 @@ func (ec *executionContext) fieldContext_QBitTorrentDaemonQuery_torrents(_ conte fc = &graphql.FieldContext{ Object: "QBitTorrentDaemonQuery", Field: field, - IsMethod: true, - IsResolver: true, + IsMethod: false, + IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "name": @@ -2721,7 +2669,7 @@ func (ec *executionContext) _QTorrent_sourceFiles(ctx context.Context, field gra 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.QTorrent().SourceFiles(rctx, obj) + return obj.SourceFiles, nil } directive1 := func(ctx context.Context) (interface{}, error) { @@ -2763,8 +2711,8 @@ func (ec *executionContext) fieldContext_QTorrent_sourceFiles(_ context.Context, fc = &graphql.FieldContext{ Object: "QTorrent", Field: field, - IsMethod: true, - IsResolver: true, + IsMethod: false, + IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, @@ -3150,7 +3098,7 @@ func (ec *executionContext) _ResolverFS_entries(ctx context.Context, field graph 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.ResolverFS().Entries(rctx, obj) + return obj.Entries, nil } directive1 := func(ctx context.Context) (interface{}, error) { @@ -3192,8 +3140,8 @@ func (ec *executionContext) fieldContext_ResolverFS_entries(_ context.Context, f fc = &graphql.FieldContext{ Object: "ResolverFS", Field: field, - IsMethod: true, - IsResolver: true, + IsMethod: false, + IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("FieldContext.Child cannot be called on type INTERFACE") }, @@ -3342,7 +3290,7 @@ func (ec *executionContext) _SimpleDir_entries(ctx context.Context, field graphq 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.SimpleDir().Entries(rctx, obj) + return obj.Entries, nil } directive1 := func(ctx context.Context) (interface{}, error) { @@ -3384,8 +3332,8 @@ func (ec *executionContext) fieldContext_SimpleDir_entries(_ context.Context, fi fc = &graphql.FieldContext{ Object: "SimpleDir", Field: field, - IsMethod: true, - IsResolver: true, + IsMethod: false, + IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("FieldContext.Child cannot be called on type INTERFACE") }, @@ -3669,7 +3617,7 @@ func (ec *executionContext) _Torrent_name(ctx context.Context, field graphql.Col 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().Name(rctx, obj) + return obj.Name, nil } directive1 := func(ctx context.Context) (interface{}, error) { @@ -3711,8 +3659,8 @@ func (ec *executionContext) fieldContext_Torrent_name(_ context.Context, field g fc = &graphql.FieldContext{ Object: "Torrent", Field: field, - IsMethod: true, - IsResolver: true, + IsMethod: false, + IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, @@ -3955,7 +3903,7 @@ func (ec *executionContext) _Torrent_files(ctx context.Context, field graphql.Co 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().Files(rctx, obj) + return obj.Files, nil } directive1 := func(ctx context.Context) (interface{}, error) { @@ -3997,8 +3945,8 @@ func (ec *executionContext) fieldContext_Torrent_files(_ context.Context, field fc = &graphql.FieldContext{ Object: "Torrent", Field: field, - IsMethod: true, - IsResolver: true, + IsMethod: false, + IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "filename": @@ -4031,7 +3979,7 @@ func (ec *executionContext) _Torrent_excludedFiles(ctx context.Context, field gr 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().ExcludedFiles(rctx, obj) + return obj.ExcludedFiles, nil } directive1 := func(ctx context.Context) (interface{}, error) { @@ -4073,8 +4021,8 @@ func (ec *executionContext) fieldContext_Torrent_excludedFiles(_ context.Context fc = &graphql.FieldContext{ Object: "Torrent", Field: field, - IsMethod: true, - IsResolver: true, + IsMethod: false, + IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "filename": @@ -4107,7 +4055,7 @@ func (ec *executionContext) _Torrent_peers(ctx context.Context, field graphql.Co 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().Peers(rctx, obj) + return obj.Peers, nil } directive1 := func(ctx context.Context) (interface{}, error) { @@ -4149,8 +4097,8 @@ func (ec *executionContext) fieldContext_Torrent_peers(_ context.Context, field fc = &graphql.FieldContext{ Object: "Torrent", Field: field, - IsMethod: true, - IsResolver: true, + IsMethod: false, + IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "ip": @@ -4757,7 +4705,7 @@ func (ec *executionContext) _TorrentDaemonMutation_validateTorrent(ctx context.C 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().ValidateTorrent(rctx, obj, fc.Args["filter"].(model.TorrentFilter)) + return obj.ValidateTorrent, nil } directive1 := func(ctx context.Context) (interface{}, error) { @@ -4799,8 +4747,8 @@ func (ec *executionContext) fieldContext_TorrentDaemonMutation_validateTorrent(c fc = &graphql.FieldContext{ Object: "TorrentDaemonMutation", Field: field, - IsMethod: true, - IsResolver: true, + IsMethod: false, + IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Boolean does not have child fields") }, @@ -4834,7 +4782,7 @@ func (ec *executionContext) _TorrentDaemonMutation_setTorrentPriority(ctx contex 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)) + return obj.SetTorrentPriority, nil } directive1 := func(ctx context.Context) (interface{}, error) { @@ -4876,8 +4824,8 @@ func (ec *executionContext) fieldContext_TorrentDaemonMutation_setTorrentPriorit fc = &graphql.FieldContext{ Object: "TorrentDaemonMutation", Field: field, - IsMethod: true, - IsResolver: true, + IsMethod: false, + IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Boolean does not have child fields") }, @@ -4911,7 +4859,7 @@ func (ec *executionContext) _TorrentDaemonMutation_cleanup(ctx context.Context, 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)) + return obj.Cleanup, nil } directive1 := func(ctx context.Context) (interface{}, error) { @@ -4953,8 +4901,8 @@ func (ec *executionContext) fieldContext_TorrentDaemonMutation_cleanup(ctx conte fc = &graphql.FieldContext{ Object: "TorrentDaemonMutation", Field: field, - IsMethod: true, - IsResolver: true, + IsMethod: false, + IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "count": @@ -4994,7 +4942,7 @@ func (ec *executionContext) _TorrentDaemonQuery_torrents(ctx context.Context, fi 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)) + return obj.Torrents, nil } directive1 := func(ctx context.Context) (interface{}, error) { @@ -5036,8 +4984,8 @@ func (ec *executionContext) fieldContext_TorrentDaemonQuery_torrents(ctx context fc = &graphql.FieldContext{ Object: "TorrentDaemonQuery", Field: field, - IsMethod: true, - IsResolver: true, + IsMethod: false, + IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "name": @@ -5091,7 +5039,7 @@ func (ec *executionContext) _TorrentDaemonQuery_clientStats(ctx context.Context, 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().ClientStats(rctx, obj) + return obj.ClientStats, nil } directive1 := func(ctx context.Context) (interface{}, error) { @@ -5133,8 +5081,8 @@ func (ec *executionContext) fieldContext_TorrentDaemonQuery_clientStats(_ contex fc = &graphql.FieldContext{ Object: "TorrentDaemonQuery", Field: field, - IsMethod: true, - IsResolver: true, + IsMethod: false, + IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "bytesWritten": @@ -5185,7 +5133,7 @@ func (ec *executionContext) _TorrentDaemonQuery_statsHistory(ctx context.Context 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().StatsHistory(rctx, obj, fc.Args["since"].(time.Time), fc.Args["infohash"].(*string)) + return obj.StatsHistory, nil } directive1 := func(ctx context.Context) (interface{}, error) { @@ -5227,8 +5175,8 @@ func (ec *executionContext) fieldContext_TorrentDaemonQuery_statsHistory(ctx con fc = &graphql.FieldContext{ Object: "TorrentDaemonQuery", Field: field, - IsMethod: true, - IsResolver: true, + IsMethod: false, + IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "timestamp": @@ -5384,7 +5332,7 @@ func (ec *executionContext) _TorrentFS_entries(ctx context.Context, field graphq 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.TorrentFS().Entries(rctx, obj) + return obj.Entries, nil } directive1 := func(ctx context.Context) (interface{}, error) { @@ -5426,8 +5374,8 @@ func (ec *executionContext) fieldContext_TorrentFS_entries(_ context.Context, fi fc = &graphql.FieldContext{ Object: "TorrentFS", Field: field, - IsMethod: true, - IsResolver: true, + IsMethod: false, + IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("FieldContext.Child cannot be called on type INTERFACE") }, @@ -5582,7 +5530,7 @@ func (ec *executionContext) _TorrentFile_priority(ctx context.Context, field gra 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.TorrentFile().Priority(rctx, obj) + return obj.Priority, nil } directive1 := func(ctx context.Context) (interface{}, error) { @@ -5624,8 +5572,8 @@ func (ec *executionContext) fieldContext_TorrentFile_priority(_ context.Context, fc = &graphql.FieldContext{ Object: "TorrentFile", Field: field, - IsMethod: true, - IsResolver: true, + IsMethod: false, + IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type TorrentPriority does not have child fields") }, @@ -8928,46 +8876,160 @@ func (ec *executionContext) unmarshalInputTorrentsFilter(ctx context.Context, ob switch k { case "infohash": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("infohash")) - data, err := ec.unmarshalOStringFilter2ᚖgitᚗkmsignᚗruᚋroyalcatᚋtstorᚋsrcᚋdeliveryᚋgraphqlᚋmodelᚐStringFilter(ctx, v) - if err != nil { - return it, err + directive0 := func(ctx context.Context) (interface{}, error) { + return ec.unmarshalOStringFilter2ᚖgitᚗkmsignᚗruᚋroyalcatᚋtstorᚋsrcᚋdeliveryᚋgraphqlᚋmodelᚐStringFilter(ctx, v) + } + + directive1 := func(ctx context.Context) (interface{}, error) { + if ec.directives.OneOf == nil { + var zeroVal *model.StringFilter + return zeroVal, 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.(*model.StringFilter); ok { + it.Infohash = data + } else if tmp == nil { + it.Infohash = nil + } else { + err := fmt.Errorf(`unexpected type %T from directive, should be *git.kmsign.ru/royalcat/tstor/src/delivery/graphql/model.StringFilter`, tmp) + return it, graphql.ErrorOnPath(ctx, err) } - it.Infohash = data case "name": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("name")) - data, err := ec.unmarshalOStringFilter2ᚖgitᚗkmsignᚗruᚋroyalcatᚋtstorᚋsrcᚋdeliveryᚋgraphqlᚋmodelᚐStringFilter(ctx, v) - if err != nil { - return it, err + directive0 := func(ctx context.Context) (interface{}, error) { + return ec.unmarshalOStringFilter2ᚖgitᚗkmsignᚗruᚋroyalcatᚋtstorᚋsrcᚋdeliveryᚋgraphqlᚋmodelᚐStringFilter(ctx, v) + } + + directive1 := func(ctx context.Context) (interface{}, error) { + if ec.directives.OneOf == nil { + var zeroVal *model.StringFilter + return zeroVal, 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.(*model.StringFilter); ok { + it.Name = data + } else if tmp == nil { + it.Name = nil + } else { + err := fmt.Errorf(`unexpected type %T from directive, should be *git.kmsign.ru/royalcat/tstor/src/delivery/graphql/model.StringFilter`, tmp) + return it, graphql.ErrorOnPath(ctx, err) } - it.Name = data case "bytesCompleted": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("bytesCompleted")) - data, err := ec.unmarshalOIntFilter2ᚖgitᚗkmsignᚗruᚋroyalcatᚋtstorᚋsrcᚋdeliveryᚋgraphqlᚋmodelᚐIntFilter(ctx, v) - if err != nil { - return it, err + directive0 := func(ctx context.Context) (interface{}, error) { + return ec.unmarshalOIntFilter2ᚖgitᚗkmsignᚗruᚋroyalcatᚋtstorᚋsrcᚋdeliveryᚋgraphqlᚋmodelᚐIntFilter(ctx, v) + } + + directive1 := func(ctx context.Context) (interface{}, error) { + if ec.directives.OneOf == nil { + var zeroVal *model.IntFilter + return zeroVal, 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.(*model.IntFilter); ok { + it.BytesCompleted = data + } else if tmp == nil { + it.BytesCompleted = nil + } else { + err := fmt.Errorf(`unexpected type %T from directive, should be *git.kmsign.ru/royalcat/tstor/src/delivery/graphql/model.IntFilter`, tmp) + return it, graphql.ErrorOnPath(ctx, err) } - it.BytesCompleted = data case "bytesMissing": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("bytesMissing")) - data, err := ec.unmarshalOIntFilter2ᚖgitᚗkmsignᚗruᚋroyalcatᚋtstorᚋsrcᚋdeliveryᚋgraphqlᚋmodelᚐIntFilter(ctx, v) - if err != nil { - return it, err + directive0 := func(ctx context.Context) (interface{}, error) { + return ec.unmarshalOIntFilter2ᚖgitᚗkmsignᚗruᚋroyalcatᚋtstorᚋsrcᚋdeliveryᚋgraphqlᚋmodelᚐIntFilter(ctx, v) + } + + directive1 := func(ctx context.Context) (interface{}, error) { + if ec.directives.OneOf == nil { + var zeroVal *model.IntFilter + return zeroVal, 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.(*model.IntFilter); ok { + it.BytesMissing = data + } else if tmp == nil { + it.BytesMissing = nil + } else { + err := fmt.Errorf(`unexpected type %T from directive, should be *git.kmsign.ru/royalcat/tstor/src/delivery/graphql/model.IntFilter`, tmp) + return it, graphql.ErrorOnPath(ctx, err) } - it.BytesMissing = data case "peersCount": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("peersCount")) - data, err := ec.unmarshalOIntFilter2ᚖgitᚗkmsignᚗruᚋroyalcatᚋtstorᚋsrcᚋdeliveryᚋgraphqlᚋmodelᚐIntFilter(ctx, v) - if err != nil { - return it, err + directive0 := func(ctx context.Context) (interface{}, error) { + return ec.unmarshalOIntFilter2ᚖgitᚗkmsignᚗruᚋroyalcatᚋtstorᚋsrcᚋdeliveryᚋgraphqlᚋmodelᚐIntFilter(ctx, v) + } + + directive1 := func(ctx context.Context) (interface{}, error) { + if ec.directives.OneOf == nil { + var zeroVal *model.IntFilter + return zeroVal, 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.(*model.IntFilter); ok { + it.PeersCount = data + } else if tmp == nil { + it.PeersCount = nil + } else { + err := fmt.Errorf(`unexpected type %T from directive, should be *git.kmsign.ru/royalcat/tstor/src/delivery/graphql/model.IntFilter`, tmp) + return it, graphql.ErrorOnPath(ctx, err) } - it.PeersCount = data 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 + directive0 := func(ctx context.Context) (interface{}, error) { + return ec.unmarshalOTorrentPriorityFilter2ᚖgitᚗkmsignᚗruᚋroyalcatᚋtstorᚋsrcᚋdeliveryᚋgraphqlᚋmodelᚐTorrentPriorityFilter(ctx, v) + } + + directive1 := func(ctx context.Context) (interface{}, error) { + if ec.directives.OneOf == nil { + var zeroVal *model.TorrentPriorityFilter + return zeroVal, 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.(*model.TorrentPriorityFilter); ok { + it.Priority = data + } else if tmp == nil { + it.Priority = nil + } else { + err := fmt.Errorf(`unexpected type %T from directive, should be *git.kmsign.ru/royalcat/tstor/src/delivery/graphql/model.TorrentPriorityFilter`, tmp) + return it, graphql.ErrorOnPath(ctx, err) } - it.Priority = data } } @@ -9133,48 +9195,17 @@ func (ec *executionContext) _ArchiveFS(ctx context.Context, sel ast.SelectionSet case "name": out.Values[i] = ec._ArchiveFS_name(ctx, field, obj) if out.Values[i] == graphql.Null { - atomic.AddUint32(&out.Invalids, 1) + out.Invalids++ } case "entries": - 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._ArchiveFS_entries(ctx, field, obj) - if res == graphql.Null { - atomic.AddUint32(&fs.Invalids, 1) - } - return res + out.Values[i] = ec._ArchiveFS_entries(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ } - - 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 "size": out.Values[i] = ec._ArchiveFS_size(ctx, field, obj) if out.Values[i] == graphql.Null { - atomic.AddUint32(&out.Invalids, 1) + out.Invalids++ } default: panic("unknown field " + strconv.Quote(field.Name)) @@ -9399,41 +9430,10 @@ func (ec *executionContext) _QBitTorrentDaemonMutation(ctx context.Context, sel case "__typename": out.Values[i] = graphql.MarshalString("QBitTorrentDaemonMutation") 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._QBitTorrentDaemonMutation_cleanup(ctx, field, obj) - if res == graphql.Null { - atomic.AddUint32(&fs.Invalids, 1) - } - return res + out.Values[i] = ec._QBitTorrentDaemonMutation_cleanup(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ } - - 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)) } @@ -9469,41 +9469,10 @@ func (ec *executionContext) _QBitTorrentDaemonQuery(ctx context.Context, sel ast case "__typename": out.Values[i] = graphql.MarshalString("QBitTorrentDaemonQuery") 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._QBitTorrentDaemonQuery_torrents(ctx, field, obj) - if res == graphql.Null { - atomic.AddUint32(&fs.Invalids, 1) - } - return res + out.Values[i] = ec._QBitTorrentDaemonQuery_torrents(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ } - - 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)) } @@ -9541,49 +9510,18 @@ func (ec *executionContext) _QTorrent(ctx context.Context, sel ast.SelectionSet, case "name": out.Values[i] = ec._QTorrent_name(ctx, field, obj) if out.Values[i] == graphql.Null { - atomic.AddUint32(&out.Invalids, 1) + out.Invalids++ } case "hash": out.Values[i] = ec._QTorrent_hash(ctx, field, obj) if out.Values[i] == graphql.Null { - atomic.AddUint32(&out.Invalids, 1) + out.Invalids++ } case "sourceFiles": - 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._QTorrent_sourceFiles(ctx, field, obj) - if res == graphql.Null { - atomic.AddUint32(&fs.Invalids, 1) - } - return res + out.Values[i] = ec._QTorrent_sourceFiles(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ } - - 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)) } @@ -9728,44 +9666,13 @@ func (ec *executionContext) _ResolverFS(ctx context.Context, sel ast.SelectionSe case "name": out.Values[i] = ec._ResolverFS_name(ctx, field, obj) if out.Values[i] == graphql.Null { - atomic.AddUint32(&out.Invalids, 1) + out.Invalids++ } case "entries": - 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._ResolverFS_entries(ctx, field, obj) - if res == graphql.Null { - atomic.AddUint32(&fs.Invalids, 1) - } - return res + out.Values[i] = ec._ResolverFS_entries(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ } - - 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)) } @@ -9841,44 +9748,13 @@ func (ec *executionContext) _SimpleDir(ctx context.Context, sel ast.SelectionSet case "name": out.Values[i] = ec._SimpleDir_name(ctx, field, obj) if out.Values[i] == graphql.Null { - atomic.AddUint32(&out.Invalids, 1) + out.Invalids++ } case "entries": - 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._SimpleDir_entries(ctx, field, obj) - if res == graphql.Null { - atomic.AddUint32(&fs.Invalids, 1) - } - return res + out.Values[i] = ec._SimpleDir_entries(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ } - - 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)) } @@ -10019,174 +9895,50 @@ func (ec *executionContext) _Torrent(ctx context.Context, sel ast.SelectionSet, case "__typename": out.Values[i] = graphql.MarshalString("Torrent") case "name": - 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_name(ctx, field, obj) - if res == graphql.Null { - atomic.AddUint32(&fs.Invalids, 1) - } - return res + out.Values[i] = ec._Torrent_name(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ } - - 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 "infohash": out.Values[i] = ec._Torrent_infohash(ctx, field, obj) if out.Values[i] == graphql.Null { - atomic.AddUint32(&out.Invalids, 1) + out.Invalids++ } case "bytesCompleted": out.Values[i] = ec._Torrent_bytesCompleted(ctx, field, obj) if out.Values[i] == graphql.Null { - atomic.AddUint32(&out.Invalids, 1) + out.Invalids++ } case "torrentFilePath": out.Values[i] = ec._Torrent_torrentFilePath(ctx, field, obj) if out.Values[i] == graphql.Null { - atomic.AddUint32(&out.Invalids, 1) + out.Invalids++ } case "bytesMissing": out.Values[i] = ec._Torrent_bytesMissing(ctx, field, obj) if out.Values[i] == graphql.Null { - atomic.AddUint32(&out.Invalids, 1) + out.Invalids++ } case "priority": out.Values[i] = ec._Torrent_priority(ctx, field, obj) if out.Values[i] == graphql.Null { - atomic.AddUint32(&out.Invalids, 1) + out.Invalids++ } case "files": - 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_files(ctx, field, obj) - if res == graphql.Null { - atomic.AddUint32(&fs.Invalids, 1) - } - return res + out.Values[i] = ec._Torrent_files(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ } - - 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 "excludedFiles": - 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_excludedFiles(ctx, field, obj) - if res == graphql.Null { - atomic.AddUint32(&fs.Invalids, 1) - } - return res + out.Values[i] = ec._Torrent_excludedFiles(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ } - - 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 "peers": - 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_peers(ctx, field, obj) - if res == graphql.Null { - atomic.AddUint32(&fs.Invalids, 1) - } - return res + out.Values[i] = ec._Torrent_peers(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ } - - 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)) } @@ -10321,113 +10073,20 @@ func (ec *executionContext) _TorrentDaemonMutation(ctx context.Context, sel ast. 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 + out.Values[i] = ec._TorrentDaemonMutation_validateTorrent(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ } - - 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 + out.Values[i] = ec._TorrentDaemonMutation_setTorrentPriority(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ } - - 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 + out.Values[i] = ec._TorrentDaemonMutation_cleanup(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ } - - 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)) } @@ -10463,113 +10122,20 @@ func (ec *executionContext) _TorrentDaemonQuery(ctx context.Context, sel ast.Sel 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 + out.Values[i] = ec._TorrentDaemonQuery_torrents(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ } - - 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 "clientStats": - 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_clientStats(ctx, field, obj) - if res == graphql.Null { - atomic.AddUint32(&fs.Invalids, 1) - } - return res + out.Values[i] = ec._TorrentDaemonQuery_clientStats(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ } - - 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 "statsHistory": - 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_statsHistory(ctx, field, obj) - if res == graphql.Null { - atomic.AddUint32(&fs.Invalids, 1) - } - return res + out.Values[i] = ec._TorrentDaemonQuery_statsHistory(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ } - - 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)) } @@ -10607,49 +10173,18 @@ func (ec *executionContext) _TorrentFS(ctx context.Context, sel ast.SelectionSet case "name": out.Values[i] = ec._TorrentFS_name(ctx, field, obj) if out.Values[i] == graphql.Null { - atomic.AddUint32(&out.Invalids, 1) + out.Invalids++ } case "torrent": out.Values[i] = ec._TorrentFS_torrent(ctx, field, obj) if out.Values[i] == graphql.Null { - atomic.AddUint32(&out.Invalids, 1) + out.Invalids++ } case "entries": - 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._TorrentFS_entries(ctx, field, obj) - if res == graphql.Null { - atomic.AddUint32(&fs.Invalids, 1) - } - return res + out.Values[i] = ec._TorrentFS_entries(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ } - - 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)) } @@ -10687,54 +10222,23 @@ func (ec *executionContext) _TorrentFile(ctx context.Context, sel ast.SelectionS case "filename": out.Values[i] = ec._TorrentFile_filename(ctx, field, obj) if out.Values[i] == graphql.Null { - atomic.AddUint32(&out.Invalids, 1) + out.Invalids++ } case "size": out.Values[i] = ec._TorrentFile_size(ctx, field, obj) if out.Values[i] == graphql.Null { - atomic.AddUint32(&out.Invalids, 1) + out.Invalids++ } case "bytesCompleted": out.Values[i] = ec._TorrentFile_bytesCompleted(ctx, field, obj) if out.Values[i] == graphql.Null { - atomic.AddUint32(&out.Invalids, 1) + out.Invalids++ } 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._TorrentFile_priority(ctx, field, obj) - if res == graphql.Null { - atomic.AddUint32(&fs.Invalids, 1) - } - return res + out.Values[i] = ec._TorrentFile_priority(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ } - - 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)) } diff --git a/src/delivery/graphql/model/entry.go b/src/delivery/graphql/model/entry.go index e5f01ee..ef3ffb7 100644 --- a/src/delivery/graphql/model/entry.go +++ b/src/delivery/graphql/model/entry.go @@ -3,7 +3,7 @@ package model import ( "context" - "git.kmsign.ru/royalcat/tstor/src/daemons/torrent" + "git.kmsign.ru/royalcat/tstor/daemons/torrent" "git.kmsign.ru/royalcat/tstor/src/vfs" ) diff --git a/src/delivery/graphql/model/mappers.go b/src/delivery/graphql/model/mappers.go index 31de5f9..3152f67 100644 --- a/src/delivery/graphql/model/mappers.go +++ b/src/delivery/graphql/model/mappers.go @@ -3,7 +3,7 @@ package model import ( "context" - "git.kmsign.ru/royalcat/tstor/src/daemons/torrent" + "git.kmsign.ru/royalcat/tstor/daemons/torrent" atorrent "github.com/anacrolix/torrent" ) diff --git a/src/delivery/graphql/model/models_gen.go b/src/delivery/graphql/model/models_gen.go index 46b5533..2a5396a 100644 --- a/src/delivery/graphql/model/models_gen.go +++ b/src/delivery/graphql/model/models_gen.go @@ -5,7 +5,7 @@ package model import ( "time" - "git.kmsign.ru/royalcat/tstor/src/daemons/torrent" + "git.kmsign.ru/royalcat/tstor/daemons/torrent" "git.kmsign.ru/royalcat/tstor/src/vfs" torrent1 "github.com/anacrolix/torrent" "github.com/anacrolix/torrent/types" diff --git a/src/delivery/graphql/resolver/qbittorrent_mutation.resolvers.go b/src/delivery/graphql/resolver/qbittorrent_mutation.resolvers.go index b80a5a6..bd5efb2 100644 --- a/src/delivery/graphql/resolver/qbittorrent_mutation.resolvers.go +++ b/src/delivery/graphql/resolver/qbittorrent_mutation.resolvers.go @@ -12,8 +12,8 @@ import ( ) // Cleanup is the resolver for the cleanup field. -func (r *qBitTorrentDaemonMutationResolver) Cleanup(ctx context.Context, obj *model.QBitTorrentDaemonMutation, dryRun bool) (*model.QBitCleanupResponse, error) { - hahses, err := r.QBitTorrentDaemon.Cleanup(ctx, dryRun) +func (r *qBitTorrentDaemonMutationResolver) Cleanup(ctx context.Context, obj *model.QBitTorrentDaemonMutation, run bool) (*model.QBitCleanupResponse, error) { + hahses, err := r.QBitTorrentDaemon.Cleanup(ctx, run) if err != nil { return nil, err } diff --git a/src/delivery/graphql/resolver/resolver.go b/src/delivery/graphql/resolver/resolver.go index c443a86..d0be310 100644 --- a/src/delivery/graphql/resolver/resolver.go +++ b/src/delivery/graphql/resolver/resolver.go @@ -1,8 +1,8 @@ package resolver import ( - "git.kmsign.ru/royalcat/tstor/src/daemons/qbittorrent" - "git.kmsign.ru/royalcat/tstor/src/daemons/torrent" + "git.kmsign.ru/royalcat/tstor/daemons/qbittorrent" + "git.kmsign.ru/royalcat/tstor/daemons/torrent" "git.kmsign.ru/royalcat/tstor/src/vfs" "github.com/go-git/go-billy/v5" ) diff --git a/src/delivery/graphql/resolver/torrent_query.resolvers.go b/src/delivery/graphql/resolver/torrent_query.resolvers.go index 906fefb..084919c 100644 --- a/src/delivery/graphql/resolver/torrent_query.resolvers.go +++ b/src/delivery/graphql/resolver/torrent_query.resolvers.go @@ -10,7 +10,7 @@ import ( "strings" "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" "git.kmsign.ru/royalcat/tstor/src/delivery/graphql/model" tinfohash "github.com/anacrolix/torrent/types/infohash" diff --git a/src/delivery/http.go b/src/delivery/http.go index 90cbd08..fc55353 100644 --- a/src/delivery/http.go +++ b/src/delivery/http.go @@ -5,10 +5,10 @@ import ( "log/slog" "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/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" echopprof "github.com/labstack/echo-contrib/pprof" "github.com/labstack/echo/v4" diff --git a/src/delivery/router.go b/src/delivery/router.go index d274c0f..c03a50e 100644 --- a/src/delivery/router.go +++ b/src/delivery/router.go @@ -4,8 +4,8 @@ import ( "context" "net/http" - "git.kmsign.ru/royalcat/tstor/src/daemons/qbittorrent" - "git.kmsign.ru/royalcat/tstor/src/daemons/torrent" + "git.kmsign.ru/royalcat/tstor/daemons/qbittorrent" + "git.kmsign.ru/royalcat/tstor/daemons/torrent" graph "git.kmsign.ru/royalcat/tstor/src/delivery/graphql" "git.kmsign.ru/royalcat/tstor/src/delivery/graphql/resolver" "git.kmsign.ru/royalcat/tstor/src/vfs" diff --git a/ui/lib/api/schema.graphql b/ui/lib/api/schema.graphql index 96c0726..0070d3c 100644 --- a/ui/lib/api/schema.graphql +++ b/ui/lib/api/schema.graphql @@ -57,8 +57,12 @@ interface Progress { current: Int! total: Int! } +type QBitCleanupResponse { + count: Int! + hashes: [String!]! +} type QBitTorrentDaemonMutation { - cleanup(dryRun: Boolean!): Int! @resolver + cleanup(run: Boolean!): QBitCleanupResponse! @resolver } type QBitTorrentDaemonQuery { torrents: [QTorrent!]! @resolver