Compare commits
2 commits
fa0d5183cd
...
1be09be9db
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1be09be9db | ||
|
|
9d9f8ae0a9 |
|
|
@ -22,4 +22,4 @@ Commits follow a Conventional Commits prefix (`fix:`, `refactor:`) in imperative
|
||||||
Document expected locations for `yt-dlp`, cookies, and OPML files when altering defaults. If a change requires bgutil or other external services, provide startup commands and update the sample `config.json`. Ensure new options degrade gracefully for existing configs and call out migration steps in the PR description.
|
Document expected locations for `yt-dlp`, cookies, and OPML files when altering defaults. If a change requires bgutil or other external services, provide startup commands and update the sample `config.json`. Ensure new options degrade gracefully for existing configs and call out migration steps in the PR description.
|
||||||
|
|
||||||
## HTTP API
|
## HTTP API
|
||||||
Enable the intake server with `http_api.enable` (binds to `127.0.0.1:4416`). Set `auth_token` for bearer auth and `queue_file` to persist pending jobs. Example: `curl -H "Authorization: Bearer $TOKEN" -d '{"url":"https://youtu.be/ID","out_dir":"Channel"}' http://127.0.0.1:4416/v1/videos`. Inspect the queue with `curl -H "Authorization: Bearer $TOKEN" http://127.0.0.1:4416/status`.
|
Enable the intake server with `http_api.enable` (binds to `127.0.0.1:4416`). Set `auth_token` or point `auth_token_file` at a mounted secret, and use `queue_file` to persist pending jobs. Example: `curl -H "Authorization: Bearer $TOKEN" -d '{"url":"https://youtu.be/ID","out_dir":"Channel"}' http://127.0.0.1:4416/v1/videos`. Inspect the queue with `curl -H "Authorization: Bearer $TOKEN" http://127.0.0.1:4416/status`.
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,12 @@ COPY <<-EOT /data/config.json
|
||||||
"daemon": true,
|
"daemon": true,
|
||||||
"dry_run": false,
|
"dry_run": false,
|
||||||
"out_dir": "/data/vids",
|
"out_dir": "/data/vids",
|
||||||
|
"http_api": {
|
||||||
|
"enable": true,
|
||||||
|
"listen": "127.0.0.1:4416",
|
||||||
|
"auth_token_file": "/run/secrets/subsyt-token",
|
||||||
|
"queue_file": "/data/api-queue.json"
|
||||||
|
},
|
||||||
"provider": {
|
"provider": {
|
||||||
"youtube": {
|
"youtube": {
|
||||||
"verbose": false,
|
"verbose": false,
|
||||||
|
|
|
||||||
|
|
@ -273,7 +273,7 @@ OPML export.
|
||||||
"http_api": {
|
"http_api": {
|
||||||
"enable": true,
|
"enable": true,
|
||||||
"listen": "127.0.0.1:4416",
|
"listen": "127.0.0.1:4416",
|
||||||
"auth_token": "super-secret",
|
"auth_token_file": "/run/secrets/subsyt-token",
|
||||||
"queue_file": "./tmp/api-queue.json"
|
"queue_file": "./tmp/api-queue.json"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -283,7 +283,7 @@ Submit new downloads with bearer authentication:
|
||||||
|
|
||||||
```
|
```
|
||||||
curl \
|
curl \
|
||||||
-H "Authorization: Bearer super-secret" \
|
-H "Authorization: Bearer $(cat /run/secrets/subsyt-token)" \
|
||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
--data '{"url":"https://youtu.be/VIDEO","out_dir":"Channel"}' \
|
--data '{"url":"https://youtu.be/VIDEO","out_dir":"Channel"}' \
|
||||||
http://127.0.0.1:4416/v1/videos
|
http://127.0.0.1:4416/v1/videos
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ type Http_api struct {
|
||||||
Enable bool
|
Enable bool
|
||||||
Listen string
|
Listen string
|
||||||
Auth_token string
|
Auth_token string
|
||||||
|
Auth_token_file string
|
||||||
Queue_file string
|
Queue_file string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
@ -22,15 +23,28 @@ type Server struct {
|
||||||
defaultOutDir string
|
defaultOutDir string
|
||||||
httpServer *http.Server
|
httpServer *http.Server
|
||||||
shutdownSignal chan struct{}
|
shutdownSignal chan struct{}
|
||||||
|
authToken string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewServer(cfg config.Http_api, defaultOutDir string, queue *Queue) *Server {
|
func NewServer(cfg config.Http_api, defaultOutDir string, queue *Queue) *Server {
|
||||||
return &Server{
|
srv := &Server{
|
||||||
cfg: cfg,
|
cfg: cfg,
|
||||||
queue: queue,
|
queue: queue,
|
||||||
defaultOutDir: defaultOutDir,
|
defaultOutDir: defaultOutDir,
|
||||||
shutdownSignal: make(chan struct{}),
|
shutdownSignal: make(chan struct{}),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
srv.authToken = strings.TrimSpace(cfg.Auth_token)
|
||||||
|
|
||||||
|
if srv.authToken == "" && cfg.Auth_token_file != "" {
|
||||||
|
if token, err := os.ReadFile(cfg.Auth_token_file); err == nil {
|
||||||
|
srv.authToken = strings.TrimSpace(string(token))
|
||||||
|
} else {
|
||||||
|
log.Printf("failed to read auth token file %s: %v", cfg.Auth_token_file, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return srv
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) Start(ctx context.Context) error {
|
func (s *Server) Start(ctx context.Context) error {
|
||||||
|
|
@ -156,7 +170,7 @@ func (s *Server) handleStatus(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) authorize(header string) bool {
|
func (s *Server) authorize(header string) bool {
|
||||||
required := strings.TrimSpace(s.cfg.Auth_token)
|
required := s.authToken
|
||||||
if required == "" {
|
if required == "" {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -87,7 +87,13 @@ func TestHandleStatus(t *testing.T) {
|
||||||
t.Fatalf("new queue: %v", err)
|
t.Fatalf("new queue: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
s := NewServer(config.Http_api{Auth_token: "secret"}, "/videos", queue)
|
tmp := t.TempDir()
|
||||||
|
tokenPath := filepath.Join(tmp, "token.txt")
|
||||||
|
if err := os.WriteFile(tokenPath, []byte("secret"), 0o600); err != nil {
|
||||||
|
t.Fatalf("write token file: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
s := NewServer(config.Http_api{Auth_token_file: tokenPath}, "/videos", queue)
|
||||||
|
|
||||||
req := httptest.NewRequest(http.MethodGet, "/status", nil)
|
req := httptest.NewRequest(http.MethodGet, "/status", nil)
|
||||||
rec := httptest.NewRecorder()
|
rec := httptest.NewRecorder()
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue