stash

package
v0.2.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 22, 2026 License: GPL-3.0 Imports: 7 Imported by: 0

Documentation

Overview

Package stash is the plugin's GraphQL client for its parent Stash instance. Modeled on StashJanitor/internal/stash (same author, GPL): raw queries over net/http, typed errors, no generated client.

Auth is either the session cookie Stash hands the plugin process or an API key from plugin settings. The API key wins when both are present: session cookies expire mid-run on long tasks (stashapp/stash#5332), so PLAN.md mandates preferring the key.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Caption

type Caption struct {
	LanguageCode string `json:"language_code"`
	CaptionType  string `json:"caption_type"`
}

Caption is one attached caption as Stash reports it.

type Client

type Client struct {
	// Endpoint is the base URL as given to NewClient, kept for logging.
	Endpoint string

	// SupportsCaptions is set by ProbeCaptions. Zero value means "not yet
	// probed"; callers must probe before building scene queries that touch
	// captions, because an unknown GraphQL field fails the entire query.
	SupportsCaptions bool
	// contains filtered or unexported fields
}

Client is a Stash GraphQL client. Safe for concurrent use.

func NewClient

func NewClient(baseURL, apiKey string, cookie *http.Cookie) *Client

NewClient builds a Client for the given base URL (scheme://host:port).

apiKey wins over cookie when both are present — that precedence lives in the shared client now, for the same reason it lived here: a session cookie expires mid-run and fails a long task partway through.

func (*Client) Execute

func (c *Client) Execute(ctx context.Context, query string, variables map[string]any, out any) error

Execute posts one GraphQL query and decodes the `data` field into out (a non-nil pointer, or nil when the caller ignores the result).

func (*Client) FindScene

func (c *Client) FindScene(ctx context.Context, id string) (*Scene, error)

FindScene fetches one scene by id. Caption fields are only requested when ProbeCaptions established they exist.

func (*Client) FindScenesPage

func (c *Client) FindScenesPage(ctx context.Context, page, perPage int) ([]Scene, int, error)

FindScenesPage returns one page of all scenes, id-ascending, plus the total count — the iteration backbone for library-wide tasks.

func (*Client) MetadataScan

func (c *Client) MetadataScan(ctx context.Context, paths []string) (string, error)

MetadataScan triggers a scan of the given paths — the only way to attach a genuinely new caption, since captions are read-only in GraphQL (PLAN.md delivery constraint 3). Returns the job id.

func (*Client) PluginSettings

func (c *Client) PluginSettings(ctx context.Context, pluginID string) (map[string]any, error)

PluginSettings fetches this plugin's settings map from Stash's configuration. Returns an empty map when the plugin has no settings yet.

func (*Client) ProbeCaptions

func (c *Client) ProbeCaptions(ctx context.Context) bool

ProbeCaptions asks, once and cheaply, whether this Stash exposes Scene.captions — the schema shifts between releases and an unknown field fails an entire query, so this must never be discovered mid-task (pattern from stash-subs stash.py:Client.probe_captions).

func (*Client) UseAPIKey

func (c *Client) UseAPIKey(key string)

UseAPIKey switches authentication to an API key.

The plugin cannot know the key up front: it connects with the session cookie Stash supplies, reads its own settings over that connection, and only then learns whether an operator configured one. Preferring the key from that point on is deliberate — session cookies expire mid-run, and a long task then fails partway through (stashapp/stash#5332).

The shared client is immutable, so this rebuilds it rather than mutating auth underneath in-flight requests.

type GraphQLError

type GraphQLError = upstream.APIError

GraphQLError is a non-empty `errors` array in the GraphQL response — schema mismatches (unknown field) and auth failures surface here.

An alias for the shared type, so a value returned by the upstream client satisfies it exactly. Each entry now also keeps its `path` and `extensions`.

type Performer

type Performer struct {
	Name string `json:"name"`
}

Performer is one of a scene's performers (name only, same reasoning).

type Scene

type Scene struct {
	ID    string `json:"id"`
	Title string `json:"title"`
	// Date is Stash's YYYY-MM-DD release date, empty when unset.
	Date       string      `json:"date"`
	Studio     *Studio     `json:"studio"`
	Performers []Performer `json:"performers"`
	Files      []SceneFile `json:"files"`
	Captions   []Caption   `json:"captions"`
	StashIDs   []StashID   `json:"stash_ids"`
}

Scene is the subset of Scene the plugin needs.

func (Scene) PerformerNames

func (s Scene) PerformerNames() []string

PerformerNames returns the scene's performer names, or nil when it has none — nil rather than an empty slice so callers get the same "absent" shape msclient.UploadRequest's omitempty expects.

func (Scene) StudioName

func (s Scene) StudioName() string

StudioName returns the scene's studio name, or "" when it has none.

type SceneFile

type SceneFile struct {
	Path         string  `json:"path"`
	Duration     float64 `json:"duration"`
	Fingerprints []struct {
		Type  string `json:"type"`
		Value string `json:"value"`
	} `json:"fingerprints"`
}

SceneFile is one file backing a scene, with the fingerprints moansubs keys on. Duration is seconds (Stash's unit for VideoFile.duration).

func (SceneFile) Fingerprint

func (f SceneFile) Fingerprint(typ string) string

Fingerprint returns the value of the named fingerprint type ("oshash", "phash", "md5"), or "" when absent.

type StashID

type StashID struct {
	Endpoint string `json:"endpoint"`
	StashID  string `json:"stash_id"`
}

StashID is one of a scene's stash-box identities (WP-C9a): Endpoint is the stash-box GraphQL URL exactly as Stash reports it (normalized by internal/hash before it goes anywhere near the moansubs server), StashID its scene id on that stash-box. `stash_ids { endpoint stash_id }` has existed on Scene since Stash 0.10 — unlike captions, this needs no probe: it's safe to request unconditionally.

type Studio

type Studio struct {
	Name string `json:"name"`
}

Studio is a scene's studio (name only — the plugin has no use for its id).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL