package session import ( "encoding/json" "os" "path/filepath" "strings" "time" ) // Stream is a streamd-ready description of one playable channel, as produced by // a provider catalog lookup. MPD holds the manifest URL whatever its type. type Stream struct { Name string `json:"name"` Title string `json:"title"` App string `json:"app"` Channel string `json:"channel"` MPD string `json:"mpd"` Key string `json:"key"` Keys []string `json:"keys,omitempty"` PSSH string `json:"pssh,omitempty"` PrimaryKID string `json:"primary_kid,omitempty"` HeadersJSON string `json:"headers_json"` Rewriter string `json:"rewriter"` LicenseURL string `json:"license_url,omitempty"` AccountID string `json:"account_id,omitempty"` VideoID string `json:"video_id,omitempty"` PlaybackURL string `json:"playback_url,omitempty"` ManifestType string `json:"manifest_type,omitempty"` } // WriteStream writes outputs///{session.json,mpd.txt,license.txt,…} // and refreshes outputs//latest. The app name comes from the caller so no // provider name is baked in here. func WriteStream(root, app string, info Stream) (string, error) { stamp := time.Now().Format("20060102-150405") dir := filepath.Join(root, "outputs", app, stamp) if err := os.MkdirAll(dir, 0o755); err != nil { return "", err } raw, err := json.MarshalIndent(info, "", " ") if err != nil { return "", err } if err := os.WriteFile(filepath.Join(dir, "session.json"), append(raw, '\n'), 0o644); err != nil { return "", err } write := func(name, val string) { if val == "" { return } _ = os.WriteFile(filepath.Join(dir, name), []byte(val+"\n"), 0o644) } write("mpd.txt", info.MPD) write("license.txt", info.LicenseURL) write("pssh.txt", info.PSSH) write("key.txt", info.Key) write("pid.txt", info.VideoID) if len(info.Keys) > 0 { write("keys.txt", strings.Join(info.Keys, "\n")) } latest := filepath.Join(root, "outputs", app, "latest") _ = os.RemoveAll(latest) _ = copyDir(dir, latest) return dir, nil }