// backend/internal/jellyfin.go package internal import ( "bytes" "encoding/json" "fmt" // <-- keep this; used by fmt.Errorf "net/http" "os" "time" ) // Minimal Jellyfin client type jfAuthResult struct { AccessToken string `json:"AccessToken"` User struct { Id string `json:"Id"` Name string `json:"Name"` } `json:"User"` } type Jellyfin struct { BaseURL string Client *http.Client } func NewJellyfin() *Jellyfin { return &Jellyfin{ BaseURL: os.Getenv("JELLYFIN_URL"), Client: &http.Client{Timeout: 10 * time.Second}, } } // Authenticate against /Users/AuthenticateByName using Pw (plaintext) func (j *Jellyfin) AuthenticateByName(username, password string) (jfAuthResult, error) { var out jfAuthResult body := map[string]string{"Username": username, "Pw": password} b, _ := json.Marshal(body) req, _ := http.NewRequest("POST", j.BaseURL+"/Users/AuthenticateByName", bytes.NewReader(b)) req.Header.Set("Content-Type", "application/json") // Jellyfin client descriptor (no token yet) req.Header.Set("Authorization", `MediaBrowser Client="Pegasus", Device="Pegasus Web", DeviceId="pegasus-web", Version="1.0.0"`) resp, err := j.Client.Do(req) if err != nil { return out, err } defer resp.Body.Close() if resp.StatusCode != 200 { return out, fmt.Errorf("login failed: %s", resp.Status) } if err := json.NewDecoder(resp.Body).Decode(&out); err != nil { return out, err } return out, nil }