package session import ( "encoding/json" "fmt" "os" "path/filepath" "strings" "time" ) type Data struct { Spotify SpotifyState `json:"spotify"` Qobuz QobuzState `json:"qobuz"` Monitor map[string]string `json:"monitor"` Meta map[string]string `json:"meta,omitempty"` } type SpotifyState struct { ClientID string `json:"client_id,omitempty"` AccessToken string `json:"access_token,omitempty"` RefreshToken string `json:"refresh_token,omitempty"` ExpiresAt time.Time `json:"expires_at,omitempty"` Scope string `json:"scope,omitempty"` } type QobuzState struct { Username string `json:"username,omitempty"` Password string `json:"password,omitempty"` AccessToken string `json:"access_token,omitempty"` } func DefaultPath() string { home, err := os.UserHomeDir() if err != nil || strings.TrimSpace(home) == "" { return ".qtransfer-session.json" } return filepath.Join(home, ".config", "qtransfer", "session.json") } func ResolvePath(path string) string { path = strings.TrimSpace(path) if path == "" { return DefaultPath() } if path == "~" { return DefaultPath() } if strings.HasPrefix(path, "~/") { home, err := os.UserHomeDir() if err == nil && home != "" { return filepath.Join(home, path[2:]) } } return path } func Load(path string) (Data, error) { path = ResolvePath(path) b, err := os.ReadFile(path) if err != nil { if os.IsNotExist(err) { return Data{}, nil } return Data{}, err } var d Data if err := json.Unmarshal(b, &d); err != nil { return Data{}, fmt.Errorf("parse session file: %w", err) } if d.Monitor == nil { d.Monitor = map[string]string{} } return d, nil } func Save(path string, data Data) error { path = ResolvePath(path) dir := filepath.Dir(path) if err := os.MkdirAll(dir, 0o700); err != nil { return fmt.Errorf("create session directory: %w", err) } b, err := json.MarshalIndent(data, "", " ") if err != nil { return fmt.Errorf("encode session: %w", err) } tmp := path + ".tmp" if err := os.WriteFile(tmp, b, 0o600); err != nil { return fmt.Errorf("write session temp file: %w", err) } if err := os.Rename(tmp, path); err != nil { return fmt.Errorf("replace session file: %w", err) } return nil }