feat(api): add gated HTTP endpoint to push files to the upload queue#216
Merged
feat(api): add gated HTTP endpoint to push files to the upload queue#216
Conversation
Adds POST /api/v1/queue/upload so external tools (Sonarr/Radarr/scripts)
can enqueue files with an explicit relative_path root. The processor
preserves the directory tree below that root in the resulting NZB
output, mirroring how the watcher behaves but without needing a watch
folder.
- queue.FileJob gains optional InputFolder + DeleteOriginal overrides;
new AddFileWithOptions threads them through goqite without touching
existing AddFile/AddFileWithPriority callers.
- processor honors job.InputFolder for relative-path output and
job.DeleteOriginal for per-job source deletion.
- New QueueConfig.MinSizeToStart gates pickup behind a cumulative
pending-bytes floor (0 disables); processor checks PendingTotalSize
before each Receive.
- New APIConfig{Enabled} plus an api_keys SQLite table (single row).
internal/apikey generates a 32-byte URL-safe key on first start,
exposes Wails GetAPIKey/RegenerateAPIKey for the desktop UI.
- cmd/web mounts the gated endpoint behind a constant-time
X-API-Key/Bearer middleware (403 when disabled, 401 on bad key) and
exposes open /api/api-key + /api/api-key/regenerate routes for the
settings page.
- Frontend: new ApiSection (toggle, key reveal/copy/regenerate, curl
example), QueueSection extended with ByteSizeInput for
min_size_to_start, Wails bindings + models updated, en/es/fr/tr i18n.
go test -race ./... and svelte-check both clean.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a third entry point to the upload queue: a gated HTTP endpoint so external automation (Sonarr/Radarr/scripts) can push files directly without needing a watched folder.
relative_pathis the root prefix to strip — it maps directly onto the processor's existinginputFolder, so the NZB lands at<output_dir>/Media/Movie/Movie 1/movie.nzband the source tree is preserved.What changed
Queue / processor
queue.FileJobgains optionalInputFolder+DeleteOriginal *bool. NewAddFileWithOptions(ctx, path, size, AddOptions{...})threads them through goqite. ExistingAddFile/AddFileWithPrioritypaths are untouched.job.InputFolderfor relative-path output andjob.DeleteOriginalas a per-job override of the global delete-original setting.QueueConfig.MinSizeToStartgates pickup behind a cumulative pending-bytes floor (0disables). Processor callsqueue.PendingTotalSizebefore eachReceive.Auth / API
APIConfig{Enabled}. The key itself lives in a new single-rowapi_keysSQLite table (migration006_add_api_keys.sql), not inconfig.yaml.internal/apikeypackage:Generate(32 bytes → base64 URL-safe),Store,EnsureKey(idempotent),Regenerate.api.enabled = true,EnsureKeyruns after the queue is wired so the gated endpoint always has something to validate against.App.GetAPIKey()/App.RegenerateAPIKey()for the desktop UI.X-API-Key(preferred) orAuthorization: Bearer <key>, compares withsubtle.ConstantTimeCompare. Returns403when the API is disabled and401on missing/invalid keys. Only/api/v1/queue/uploadis gated; existing/api/*UI routes remain open. Two open helper routes (/api/api-key,/api/api-key/regenerate) back the settings page in web mode.relative_pathvalues that aren't a parent prefix offile— so we never emit an NZB at the output root by accident.Frontend
ApiSection.svelte(Automation tab): enable toggle, key display with reveal/copy/regenerate, and a copy-pasteable curl example.QueueSection.svelteextended withmin_size_to_startusing the existingByteSizeInput(presets: disabled, 50/100/200/500 GB).App.js,App.d.ts,models.ts) regenerated to expose the new methods + config fields.client.ts/web-client.tsforgetApiKey()/regenerateApiKey().settings.api.*andsettings.queue.min_size_to_start*added across en/es/fr/tr.Notes for reviewers
FOLDER:prefix is still available to internal call sites.FileJobJSON in goqite deserializes cleanly because the new fields are pointer/zero-value optional.Test plan
go test -race ./internal/queue/... ./internal/apikey/... ./internal/processor/... ./internal/watcher/... ./pkg/...passesgo vet ./internal/... ./pkg/... ./cmd/postie/... ./cmd/web/...cleanbun run check(svelte-check): 0 errors, 0 warningscurl -X POST -H \"X-API-Key: <key>\" -d '{\"file\":\"...\",\"relative_path\":\"...\"}' http://localhost:8080/api/v1/queue/uploadand confirm:delete_after_upload: true, the source file is removed after successqueue.min_size_to_startset, processing waits until the threshold is metapi.enabled = false, 400 on mismatchedrelative_path