style tables and add out/err highlights

improve projector open error message if an invalid monitor index is passed.
it now prints the monitor name and suggests `gobs-cli prj ls-m`

improve error message for sceneitem commands if a scene item in a group is queried without the --group flag.
This commit is contained in:
onyx-and-iris 2025-06-21 06:41:12 +01:00
parent d699939298
commit 7147c3f1ca
11 changed files with 424 additions and 150 deletions

View File

@ -7,7 +7,8 @@ import (
"strings" "strings"
"github.com/andreykaipov/goobs/api/requests/filters" "github.com/andreykaipov/goobs/api/requests/filters"
"github.com/aquasecurity/table" "github.com/charmbracelet/lipgloss"
"github.com/charmbracelet/lipgloss/table"
) )
// FilterCmd provides commands to manage filters in OBS Studio. // FilterCmd provides commands to manage filters in OBS Studio.
@ -25,6 +26,7 @@ type FilterListCmd struct {
} }
// Run executes the command to list all filters in a scene. // Run executes the command to list all filters in a scene.
// nolint: misspell
func (cmd *FilterListCmd) Run(ctx *context) error { func (cmd *FilterListCmd) Run(ctx *context) error {
if cmd.SourceName == "" { if cmd.SourceName == "" {
currentScene, err := ctx.Client.Scenes.GetCurrentProgramScene() currentScene, err := ctx.Client.Scenes.GetCurrentProgramScene()
@ -42,14 +44,35 @@ func (cmd *FilterListCmd) Run(ctx *context) error {
} }
if len(sourceFilters.Filters) == 0 { if len(sourceFilters.Filters) == 0 {
fmt.Fprintf(ctx.Out, "No filters found for source %s.\n", cmd.SourceName) fmt.Fprintf(ctx.Out, "No filters found for source %s.\n", ctx.Style.Highlight(cmd.SourceName))
return nil return nil
} }
t := table.New(ctx.Out) t := table.New().Border(lipgloss.RoundedBorder()).
t.SetPadding(3) BorderStyle(lipgloss.NewStyle().Foreground(ctx.Style.border)).
t.SetAlignment(table.AlignLeft, table.AlignLeft, table.AlignCenter, table.AlignLeft) Headers("Filter Name", "Kind", "Enabled", "Settings").
t.SetHeaders("Filter Name", "Kind", "Enabled", "Settings") StyleFunc(func(row, col int) lipgloss.Style {
style := lipgloss.NewStyle().Padding(0, 3)
switch col {
case 0:
style = style.Align(lipgloss.Left)
case 1:
style = style.Align(lipgloss.Left)
case 2:
style = style.Align(lipgloss.Center)
case 3:
style = style.Align(lipgloss.Left)
}
switch {
case row == table.HeaderRow:
style = style.Bold(true).Align(lipgloss.Center)
case row%2 == 0:
style = style.Foreground(ctx.Style.evenRows)
default:
style = style.Foreground(ctx.Style.oddRows)
}
return style
})
for _, filter := range sourceFilters.Filters { for _, filter := range sourceFilters.Filters {
defaultSettings, err := ctx.Client.Filters.GetSourceFilterDefaultSettings( defaultSettings, err := ctx.Client.Filters.GetSourceFilterDefaultSettings(
@ -58,7 +81,7 @@ func (cmd *FilterListCmd) Run(ctx *context) error {
) )
if err != nil { if err != nil {
return fmt.Errorf("failed to get default settings for filter %s: %w", return fmt.Errorf("failed to get default settings for filter %s: %w",
filter.FilterName, err) ctx.Style.Error(filter.FilterName), err)
} }
maps.Insert(defaultSettings.DefaultFilterSettings, maps.All(filter.FilterSettings)) maps.Insert(defaultSettings.DefaultFilterSettings, maps.All(filter.FilterSettings))
@ -70,14 +93,14 @@ func (cmd *FilterListCmd) Run(ctx *context) error {
return strings.ToLower(lines[i]) < strings.ToLower(lines[j]) return strings.ToLower(lines[i]) < strings.ToLower(lines[j])
}) })
t.AddRow( t.Row(
filter.FilterName, filter.FilterName,
snakeCaseToTitleCase(filter.FilterKind), snakeCaseToTitleCase(filter.FilterKind),
getEnabledMark(filter.FilterEnabled), getEnabledMark(filter.FilterEnabled),
strings.Join(lines, "\n"), strings.Join(lines, "\n"),
) )
} }
t.Render() fmt.Fprintln(ctx.Out, t.Render())
return nil return nil
} }
@ -97,10 +120,10 @@ func (cmd *FilterEnableCmd) Run(ctx *context) error {
) )
if err != nil { if err != nil {
return fmt.Errorf("failed to enable filter %s on source %s: %w", return fmt.Errorf("failed to enable filter %s on source %s: %w",
cmd.FilterName, cmd.SourceName, err) ctx.Style.Error(cmd.FilterName), ctx.Style.Error(cmd.SourceName), err)
} }
fmt.Fprintf(ctx.Out, "Filter %s enabled on source %s.\n", fmt.Fprintf(ctx.Out, "Filter %s enabled on source %s.\n",
cmd.FilterName, cmd.SourceName) ctx.Style.Highlight(cmd.FilterName), ctx.Style.Highlight(cmd.SourceName))
return nil return nil
} }
@ -120,10 +143,10 @@ func (cmd *FilterDisableCmd) Run(ctx *context) error {
) )
if err != nil { if err != nil {
return fmt.Errorf("failed to disable filter %s on source %s: %w", return fmt.Errorf("failed to disable filter %s on source %s: %w",
cmd.FilterName, cmd.SourceName, err) ctx.Style.Error(cmd.FilterName), ctx.Style.Error(cmd.SourceName), err)
} }
fmt.Fprintf(ctx.Out, "Filter %s disabled on source %s.\n", fmt.Fprintf(ctx.Out, "Filter %s disabled on source %s.\n",
cmd.FilterName, cmd.SourceName) ctx.Style.Highlight(cmd.FilterName), ctx.Style.Highlight(cmd.SourceName))
return nil return nil
} }
@ -142,7 +165,7 @@ func (cmd *FilterToggleCmd) Run(ctx *context) error {
) )
if err != nil { if err != nil {
return fmt.Errorf("failed to get filter %s on source %s: %w", return fmt.Errorf("failed to get filter %s on source %s: %w",
cmd.FilterName, cmd.SourceName, err) ctx.Style.Error(cmd.FilterName), ctx.Style.Error(cmd.SourceName), err)
} }
newStatus := !filter.FilterEnabled newStatus := !filter.FilterEnabled
@ -154,15 +177,15 @@ func (cmd *FilterToggleCmd) Run(ctx *context) error {
) )
if err != nil { if err != nil {
return fmt.Errorf("failed to toggle filter %s on source %s: %w", return fmt.Errorf("failed to toggle filter %s on source %s: %w",
cmd.FilterName, cmd.SourceName, err) ctx.Style.Error(cmd.FilterName), ctx.Style.Error(cmd.SourceName), err)
} }
if newStatus { if newStatus {
fmt.Fprintf(ctx.Out, "Filter %s on source %s is now enabled.\n", fmt.Fprintf(ctx.Out, "Filter %s on source %s is now enabled.\n",
cmd.FilterName, cmd.SourceName) ctx.Style.Highlight(cmd.FilterName), ctx.Style.Highlight(cmd.SourceName))
} else { } else {
fmt.Fprintf(ctx.Out, "Filter %s on source %s is now disabled.\n", fmt.Fprintf(ctx.Out, "Filter %s on source %s is now disabled.\n",
cmd.FilterName, cmd.SourceName) ctx.Style.Highlight(cmd.FilterName), ctx.Style.Highlight(cmd.SourceName))
} }
return nil return nil
} }
@ -182,14 +205,14 @@ func (cmd *FilterStatusCmd) Run(ctx *context) error {
) )
if err != nil { if err != nil {
return fmt.Errorf("failed to get status of filter %s on source %s: %w", return fmt.Errorf("failed to get status of filter %s on source %s: %w",
cmd.FilterName, cmd.SourceName, err) ctx.Style.Error(cmd.FilterName), ctx.Style.Error(cmd.SourceName), err)
} }
if filter.FilterEnabled { if filter.FilterEnabled {
fmt.Fprintf(ctx.Out, "Filter %s on source %s is enabled.\n", fmt.Fprintf(ctx.Out, "Filter %s on source %s is enabled.\n",
cmd.FilterName, cmd.SourceName) ctx.Style.Highlight(cmd.FilterName), ctx.Style.Highlight(cmd.SourceName))
} else { } else {
fmt.Fprintf(ctx.Out, "Filter %s on source %s is disabled.\n", fmt.Fprintf(ctx.Out, "Filter %s on source %s is disabled.\n",
cmd.FilterName, cmd.SourceName) ctx.Style.Highlight(cmd.FilterName), ctx.Style.Highlight(cmd.SourceName))
} }
return nil return nil
} }

View File

@ -4,7 +4,8 @@ import (
"fmt" "fmt"
"github.com/andreykaipov/goobs/api/requests/sceneitems" "github.com/andreykaipov/goobs/api/requests/sceneitems"
"github.com/aquasecurity/table" "github.com/charmbracelet/lipgloss"
"github.com/charmbracelet/lipgloss/table"
) )
// GroupCmd provides commands to manage groups in OBS Studio. // GroupCmd provides commands to manage groups in OBS Studio.
@ -22,6 +23,7 @@ type GroupListCmd struct {
} }
// Run executes the command to list all groups in a scene. // Run executes the command to list all groups in a scene.
// nolint: misspell
func (cmd *GroupListCmd) Run(ctx *context) error { func (cmd *GroupListCmd) Run(ctx *context) error {
if cmd.SceneName == "" { if cmd.SceneName == "" {
currentScene, err := ctx.Client.Scenes.GetCurrentProgramScene() currentScene, err := ctx.Client.Scenes.GetCurrentProgramScene()
@ -37,17 +39,44 @@ func (cmd *GroupListCmd) Run(ctx *context) error {
return fmt.Errorf("failed to get scene item list: %w", err) return fmt.Errorf("failed to get scene item list: %w", err)
} }
t := table.New(ctx.Out) t := table.New().Border(lipgloss.RoundedBorder()).
t.SetPadding(3) BorderStyle(lipgloss.NewStyle().Foreground(ctx.Style.border)).
t.SetAlignment(table.AlignCenter, table.AlignLeft, table.AlignCenter) Headers("ID", "Group Name", "Enabled").
t.SetHeaders("ID", "Group Name", "Enabled") StyleFunc(func(row, col int) lipgloss.Style {
style := lipgloss.NewStyle().Padding(0, 3)
switch col {
case 0:
style = style.Align(lipgloss.Center)
case 1:
style = style.Align(lipgloss.Left)
case 2:
style = style.Align(lipgloss.Center)
}
switch {
case row == table.HeaderRow:
style = style.Bold(true).Align(lipgloss.Center)
case row%2 == 0:
style = style.Foreground(ctx.Style.evenRows)
default:
style = style.Foreground(ctx.Style.oddRows)
}
return style
})
var found bool
for _, item := range resp.SceneItems { for _, item := range resp.SceneItems {
if item.IsGroup { if item.IsGroup {
t.AddRow(fmt.Sprintf("%d", item.SceneItemID), item.SourceName, getEnabledMark(item.SceneItemEnabled)) t.Row(fmt.Sprintf("%d", item.SceneItemID), item.SourceName, getEnabledMark(item.SceneItemEnabled))
found = true
} }
} }
t.Render()
if !found {
fmt.Fprintf(ctx.Out, "No groups found in scene %s.\n", ctx.Style.Highlight(cmd.SceneName))
return nil
}
fmt.Fprintln(ctx.Out, t.Render())
return nil return nil
} }
@ -75,13 +104,17 @@ func (cmd *GroupShowCmd) Run(ctx *context) error {
if err != nil { if err != nil {
return fmt.Errorf("failed to set scene item enabled: %w", err) return fmt.Errorf("failed to set scene item enabled: %w", err)
} }
fmt.Fprintf(ctx.Out, "Group %s is now shown.\n", cmd.GroupName) fmt.Fprintf(ctx.Out, "Group %s is now shown.\n", ctx.Style.Highlight(cmd.GroupName))
found = true found = true
break break
} }
} }
if !found { if !found {
return fmt.Errorf("group '%s' not found", cmd.GroupName) return fmt.Errorf(
"group %s not found in scene %s",
ctx.Style.Error(cmd.GroupName),
ctx.Style.Error(cmd.SceneName),
)
} }
return nil return nil
} }
@ -110,13 +143,17 @@ func (cmd *GroupHideCmd) Run(ctx *context) error {
if err != nil { if err != nil {
return fmt.Errorf("failed to set scene item enabled: %w", err) return fmt.Errorf("failed to set scene item enabled: %w", err)
} }
fmt.Fprintf(ctx.Out, "Group %s is now hidden.\n", cmd.GroupName) fmt.Fprintf(ctx.Out, "Group %s is now hidden.\n", ctx.Style.Highlight(cmd.GroupName))
found = true found = true
break break
} }
} }
if !found { if !found {
return fmt.Errorf("group '%s' not found", cmd.GroupName) return fmt.Errorf(
"group %s not found in scene %s",
ctx.Style.Error(cmd.GroupName),
ctx.Style.Error(cmd.SceneName),
)
} }
return nil return nil
} }
@ -147,16 +184,20 @@ func (cmd *GroupToggleCmd) Run(ctx *context) error {
return fmt.Errorf("failed to set scene item enabled: %w", err) return fmt.Errorf("failed to set scene item enabled: %w", err)
} }
if newState { if newState {
fmt.Fprintf(ctx.Out, "Group %s is now shown.\n", cmd.GroupName) fmt.Fprintf(ctx.Out, "Group %s is now shown.\n", ctx.Style.Highlight(cmd.GroupName))
} else { } else {
fmt.Fprintf(ctx.Out, "Group %s is now hidden.\n", cmd.GroupName) fmt.Fprintf(ctx.Out, "Group %s is now hidden.\n", ctx.Style.Highlight(cmd.GroupName))
} }
found = true found = true
break break
} }
} }
if !found { if !found {
return fmt.Errorf("group '%s' not found", cmd.GroupName) return fmt.Errorf(
"group %s not found in scene %s",
ctx.Style.Error(cmd.GroupName),
ctx.Style.Error(cmd.SceneName),
)
} }
return nil return nil
@ -178,12 +219,12 @@ func (cmd *GroupStatusCmd) Run(ctx *context) error {
for _, item := range resp.SceneItems { for _, item := range resp.SceneItems {
if item.IsGroup && item.SourceName == cmd.GroupName { if item.IsGroup && item.SourceName == cmd.GroupName {
if item.SceneItemEnabled { if item.SceneItemEnabled {
fmt.Fprintf(ctx.Out, "Group %s is shown.\n", cmd.GroupName) fmt.Fprintf(ctx.Out, "Group %s is shown.\n", ctx.Style.Highlight(cmd.GroupName))
} else { } else {
fmt.Fprintf(ctx.Out, "Group %s is hidden.\n", cmd.GroupName) fmt.Fprintf(ctx.Out, "Group %s is hidden.\n", ctx.Style.Highlight(cmd.GroupName))
} }
return nil return nil
} }
} }
return fmt.Errorf("group '%s' not found", cmd.GroupName) return fmt.Errorf("group %s not found in scene %s", ctx.Style.Error(cmd.GroupName), ctx.Style.Error(cmd.SceneName))
} }

View File

@ -1,9 +1,12 @@
package main package main
import ( import (
"fmt"
"github.com/andreykaipov/goobs/api/requests/general" "github.com/andreykaipov/goobs/api/requests/general"
"github.com/andreykaipov/goobs/api/typedefs" "github.com/andreykaipov/goobs/api/typedefs"
"github.com/aquasecurity/table" "github.com/charmbracelet/lipgloss"
"github.com/charmbracelet/lipgloss/table"
) )
// HotkeyCmd provides commands to manage hotkeys in OBS Studio. // HotkeyCmd provides commands to manage hotkeys in OBS Studio.
@ -23,15 +26,26 @@ func (cmd *HotkeyListCmd) Run(ctx *context) error {
return err return err
} }
t := table.New(ctx.Out) t := table.New().Border(lipgloss.RoundedBorder()).
t.SetPadding(3) BorderStyle(lipgloss.NewStyle().Foreground(ctx.Style.border)).
t.SetAlignment(table.AlignLeft) Headers("Hotkey Name").
t.SetHeaders("Hotkey Name") StyleFunc(func(row, _ int) lipgloss.Style {
style := lipgloss.NewStyle().Padding(0, 3)
switch {
case row == table.HeaderRow:
style = style.Bold(true).Align(lipgloss.Center) // nolint: misspell
case row%2 == 0:
style = style.Foreground(ctx.Style.evenRows)
default:
style = style.Foreground(ctx.Style.oddRows)
}
return style
})
for _, hotkey := range resp.Hotkeys { for _, hotkey := range resp.Hotkeys {
t.AddRow(hotkey) t.Row(hotkey)
} }
t.Render() fmt.Fprintln(ctx.Out, t.Render())
return nil return nil
} }

View File

@ -1,3 +1,4 @@
// nolint: misspell
package main package main
import ( import (
@ -6,7 +7,8 @@ import (
"strings" "strings"
"github.com/andreykaipov/goobs/api/requests/inputs" "github.com/andreykaipov/goobs/api/requests/inputs"
"github.com/aquasecurity/table" "github.com/charmbracelet/lipgloss"
"github.com/charmbracelet/lipgloss/table"
) )
// InputCmd provides commands to manage inputs in OBS Studio. // InputCmd provides commands to manage inputs in OBS Studio.
@ -34,15 +36,35 @@ func (cmd *InputListCmd) Run(ctx *context) error {
return err return err
} }
t := table.New(ctx.Out) t := table.New().Border(lipgloss.RoundedBorder()).
t.SetPadding(3) BorderStyle(lipgloss.NewStyle().Foreground(ctx.Style.border))
if cmd.UUID { if cmd.UUID {
t.SetAlignment(table.AlignLeft, table.AlignLeft, table.AlignCenter, table.AlignLeft) t.Headers("Input Name", "Kind", "Muted", "UUID")
t.SetHeaders("Input Name", "Kind", "Muted", "UUID")
} else { } else {
t.SetAlignment(table.AlignLeft, table.AlignLeft, table.AlignCenter) t.Headers("Input Name", "Kind", "Muted")
t.SetHeaders("Input Name", "Kind", "Muted")
} }
t.StyleFunc(func(row, col int) lipgloss.Style {
style := lipgloss.NewStyle().Padding(0, 3)
switch col {
case 0:
style = style.Align(lipgloss.Left)
case 1:
style = style.Align(lipgloss.Left)
case 2:
style = style.Align(lipgloss.Center)
case 3:
style = style.Align(lipgloss.Left)
}
switch {
case row == table.HeaderRow:
style = style.Bold(true).Align(lipgloss.Center)
case row%2 == 0:
style = style.Foreground(ctx.Style.evenRows)
default:
style = style.Foreground(ctx.Style.oddRows)
}
return style
})
sort.Slice(resp.Inputs, func(i, j int) bool { sort.Slice(resp.Inputs, func(i, j int) bool {
return resp.Inputs[i].InputName < resp.Inputs[j].InputName return resp.Inputs[i].InputName < resp.Inputs[j].InputName
@ -79,9 +101,9 @@ func (cmd *InputListCmd) Run(ctx *context) error {
for _, f := range filters { for _, f := range filters {
if f.enabled && strings.Contains(input.InputKind, f.keyword) { if f.enabled && strings.Contains(input.InputKind, f.keyword) {
if cmd.UUID { if cmd.UUID {
t.AddRow(input.InputName, input.InputKind, muteMark, input.InputUuid) t.Row(input.InputName, input.InputKind, muteMark, input.InputUuid)
} else { } else {
t.AddRow(input.InputName, input.InputKind, muteMark) t.Row(input.InputName, input.InputKind, muteMark)
} }
added = true added = true
break break
@ -90,13 +112,13 @@ func (cmd *InputListCmd) Run(ctx *context) error {
if !added && (!cmd.Input && !cmd.Output && !cmd.Colour && !cmd.Ffmpeg && !cmd.Vlc) { if !added && (!cmd.Input && !cmd.Output && !cmd.Colour && !cmd.Ffmpeg && !cmd.Vlc) {
if cmd.UUID { if cmd.UUID {
t.AddRow(input.InputName, snakeCaseToTitleCase(input.InputKind), muteMark, input.InputUuid) t.Row(input.InputName, snakeCaseToTitleCase(input.InputKind), muteMark, input.InputUuid)
} else { } else {
t.AddRow(input.InputName, snakeCaseToTitleCase(input.InputKind), muteMark) t.Row(input.InputName, snakeCaseToTitleCase(input.InputKind), muteMark)
} }
} }
} }
t.Render() fmt.Fprintln(ctx.Out, t.Render())
return nil return nil
} }
@ -114,7 +136,7 @@ func (cmd *InputMuteCmd) Run(ctx *context) error {
return fmt.Errorf("failed to mute input: %w", err) return fmt.Errorf("failed to mute input: %w", err)
} }
fmt.Fprintf(ctx.Out, "Muted input: %s\n", cmd.InputName) fmt.Fprintf(ctx.Out, "Muted input: %s\n", ctx.Style.Highlight(cmd.InputName))
return nil return nil
} }
@ -132,7 +154,7 @@ func (cmd *InputUnmuteCmd) Run(ctx *context) error {
return fmt.Errorf("failed to unmute input: %w", err) return fmt.Errorf("failed to unmute input: %w", err)
} }
fmt.Fprintf(ctx.Out, "Unmuted input: %s\n", cmd.InputName) fmt.Fprintf(ctx.Out, "Unmuted input: %s\n", ctx.Style.Highlight(cmd.InputName))
return nil return nil
} }
@ -160,9 +182,9 @@ func (cmd *InputToggleCmd) Run(ctx *context) error {
} }
if newMuteState { if newMuteState {
fmt.Fprintf(ctx.Out, "Muted input: %s\n", cmd.InputName) fmt.Fprintf(ctx.Out, "Muted input: %s\n", ctx.Style.Highlight(cmd.InputName))
} else { } else {
fmt.Fprintf(ctx.Out, "Unmuted input: %s\n", cmd.InputName) fmt.Fprintf(ctx.Out, "Unmuted input: %s\n", ctx.Style.Highlight(cmd.InputName))
} }
return nil return nil
} }

View File

@ -5,7 +5,8 @@ import (
"slices" "slices"
"github.com/andreykaipov/goobs/api/requests/config" "github.com/andreykaipov/goobs/api/requests/config"
"github.com/aquasecurity/table" "github.com/charmbracelet/lipgloss"
"github.com/charmbracelet/lipgloss/table"
) )
// ProfileCmd provides commands to manage profiles in OBS Studio. // ProfileCmd provides commands to manage profiles in OBS Studio.
@ -21,16 +22,34 @@ type ProfileCmd struct {
type ProfileListCmd struct{} // size = 0x0 type ProfileListCmd struct{} // size = 0x0
// Run executes the command to list all profiles. // Run executes the command to list all profiles.
// nolint: misspell
func (cmd *ProfileListCmd) Run(ctx *context) error { func (cmd *ProfileListCmd) Run(ctx *context) error {
profiles, err := ctx.Client.Config.GetProfileList() profiles, err := ctx.Client.Config.GetProfileList()
if err != nil { if err != nil {
return err return err
} }
t := table.New(ctx.Out) t := table.New().Border(lipgloss.RoundedBorder()).
t.SetPadding(3) BorderStyle(lipgloss.NewStyle().Foreground(ctx.Style.border)).
t.SetAlignment(table.AlignLeft, table.AlignCenter) Headers("Profile Name", "Current").
t.SetHeaders("Profile Name", "Current") StyleFunc(func(row, col int) lipgloss.Style {
style := lipgloss.NewStyle().Padding(0, 3)
switch col {
case 0:
style = style.Align(lipgloss.Left)
case 1:
style = style.Align(lipgloss.Center)
}
switch {
case row == table.HeaderRow:
style = style.Bold(true).Align(lipgloss.Center)
case row%2 == 0:
style = style.Foreground(ctx.Style.evenRows)
default:
style = style.Foreground(ctx.Style.oddRows)
}
return style
})
for _, profile := range profiles.Profiles { for _, profile := range profiles.Profiles {
var enabledMark string var enabledMark string
@ -38,9 +57,9 @@ func (cmd *ProfileListCmd) Run(ctx *context) error {
enabledMark = getEnabledMark(true) enabledMark = getEnabledMark(true)
} }
t.AddRow(profile, enabledMark) t.Row(profile, enabledMark)
} }
t.Render() fmt.Fprintln(ctx.Out, t.Render())
return nil return nil
} }
@ -53,7 +72,7 @@ func (cmd *ProfileCurrentCmd) Run(ctx *context) error {
if err != nil { if err != nil {
return err return err
} }
fmt.Fprintf(ctx.Out, "Current profile: %s\n", profiles.CurrentProfileName) fmt.Fprintf(ctx.Out, "Current profile: %s\n", ctx.Style.Highlight(profiles.CurrentProfileName))
return nil return nil
} }
@ -72,15 +91,20 @@ func (cmd *ProfileSwitchCmd) Run(ctx *context) error {
current := profiles.CurrentProfileName current := profiles.CurrentProfileName
if current == cmd.Name { if current == cmd.Name {
return nil return fmt.Errorf("already using profile %s", ctx.Style.Error(cmd.Name))
} }
_, err = ctx.Client.Config.SetCurrentProfile(config.NewSetCurrentProfileParams().WithProfileName(cmd.Name)) _, err = ctx.Client.Config.SetCurrentProfile(config.NewSetCurrentProfileParams().WithProfileName(cmd.Name))
if err != nil { if err != nil {
return err return fmt.Errorf("failed to switch to profile %s: %w", ctx.Style.Error(cmd.Name), err)
} }
fmt.Fprintf(ctx.Out, "Switched from profile %s to %s\n", current, cmd.Name) fmt.Fprintf(
ctx.Out,
"Switched from profile %s to %s\n",
ctx.Style.Highlight(current),
ctx.Style.Highlight(cmd.Name),
)
return nil return nil
} }
@ -98,15 +122,15 @@ func (cmd *ProfileCreateCmd) Run(ctx *context) error {
} }
if slices.Contains(profiles.Profiles, cmd.Name) { if slices.Contains(profiles.Profiles, cmd.Name) {
return fmt.Errorf("profile %s already exists", cmd.Name) return fmt.Errorf("profile %s already exists", ctx.Style.Error(cmd.Name))
} }
_, err = ctx.Client.Config.CreateProfile(config.NewCreateProfileParams().WithProfileName(cmd.Name)) _, err = ctx.Client.Config.CreateProfile(config.NewCreateProfileParams().WithProfileName(cmd.Name))
if err != nil { if err != nil {
return err return fmt.Errorf("failed to create profile %s: %w", ctx.Style.Error(cmd.Name), err)
} }
fmt.Fprintf(ctx.Out, "Created profile: %s\n", cmd.Name) fmt.Fprintf(ctx.Out, "Created profile: %s\n", ctx.Style.Highlight(cmd.Name))
return nil return nil
} }
@ -124,19 +148,21 @@ func (cmd *ProfileRemoveCmd) Run(ctx *context) error {
} }
if !slices.Contains(profiles.Profiles, cmd.Name) { if !slices.Contains(profiles.Profiles, cmd.Name) {
return fmt.Errorf("profile %s does not exist", cmd.Name) return fmt.Errorf("profile %s does not exist", ctx.Style.Error(cmd.Name))
} }
// Prevent deletion of the current profile
// This is allowed in OBS Studio (with a confirmation prompt), but we want to prevent it here
if profiles.CurrentProfileName == cmd.Name { if profiles.CurrentProfileName == cmd.Name {
return fmt.Errorf("cannot delete current profile %s", cmd.Name) return fmt.Errorf("cannot delete current profile %s", ctx.Style.Error(cmd.Name))
} }
_, err = ctx.Client.Config.RemoveProfile(config.NewRemoveProfileParams().WithProfileName(cmd.Name)) _, err = ctx.Client.Config.RemoveProfile(config.NewRemoveProfileParams().WithProfileName(cmd.Name))
if err != nil { if err != nil {
return err return fmt.Errorf("failed to delete profile %s: %w", ctx.Style.Error(cmd.Name), err)
} }
fmt.Fprintf(ctx.Out, "Deleted profile: %s\n", cmd.Name) fmt.Fprintf(ctx.Out, "Deleted profile: %s\n", ctx.Style.Highlight(cmd.Name))
return nil return nil
} }

View File

@ -4,7 +4,8 @@ import (
"fmt" "fmt"
"github.com/andreykaipov/goobs/api/requests/ui" "github.com/andreykaipov/goobs/api/requests/ui"
"github.com/aquasecurity/table" "github.com/charmbracelet/lipgloss"
"github.com/charmbracelet/lipgloss/table"
) )
// ProjectorCmd provides a command to manage projectors in OBS. // ProjectorCmd provides a command to manage projectors in OBS.
@ -17,6 +18,7 @@ type ProjectorCmd struct {
type ProjectorListMonitorsCmd struct{} // size = 0x0 type ProjectorListMonitorsCmd struct{} // size = 0x0
// Run executes the command to list all monitors available for projectors. // Run executes the command to list all monitors available for projectors.
// nolint: misspell
func (cmd *ProjectorListMonitorsCmd) Run(ctx *context) error { func (cmd *ProjectorListMonitorsCmd) Run(ctx *context) error {
monitors, err := ctx.Client.Ui.GetMonitorList() monitors, err := ctx.Client.Ui.GetMonitorList()
if err != nil { if err != nil {
@ -24,20 +26,37 @@ func (cmd *ProjectorListMonitorsCmd) Run(ctx *context) error {
} }
if len(monitors.Monitors) == 0 { if len(monitors.Monitors) == 0 {
ctx.Out.Write([]byte("No monitors found for projectors.\n")) fmt.Fprintf(ctx.Out, "No monitors found.\n")
return nil return nil
} }
t := table.New(ctx.Out) t := table.New().Border(lipgloss.RoundedBorder()).
t.SetPadding(3) BorderStyle(lipgloss.NewStyle().Foreground(ctx.Style.border)).
t.SetAlignment(table.AlignCenter, table.AlignLeft) Headers("Monitor ID", "Monitor Name").
t.SetHeaders("Monitor ID", "Monitor Name") StyleFunc(func(row, col int) lipgloss.Style {
style := lipgloss.NewStyle().Padding(0, 3)
switch col {
case 0:
style = style.Align(lipgloss.Center)
case 1:
style = style.Align(lipgloss.Left)
}
switch {
case row == table.HeaderRow:
style = style.Bold(true).Align(lipgloss.Center)
case row%2 == 0:
style = style.Foreground(ctx.Style.evenRows)
default:
style = style.Foreground(ctx.Style.oddRows)
}
return style
})
for _, monitor := range monitors.Monitors { for _, monitor := range monitors.Monitors {
t.AddRow(fmt.Sprintf("%d", monitor.MonitorIndex), monitor.MonitorName) t.Row(fmt.Sprintf("%d", monitor.MonitorIndex), monitor.MonitorName)
} }
t.Render() fmt.Fprintln(ctx.Out, t.Render())
return nil return nil
} }
@ -57,10 +76,36 @@ func (cmd *ProjectorOpenCmd) Run(ctx *context) error {
cmd.SourceName = currentScene.SceneName cmd.SourceName = currentScene.SceneName
} }
monitors, err := ctx.Client.Ui.GetMonitorList()
if err != nil {
return err
}
var monitorName string
for _, monitor := range monitors.Monitors {
if monitor.MonitorIndex == cmd.MonitorIndex {
monitorName = monitor.MonitorName
break
}
}
if monitorName == "" {
return fmt.Errorf(
"monitor with index %s not found. use %s to list available monitors",
ctx.Style.Error(fmt.Sprintf("%d", cmd.MonitorIndex)),
ctx.Style.Error("gobs-cli prj ls-m"),
)
}
ctx.Client.Ui.OpenSourceProjector(ui.NewOpenSourceProjectorParams(). ctx.Client.Ui.OpenSourceProjector(ui.NewOpenSourceProjectorParams().
WithSourceName(cmd.SourceName). WithSourceName(cmd.SourceName).
WithMonitorIndex(cmd.MonitorIndex)) WithMonitorIndex(cmd.MonitorIndex))
fmt.Fprintf(ctx.Out, "Opened projector for source '%s' on monitor index %d.\n", cmd.SourceName, cmd.MonitorIndex) fmt.Fprintf(
ctx.Out,
"Opened projector for source %s on monitor %s.\n",
ctx.Style.Highlight(cmd.SourceName),
ctx.Style.Highlight(monitorName),
)
return nil return nil
} }

View File

@ -60,7 +60,11 @@ func (cmd *RecordStopCmd) Run(ctx *context) error {
if err != nil { if err != nil {
return err return err
} }
fmt.Fprintf(ctx.Out, "%s", fmt.Sprintf("Recording stopped successfully. Output file: %s\n", resp.OutputPath)) fmt.Fprintf(
ctx.Out,
"%s",
fmt.Sprintf("Recording stopped successfully. Output file: %s\n", ctx.Style.Highlight(resp.OutputPath)),
)
return nil return nil
} }
@ -169,7 +173,7 @@ func (cmd *RecordDirectoryCmd) Run(ctx *context) error {
if err != nil { if err != nil {
return err return err
} }
fmt.Fprintf(ctx.Out, "Current recording directory: %s\n", resp.RecordDirectory) fmt.Fprintf(ctx.Out, "Current recording directory: %s\n", ctx.Style.Highlight(resp.RecordDirectory))
return nil return nil
} }
@ -180,6 +184,6 @@ func (cmd *RecordDirectoryCmd) Run(ctx *context) error {
return err return err
} }
fmt.Fprintf(ctx.Out, "Recording directory set to: %s\n", cmd.RecordDirectory) fmt.Fprintf(ctx.Out, "Recording directory set to: %s\n", ctx.Style.Highlight(cmd.RecordDirectory))
return nil return nil
} }

View File

@ -5,7 +5,8 @@ import (
"slices" "slices"
"github.com/andreykaipov/goobs/api/requests/scenes" "github.com/andreykaipov/goobs/api/requests/scenes"
"github.com/aquasecurity/table" "github.com/charmbracelet/lipgloss"
"github.com/charmbracelet/lipgloss/table"
) )
// SceneCmd provides commands to manage scenes in OBS Studio. // SceneCmd provides commands to manage scenes in OBS Studio.
@ -21,6 +22,7 @@ type SceneListCmd struct {
} }
// Run executes the command to list all scenes. // Run executes the command to list all scenes.
// nolint: misspell
func (cmd *SceneListCmd) Run(ctx *context) error { func (cmd *SceneListCmd) Run(ctx *context) error {
scenes, err := ctx.Client.Scenes.GetSceneList() scenes, err := ctx.Client.Scenes.GetSceneList()
if err != nil { if err != nil {
@ -32,15 +34,33 @@ func (cmd *SceneListCmd) Run(ctx *context) error {
return err return err
} }
t := table.New(ctx.Out) t := table.New().Border(lipgloss.RoundedBorder()).
t.SetPadding(3) BorderStyle(lipgloss.NewStyle().Foreground(ctx.Style.border))
if cmd.UUID { if cmd.UUID {
t.SetAlignment(table.AlignLeft, table.AlignCenter, table.AlignLeft) t.Headers("Scene Name", "Active", "UUID")
t.SetHeaders("Scene Name", "Active", "UUID")
} else { } else {
t.SetAlignment(table.AlignLeft, table.AlignCenter) t.Headers("Scene Name", "Active")
t.SetHeaders("Scene Name", "Active")
} }
t.StyleFunc(func(row, col int) lipgloss.Style {
style := lipgloss.NewStyle().Padding(0, 3)
switch col {
case 0:
style = style.Align(lipgloss.Left)
case 1:
style = style.Align(lipgloss.Center)
case 2:
style = style.Align(lipgloss.Left)
}
switch {
case row == table.HeaderRow:
style = style.Bold(true).Align(lipgloss.Center)
case row%2 == 0:
style = style.Foreground(ctx.Style.evenRows)
default:
style = style.Foreground(ctx.Style.oddRows)
}
return style
})
slices.Reverse(scenes.Scenes) slices.Reverse(scenes.Scenes)
for _, scene := range scenes.Scenes { for _, scene := range scenes.Scenes {
@ -49,12 +69,12 @@ func (cmd *SceneListCmd) Run(ctx *context) error {
activeMark = getEnabledMark(true) activeMark = getEnabledMark(true)
} }
if cmd.UUID { if cmd.UUID {
t.AddRow(scene.SceneName, activeMark, scene.SceneUuid) t.Row(scene.SceneName, activeMark, scene.SceneUuid)
} else { } else {
t.AddRow(scene.SceneName, activeMark) t.Row(scene.SceneName, activeMark)
} }
} }
t.Render() fmt.Fprintln(ctx.Out, t.Render())
return nil return nil
} }
@ -70,13 +90,13 @@ func (cmd *SceneCurrentCmd) Run(ctx *context) error {
if err != nil { if err != nil {
return err return err
} }
fmt.Fprintln(ctx.Out, scene.SceneName) fmt.Fprintf(ctx.Out, "Current preview scene: %s\n", ctx.Style.Highlight(scene.SceneName))
} else { } else {
scene, err := ctx.Client.Scenes.GetCurrentProgramScene() scene, err := ctx.Client.Scenes.GetCurrentProgramScene()
if err != nil { if err != nil {
return err return err
} }
fmt.Fprintln(ctx.Out, scene.SceneName) fmt.Fprintf(ctx.Out, "Current program scene: %s\n", ctx.Style.Highlight(scene.SceneName))
} }
return nil return nil
} }
@ -96,7 +116,7 @@ func (cmd *SceneSwitchCmd) Run(ctx *context) error {
return err return err
} }
fmt.Fprintln(ctx.Out, "Switched to preview scene:", cmd.NewScene) fmt.Fprintf(ctx.Out, "Switched to preview scene: %s\n", ctx.Style.Highlight(cmd.NewScene))
} else { } else {
_, err := ctx.Client.Scenes.SetCurrentProgramScene(scenes.NewSetCurrentProgramSceneParams(). _, err := ctx.Client.Scenes.SetCurrentProgramScene(scenes.NewSetCurrentProgramSceneParams().
WithSceneName(cmd.NewScene)) WithSceneName(cmd.NewScene))
@ -104,7 +124,7 @@ func (cmd *SceneSwitchCmd) Run(ctx *context) error {
return err return err
} }
fmt.Fprintln(ctx.Out, "Switched to program scene:", cmd.NewScene) fmt.Fprintf(ctx.Out, "Switched to program scene: %s\n", ctx.Style.Highlight(cmd.NewScene))
} }
return nil return nil
} }

View File

@ -4,7 +4,8 @@ import (
"fmt" "fmt"
"github.com/andreykaipov/goobs/api/requests/config" "github.com/andreykaipov/goobs/api/requests/config"
"github.com/aquasecurity/table" "github.com/charmbracelet/lipgloss"
"github.com/charmbracelet/lipgloss/table"
) )
// SceneCollectionCmd provides commands to manage scene collections in OBS Studio. // SceneCollectionCmd provides commands to manage scene collections in OBS Studio.
@ -19,21 +20,37 @@ type SceneCollectionCmd struct {
type SceneCollectionListCmd struct{} // size = 0x0 type SceneCollectionListCmd struct{} // size = 0x0
// Run executes the command to list all scene collections. // Run executes the command to list all scene collections.
// nolint: misspell
func (cmd *SceneCollectionListCmd) Run(ctx *context) error { func (cmd *SceneCollectionListCmd) Run(ctx *context) error {
collections, err := ctx.Client.Config.GetSceneCollectionList() collections, err := ctx.Client.Config.GetSceneCollectionList()
if err != nil { if err != nil {
return fmt.Errorf("failed to get scene collection list: %w", err) return fmt.Errorf("failed to get scene collection list: %w", err)
} }
t := table.New(ctx.Out) t := table.New().Border(lipgloss.RoundedBorder()).
t.SetPadding(3) BorderStyle(lipgloss.NewStyle().Foreground(ctx.Style.border)).
t.SetAlignment(table.AlignLeft) Headers("Scene Collection Name").
t.SetHeaders("Scene Collection Name") StyleFunc(func(row, col int) lipgloss.Style {
style := lipgloss.NewStyle().Padding(0, 3)
switch col {
case 0:
style = style.Align(lipgloss.Left)
}
switch {
case row == table.HeaderRow:
style = style.Bold(true).Align(lipgloss.Center)
case row%2 == 0:
style = style.Foreground(ctx.Style.evenRows)
default:
style = style.Foreground(ctx.Style.oddRows)
}
return style
})
for _, collection := range collections.SceneCollections { for _, collection := range collections.SceneCollections {
t.AddRow(collection) t.Row(collection)
} }
t.Render() fmt.Fprintln(ctx.Out, t.Render())
return nil return nil
} }
@ -65,17 +82,17 @@ func (cmd *SceneCollectionSwitchCmd) Run(ctx *context) error {
current := collections.CurrentSceneCollectionName current := collections.CurrentSceneCollectionName
if current == cmd.Name { if current == cmd.Name {
return fmt.Errorf("scene collection %s is already active", cmd.Name) return fmt.Errorf("scene collection %s is already active", ctx.Style.Error(cmd.Name))
} }
_, err = ctx.Client.Config.SetCurrentSceneCollection( _, err = ctx.Client.Config.SetCurrentSceneCollection(
config.NewSetCurrentSceneCollectionParams().WithSceneCollectionName(cmd.Name), config.NewSetCurrentSceneCollectionParams().WithSceneCollectionName(cmd.Name),
) )
if err != nil { if err != nil {
return fmt.Errorf("failed to switch scene collection: %w", err) return fmt.Errorf("failed to switch scene collection %s: %w", ctx.Style.Error(cmd.Name), err)
} }
fmt.Fprintf(ctx.Out, "Switched to scene collection: %s\n", cmd.Name) fmt.Fprintf(ctx.Out, "Switched to scene collection: %s\n", ctx.Style.Highlight(cmd.Name))
return nil return nil
} }
@ -91,9 +108,9 @@ func (cmd *SceneCollectionCreateCmd) Run(ctx *context) error {
config.NewCreateSceneCollectionParams().WithSceneCollectionName(cmd.Name), config.NewCreateSceneCollectionParams().WithSceneCollectionName(cmd.Name),
) )
if err != nil { if err != nil {
return fmt.Errorf("failed to create scene collection: %w", err) return fmt.Errorf("failed to create scene collection %s: %w", ctx.Style.Error(cmd.Name), err)
} }
fmt.Fprintf(ctx.Out, "Created scene collection: %s\n", cmd.Name) fmt.Fprintf(ctx.Out, "Created scene collection: %s\n", ctx.Style.Highlight(cmd.Name))
return nil return nil
} }

View File

@ -1,3 +1,4 @@
// nolint: misspell
package main package main
import ( import (
@ -6,7 +7,8 @@ import (
"github.com/andreykaipov/goobs" "github.com/andreykaipov/goobs"
"github.com/andreykaipov/goobs/api/requests/sceneitems" "github.com/andreykaipov/goobs/api/requests/sceneitems"
"github.com/aquasecurity/table" "github.com/charmbracelet/lipgloss"
"github.com/charmbracelet/lipgloss/table"
) )
// SceneItemCmd provides commands to manage scene items in OBS Studio. // SceneItemCmd provides commands to manage scene items in OBS Studio.
@ -42,19 +44,41 @@ func (cmd *SceneItemListCmd) Run(ctx *context) error {
} }
if len(resp.SceneItems) == 0 { if len(resp.SceneItems) == 0 {
fmt.Fprintf(ctx.Out, "No scene items found in scene '%s'.\n", cmd.SceneName) fmt.Fprintf(ctx.Out, "No scene items found in scene %s.\n", ctx.Style.Highlight(cmd.SceneName))
return nil return nil
} }
t := table.New(ctx.Out) t := table.New().Border(lipgloss.RoundedBorder()).
t.SetPadding(3) BorderStyle(lipgloss.NewStyle().Foreground(ctx.Style.border))
if cmd.UUID { if cmd.UUID {
t.SetAlignment(table.AlignCenter, table.AlignLeft, table.AlignCenter, table.AlignCenter, table.AlignCenter) t.Headers("Item ID", "Item Name", "In Group", "Enabled", "UUID")
t.SetHeaders("Item ID", "Item Name", "In Group", "Enabled", "UUID")
} else { } else {
t.SetAlignment(table.AlignCenter, table.AlignLeft, table.AlignCenter, table.AlignCenter) t.Headers("Item ID", "Item Name", "In Group", "Enabled")
t.SetHeaders("Item ID", "Item Name", "In Group", "Enabled")
} }
t.StyleFunc(func(row, col int) lipgloss.Style {
style := lipgloss.NewStyle().Padding(0, 3)
switch col {
case 0:
style = style.Align(lipgloss.Left)
case 1:
style = style.Align(lipgloss.Left)
case 2:
style = style.Align(lipgloss.Center)
case 3:
style = style.Align(lipgloss.Center)
case 4:
style = style.Align(lipgloss.Left)
}
switch {
case row == table.HeaderRow:
style = style.Bold(true).Align(lipgloss.Center)
case row%2 == 0:
style = style.Foreground(ctx.Style.evenRows)
default:
style = style.Foreground(ctx.Style.oddRows)
}
return style
})
sort.Slice(resp.SceneItems, func(i, j int) bool { sort.Slice(resp.SceneItems, func(i, j int) bool {
return resp.SceneItems[i].SceneItemID < resp.SceneItems[j].SceneItemID return resp.SceneItems[i].SceneItemID < resp.SceneItems[j].SceneItemID
@ -65,7 +89,11 @@ func (cmd *SceneItemListCmd) Run(ctx *context) error {
resp, err := ctx.Client.SceneItems.GetGroupSceneItemList(sceneitems.NewGetGroupSceneItemListParams(). resp, err := ctx.Client.SceneItems.GetGroupSceneItemList(sceneitems.NewGetGroupSceneItemListParams().
WithSceneName(item.SourceName)) WithSceneName(item.SourceName))
if err != nil { if err != nil {
return fmt.Errorf("failed to get group scene item list for '%s': %w", item.SourceName, err) return fmt.Errorf(
"failed to get group scene item list for group %s: %w",
ctx.Style.Error(item.SourceName),
err,
)
} }
sort.Slice(resp.SceneItems, func(i, j int) bool { sort.Slice(resp.SceneItems, func(i, j int) bool {
@ -74,7 +102,7 @@ func (cmd *SceneItemListCmd) Run(ctx *context) error {
for _, groupItem := range resp.SceneItems { for _, groupItem := range resp.SceneItems {
if cmd.UUID { if cmd.UUID {
t.AddRow( t.Row(
fmt.Sprintf("%d", groupItem.SceneItemID), fmt.Sprintf("%d", groupItem.SceneItemID),
groupItem.SourceName, groupItem.SourceName,
item.SourceName, item.SourceName,
@ -82,7 +110,7 @@ func (cmd *SceneItemListCmd) Run(ctx *context) error {
groupItem.SourceUuid, groupItem.SourceUuid,
) )
} else { } else {
t.AddRow( t.Row(
fmt.Sprintf("%d", groupItem.SceneItemID), fmt.Sprintf("%d", groupItem.SceneItemID),
groupItem.SourceName, groupItem.SourceName,
item.SourceName, item.SourceName,
@ -92,26 +120,26 @@ func (cmd *SceneItemListCmd) Run(ctx *context) error {
} }
} else { } else {
if cmd.UUID { if cmd.UUID {
t.AddRow(fmt.Sprintf("%d", item.SceneItemID), item.SourceName, "", t.Row(fmt.Sprintf("%d", item.SceneItemID), item.SourceName, "",
getEnabledMark(item.SceneItemEnabled), item.SourceUuid) getEnabledMark(item.SceneItemEnabled), item.SourceUuid)
} else { } else {
t.AddRow(fmt.Sprintf("%d", item.SceneItemID), item.SourceName, "", getEnabledMark(item.SceneItemEnabled)) t.Row(fmt.Sprintf("%d", item.SceneItemID), item.SourceName, "", getEnabledMark(item.SceneItemEnabled))
} }
} }
} }
t.Render() fmt.Fprintln(ctx.Out, t.Render())
return nil return nil
} }
// getSceneNameAndItemID retrieves the scene name and item ID for a given item in a scene or group. // getSceneNameAndItemID retrieves the scene name and item ID for a given item in a scene or group.
func getSceneNameAndItemID( func getSceneNameAndItemID(
client *goobs.Client, ctx *context,
sceneName string, sceneName string,
itemName string, itemName string,
group string, group string,
) (string, int, error) { ) (string, int, error) {
if group != "" { if group != "" {
resp, err := client.SceneItems.GetGroupSceneItemList(sceneitems.NewGetGroupSceneItemListParams(). resp, err := ctx.Client.SceneItems.GetGroupSceneItemList(sceneitems.NewGetGroupSceneItemListParams().
WithSceneName(group)) WithSceneName(group))
if err != nil { if err != nil {
return "", 0, err return "", 0, err
@ -121,13 +149,22 @@ func getSceneNameAndItemID(
return group, int(item.SceneItemID), nil return group, int(item.SceneItemID), nil
} }
} }
return "", 0, fmt.Errorf("item '%s' not found in scene '%s'", itemName, sceneName) return "", 0, fmt.Errorf("item %s not found in scene %s", ctx.Style.Error(itemName), ctx.Style.Error(sceneName))
} }
itemID, err := client.SceneItems.GetSceneItemId(sceneitems.NewGetSceneItemIdParams(). itemID, err := ctx.Client.SceneItems.GetSceneItemId(sceneitems.NewGetSceneItemIdParams().
WithSceneName(sceneName). WithSceneName(sceneName).
WithSourceName(itemName)) WithSourceName(itemName))
if err != nil { if err != nil {
if err.Error() == "request GetSceneItemId: ResourceNotFound (600): No scene items were found in the specified scene by that name or offset." {
return "", 0, fmt.Errorf(
"item %s not found in scene %s. is it in a group? if so use the %s flag to specify the parent group\nuse %s for a list of items in the scene",
ctx.Style.Error(itemName),
ctx.Style.Error(sceneName),
ctx.Style.Error("--group"),
ctx.Style.Error("gobs-cli si ls"),
)
}
return "", 0, err return "", 0, err
} }
return sceneName, int(itemID.SceneItemId), nil return sceneName, int(itemID.SceneItemId), nil
@ -143,7 +180,7 @@ type SceneItemShowCmd struct {
// Run executes the command to show a scene item. // Run executes the command to show a scene item.
func (cmd *SceneItemShowCmd) Run(ctx *context) error { func (cmd *SceneItemShowCmd) Run(ctx *context) error {
sceneName, sceneItemID, err := getSceneNameAndItemID(ctx.Client, cmd.SceneName, cmd.ItemName, cmd.Group) sceneName, sceneItemID, err := getSceneNameAndItemID(ctx, cmd.SceneName, cmd.ItemName, cmd.Group)
if err != nil { if err != nil {
return err return err
} }
@ -157,9 +194,14 @@ func (cmd *SceneItemShowCmd) Run(ctx *context) error {
} }
if cmd.Group != "" { if cmd.Group != "" {
fmt.Fprintf(ctx.Out, "Scene item '%s' in group '%s' is now visible.\n", cmd.ItemName, cmd.Group) fmt.Fprintf(
ctx.Out,
"Scene item %s in group %s is now visible.\n",
ctx.Style.Highlight(cmd.ItemName),
ctx.Style.Highlight(cmd.Group),
)
} else { } else {
fmt.Fprintf(ctx.Out, "Scene item '%s' in scene '%s' is now visible.\n", cmd.ItemName, cmd.SceneName) fmt.Fprintf(ctx.Out, "Scene item %s in scene %s is now visible.\n", ctx.Style.Highlight(cmd.ItemName), ctx.Style.Highlight(cmd.SceneName))
} }
return nil return nil
@ -175,7 +217,7 @@ type SceneItemHideCmd struct {
// Run executes the command to hide a scene item. // Run executes the command to hide a scene item.
func (cmd *SceneItemHideCmd) Run(ctx *context) error { func (cmd *SceneItemHideCmd) Run(ctx *context) error {
sceneName, sceneItemID, err := getSceneNameAndItemID(ctx.Client, cmd.SceneName, cmd.ItemName, cmd.Group) sceneName, sceneItemID, err := getSceneNameAndItemID(ctx, cmd.SceneName, cmd.ItemName, cmd.Group)
if err != nil { if err != nil {
return err return err
} }
@ -189,9 +231,14 @@ func (cmd *SceneItemHideCmd) Run(ctx *context) error {
} }
if cmd.Group != "" { if cmd.Group != "" {
fmt.Fprintf(ctx.Out, "Scene item '%s' in group '%s' is now hidden.\n", cmd.ItemName, cmd.Group) fmt.Fprintf(
ctx.Out,
"Scene item %s in group %s is now hidden.\n",
ctx.Style.Highlight(cmd.ItemName),
ctx.Style.Highlight(cmd.Group),
)
} else { } else {
fmt.Fprintf(ctx.Out, "Scene item '%s' in scene '%s' is now hidden.\n", cmd.ItemName, cmd.SceneName) fmt.Fprintf(ctx.Out, "Scene item %s in scene %s is now hidden.\n", ctx.Style.Highlight(cmd.ItemName), ctx.Style.Highlight(cmd.SceneName))
} }
return nil return nil
@ -218,7 +265,7 @@ type SceneItemToggleCmd struct {
// Run executes the command to toggle the visibility of a scene item. // Run executes the command to toggle the visibility of a scene item.
func (cmd *SceneItemToggleCmd) Run(ctx *context) error { func (cmd *SceneItemToggleCmd) Run(ctx *context) error {
sceneName, sceneItemID, err := getSceneNameAndItemID(ctx.Client, cmd.SceneName, cmd.ItemName, cmd.Group) sceneName, sceneItemID, err := getSceneNameAndItemID(ctx, cmd.SceneName, cmd.ItemName, cmd.Group)
if err != nil { if err != nil {
return err return err
} }
@ -237,9 +284,14 @@ func (cmd *SceneItemToggleCmd) Run(ctx *context) error {
} }
if itemEnabled { if itemEnabled {
fmt.Fprintf(ctx.Out, "Scene item '%s' in scene '%s' is now hidden.\n", cmd.ItemName, cmd.SceneName) fmt.Fprintf(
ctx.Out,
"Scene item %s in scene %s is now hidden.\n",
ctx.Style.Highlight(cmd.ItemName),
ctx.Style.Highlight(cmd.SceneName),
)
} else { } else {
fmt.Fprintf(ctx.Out, "Scene item '%s' in scene '%s' is now visible.\n", cmd.ItemName, cmd.SceneName) fmt.Fprintf(ctx.Out, "Scene item %s in scene %s is now visible.\n", ctx.Style.Highlight(cmd.ItemName), ctx.Style.Highlight(cmd.SceneName))
} }
return nil return nil
@ -255,7 +307,7 @@ type SceneItemVisibleCmd struct {
// Run executes the command to check the visibility of a scene item. // Run executes the command to check the visibility of a scene item.
func (cmd *SceneItemVisibleCmd) Run(ctx *context) error { func (cmd *SceneItemVisibleCmd) Run(ctx *context) error {
sceneName, sceneItemID, err := getSceneNameAndItemID(ctx.Client, cmd.SceneName, cmd.ItemName, cmd.Group) sceneName, sceneItemID, err := getSceneNameAndItemID(ctx, cmd.SceneName, cmd.ItemName, cmd.Group)
if err != nil { if err != nil {
return err return err
} }
@ -266,9 +318,14 @@ func (cmd *SceneItemVisibleCmd) Run(ctx *context) error {
} }
if itemEnabled { if itemEnabled {
fmt.Fprintf(ctx.Out, "Scene item '%s' in scene '%s' is visible.\n", cmd.ItemName, cmd.SceneName) fmt.Fprintf(
ctx.Out,
"Scene item %s in scene %s is visible.\n",
ctx.Style.Highlight(cmd.ItemName),
ctx.Style.Highlight(cmd.SceneName),
)
} else { } else {
fmt.Fprintf(ctx.Out, "Scene item '%s' in scene '%s' is hidden.\n", cmd.ItemName, cmd.SceneName) fmt.Fprintf(ctx.Out, "Scene item %s in scene %s is hidden.\n", ctx.Style.Highlight(cmd.ItemName), ctx.Style.Highlight(cmd.SceneName))
} }
return nil return nil
} }
@ -299,7 +356,7 @@ type SceneItemTransformCmd struct {
// Run executes the command to transform a scene item. // Run executes the command to transform a scene item.
func (cmd *SceneItemTransformCmd) Run(ctx *context) error { func (cmd *SceneItemTransformCmd) Run(ctx *context) error {
sceneName, sceneItemID, err := getSceneNameAndItemID(ctx.Client, cmd.SceneName, cmd.ItemName, cmd.Group) sceneName, sceneItemID, err := getSceneNameAndItemID(ctx, cmd.SceneName, cmd.ItemName, cmd.Group)
if err != nil { if err != nil {
return err return err
} }
@ -372,9 +429,14 @@ func (cmd *SceneItemTransformCmd) Run(ctx *context) error {
} }
if cmd.Group != "" { if cmd.Group != "" {
fmt.Fprintf(ctx.Out, "Scene item '%s' in group '%s' transformed.\n", cmd.ItemName, cmd.Group) fmt.Fprintf(
ctx.Out,
"Scene item %s in group %s transformed.\n",
ctx.Style.Highlight(cmd.ItemName),
ctx.Style.Highlight(cmd.Group),
)
} else { } else {
fmt.Fprintf(ctx.Out, "Scene item '%s' in scene '%s' transformed.\n", cmd.ItemName, cmd.SceneName) fmt.Fprintf(ctx.Out, "Scene item %s in scene %s transformed.\n", ctx.Style.Highlight(cmd.ItemName), ctx.Style.Highlight(cmd.SceneName))
} }
return nil return nil

View File

@ -36,6 +36,6 @@ func (cmd *ScreenshotSaveCmd) Run(ctx *context) error {
return fmt.Errorf("failed to take screenshot: %w", err) return fmt.Errorf("failed to take screenshot: %w", err)
} }
fmt.Fprintf(ctx.Out, "Screenshot saved to %s.\n", cmd.FilePath) fmt.Fprintf(ctx.Out, "Screenshot saved to %s.\n", ctx.Style.Highlight(cmd.FilePath))
return nil return nil
} }