mirror of
https://github.com/onyx-and-iris/gobs-cli.git
synced 2026-04-18 07:03:37 +00:00
Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 82c0756dde | |||
| 4395c981c6 | |||
| dc043b5847 | |||
| c8a055fa28 | |||
| d9c0e40d8f | |||
| 42ab45b9fb | |||
| 27c3c5369b | |||
| 0a0c75ae51 | |||
| cf5da68137 | |||
| 14d9feb43e | |||
| 8204d6520d |
33
CHANGELOG.md
33
CHANGELOG.md
@@ -5,13 +5,40 @@ All notable changes to this project will be documented in this file.
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
# [0.10.0]
|
||||
# [0.11.0] - 2025-06-20
|
||||
|
||||
### Added
|
||||
|
||||
- input list, scene list and sceneitem list now accept --uuid flag.
|
||||
- Active column added to scene list table.
|
||||
|
||||
### Changed
|
||||
|
||||
- scene list no longer prints the UUIDs by default, enable it with the --uuid flag.
|
||||
|
||||
# [0.10.3] - 2025-06-07
|
||||
|
||||
### Added
|
||||
|
||||
- filter list:
|
||||
- --ffmpeg, --vlc flags
|
||||
- Muted column to list table
|
||||
|
||||
# [0.10.2] - 2025-06-04
|
||||
|
||||
### Added
|
||||
|
||||
- screenshot save command, see [ScreenshotCmd](https://github.com/onyx-and-iris/gobs-cli?tab=readme-ov-file#screenshotcmd)
|
||||
|
||||
# [0.9.0]
|
||||
### Fixed
|
||||
|
||||
- filter list:
|
||||
- sourceName arg now defaults to current scene.
|
||||
- defaults are printed for any unmodified values.
|
||||
- sceneitem list:
|
||||
- prints enabled mark instead of true/false
|
||||
|
||||
# [0.9.0] - 2025-06-02
|
||||
|
||||
### Added
|
||||
|
||||
@@ -21,7 +48,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
- version command renamed to obs-version
|
||||
|
||||
# [0.8.2]
|
||||
# [0.8.2] - 2025-05-29
|
||||
|
||||
### Added
|
||||
|
||||
|
||||
19
README.md
19
README.md
@@ -54,6 +54,10 @@ gobs-cli obs-version
|
||||
### SceneCmd
|
||||
|
||||
- list: List all scenes.
|
||||
- flags:
|
||||
|
||||
*optional*
|
||||
- --UUID: Display UUIDs of scenes.
|
||||
|
||||
```console
|
||||
gobs-cli scene list
|
||||
@@ -87,6 +91,10 @@ gobs-cli scene switch --preview LIVE
|
||||
### SceneItemCmd
|
||||
|
||||
- list: List all scene items.
|
||||
- flags:
|
||||
|
||||
*optional*
|
||||
- --UUID: Display UUIDs of scene items.
|
||||
|
||||
*optional*
|
||||
- args: SceneName
|
||||
@@ -223,6 +231,9 @@ gobs-cli group status START "test_group"
|
||||
- --input: List all inputs.
|
||||
- --output: List all outputs.
|
||||
- --colour: List all colour sources.
|
||||
- --ffmpeg: List all ffmpeg sources.
|
||||
- --vlc: List all VLC sources.
|
||||
- --uuid: Display UUIDs of inputs.
|
||||
|
||||
```console
|
||||
gobs-cli input list
|
||||
@@ -513,6 +524,10 @@ gobs-cli hotkey trigger-sequence OBS_KEY_F1 --shift --ctrl
|
||||
|
||||
- list: List all filters.
|
||||
|
||||
*optional*
|
||||
- args: SourceName
|
||||
- defaults to current scene
|
||||
|
||||
```console
|
||||
gobs-cli filter list
|
||||
```
|
||||
@@ -561,7 +576,7 @@ gobs-cli projector list-monitors
|
||||
- defaults to 0
|
||||
|
||||
*optional*
|
||||
- args: <source_name>
|
||||
- args: SourceName
|
||||
- defaults to current scene
|
||||
|
||||
```console
|
||||
@@ -585,7 +600,7 @@ gobs-cli projector open --monitor-index=1 "test_group"
|
||||
- --quality:
|
||||
- defaults to -1
|
||||
|
||||
- args: <source_name> <output_path>
|
||||
- args: SourceName FilePath
|
||||
|
||||
```console
|
||||
gobs-cli screenshot save --width=2560 --height=1440 "Scene" "C:\Users\me\Videos\screenshot.png"
|
||||
|
||||
31
filter.go
31
filter.go
@@ -2,6 +2,7 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"maps"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
@@ -20,19 +21,27 @@ type FilterCmd struct {
|
||||
|
||||
// FilterListCmd provides a command to list all filters in a scene.
|
||||
type FilterListCmd struct {
|
||||
SourceName string `arg:"" help:"Name of the source to list filters from."`
|
||||
SourceName string `arg:"" help:"Name of the source to list filters from." default:""`
|
||||
}
|
||||
|
||||
// Run executes the command to list all filters in a scene.
|
||||
func (cmd *FilterListCmd) Run(ctx *context) error {
|
||||
filters, err := ctx.Client.Filters.GetSourceFilterList(
|
||||
if cmd.SourceName == "" {
|
||||
currentScene, err := ctx.Client.Scenes.GetCurrentProgramScene()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get current program scene: %w", err)
|
||||
}
|
||||
cmd.SourceName = currentScene.SceneName
|
||||
}
|
||||
|
||||
sourceFilters, err := ctx.Client.Filters.GetSourceFilterList(
|
||||
filters.NewGetSourceFilterListParams().WithSourceName(cmd.SourceName),
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(filters.Filters) == 0 {
|
||||
if len(sourceFilters.Filters) == 0 {
|
||||
fmt.Fprintf(ctx.Out, "No filters found for source %s.\n", cmd.SourceName)
|
||||
return nil
|
||||
}
|
||||
@@ -42,10 +51,20 @@ func (cmd *FilterListCmd) Run(ctx *context) error {
|
||||
t.SetAlignment(table.AlignLeft, table.AlignLeft, table.AlignCenter, table.AlignLeft)
|
||||
t.SetHeaders("Filter Name", "Kind", "Enabled", "Settings")
|
||||
|
||||
for _, filter := range filters.Filters {
|
||||
for _, filter := range sourceFilters.Filters {
|
||||
defaultSettings, err := ctx.Client.Filters.GetSourceFilterDefaultSettings(
|
||||
filters.NewGetSourceFilterDefaultSettingsParams().
|
||||
WithFilterKind(filter.FilterKind),
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get default settings for filter %s: %w",
|
||||
filter.FilterName, err)
|
||||
}
|
||||
maps.Insert(defaultSettings.DefaultFilterSettings, maps.All(filter.FilterSettings))
|
||||
|
||||
var lines []string
|
||||
for k, v := range filter.FilterSettings {
|
||||
lines = append(lines, fmt.Sprintf("%s %v", k, v))
|
||||
for k, v := range defaultSettings.DefaultFilterSettings {
|
||||
lines = append(lines, fmt.Sprintf("%s: %v", snakeCaseToTitleCase(k), v))
|
||||
}
|
||||
sort.Slice(lines, func(i, j int) bool {
|
||||
return strings.ToLower(lines[i]) < strings.ToLower(lines[j])
|
||||
|
||||
68
input.go
68
input.go
@@ -2,6 +2,7 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/andreykaipov/goobs/api/requests/inputs"
|
||||
@@ -21,6 +22,9 @@ type InputListCmd struct {
|
||||
Input bool `flag:"" help:"List all inputs." aliases:"i"`
|
||||
Output bool `flag:"" help:"List all outputs." aliases:"o"`
|
||||
Colour bool `flag:"" help:"List all colour sources." aliases:"c"`
|
||||
Ffmpeg bool `flag:"" help:"List all ffmpeg sources." aliases:"f"`
|
||||
Vlc bool `flag:"" help:"List all VLC sources." aliases:"v"`
|
||||
UUID bool `flag:"" help:"Display UUIDs of inputs." aliases:"u"`
|
||||
}
|
||||
|
||||
// Run executes the command to list all inputs.
|
||||
@@ -32,22 +36,64 @@ func (cmd *InputListCmd) Run(ctx *context) error {
|
||||
|
||||
t := table.New(ctx.Out)
|
||||
t.SetPadding(3)
|
||||
t.SetAlignment(table.AlignLeft, table.AlignLeft)
|
||||
t.SetHeaders("Input Name", "Kind")
|
||||
if cmd.UUID {
|
||||
t.SetAlignment(table.AlignLeft, table.AlignLeft, table.AlignCenter, table.AlignLeft)
|
||||
t.SetHeaders("Input Name", "Kind", "Muted", "UUID")
|
||||
} else {
|
||||
t.SetAlignment(table.AlignLeft, table.AlignLeft, table.AlignCenter)
|
||||
t.SetHeaders("Input Name", "Kind", "Muted")
|
||||
}
|
||||
|
||||
sort.Slice(resp.Inputs, func(i, j int) bool {
|
||||
return resp.Inputs[i].InputName < resp.Inputs[j].InputName
|
||||
})
|
||||
|
||||
for _, input := range resp.Inputs {
|
||||
if cmd.Input && strings.Contains(input.InputKind, "input") {
|
||||
t.AddRow(input.InputName, input.InputKind)
|
||||
var muteMark string
|
||||
resp, err := ctx.Client.Inputs.GetInputMute(
|
||||
inputs.NewGetInputMuteParams().WithInputName(input.InputName),
|
||||
)
|
||||
if err != nil {
|
||||
if err.Error() == "request GetInputMute: InvalidResourceState (604): The specified input does not support audio." {
|
||||
muteMark = "N/A"
|
||||
} else {
|
||||
return fmt.Errorf("failed to get input mute state: %w", err)
|
||||
}
|
||||
if cmd.Output && strings.Contains(input.InputKind, "output") {
|
||||
t.AddRow(input.InputName, input.InputKind)
|
||||
}
|
||||
if cmd.Colour && strings.Contains(input.InputKind, "color") { // nolint
|
||||
t.AddRow(input.InputName, input.InputKind)
|
||||
} else {
|
||||
muteMark = getEnabledMark(resp.InputMuted)
|
||||
}
|
||||
|
||||
if !cmd.Input && !cmd.Output && !cmd.Colour {
|
||||
t.AddRow(input.InputName, input.InputKind)
|
||||
type filter struct {
|
||||
enabled bool
|
||||
keyword string
|
||||
}
|
||||
filters := []filter{
|
||||
{cmd.Input, "input"},
|
||||
{cmd.Output, "output"},
|
||||
{cmd.Colour, "color"}, // nolint: misspell
|
||||
{cmd.Ffmpeg, "ffmpeg"},
|
||||
{cmd.Vlc, "vlc"},
|
||||
}
|
||||
|
||||
var added bool
|
||||
for _, f := range filters {
|
||||
if f.enabled && strings.Contains(input.InputKind, f.keyword) {
|
||||
if cmd.UUID {
|
||||
t.AddRow(input.InputName, input.InputKind, muteMark, input.InputUuid)
|
||||
} else {
|
||||
t.AddRow(input.InputName, input.InputKind, muteMark)
|
||||
}
|
||||
added = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !added && (!cmd.Input && !cmd.Output && !cmd.Colour && !cmd.Ffmpeg && !cmd.Vlc) {
|
||||
if cmd.UUID {
|
||||
t.AddRow(input.InputName, snakeCaseToTitleCase(input.InputKind), muteMark, input.InputUuid)
|
||||
} else {
|
||||
t.AddRow(input.InputName, snakeCaseToTitleCase(input.InputKind), muteMark)
|
||||
}
|
||||
}
|
||||
}
|
||||
t.Render()
|
||||
|
||||
30
main.go
30
main.go
@@ -33,21 +33,21 @@ type CLI struct {
|
||||
Version VersionFlag `help:"Print gobs-cli version information and quit" name:"version" short:"v"`
|
||||
|
||||
ObsVersion ObsVersionCmd `help:"Print OBS client and websocket version." cmd:"" aliases:"v"`
|
||||
Scene SceneCmd `help:"Manage scenes." cmd:"" aliases:"sc"`
|
||||
Sceneitem SceneItemCmd `help:"Manage scene items." cmd:"" aliases:"si"`
|
||||
Group GroupCmd `help:"Manage groups." cmd:"" aliases:"g"`
|
||||
Input InputCmd `help:"Manage inputs." cmd:"" aliases:"i"`
|
||||
Record RecordCmd `help:"Manage recording." cmd:"" aliases:"rec"`
|
||||
Stream StreamCmd `help:"Manage streaming." cmd:"" aliases:"st"`
|
||||
Scenecollection SceneCollectionCmd `help:"Manage scene collections." cmd:"" aliases:"scn"`
|
||||
Profile ProfileCmd `help:"Manage profiles." cmd:"" aliases:"p"`
|
||||
Replaybuffer ReplayBufferCmd `help:"Manage replay buffer." cmd:"" aliases:"rb"`
|
||||
Studiomode StudioModeCmd `help:"Manage studio mode." cmd:"" aliases:"sm"`
|
||||
Virtualcam VirtualCamCmd `help:"Manage virtual camera." cmd:"" aliases:"vc"`
|
||||
Hotkey HotkeyCmd `help:"Manage hotkeys." cmd:"" aliases:"hk"`
|
||||
Filter FilterCmd `help:"Manage filters." cmd:"" aliases:"f"`
|
||||
Projector ProjectorCmd `help:"Manage projectors." cmd:"" aliases:"prj"`
|
||||
Screenshot ScreenshotCmd `help:"Take screenshots." cmd:"" aliases:"ss"`
|
||||
Scene SceneCmd `help:"Manage scenes." cmd:"" aliases:"sc" group:"Scene"`
|
||||
Sceneitem SceneItemCmd `help:"Manage scene items." cmd:"" aliases:"si" group:"Scene Item"`
|
||||
Group GroupCmd `help:"Manage groups." cmd:"" aliases:"g" group:"Group"`
|
||||
Input InputCmd `help:"Manage inputs." cmd:"" aliases:"i" group:"Input"`
|
||||
Record RecordCmd `help:"Manage recording." cmd:"" aliases:"rec" group:"Recording"`
|
||||
Stream StreamCmd `help:"Manage streaming." cmd:"" aliases:"st" group:"Streaming"`
|
||||
Scenecollection SceneCollectionCmd `help:"Manage scene collections." cmd:"" aliases:"scn" group:"Scene Collection"`
|
||||
Profile ProfileCmd `help:"Manage profiles." cmd:"" aliases:"p" group:"Profile"`
|
||||
Replaybuffer ReplayBufferCmd `help:"Manage replay buffer." cmd:"" aliases:"rb" group:"Replay Buffer"`
|
||||
Studiomode StudioModeCmd `help:"Manage studio mode." cmd:"" aliases:"sm" group:"Studio Mode"`
|
||||
Virtualcam VirtualCamCmd `help:"Manage virtual camera." cmd:"" aliases:"vc" group:"Virtual Camera"`
|
||||
Hotkey HotkeyCmd `help:"Manage hotkeys." cmd:"" aliases:"hk" group:"Hotkey"`
|
||||
Filter FilterCmd `help:"Manage filters." cmd:"" aliases:"f" group:"Filter"`
|
||||
Projector ProjectorCmd `help:"Manage projectors." cmd:"" aliases:"prj" group:"Projector"`
|
||||
Screenshot ScreenshotCmd `help:"Take screenshots." cmd:"" aliases:"ss" group:"Screenshot"`
|
||||
}
|
||||
|
||||
type context struct {
|
||||
|
||||
28
scene.go
28
scene.go
@@ -16,7 +16,9 @@ type SceneCmd struct {
|
||||
}
|
||||
|
||||
// SceneListCmd provides a command to list all scenes.
|
||||
type SceneListCmd struct{} // size = 0x0
|
||||
type SceneListCmd struct {
|
||||
UUID bool `flag:"" help:"Display UUIDs of scenes."`
|
||||
}
|
||||
|
||||
// Run executes the command to list all scenes.
|
||||
func (cmd *SceneListCmd) Run(ctx *context) error {
|
||||
@@ -25,14 +27,32 @@ func (cmd *SceneListCmd) Run(ctx *context) error {
|
||||
return err
|
||||
}
|
||||
|
||||
currentScene, err := ctx.Client.Scenes.GetCurrentProgramScene()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
t := table.New(ctx.Out)
|
||||
t.SetPadding(3)
|
||||
t.SetAlignment(table.AlignLeft, table.AlignLeft)
|
||||
t.SetHeaders("Scene Name", "UUID")
|
||||
if cmd.UUID {
|
||||
t.SetAlignment(table.AlignLeft, table.AlignCenter, table.AlignLeft)
|
||||
t.SetHeaders("Scene Name", "Active", "UUID")
|
||||
} else {
|
||||
t.SetAlignment(table.AlignLeft, table.AlignCenter)
|
||||
t.SetHeaders("Scene Name", "Active")
|
||||
}
|
||||
|
||||
slices.Reverse(scenes.Scenes)
|
||||
for _, scene := range scenes.Scenes {
|
||||
t.AddRow(scene.SceneName, scene.SceneUuid)
|
||||
var activeMark string
|
||||
if scene.SceneName == currentScene.SceneName {
|
||||
activeMark = getEnabledMark(true)
|
||||
}
|
||||
if cmd.UUID {
|
||||
t.AddRow(scene.SceneName, activeMark, scene.SceneUuid)
|
||||
} else {
|
||||
t.AddRow(scene.SceneName, activeMark)
|
||||
}
|
||||
}
|
||||
t.Render()
|
||||
return nil
|
||||
|
||||
27
sceneitem.go
27
sceneitem.go
@@ -21,7 +21,8 @@ type SceneItemCmd struct {
|
||||
|
||||
// SceneItemListCmd provides a command to list all scene items in a scene.
|
||||
type SceneItemListCmd struct {
|
||||
SceneName string `arg:"" help:"Name of the scene to list items from." default:""`
|
||||
UUID bool `flag:"" help:"Display UUIDs of scene items."`
|
||||
SceneName string ` help:"Name of the scene to list items from." arg:"" default:""`
|
||||
}
|
||||
|
||||
// Run executes the command to list all scene items in a scene.
|
||||
@@ -47,8 +48,13 @@ func (cmd *SceneItemListCmd) Run(ctx *context) error {
|
||||
|
||||
t := table.New(ctx.Out)
|
||||
t.SetPadding(3)
|
||||
if cmd.UUID {
|
||||
t.SetAlignment(table.AlignCenter, table.AlignLeft, table.AlignCenter, table.AlignCenter, table.AlignCenter)
|
||||
t.SetHeaders("Item ID", "Item Name", "In Group", "Enabled", "UUID")
|
||||
} else {
|
||||
t.SetAlignment(table.AlignCenter, table.AlignLeft, table.AlignCenter, table.AlignCenter)
|
||||
t.SetHeaders("Item ID", "Item Name", "In Group", "Enabled")
|
||||
}
|
||||
|
||||
sort.Slice(resp.SceneItems, func(i, j int) bool {
|
||||
return resp.SceneItems[i].SceneItemID < resp.SceneItems[j].SceneItemID
|
||||
@@ -67,15 +73,30 @@ func (cmd *SceneItemListCmd) Run(ctx *context) error {
|
||||
})
|
||||
|
||||
for _, groupItem := range resp.SceneItems {
|
||||
if cmd.UUID {
|
||||
t.AddRow(
|
||||
fmt.Sprintf("%d", groupItem.SceneItemID),
|
||||
groupItem.SourceName,
|
||||
item.SourceName,
|
||||
fmt.Sprintf("%t", item.SceneItemEnabled && groupItem.SceneItemEnabled),
|
||||
getEnabledMark(item.SceneItemEnabled && groupItem.SceneItemEnabled),
|
||||
groupItem.SourceUuid,
|
||||
)
|
||||
} else {
|
||||
t.AddRow(
|
||||
fmt.Sprintf("%d", groupItem.SceneItemID),
|
||||
groupItem.SourceName,
|
||||
item.SourceName,
|
||||
getEnabledMark(item.SceneItemEnabled && groupItem.SceneItemEnabled),
|
||||
)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
t.AddRow(fmt.Sprintf("%d", item.SceneItemID), item.SourceName, "", fmt.Sprintf("%t", item.SceneItemEnabled))
|
||||
if cmd.UUID {
|
||||
t.AddRow(fmt.Sprintf("%d", item.SceneItemID), item.SourceName, "",
|
||||
getEnabledMark(item.SceneItemEnabled), item.SourceUuid)
|
||||
} else {
|
||||
t.AddRow(fmt.Sprintf("%d", item.SceneItemID), item.SourceName, "", getEnabledMark(item.SceneItemEnabled))
|
||||
}
|
||||
}
|
||||
}
|
||||
t.Render()
|
||||
|
||||
4
util.go
4
util.go
@@ -16,9 +16,9 @@ func snakeCaseToTitleCase(snake string) string {
|
||||
|
||||
func getEnabledMark(enabled bool) string {
|
||||
if enabled {
|
||||
return "\u2713" // green check mark
|
||||
return "\u2713" // check mark
|
||||
}
|
||||
return "\u274c" // red cross mark
|
||||
return "\u274c" // cross mark
|
||||
}
|
||||
|
||||
func trimPrefix(s, prefix string) string {
|
||||
|
||||
Reference in New Issue
Block a user