plugins

package
v0.0.5 Latest Latest
Warning

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

Go to latest
Published: Jan 26, 2026 License: MIT Imports: 29 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var AllowedDownloadHosts = []string{"https://github.com/"}

AllowedDownloadHosts lists the allowed host prefixes for plugin download URLs. Tests can override this to allow test servers.

View Source
var AllowedFetchHosts = []string{"https://raw.githubusercontent.com/"}

AllowedFetchHosts lists the allowed host prefixes for repository manifest URLs. Tests can override this to allow test servers.

View Source
var SupportedManifestVersions = []int{1}

SupportedManifestVersions lists manifest versions this Shisho release supports.

Functions

func BuildBookContext

func BuildBookContext(book *models.Book) map[string]interface{}

BuildBookContext converts a Book model to a map for plugin context.

func BuildFileContext

func BuildFileContext(file *models.File) map[string]interface{}

BuildFileContext converts a File model to a map for plugin context.

func InjectHostAPIs

func InjectHostAPIs(rt *Runtime, configGetter ConfigGetter) error

InjectHostAPIs sets up the shisho.* APIs in a plugin's goja runtime. The logPrefix is derived from the runtime's scope and pluginID. The configGetter provides config values for the plugin.

func NewHandler

func NewHandler(service *Service, manager *Manager, installer *Installer) *handler

NewHandler creates a handler for testing and external route registration.

func RegisterLibraryRoutes

func RegisterLibraryRoutes(g *echo.Group, service *Service, authMiddleware *auth.Middleware)

RegisterLibraryRoutes registers per-library plugin order routes on a libraries group.

func RegisterRoutesWithGroup

func RegisterRoutesWithGroup(g *echo.Group, service *Service, manager *Manager, installer *Installer)

RegisterRoutesWithGroup registers plugin management API routes.

Types

type AvailablePlugin

type AvailablePlugin struct {
	ID          string          `json:"id"`
	Name        string          `json:"name"`
	Description string          `json:"description"`
	Author      string          `json:"author"`
	Homepage    string          `json:"homepage"`
	Versions    []PluginVersion `json:"versions"`
}

AvailablePlugin describes a plugin available for installation from a repository.

type Capabilities

type Capabilities struct {
	InputConverter   *InputConverterCap   `json:"inputConverter"`
	FileParser       *FileParserCap       `json:"fileParser"`
	OutputGenerator  *OutputGeneratorCap  `json:"outputGenerator"`
	MetadataEnricher *MetadataEnricherCap `json:"metadataEnricher"`
	IdentifierTypes  []IdentifierTypeCap  `json:"identifierTypes"`
	HTTPAccess       *HTTPAccessCap       `json:"httpAccess"`
	FileAccess       *FileAccessCap       `json:"fileAccess"`
	FFmpegAccess     *FFmpegAccessCap     `json:"ffmpegAccess"`
}

type ConfigField

type ConfigField struct {
	Type        string         `json:"type"` // string, boolean, number, select, textarea
	Label       string         `json:"label"`
	Description string         `json:"description"`
	Required    bool           `json:"required"`
	Secret      bool           `json:"secret"`
	Default     interface{}    `json:"default"`
	Min         *float64       `json:"min"`
	Max         *float64       `json:"max"`
	Options     []SelectOption `json:"options"`
}

type ConfigGetter

type ConfigGetter interface {
	GetConfigRaw(ctx context.Context, scope, pluginID, key string) (*string, error)
	GetAllConfigRaw(ctx context.Context, scope, pluginID string) (map[string]*string, error)
}

ConfigGetter provides config values for a plugin at runtime.

type ConfigSchema

type ConfigSchema map[string]ConfigField

type ConvertResult

type ConvertResult struct {
	Success    bool
	TargetPath string
}

ConvertResult is the result of an input converter hook.

type EnrichmentResult

type EnrichmentResult struct {
	Modified bool
	Metadata *mediafile.ParsedMetadata // nil if Modified is false
}

EnrichmentResult is the result of a metadata enricher hook.

type FFmpegAccessCap

type FFmpegAccessCap struct {
	Description string `json:"description"`
}

type FSContext

type FSContext struct {
	// contains filtered or unexported fields
}

FSContext tracks allowed paths and temp dir for a single hook invocation. It controls what filesystem operations a plugin can perform.

func NewFSContext

func NewFSContext(pluginDir string, allowedPaths []string, fileAccessCap *FileAccessCap) *FSContext

NewFSContext creates a new FSContext for a hook invocation.

func (*FSContext) Cleanup

func (ctx *FSContext) Cleanup() error

Cleanup removes the temp directory if it was created.

type FileAccessCap

type FileAccessCap struct {
	Level       string `json:"level"` // "read" or "readwrite"
	Description string `json:"description"`
}

type FileParserCap

type FileParserCap struct {
	Description string   `json:"description"`
	Types       []string `json:"types"`
	MIMETypes   []string `json:"mimeTypes"`
}

type HTTPAccessCap

type HTTPAccessCap struct {
	Description string   `json:"description"`
	Domains     []string `json:"domains"`
}

type IdentifierTypeCap

type IdentifierTypeCap struct {
	ID          string `json:"id"`
	Name        string `json:"name"`
	URLTemplate string `json:"urlTemplate"`
	Pattern     string `json:"pattern"`
}

type InputConverterCap

type InputConverterCap struct {
	Description string   `json:"description"`
	SourceTypes []string `json:"sourceTypes"`
	MIMETypes   []string `json:"mimeTypes"`
	TargetType  string   `json:"targetType"`
}

type Installer

type Installer struct {
	// contains filtered or unexported fields
}

Installer handles downloading and extracting plugins.

func NewInstaller

func NewInstaller(pluginDir string) *Installer

NewInstaller creates a new Installer.

func (*Installer) InstallPlugin

func (inst *Installer) InstallPlugin(ctx context.Context, scope, pluginID, downloadURL, expectedSHA256 string) (*Manifest, error)

InstallPlugin downloads a plugin ZIP, verifies its SHA256, and extracts it. Returns the parsed manifest from the extracted plugin.

func (*Installer) PluginDir

func (inst *Installer) PluginDir() string

PluginDir returns the base directory for installed plugins.

func (*Installer) UninstallPlugin

func (inst *Installer) UninstallPlugin(scope, pluginID string) error

UninstallPlugin removes a plugin's files from disk.

func (*Installer) UpdatePlugin

func (inst *Installer) UpdatePlugin(ctx context.Context, scope, pluginID, downloadURL, expectedSHA256 string) (*Manifest, error)

UpdatePlugin replaces an existing plugin with a new version.

type Manager

type Manager struct {
	// contains filtered or unexported fields
}

Manager holds loaded Runtime instances indexed by "scope/id". It coordinates loading at startup, unloading, and hot-reloading on install/update/enable.

func NewManager

func NewManager(service *Service, pluginDir string) *Manager

NewManager creates a new Manager.

func (*Manager) CheckForUpdates

func (m *Manager) CheckForUpdates(ctx context.Context) error

CheckForUpdates checks all installed plugins against enabled repositories for available updates. It sets or clears UpdateAvailableVersion on each plugin.

func (*Manager) GetOrderedRuntimes

func (m *Manager) GetOrderedRuntimes(ctx context.Context, hookType string, libraryID int) ([]*Runtime, error)

GetOrderedRuntimes returns runtimes for a hook type in user-defined order. If libraryID > 0 and the library has customized the order for this hook type, uses the per-library order (only enabled entries). Otherwise falls back to global order. In both paths, only runtimes that are actually loaded (globally enabled) are returned.

func (*Manager) GetOutputGenerator

func (m *Manager) GetOutputGenerator(formatID string) *PluginGenerator

GetOutputGenerator returns the PluginGenerator for a given format ID. Returns nil if no plugin provides that format.

func (*Manager) GetParserForType

func (m *Manager) GetParserForType(fileType string) *Runtime

GetParserForType returns the first loaded runtime that has a fileParser for the given type.

func (*Manager) GetRuntime

func (m *Manager) GetRuntime(scope, id string) *Runtime

GetRuntime returns the runtime for a plugin (nil if not loaded).

func (*Manager) LoadAll

func (m *Manager) LoadAll(ctx context.Context) error

LoadAll loads all enabled plugins from the database at startup. Errors are stored in plugins.LoadError and don't prevent other plugins from loading.

func (*Manager) LoadPlugin

func (m *Manager) LoadPlugin(ctx context.Context, scope, id string) error

LoadPlugin loads a single plugin (called during install/enable).

func (*Manager) RegisteredConverterExtensions

func (m *Manager) RegisteredConverterExtensions() map[string]struct{}

RegisteredConverterExtensions returns source extensions that have input converters.

func (*Manager) RegisteredFileExtensions

func (m *Manager) RegisteredFileExtensions() map[string]struct{}

RegisteredFileExtensions returns all file extensions registered by plugin fileParsers (excluding reserved built-in extensions: epub, cbz, m4b).

func (*Manager) RegisteredOutputFormats

func (m *Manager) RegisteredOutputFormats() []OutputFormatInfo

RegisteredOutputFormats returns all format IDs registered by plugin output generators, along with their source type restrictions.

func (*Manager) ReloadPlugin

func (m *Manager) ReloadPlugin(ctx context.Context, scope, id string) error

ReloadPlugin performs a hot-reload (called during update). Acquires write lock on old runtime (waits for in-progress hooks), then swaps.

func (*Manager) RunFileParser

func (m *Manager) RunFileParser(ctx context.Context, rt *Runtime, filePath, fileType string) (*mediafile.ParsedMetadata, error)

RunFileParser invokes a plugin's fileParser.parse() hook.

func (*Manager) RunFingerprint

func (m *Manager) RunFingerprint(rt *Runtime, bookCtx, fileCtx map[string]interface{}) (string, error)

RunFingerprint invokes a plugin's outputGenerator.fingerprint() hook.

func (*Manager) RunInputConverter

func (m *Manager) RunInputConverter(ctx context.Context, rt *Runtime, sourcePath, targetDir string) (*ConvertResult, error)

RunInputConverter invokes a plugin's inputConverter.convert() hook.

func (*Manager) RunMetadataEnricher

func (m *Manager) RunMetadataEnricher(ctx context.Context, rt *Runtime, enrichCtx map[string]interface{}) (*EnrichmentResult, error)

RunMetadataEnricher invokes a plugin's metadataEnricher.enrich() hook.

func (*Manager) RunOutputGenerator

func (m *Manager) RunOutputGenerator(ctx context.Context, rt *Runtime, sourcePath, destPath string, bookCtx, fileCtx map[string]interface{}) error

RunOutputGenerator invokes a plugin's outputGenerator.generate() hook.

func (*Manager) UnloadPlugin

func (m *Manager) UnloadPlugin(scope, id string)

UnloadPlugin removes a plugin from memory (called during uninstall/disable).

type Manifest

type Manifest struct {
	ManifestVersion  int          `json:"manifestVersion"`
	ID               string       `json:"id"`
	Name             string       `json:"name"`
	Version          string       `json:"version"`
	Description      string       `json:"description"`
	Author           string       `json:"author"`
	Homepage         string       `json:"homepage"`
	License          string       `json:"license"`
	MinShishoVersion string       `json:"minShishoVersion"`
	Capabilities     Capabilities `json:"capabilities"`
	ConfigSchema     ConfigSchema `json:"configSchema"`
}

func ParseManifest

func ParseManifest(data []byte) (*Manifest, error)

ParseManifest parses and validates a manifest.json byte slice.

type MetadataEnricherCap

type MetadataEnricherCap struct {
	Description string   `json:"description"`
	FileTypes   []string `json:"fileTypes"`
}

type OutputFormatInfo

type OutputFormatInfo struct {
	ID          string
	Name        string
	SourceTypes []string
	Scope       string
	PluginID    string
}

OutputFormatInfo describes a plugin-provided output format.

type OutputGeneratorCap

type OutputGeneratorCap struct {
	Description string   `json:"description"`
	ID          string   `json:"id"`
	Name        string   `json:"name"`
	SourceTypes []string `json:"sourceTypes"`
}

type PluginGenerator

type PluginGenerator struct {
	// contains filtered or unexported fields
}

PluginGenerator adapts a plugin's outputGenerator hook to the filegen.Generator interface.

func NewPluginGenerator

func NewPluginGenerator(manager *Manager, scope, pluginID, formatID string) *PluginGenerator

NewPluginGenerator creates a new PluginGenerator.

func (*PluginGenerator) Fingerprint

func (g *PluginGenerator) Fingerprint(book *models.Book, file *models.File) (string, error)

Fingerprint returns the plugin's fingerprint string for cache invalidation.

func (*PluginGenerator) Generate

func (g *PluginGenerator) Generate(ctx context.Context, srcPath, destPath string, book *models.Book, file *models.File) error

Generate implements filegen.Generator by delegating to the plugin's outputGenerator.generate() hook.

func (*PluginGenerator) SupportedType

func (g *PluginGenerator) SupportedType() string

SupportedType implements filegen.Generator.

type PluginVersion

type PluginVersion struct {
	Version          string `json:"version"`
	MinShishoVersion string `json:"minShishoVersion"`
	ManifestVersion  int    `json:"manifestVersion"`
	ReleaseDate      string `json:"releaseDate"`
	Changelog        string `json:"changelog"`
	DownloadURL      string `json:"downloadUrl"`
	SHA256           string `json:"sha256"`
}

PluginVersion describes a specific version of an available plugin.

func FilterCompatibleVersions

func FilterCompatibleVersions(versions []PluginVersion) []PluginVersion

FilterCompatibleVersions returns only versions with a manifestVersion supported by this Shisho release.

type RepositoryManifest

type RepositoryManifest struct {
	RepositoryVersion int               `json:"repositoryVersion"`
	Scope             string            `json:"scope"`
	Name              string            `json:"name"`
	Plugins           []AvailablePlugin `json:"plugins"`
}

RepositoryManifest is the parsed JSON from a repository URL.

func FetchRepository

func FetchRepository(rawURL string) (*RepositoryManifest, error)

FetchRepository downloads and parses a repository manifest from the given URL. Only HTTPS URLs to allowed hosts (raw.githubusercontent.com by default) are permitted.

type Runtime

type Runtime struct {
	// contains filtered or unexported fields
}

Runtime wraps a goja VM for a single plugin. It loads manifest.json, executes main.js (which defines a `plugin` global via IIFE), and extracts hook function references.

func LoadPlugin

func LoadPlugin(dir, scope, pluginID string) (*Runtime, error)

LoadPlugin creates a new Runtime by reading manifest.json and executing main.js from the given plugin directory.

func (*Runtime) HookTypes

func (rt *Runtime) HookTypes() []string

HookTypes returns the list of hook type strings this plugin provides, sorted alphabetically for deterministic output.

func (*Runtime) Manifest

func (rt *Runtime) Manifest() *Manifest

Manifest returns the parsed manifest.

func (*Runtime) PluginID

func (rt *Runtime) PluginID() string

PluginID returns the plugin's ID (e.g., "goodreads-metadata").

func (*Runtime) Scope

func (rt *Runtime) Scope() string

Scope returns the plugin's scope (e.g., "shisho").

func (*Runtime) SetFSContext

func (rt *Runtime) SetFSContext(ctx *FSContext)

SetFSContext sets the filesystem context for the current hook invocation. Called by hook execution code before invoking hooks. Pass nil to clear.

type SelectOption

type SelectOption struct {
	Value string `json:"value"`
	Label string `json:"label"`
}

type Service

type Service struct {
	// contains filtered or unexported fields
}

Service provides database operations for plugin management.

func NewService

func NewService(db *bun.DB) *Service

NewService creates a new plugin service.

func (*Service) AddRepository

func (s *Service) AddRepository(ctx context.Context, repo *models.PluginRepository) error

AddRepository inserts a new plugin repository.

func (*Service) AppendToOrder

func (s *Service) AppendToOrder(ctx context.Context, hookType, scope, pluginID string) error

AppendToOrder appends a plugin to the end of the order for a hook type.

func (*Service) GetAllConfigRaw

func (s *Service) GetAllConfigRaw(ctx context.Context, scope, pluginID string) (map[string]*string, error)

GetAllConfigRaw returns all raw config key-value pairs for a plugin.

func (*Service) GetConfig

func (s *Service) GetConfig(ctx context.Context, scope, pluginID string, schema ConfigSchema, raw bool) (map[string]interface{}, error)

GetConfig returns the configuration values for a plugin. If raw is false, secret values are masked with "***". The schema is used to determine which fields are secrets.

func (*Service) GetConfigRaw

func (s *Service) GetConfigRaw(ctx context.Context, scope, pluginID, key string) (*string, error)

GetConfigRaw returns the raw value for a single config key.

func (*Service) GetLibraryOrder

func (s *Service) GetLibraryOrder(ctx context.Context, libraryID int, hookType string) ([]*models.LibraryPlugin, error)

GetLibraryOrder returns the per-library plugin order for a hook type, sorted by position.

func (*Service) GetOrder

func (s *Service) GetOrder(ctx context.Context, hookType string) ([]*models.PluginOrder, error)

GetOrder returns the plugin order entries for a hook type, sorted by position.

func (*Service) GetPlugin

func (s *Service) GetPlugin(ctx context.Context, scope, id string) (*models.Plugin, error)

GetPlugin returns a single plugin by scope and ID, or nil if not found.

func (*Service) GetRepository

func (s *Service) GetRepository(ctx context.Context, scope string) (*models.PluginRepository, error)

GetRepository returns a single plugin repository by scope.

func (*Service) InstallPlugin

func (s *Service) InstallPlugin(ctx context.Context, plugin *models.Plugin) error

InstallPlugin inserts a new plugin record.

func (*Service) IsLibraryCustomized

func (s *Service) IsLibraryCustomized(ctx context.Context, libraryID int, hookType string) (bool, error)

IsLibraryCustomized checks if a library has customized plugin order for a hook type.

func (*Service) ListIdentifierTypes

func (s *Service) ListIdentifierTypes(ctx context.Context) ([]*models.PluginIdentifierType, error)

ListIdentifierTypes returns all plugin-registered identifier types.

func (*Service) ListPlugins

func (s *Service) ListPlugins(ctx context.Context) ([]*models.Plugin, error)

ListPlugins returns all installed plugins.

func (*Service) ListRepositories

func (s *Service) ListRepositories(ctx context.Context) ([]*models.PluginRepository, error)

ListRepositories returns all plugin repositories, ordered by official first then by scope.

func (*Service) RemoveRepository

func (s *Service) RemoveRepository(ctx context.Context, scope string) error

RemoveRepository removes a non-official plugin repository by scope.

func (*Service) ResetAllLibraryOrders

func (s *Service) ResetAllLibraryOrders(ctx context.Context, libraryID int) error

ResetAllLibraryOrders removes all per-library plugin customizations for a library.

func (*Service) ResetLibraryOrder

func (s *Service) ResetLibraryOrder(ctx context.Context, libraryID int, hookType string) error

ResetLibraryOrder removes per-library customization for a specific hook type.

func (*Service) RetrievePlugin

func (s *Service) RetrievePlugin(ctx context.Context, scope, id string) (*models.Plugin, error)

RetrievePlugin returns a single plugin by scope and id.

func (*Service) SetConfig

func (s *Service) SetConfig(ctx context.Context, scope, pluginID, key, value string) error

SetConfig upserts a single config key-value pair for a plugin.

func (*Service) SetLibraryOrder

func (s *Service) SetLibraryOrder(ctx context.Context, libraryID int, hookType string, entries []models.LibraryPlugin) error

SetLibraryOrder replaces all per-library plugin order entries for a hook type. Also creates the customization record if it doesn't exist.

func (*Service) SetOrder

func (s *Service) SetOrder(ctx context.Context, hookType string, entries []models.PluginOrder) error

SetOrder replaces all order entries for a hook type in a transaction.

func (*Service) UninstallPlugin

func (s *Service) UninstallPlugin(ctx context.Context, scope, id string) error

UninstallPlugin removes a plugin and its related data (configs, orders cascade via FK).

func (*Service) UpdatePlugin

func (s *Service) UpdatePlugin(ctx context.Context, plugin *models.Plugin) error

UpdatePlugin updates an existing plugin record.

func (*Service) UpdateRepository

func (s *Service) UpdateRepository(ctx context.Context, repo *models.PluginRepository) error

UpdateRepository updates an existing plugin repository.

func (*Service) UpsertIdentifierTypes

func (s *Service) UpsertIdentifierTypes(ctx context.Context, scope, pluginID string, types []IdentifierTypeCap) error

UpsertIdentifierTypes replaces all identifier types for a plugin in a transaction.

Jump to

Keyboard shortcuts

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