mirror of
https://github.com/onyx-and-iris/obsws-cli.git
synced 2026-04-07 01:23:35 +00:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3eaa3992a0 | |||
| 7c86aa8a8b | |||
| 09ca892fcb | |||
| 81fcb4e504 |
@@ -5,12 +5,13 @@ 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/),
|
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).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
# [0.23.0] - 2026-01-09
|
# [0.24.0] - 2026-01-09
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- new subcommands added to input, see [Input](https://github.com/onyx-and-iris/obsws-cli?tab=readme-ov-file#input)
|
- new subcommands added to input, see [Input](https://github.com/onyx-and-iris/obsws-cli?tab=readme-ov-file#input)
|
||||||
- settings command group, see [Settings](https://github.com/onyx-and-iris/obsws-cli?tab=readme-ov-file#settings)
|
- settings command group, see [Settings](https://github.com/onyx-and-iris/obsws-cli?tab=readme-ov-file#settings)
|
||||||
|
- media command group, see [Media](https://github.com/onyx-and-iris/obsws-cli?tab=readme-ov-file#media)
|
||||||
|
|
||||||
|
|
||||||
# [0.20.0] - 2025-07-14
|
# [0.20.0] - 2025-07-14
|
||||||
|
|||||||
38
README.md
38
README.md
@@ -776,6 +776,44 @@ obsws-cli settings video
|
|||||||
obsws-cli settings video --base-width=1920 --base-height=1080
|
obsws-cli settings video --base-width=1920 --base-height=1080
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### Media
|
||||||
|
|
||||||
|
- cursor: Get/set the cursor position of a media input.
|
||||||
|
- args: InputName
|
||||||
|
|
||||||
|
*optional*
|
||||||
|
- TimeString
|
||||||
|
|
||||||
|
```console
|
||||||
|
obsws-cli media cursor "Media"
|
||||||
|
|
||||||
|
obsws-cli media cursor "Media" "00:08:30"
|
||||||
|
```
|
||||||
|
|
||||||
|
- play: Plays a media input.
|
||||||
|
|
||||||
|
```console
|
||||||
|
obsws-cli media play "Media"
|
||||||
|
```
|
||||||
|
|
||||||
|
- pause: Pauses a media input.
|
||||||
|
|
||||||
|
```console
|
||||||
|
obsws-cli media pause "Media"
|
||||||
|
```
|
||||||
|
|
||||||
|
- stop: Stops a media input.
|
||||||
|
|
||||||
|
```console
|
||||||
|
obsws-cli media stop "Media"
|
||||||
|
```
|
||||||
|
|
||||||
|
- restart: Restarts a media input.
|
||||||
|
|
||||||
|
```console
|
||||||
|
obsws-cli media restart "Media"
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# SPDX-FileCopyrightText: 2025-present onyx-and-iris <code@onyxandiris.online>
|
# SPDX-FileCopyrightText: 2025-present onyx-and-iris <code@onyxandiris.online>
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: MIT
|
# SPDX-License-Identifier: MIT
|
||||||
__version__ = '0.23.0'
|
__version__ = '0.24.0'
|
||||||
|
|||||||
@@ -18,10 +18,12 @@ for sub_typer in (
|
|||||||
'group',
|
'group',
|
||||||
'hotkey',
|
'hotkey',
|
||||||
'input',
|
'input',
|
||||||
|
'media',
|
||||||
'profile',
|
'profile',
|
||||||
'projector',
|
'projector',
|
||||||
'record',
|
'record',
|
||||||
'replaybuffer',
|
'replaybuffer',
|
||||||
|
'settings',
|
||||||
'scene',
|
'scene',
|
||||||
'scenecollection',
|
'scenecollection',
|
||||||
'sceneitem',
|
'sceneitem',
|
||||||
@@ -30,7 +32,6 @@ for sub_typer in (
|
|||||||
'studiomode',
|
'studiomode',
|
||||||
'text',
|
'text',
|
||||||
'virtualcam',
|
'virtualcam',
|
||||||
'settings',
|
|
||||||
):
|
):
|
||||||
module = importlib.import_module(f'.{sub_typer}', package=__package__)
|
module = importlib.import_module(f'.{sub_typer}', package=__package__)
|
||||||
app.add_typer(module.app, name=sub_typer)
|
app.add_typer(module.app, name=sub_typer)
|
||||||
|
|||||||
99
obsws_cli/media.py
Normal file
99
obsws_cli/media.py
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
"""module containing commands for media inputs."""
|
||||||
|
|
||||||
|
from typing import Annotated, Optional
|
||||||
|
|
||||||
|
import typer
|
||||||
|
|
||||||
|
from . import console, util
|
||||||
|
from .alias import SubTyperAliasGroup
|
||||||
|
|
||||||
|
app = typer.Typer(cls=SubTyperAliasGroup)
|
||||||
|
|
||||||
|
|
||||||
|
@app.callback()
|
||||||
|
def main():
|
||||||
|
"""Commands for media inputs."""
|
||||||
|
|
||||||
|
|
||||||
|
@app.command('cursor | c')
|
||||||
|
def cursor(
|
||||||
|
ctx: typer.Context,
|
||||||
|
input_name: Annotated[
|
||||||
|
str, typer.Argument(..., help='The name of the media input.')
|
||||||
|
],
|
||||||
|
timecode: Annotated[
|
||||||
|
Optional[str],
|
||||||
|
typer.Argument(
|
||||||
|
..., help='The timecode to set the cursor to (format: HH:MM:SS).'
|
||||||
|
),
|
||||||
|
] = None,
|
||||||
|
):
|
||||||
|
"""Get/set the cursor position of a media input."""
|
||||||
|
if timecode is None:
|
||||||
|
resp = ctx.obj['obsws'].get_media_input_status(input_name)
|
||||||
|
console.out.print(
|
||||||
|
f'Cursor for {console.highlight(ctx, input_name)} is at {util.milliseconds_to_timecode(resp.media_cursor)}.'
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
cursor_position = util.timecode_to_milliseconds(timecode)
|
||||||
|
ctx.obj['obsws'].set_media_input_cursor(input_name, cursor_position)
|
||||||
|
console.out.print(
|
||||||
|
f'Cursor for {console.highlight(ctx, input_name)} set to {timecode}.'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@app.command('play | p')
|
||||||
|
def play(
|
||||||
|
ctx: typer.Context,
|
||||||
|
input_name: Annotated[
|
||||||
|
str, typer.Argument(..., help='The name of the media input.')
|
||||||
|
],
|
||||||
|
):
|
||||||
|
"""Get/set the playing status of a media input."""
|
||||||
|
ctx.obj['obsws'].trigger_media_input_action(
|
||||||
|
input_name, 'OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PLAY'
|
||||||
|
)
|
||||||
|
console.out.print(f'Playing media input {console.highlight(ctx, input_name)}.')
|
||||||
|
|
||||||
|
|
||||||
|
@app.command('pause | pa')
|
||||||
|
def pause(
|
||||||
|
ctx: typer.Context,
|
||||||
|
input_name: Annotated[
|
||||||
|
str, typer.Argument(..., help='The name of the media input.')
|
||||||
|
],
|
||||||
|
):
|
||||||
|
"""Pause a media input."""
|
||||||
|
ctx.obj['obsws'].trigger_media_input_action(
|
||||||
|
input_name, 'OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PAUSE'
|
||||||
|
)
|
||||||
|
console.out.print(f'Paused media input {console.highlight(ctx, input_name)}.')
|
||||||
|
|
||||||
|
|
||||||
|
@app.command('stop | s')
|
||||||
|
def stop(
|
||||||
|
ctx: typer.Context,
|
||||||
|
input_name: Annotated[
|
||||||
|
str, typer.Argument(..., help='The name of the media input.')
|
||||||
|
],
|
||||||
|
):
|
||||||
|
"""Stop a media input."""
|
||||||
|
ctx.obj['obsws'].trigger_media_input_action(
|
||||||
|
input_name, 'OBS_WEBSOCKET_MEDIA_INPUT_ACTION_STOP'
|
||||||
|
)
|
||||||
|
console.out.print(f'Stopped media input {console.highlight(ctx, input_name)}.')
|
||||||
|
|
||||||
|
|
||||||
|
@app.command('restart | r')
|
||||||
|
def restart(
|
||||||
|
ctx: typer.Context,
|
||||||
|
input_name: Annotated[
|
||||||
|
str, typer.Argument(..., help='The name of the media input.')
|
||||||
|
],
|
||||||
|
):
|
||||||
|
"""Restart a media input."""
|
||||||
|
ctx.obj['obsws'].trigger_media_input_action(
|
||||||
|
input_name, 'OBS_WEBSOCKET_MEDIA_INPUT_ACTION_RESTART'
|
||||||
|
)
|
||||||
|
console.out.print(f'Restarted media input {console.highlight(ctx, input_name)}.')
|
||||||
@@ -20,3 +20,28 @@ def check_mark(value: bool, empty_if_false: bool = False) -> str:
|
|||||||
if os.getenv('NO_COLOR', '') != '':
|
if os.getenv('NO_COLOR', '') != '':
|
||||||
return '✓' if value else '✗'
|
return '✓' if value else '✗'
|
||||||
return '✅' if value else '❌'
|
return '✅' if value else '❌'
|
||||||
|
|
||||||
|
|
||||||
|
def timecode_to_milliseconds(timecode: str) -> int:
|
||||||
|
"""Convert a timecode string (HH:MM:SS) to total milliseconds."""
|
||||||
|
match timecode.split(':'):
|
||||||
|
case [mm, ss]:
|
||||||
|
hours = 0
|
||||||
|
minutes = int(mm)
|
||||||
|
seconds = int(ss)
|
||||||
|
case [hh, mm, ss]:
|
||||||
|
hours = int(hh)
|
||||||
|
minutes = int(mm)
|
||||||
|
seconds = int(ss)
|
||||||
|
return (hours * 3600 + minutes * 60 + seconds) * 1000
|
||||||
|
|
||||||
|
|
||||||
|
def milliseconds_to_timecode(milliseconds: int) -> str:
|
||||||
|
"""Convert total milliseconds to a timecode string (HH:MM:SS)."""
|
||||||
|
total_seconds = milliseconds // 1000
|
||||||
|
hours = total_seconds // 3600
|
||||||
|
minutes = (total_seconds % 3600) // 60
|
||||||
|
seconds = total_seconds % 60
|
||||||
|
if hours == 0:
|
||||||
|
return f'{minutes:02}:{seconds:02}'
|
||||||
|
return f'{hours:02}:{minutes:02}:{seconds:02}'
|
||||||
|
|||||||
Reference in New Issue
Block a user