handler

package
v0.0.48 Latest Latest
Warning

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

Go to latest
Published: Apr 29, 2026 License: MIT Imports: 32 Imported by: 0

Documentation

Overview

Package handler contains HTTP request handlers for the API server.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type ConfigHandler

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

ConfigHandler serves the GET/POST /config and GET/PUT /config/yaml endpoints.

The /config/yaml endpoints expose every editable resource — GlobalConfig, streams, and hooks — as a single YAML document, so the frontend editor can round-trip the entire system configuration in one screen.

func NewConfigHandler

func NewConfigHandler(i do.Injector) (*ConfigHandler, error)

NewConfigHandler creates a ConfigHandler from the DI injector. The RuntimeConfigManager is injected later via SetRuntimeManager because it depends on services that themselves depend on this handler (circular DI).

func (*ConfigHandler) GetConfig

func (h *ConfigHandler) GetConfig(w http.ResponseWriter, _ *http.Request)

GetConfig returns static enum values, host-detected hardware capabilities, current GlobalConfig, and derived publisher ports.

@Summary Get server configuration. @Description Returns available hardware accelerators (OS-detected), static enum lists, publisher listener ports, and the current runtime GlobalConfig. @Tags system @Produce json @Success 200 {object} apidocs.ConfigData @Router /config [get].

func (*ConfigHandler) GetConfigDefaults added in v0.0.33

func (h *ConfigHandler) GetConfigDefaults(w http.ResponseWriter, _ *http.Request)

GetConfigDefaults returns the implicit values the server applies when the corresponding configuration field is left zero / empty by the user.

Frontend usage: fetch once on app init, cache, use as form field placeholder text so users see the actual default value (e.g. "1024", "aac", "h264") instead of a generic "default" word.

Note: a few fields with context-aware resolution (video codec name depending on HW backend) are NOT included here — they need the caller's current HW selection to compute. Frontend handles those client-side.

@Summary Get system configuration defaults. @Description Static values the server fills in for unset configuration fields. Use as form placeholders so users see real defaults instead of "default" text. @Tags system @Produce json @Success 200 {object} handler.configDefaultsResponse @Router /config/defaults [get].

func (*ConfigHandler) GetConfigYAML

func (h *ConfigHandler) GetConfigYAML(w http.ResponseWriter, r *http.Request)

GetConfigYAML returns the entire system state — GlobalConfig, all streams, all hooks — as one YAML document. The frontend editor uses this to populate its initial buffer.

@Summary Get full system configuration as YAML @Description Returns global_config, streams, and hooks bundled in a single YAML document. Pair with PUT /config/yaml to round-trip an editor. @Tags system @Produce application/yaml @Success 200 {string} string "YAML document" @Failure 500 {object} map[string]any @Router /config/yaml [get].

func (*ConfigHandler) ProbeTranscoder added in v0.0.36

func (h *ConfigHandler) ProbeTranscoder(w http.ResponseWriter, r *http.Request)

ProbeTranscoder runs a capability probe against the FFmpeg binary at the requested path WITHOUT touching the live config. UI calls this behind a "Test" button so operators can validate a candidate path before committing it via POST /config.

Response: 200 with the full ProbeResult regardless of compatibility — the result's `ok` field tells the caller whether the binary passes. 4xx is reserved for malformed bodies; 5xx for invocation errors (binary missing, not executable, not actually FFmpeg).

@Summary Probe an FFmpeg binary for app compatibility. @Description Inspects the binary at ffmpeg_path (empty = $PATH) and reports which required / optional encoders + muxers are available. Pure check — does not modify config. @Tags system @Accept json @Produce json @Param body body handler.probeRequest true "Path to probe (empty = use $PATH)" @Success 200 {object} transcoder.ProbeResult @Failure 400 {object} apidocs.ErrorBody @Failure 502 {object} apidocs.ErrorBody @Router /config/transcoder/probe [post].

func (*ConfigHandler) ReplaceConfigYAML

func (h *ConfigHandler) ReplaceConfigYAML(w http.ResponseWriter, r *http.Request)

ReplaceConfigYAML replaces the entire system configuration with the YAML body. Performs a full replace, not a merge:

  • GlobalConfig sections omitted from the body are treated as absent and the corresponding service is stopped.
  • Streams omitted from the body are stopped and deleted.
  • Hooks omitted from the body are deleted.

All field errors are collected and returned together so the editor can highlight every issue in one round-trip.

@Summary Replace full system configuration from YAML @Description Replaces global_config, streams, and hooks with the request body. Validation errors are returned as a list. On success, the runtime manager + coordinator diff against the previous state and start/stop/restart services accordingly. @Tags system @Accept application/yaml @Produce json @Param body body string true "Full system configuration YAML document" @Success 200 {object} map[string]any @Failure 400 {object} map[string]any @Failure 422 {object} map[string]any @Failure 500 {object} map[string]any @Router /config/yaml [put].

func (*ConfigHandler) SetRuntimeManager

func (h *ConfigHandler) SetRuntimeManager(m RuntimeConfigManager)

SetRuntimeManager injects the RuntimeManager after construction (breaks the circular DI dependency).

func (*ConfigHandler) UpdateConfig

func (h *ConfigHandler) UpdateConfig(w http.ResponseWriter, r *http.Request)

UpdateConfig partially updates the runtime GlobalConfig, persists it to the store, and hot-reloads services (start/stop) to match the new configuration.

Only the fields present in the request body are updated; omitted fields keep their current values. Sending a section as JSON null disables that service.

@Summary Partially update server configuration. @Description Merges the request body into the current GlobalConfig and applies it — services are started or stopped to match. @Tags system @Accept json @Produce json @Param body body domain.GlobalConfig true "Partial configuration to merge" @Success 200 {object} apidocs.ConfigUpdateResponse @Failure 400 {object} apidocs.ErrorResponse @Failure 500 {object} apidocs.ErrorResponse @Router /config [post].

type HookHandler

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

HookHandler handles webhook and hook management REST endpoints.

func NewHookHandler

func NewHookHandler(i do.Injector) (*HookHandler, error)

NewHookHandler creates a HookHandler and registers it with the DI injector.

func (*HookHandler) Create

func (h *HookHandler) Create(w http.ResponseWriter, r *http.Request)

Create registers a new hook. @Summary Create hook @Tags hooks @Accept json @Produce json @Param body body domain.Hook true "Hook configuration" @Success 201 {object} apidocs.HookData @Failure 400 {object} apidocs.ErrorBody @Failure 500 {object} apidocs.ErrorBody @Router /hooks [post].

func (*HookHandler) Delete

func (h *HookHandler) Delete(w http.ResponseWriter, r *http.Request)

Delete removes a hook. @Summary Delete hook @Tags hooks @Param hid path string true "Hook ID" @Success 204 "No Content" @Failure 500 {object} apidocs.ErrorBody @Router /hooks/{hid} [delete].

func (*HookHandler) Get

func (h *HookHandler) Get(w http.ResponseWriter, r *http.Request)

Get returns one hook. @Summary Get hook @Tags hooks @Produce json @Param hid path string true "Hook ID" @Success 200 {object} apidocs.HookData @Failure 404 {object} apidocs.ErrorBody @Router /hooks/{hid} [get].

func (*HookHandler) List

func (h *HookHandler) List(w http.ResponseWriter, r *http.Request)

List registered hooks. @Summary List hooks @Tags hooks @Produce json @Success 200 {object} apidocs.HookList @Failure 500 {object} apidocs.ErrorBody @Router /hooks [get].

func (*HookHandler) Test

func (h *HookHandler) Test(w http.ResponseWriter, r *http.Request)

Test delivers a synthetic event to an HTTP hook (same signing/delivery path as production). @Summary Test hook delivery @Tags hooks @Produce json @Param hid path string true "Hook ID" @Success 200 {object} apidocs.HookTestData @Failure 400 {object} apidocs.ErrorBody @Failure 404 {object} apidocs.ErrorBody @Failure 502 {object} apidocs.ErrorBody @Router /hooks/{hid}/test [post].

func (*HookHandler) Update

func (h *HookHandler) Update(w http.ResponseWriter, r *http.Request)

Update replaces hook configuration. @Summary Update hook @Tags hooks @Accept json @Produce json @Param hid path string true "Hook ID" @Param body body domain.Hook true "Hook configuration" @Success 200 {object} apidocs.HookData @Failure 400 {object} apidocs.ErrorBody @Failure 404 {object} apidocs.ErrorBody @Failure 500 {object} apidocs.ErrorBody @Router /hooks/{hid} [put].

type RecordingHandler

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

RecordingHandler handles DVR recording and playback REST endpoints.

func NewRecordingHandler

func NewRecordingHandler(i do.Injector) (*RecordingHandler, error)

NewRecordingHandler creates a RecordingHandler and registers it with the DI injector.

func (*RecordingHandler) Get

Get returns one recording's lifecycle metadata by id. @Summary Get recording @Tags recordings @Produce json @Param rid path string true "Recording ID (= stream code)" @Success 200 {object} apidocs.RecordingData @Failure 404 {object} apidocs.ErrorBody @Router /recordings/{rid} [get].

func (*RecordingHandler) Info

Info returns full DVR metadata for a recording: dvr_range, gaps, segment count, total size. Data is read from index.json on disk, so it is always up-to-date. @Summary DVR recording info @Tags recordings @Produce json @Param rid path string true "Recording ID (= stream code)" @Success 200 {object} map[string]any @Failure 404 {object} apidocs.ErrorBody @Router /recordings/{rid}/info [get].

func (*RecordingHandler) ListByStream

func (h *RecordingHandler) ListByStream(w http.ResponseWriter, r *http.Request)

ListByStream lists recording metadata for a stream. @Summary List recordings by stream @Tags recordings @Produce json @Param code path string true "Stream code" @Success 200 {object} apidocs.RecordingList @Failure 500 {object} apidocs.ErrorBody @Router /streams/{code}/recordings [get].

func (*RecordingHandler) Playlist

func (h *RecordingHandler) Playlist(w http.ResponseWriter, r *http.Request)

Playlist serves the M3U8 playlist written to disk by the DVR worker. Reads playlist.m3u8 directly for an always-current response. @Summary Recording M3U8 playlist @Tags recordings @Produce plain @Param rid path string true "Recording ID (= stream code)" @Success 200 {string} string "M3U8 body" @Failure 404 {object} apidocs.ErrorBody @Router /recordings/{rid}/playlist.m3u8 [get].

func (*RecordingHandler) ServeSegment

func (h *RecordingHandler) ServeSegment(w http.ResponseWriter, r *http.Request)

ServeSegment serves a DVR TS segment file from the recording's SegmentDir. @Summary Serve DVR segment @Tags recordings @Produce octet-stream @Param rid path string true "Recording ID (= stream code)" @Param file path string true "Segment filename (e.g. 000000.ts)" @Success 200 {file} binary @Failure 404 {object} apidocs.ErrorBody @Router /recordings/{rid}/{file} [get].

func (*RecordingHandler) Timeshift

func (h *RecordingHandler) Timeshift(w http.ResponseWriter, r *http.Request)

Timeshift builds and returns a dynamic VOD M3U8 for a time window.

Query parameters (mutually exclusive for start point):

  • from=<RFC3339> absolute start time, e.g. 2026-04-06T14:30:00Z
  • offset_sec=<N> seconds from recording start (relative)

Optional:

  • duration=<N> window length in seconds (default: all remaining)

Example:

GET /recordings/test/timeshift.m3u8?from=2026-04-06T14:30:00Z&duration=3600
GET /recordings/test/timeshift.m3u8?offset_sec=1800&duration=3600

@Summary Timeshift VOD playlist @Tags recordings @Produce plain @Param rid path string true "Recording ID (= stream code)" @Param from query string false "Absolute start time (RFC3339)" @Param offset_sec query int false "Relative start offset in seconds from recording start" @Param duration query int false "Window duration in seconds (default: all remaining)" @Success 200 {string} string "M3U8 body" @Failure 400 {object} apidocs.ErrorBody @Failure 404 {object} apidocs.ErrorBody @Router /recordings/{rid}/timeshift.m3u8 [get].

type RuntimeConfigManager

type RuntimeConfigManager interface {
	CurrentConfig() *domain.GlobalConfig
	Apply(ctx context.Context, newCfg *domain.GlobalConfig) error
}

RuntimeConfigManager is the subset of runtime.Manager that the config handler needs.

type SessionHandler added in v0.0.42

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

SessionHandler exposes the play-sessions tracker over HTTP.

Routes (registered by api.Server):

GET    /streams/{code}/sessions       — sessions for one stream
GET    /sessions                      — all active sessions across streams
GET    /sessions/{id}                 — single session
DELETE /sessions/{id}                 — force-close ("kick") a session

func NewSessionHandler added in v0.0.42

func NewSessionHandler(i do.Injector) (*SessionHandler, error)

NewSessionHandler returns a handler reading the tracker from DI. The tracker is registered as *sessions.Service in main.go's wireServices. Returning an error from this constructor is reserved for future config validation; today it always succeeds.

func (*SessionHandler) Delete added in v0.0.42

func (h *SessionHandler) Delete(w http.ResponseWriter, r *http.Request)

Delete force-closes ("kicks") a session. Idempotent — returns 204 even when the session was already gone, so ops scripts can fire-and-forget.

@Summary Kick a play session @Tags sessions @Param id path string true "Session ID" @Success 204 "kicked" @Failure 404 {object} apidocs.ErrorBody @Router /sessions/{id} [delete].

func (*SessionHandler) Get added in v0.0.42

Get returns one session by ID.

@Summary Get a play session by ID @Tags sessions @Produce json @Param id path string true "Session ID" @Success 200 {object} domain.PlaySession @Failure 404 {object} apidocs.ErrorBody @Router /sessions/{id} [get].

func (*SessionHandler) List added in v0.0.42

List returns every active session. Optional filters: ?proto=hls|dash|..., ?status=active|closed, ?limit=N (1..1000).

@Summary List play sessions @Tags sessions @Produce json @Param proto query string false "Filter by protocol (hls|dash|rtmp|srt|rtsp)" @Param status query string false "Filter by status (active|closed)" @Param limit query int false "Max sessions to return (default 0 = no cap)" @Success 200 {object} apidocs.SessionList @Router /sessions [get].

func (*SessionHandler) ListByStream added in v0.0.42

func (h *SessionHandler) ListByStream(w http.ResponseWriter, r *http.Request)

ListByStream returns sessions for a single stream — the same payload shape as List, but scoped to chi.URLParam("code").

@Summary List sessions for a stream @Tags sessions @Produce json @Param code path string true "Stream code" @Param proto query string false "Filter by protocol" @Param status query string false "Filter by status" @Param limit query int false "Max sessions to return" @Success 200 {object} apidocs.SessionList @Failure 400 {object} apidocs.ErrorBody @Router /streams/{code}/sessions [get].

type StreamHandler

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

StreamHandler handles stream lifecycle REST endpoints.

func NewStreamHandler

func NewStreamHandler(i do.Injector) (*StreamHandler, error)

NewStreamHandler creates a StreamHandler and registers it with the DI injector.

func (*StreamHandler) Delete

func (h *StreamHandler) Delete(w http.ResponseWriter, r *http.Request)

Delete removes a stream and stops its pipeline. @Summary Delete stream @Tags streams @Param code path string true "Stream code" @Success 204 "No Content" @Failure 500 {object} apidocs.ErrorBody @Router /streams/{code} [delete].

func (*StreamHandler) Get

Get returns one stream by code. @Summary Get stream @Tags streams @Produce json @Param code path string true "Stream code (a-zA-Z0-9_)" @Success 200 {object} apidocs.StreamData @Failure 404 {object} apidocs.ErrorBody @Failure 500 {object} apidocs.ErrorBody @Router /streams/{code} [get].

func (*StreamHandler) List

func (h *StreamHandler) List(w http.ResponseWriter, r *http.Request)

List streams; optional ?status=idle|active|degraded|stopped. @Summary List streams @Tags streams @Produce json @Param status query string false "Filter by status" @Success 200 {object} apidocs.StreamList @Failure 400 {object} apidocs.ErrorBody @Failure 500 {object} apidocs.ErrorBody @Router /streams [get].

func (*StreamHandler) Put

Put creates a new stream or partially updates an existing one. Only fields present in the request body are applied; omitted fields keep their current values. @Summary Create or partial-update stream @Tags streams @Accept json @Produce json @Param code path string true "Stream code" @Param body body apidocs.StreamPutRequest true "Partial or full stream document" @Success 200 {object} apidocs.StreamData @Success 201 {object} apidocs.StreamData @Failure 400 {object} apidocs.ErrorBody @Failure 500 {object} apidocs.ErrorBody @Router /streams/{code} [post].

func (*StreamHandler) Restart

func (h *StreamHandler) Restart(w http.ResponseWriter, r *http.Request)

Restart stops the running pipeline (if any), waits for full cleanup, then starts a fresh pipeline. This guarantees all goroutines have exited and on-disk segments have been removed before the new pipeline begins. @Summary Restart stream pipeline @Tags streams @Produce json @Param code path string true "Stream code" @Success 200 {object} apidocs.StreamActionData @Failure 400 {object} apidocs.ErrorBody @Failure 404 {object} apidocs.ErrorBody @Failure 500 {object} apidocs.ErrorBody @Router /streams/{code}/restart [post].

func (*StreamHandler) SwitchInput

func (h *StreamHandler) SwitchInput(w http.ResponseWriter, r *http.Request)

SwitchInput forces the active ingest source to the given input priority at runtime. The switch is temporary — it reverts automatically when the selected input degrades permanently. Switching to a different priority replaces any previous manual override.

@Summary Manual input switch @Tags streams @Produce json @Param code path string true "Stream code" @Param body body apidocs.InputSwitchRequest true "Target input priority" @Success 200 {object} apidocs.StreamActionData @Failure 400 {object} apidocs.ErrorBody @Failure 404 {object} apidocs.ErrorBody @Failure 500 {object} apidocs.ErrorBody @Router /streams/{code}/inputs/switch [post].

type VODHandler

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

VODHandler manages VOD mount registrations and serves live filesystem listings for the UI. The system never indexes file content — listings come straight from the host filesystem on every request.

func NewVODHandler

func NewVODHandler(i do.Injector) (*VODHandler, error)

NewVODHandler wires the handler from DI.

func (*VODHandler) Create

func (h *VODHandler) Create(w http.ResponseWriter, r *http.Request)

Create registers a new VOD mount. Name must be unique; storage must be an absolute host path. The directory is not required to exist at create time — operators may provision it later — but a missing directory will surface as an error from List/Resolve until it is fixed.

@Summary Create VOD mount @Tags vod @Accept json @Produce json @Param body body domain.VODMount true "VOD mount" @Success 201 {object} apidocs.VODMountData @Failure 400 {object} apidocs.ErrorBody @Failure 409 {object} apidocs.ErrorBody @Failure 500 {object} apidocs.ErrorBody @Router /vod [post].

func (*VODHandler) Delete

func (h *VODHandler) Delete(w http.ResponseWriter, r *http.Request)

Delete removes a mount. Files on disk are untouched.

@Summary Delete VOD mount @Tags vod @Param name path string true "Mount name" @Success 204 "No Content" @Failure 500 {object} apidocs.ErrorBody @Router /vod/{name} [delete].

func (*VODHandler) DeleteFile

func (h *VODHandler) DeleteFile(w http.ResponseWriter, r *http.Request)

DeleteFile removes a single file from a VOD mount. The wildcard path is the file's location relative to the mount root. Directories are refused — this endpoint is intentionally narrow so an operator typo cannot wipe a tree.

@Summary Delete a file from a VOD mount @Tags vod @Param name path string true "Mount name" @Param path path string true "File path inside the mount (forward-slash separated)" @Success 204 "No Content" @Failure 400 {object} apidocs.ErrorBody @Failure 404 {object} apidocs.ErrorBody @Failure 500 {object} apidocs.ErrorBody @Router /vod/{name}/files/{path} [delete].

func (*VODHandler) Get

func (h *VODHandler) Get(w http.ResponseWriter, r *http.Request)

Get returns one mount by name.

@Summary Get VOD mount @Tags vod @Produce json @Param name path string true "Mount name" @Success 200 {object} apidocs.VODMountData @Failure 404 {object} apidocs.ErrorBody @Router /vod/{name} [get].

func (*VODHandler) List

func (h *VODHandler) List(w http.ResponseWriter, r *http.Request)

List returns all registered VOD mounts.

@Summary List VOD mounts @Tags vod @Produce json @Success 200 {object} apidocs.VODMountList @Failure 500 {object} apidocs.ErrorBody @Router /vod [get].

func (*VODHandler) ListFiles

func (h *VODHandler) ListFiles(w http.ResponseWriter, r *http.Request)

ListFiles lists the contents of a directory inside a mount, one level deep. The optional ?path= query selects a subdirectory; defaults to the mount root. Listings are computed live from the host filesystem; the system never caches or indexes file content.

@Summary List files in a VOD mount @Tags vod @Produce json @Param name path string true "Mount name" @Param path query string false "Subdirectory (relative, no leading slash)" @Success 200 {object} apidocs.VODFileList @Failure 400 {object} apidocs.ErrorBody @Failure 404 {object} apidocs.ErrorBody @Failure 500 {object} apidocs.ErrorBody @Router /vod/{name}/files [get].

func (*VODHandler) Raw

func (h *VODHandler) Raw(w http.ResponseWriter, r *http.Request)

Raw streams a single file from a VOD mount over HTTP. The browser hits this endpoint directly via the play_url returned by ListFiles. http.ServeFile handles Content-Type detection and Range requests so the browser's <video> tag can seek inside the file.

@Summary Stream a VOD file over HTTP @Description Returns the raw bytes of a file inside a VOD mount. Supports HTTP Range requests so an HTML5 video player can seek. @Tags vod @Produce octet-stream @Param name path string true "Mount name" @Param path path string true "File path inside the mount (forward-slash separated)" @Success 200 {file} file @Success 206 {file} file @Failure 400 {object} apidocs.ErrorBody @Failure 404 {object} apidocs.ErrorBody @Router /vod/{name}/raw/{path} [get].

func (*VODHandler) Update

func (h *VODHandler) Update(w http.ResponseWriter, r *http.Request)

Update replaces a mount's storage / comment. Name in URL wins over body.

@Summary Update VOD mount @Tags vod @Accept json @Produce json @Param name path string true "Mount name" @Param body body domain.VODMount true "VOD mount" @Success 200 {object} apidocs.VODMountData @Failure 400 {object} apidocs.ErrorBody @Failure 404 {object} apidocs.ErrorBody @Failure 500 {object} apidocs.ErrorBody @Router /vod/{name} [put].

func (*VODHandler) UploadFile

func (h *VODHandler) UploadFile(w http.ResponseWriter, r *http.Request)

UploadFile accepts a multipart upload and stores it inside a VOD mount. The form field "file" holds the bytes; the optional ?path= query selects a subdirectory under the mount root (created on demand). Only files with a known video extension are accepted; the destination filename is taken from the upload header and stripped to its base via filepath.Base. Existing files are not overwritten — clients must DELETE first.

@Summary Upload a file to a VOD mount @Tags vod @Accept multipart/form-data @Produce json @Param name path string true "Mount name" @Param path query string false "Subdirectory (relative, no leading slash)" @Param file formData file true "Video file (mp4, mkv, mov, …)" @Success 201 {object} apidocs.VODFileData @Failure 400 {object} apidocs.ErrorBody @Failure 404 {object} apidocs.ErrorBody @Failure 409 {object} apidocs.ErrorBody @Failure 413 {object} apidocs.ErrorBody @Failure 500 {object} apidocs.ErrorBody @Router /vod/{name}/files [post].

type WatermarkHandler added in v0.0.44

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

WatermarkHandler exposes the asset library over REST. Mirrors the VOD handler shape (list / upload / get / raw / delete) so the UI's file management widgets can be reused with minimal adaptation.

func NewWatermarkHandler added in v0.0.44

func NewWatermarkHandler(i do.Injector) (*WatermarkHandler, error)

NewWatermarkHandler is the samber/do constructor.

func (*WatermarkHandler) Delete added in v0.0.44

func (h *WatermarkHandler) Delete(w http.ResponseWriter, r *http.Request)

Delete removes an asset. Idempotent — repeat deletes after success return 404, but never 500.

@Summary Delete a watermark asset @Tags watermarks @Param id path string true "Asset ID" @Success 204 "No Content" @Failure 400 {object} apidocs.ErrorBody @Failure 404 {object} apidocs.ErrorBody @Failure 500 {object} apidocs.ErrorBody @Router /watermarks/{id} [delete].

func (*WatermarkHandler) Get added in v0.0.44

Get returns a single asset's metadata.

@Summary Get watermark metadata @Tags watermarks @Produce json @Param id path string true "Asset ID" @Success 200 {object} apidocs.WatermarkAssetData @Failure 400 {object} apidocs.ErrorBody @Failure 404 {object} apidocs.ErrorBody @Router /watermarks/{id} [get].

func (*WatermarkHandler) List added in v0.0.44

List returns every asset, newest first.

@Summary List watermark assets @Tags watermarks @Produce json @Success 200 {object} apidocs.WatermarkAssetList @Failure 500 {object} apidocs.ErrorBody @Router /watermarks [get].

func (*WatermarkHandler) Raw added in v0.0.44

Raw streams the binary image bytes. Used by the UI to preview an asset before applying it to a stream and by player-side overlays that need to fetch the same bitmap as ffmpeg.

@Summary Download watermark image @Tags watermarks @Produce image/png @Param id path string true "Asset ID" @Success 200 {file} binary @Failure 404 {object} apidocs.ErrorBody @Router /watermarks/{id}/raw [get].

func (*WatermarkHandler) Upload added in v0.0.44

func (h *WatermarkHandler) Upload(w http.ResponseWriter, r *http.Request)

Upload accepts a multipart "file" field. Optional ?name= sets the display name; absent uses the upload's basename.

@Summary Upload a watermark image @Tags watermarks @Accept multipart/form-data @Produce json @Param file formData file true "Image file (PNG / JPG / GIF, ≤ 8 MiB)" @Param name query string false "Display name (defaults to filename)" @Success 201 {object} apidocs.WatermarkAssetData @Failure 400 {object} apidocs.ErrorBody @Failure 413 {object} apidocs.ErrorBody @Failure 415 {object} apidocs.ErrorBody @Failure 500 {object} apidocs.ErrorBody @Router /watermarks [post].

Jump to

Keyboard shortcuts

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