elektordi / obs-websocket-py Goto Github PK
View Code? Open in Web Editor NEWPython library to communicate with an obs-websocket server (for OBS Studio)
License: MIT License
Python library to communicate with an obs-websocket server (for OBS Studio)
License: MIT License
It would be useful if the socket can auto reconnect when connection to OBS breaks.
I noticed there doesn't seem to be the ability to control the Virtual Camera start and stopping. When I run GetStreamingStatus it returns a T/F value for the Vitrual camera but I couldn't call it on and off. I know it said not to edit the files but I was able to add Virtual Camera support with the addition of a few extra lines in the events and requests .py. Not sure if I did this completely correct but it's enabled control for me.
Events.py, pasted before "class StreamStarting(Baseevents):"
class VirtualCamStarted(Baseevents):
"""VirtualCam started successfully.
"""
def __init__(self):
Baseevents.__init__(self)
self.name = 'VirtualCamStarted'
class VirtualCamStopped(Baseevents):
"""VirtualCam stopped successfully.
"""
def __init__(self):
Baseevents.__init__(self)
self.name = 'VirtualCamStopped'
requests .py, note edits are marked
class GetStreamingStatus(Baserequests):
"""Get current streaming and recording status.
:Returns:
*streaming*
type: boolean
Current streaming status.
*recording*
type: boolean
Current recording status.
*stream_timecode*
type: String (optional)
Time elapsed since streaming started (only present if currently streaming).
*rec_timecode*
type: String (optional)
Time elapsed since recording started (only present if currently recording).
*preview_only*
type: boolean
Always false. Retrocompatibility with OBSRemote.
"""
def __init__(self):
Baserequests.__init__(self)
self.name = 'GetStreamingStatus'
self.datain['streaming'] = None
self.datain['recording'] = None
# Start Edit
self.datain['virtualcam'] = None
# End Edit
self.datain['stream-timecode'] = None
self.datain['rec-timecode'] = None
self.datain['preview-only'] = None
def getStreaming(self):
return self.datain['streaming']
def getRecording(self):
return self.datain['recording']
# Start Edit
def getVirtualCam(self):
return self.datain['virtualcam']
# End Edit
def getStreamTimecode(self):
return self.datain['stream-timecode']
def getRecTimecode(self):
return self.datain['rec-timecode']
def getPreviewOnly(self):
return self.datain['preview-only']
# Start Edit
class StartStopVirtualCam(Baserequests):
"""Toggle Virtual Camera on or off (depending on the current stream state).
"""
def __init__(self):
Baserequests.__init__(self)
self.name = 'StartStopVirtualCam'
class StartVirtualCam(Baserequests):
"""Start Virtualcam.
Will return an `error` if cam is already active.
:Arguments:
"""
def __init__(self, stream=None):
Baserequests.__init__(self)
self.name = 'StartVirtualCam'
class StopVirtualCam(Baserequests):
"""Stop Virtualcam.
Will return an `error` if cam is not active.
"""
def __init__(self):
Baserequests.__init__(self)
self.name = 'StopVirtualCam'
# End Edit
Could be cool to have Py3 compat.
Putting an issue for this so people can follow up.
If there is some Py3 experts out there, feel free to take a look, never used it myself...
Hi, thanks for excellent work on this library, I am using and appreciating!
There is an issue with the class "SetSceneItemProperties", and possibly others that prevent many fields from being set in OBS. Wrapper currently sends request as single object with keys and values exactly according to obs-websocket documentation for all possible fields. Documentation is slightly convoluted however, the correct behavior for this class should be to send an object with nested objects for "Position, Scale, Crop, and Bound". See comments from haganbmj here:
obs-websocket-community-projects/obs-websocket-js#128
Any field listed in obs-websocket documentation in "x.x" format is referring to a nested object, whereas wrapper is sending the "x.x" documented field as individual keys.
We can observe this in the difference between a set and get request on this class:
<SetSceneItemProperties request ({'item': 'test', 'scene-name': None, 'position.x': 0, 'position.y': 0, 'position.alignment': 5, 'rotation': None, 'scale.x': None, 'scale.y': None, 'crop.top': None, 'crop.bottom': None, 'crop.left': None, 'crop.right': None, 'visible': None, 'locked': None, 'bounds.type': None, 'bounds.alignment': None, 'bounds.x': None, 'bounds.y': None})
called: success ({})>
<GetSceneItemProperties request ({'item': 'test', 'scene-name': None}) called: success ({'bounds': {'alignment': 0, 'type': 'OBS_BOUNDS_NONE', 'x': 0.0, 'y': 0.0}, 'crop': {'bottom': 0, 'left': 0, 'right': 0, 'top': 0}, 'height': 1080.0, 'locked': False, 'name': 'test', 'position': {'alignment': 5, 'x': 1890.0, 'y': 0.0}, 'rotation': 0.0, 'scale': {'x': 1.0, 'y': 1.0}, 'sourceHeight': 1080, 'sourceWidth': 2160, 'visible': True, 'width': 2160.0})>
The OBS Logs show that the set request has failed to properly set those parameters that are shown as being nested in the get request (specifically position in this example):
17:47:35.363: [obs-websocket] Request >> '{"item": "test", "scene-name": null, "position.x": 0, "position.y": 0, "position.alignment": 5, "rotation": null, "scale.x": null, "scale.y": null, "crop.top": null, "crop.bottom": null, "crop.left": null, "crop.right": null, "visible": null, "locked": null, "bounds.type": null, "bounds.alignment": null, "bounds.x": null, "bounds.y": null, "request-type": "SetSceneItemProperties", "message-id": "3"}'
17:47:35.363: [obs-websocket] Update << '{
17:47:35.363: "item-id": 4,
17:47:35.363: "item-name": "test",
17:47:35.363: "scene-name": "1",
17:47:35.363: "transform": {
17:47:35.363: "bounds": {
17:47:35.363: "alignment": 0,
17:47:35.363: "type": "OBS_BOUNDS_NONE",
17:47:35.363: "x": 0.0,
17:47:35.363: "y": 0.0
17:47:35.363: },
17:47:35.363: "crop": {
17:47:35.363: "bottom": 0,
17:47:35.363: "left": 0,
17:47:35.363: "right": 0,
17:47:35.363: "top": 0
17:47:35.363: },
17:47:35.363: "height": 1080.0,
17:47:35.363: "locked": false,
17:47:35.363: "position": {
17:47:35.363: "alignment": 5,
17:47:35.363: "x": 1890.0,
17:47:35.363: "y": 0.0
17:47:35.363: },
17:47:35.363: "rotation": 0.0,
17:47:35.363: "scale": {
17:47:35.363: "x": 1.0,
17:47:35.363: "y": 1.0
17:47:35.363: },
17:47:35.363: "sourceHeight": 1080,
17:47:35.363: "sourceWidth": 2160,
17:47:35.363: "visible": true,
17:47:35.363: "width": 2160.0
17:47:35.363: },
17:47:35.363: "update-type": "SceneItemTransformChanged"
17:47:35.363: }'
17:47:35.363: [obs-websocket] Response << '{
17:47:35.363: "message-id": "3",
17:47:35.363: "status": "ok"
The classes marked in obs-websocket as being deprecated (SetSceneItemPosition, SetSceneItemTransform, SetSceneItemCrop) Are still working correctly with the Wrapper and I am currently using as a work around. Although I do not currently use it, it should be noted there is no alternative class for setting "Bounds".
I briefly attempted to wrap my head around adding this into code myself but have limited time and skill at the moment (although I may still eventually return to attempt it). As mentioned above the deprecated classes are working for me but I didn't see any open or closed issue regarding this and figured I would submit in case you were unaware, or obs-websocket eventually drops the older classes.
Thanks again!
76cdd5b changed the signature for SetVolume from
def __init__(self, source, volume):
to
def __init__(self, volume, source, useDecibel=None):
This broke API compatibility and that argument order doesn't make any sense (compared to other requests).
Following code is working (changing the scene in OBS)
ws = obsws(host, port, password)
ws.connect()
ws.call(requests.SetCurrentScene('Clone Hero'))
But is outputting these errors in console:
Invalid message: {
"duration": 300,
"from-scene": "Clone Hero Menu Nav",
"name": "Fade",
"to-scene": "Clone Hero",
"type": "fade_transition",
"update-type": "TransitionVideoEnd"
} (Invalid event TransitionVideoEnd)
Invalid message: {
"duration": 300,
"name": "Fade",
"to-scene": "Clone Hero",
"type": "fade_transition",
"update-type": "TransitionEnd"
} (Invalid event TransitionEnd)
Pardon my broken English.
I want to use "TakeSourceScreenshot" in python.
( "TakeSourceScreenshot" is implemented in obs-websocket 4.6.0)
Could you add the method "TakeSourceScreenShot"?
I'll look into OrderedDict...
And it has to be stable between python2 and 3!
Hello , I am just working on a project using both libraries obs-websocket + APScheduler .
I used obs-websocket in conjunction with APSscheduler in order to schedule some jobs. The jobs update some scenes and objects inside the scene.
I used atomical function like this:
def createOBSWS():
host = settings.WS_HOST
port = settings.WS_PORT
password = settings.WS_PASS
websocket = obsws(host, port, password)
return websocket
....
....
if (websocket is None):
websocket = createOBSWS()
websocket.connect()
websocket.call(requests.SetCurrentScene(sceneName))
websocket.disconnect()
In both linux and win box , I am getting this kind of errors .
WIN
.... venv\lib\site-packages\websocket\_socket.py", line 139, in _send return sock.send(data) OSError: [WinError 10038] Tentativo di operazione su un elemento diverso dal socket
DEB
lib/python3.5/site-packages/websocket/_socket.py", line 139, in _send return sock.send(data) OSError: [Errno 9] Bad file descriptor
They are both related.
I supposed that I call the disconnect before sending the command to the obs-websocket-server , but I followed your examples.
I tried your last release 0.5, python 3.5 (Debian), python 3.6 (Win)
Hello.
Is it possible to build obs web sockets such that i can send requests to OBS functions directly?
While using Python and obs-websocket-py trying to use SetCurrentScene results in
<SetCurrentScene request({u"error" : u"requested scene does not exist"}) called: failed ({"scene-name" : u"s2"})>
or any other name results in "scene does not exist" error, even if the scene does exists and is read by using GetSceneList(). Same happens for setting source properties - the module always returns a "not found" error, even if scenes / sources can be found in the scene via obs-websocket.py.
Make two scenes in OBS, "s1" and "s2". Then:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import obswebsocket as obsw
import obswebsocket.requests as obsr
client = obsw.obsws("localhost", 4444, "password")
client.connect()
scenes = client.call(obsr.GetSceneList()).dataout["scenes"]
newScene = scenes[1]
res = client.call(obsr.SetCurrentScene(newScene["name"]))
print res
client.disconnect()
Hi, i'm having a Problem with getting a MessageTimeout after i send a request to GetSceneItemList with the current PreviewScene after an on_preview Event, when i try this on other parts of my code it works fine and does not result in a timeout. According to the log of OBS and Wireshark a response (including "status":"ok") is send by the websocket plugin
in other words:
when i make the request (GetSceneItemList) at the begining of my script (with the Scene Name i get via the getPreviewScene Request) evrything works fine, but when i make the request as a response for an PreviewSceneChange with the Scene name i get from the Event, the request runs into a timeout even though OBS and Wireshark confirm that a response has been send
Exception in thread Thread-1:
Traceback (most recent call last):
File "C:\Users\Niklas\AppData\Local\Programs\Python\Python310\lib\threading.py", line 1009, in _bootstrap_inner
self.run()
File "C:\Users\Niklas\AppData\Local\Programs\Python\Python310\lib\site-packages\obswebsocket\core.py", line 236, in run
self.core.eventmanager.trigger(obj)
File "C:\Users\Niklas\AppData\Local\Programs\Python\Python310\lib\site-packages\obswebsocket\core.py", line 281, in trigger
callback(data)
File "C:\Users\Niklas\Documents\scripte\python\obs-ws\app.py", line 120, in on_preview
scene_Prev = getSrcForScene(current_Prev)
File "C:\Users\Niklas\Documents\scripte\python\obs-ws\app.py", line 46, in getSrcForScene
result = ws.call(requests.GetSceneItemList(sceneName))
File "C:\Users\Niklas\AppData\Local\Programs\Python\Python310\lib\site-packages\obswebsocket\core.py", line 162, in call
r = self.send(payload)
File "C:\Users\Niklas\AppData\Local\Programs\Python\Python310\lib\site-packages\obswebsocket\core.py", line 179, in send
return self._wait_message(message_id)
File "C:\Users\Niklas\AppData\Local\Programs\Python\Python310\lib\site-packages\obswebsocket\core.py", line 187, in _wait_message
raise exceptions.MessageTimeout(u"No answer for message {}".format(
obswebsocket.exceptions.MessageTimeout: No answer for message 18
I tested this on a windows 10 and an ubuntu Maschine, both running OBS Version 27.1.3 and obs-websocket-py Version 0.5.3
Hi devs,
First, thanks for the awesome module.
I am trying to use SetSourceSettings to change the video playing on a VLC source.
Here is the code I'm using:
video = '/home/streamgaki/Desktop/Videos To Play/Highschool Batsu Clip - Ten Ten.mkv'
request = {'playlist': {'hidden': False, 'selected': False, 'value': video}}
thecall = self.obss.call(requests.SetSourceSettings("VLC", request))
Printing the result of this request gives:
<SetSourceSettings request ({'sourceName': 'VLC', 'sourceSettings': {'playlist': {'hidden': False, 'selected': False, 'value': '/home/streamgaki/Desktop/Videos To Play/Highschool Batsu Clip - Ten Ten.mkv'}}, 'sourceType': None}) called: success ({'sourceName': 'VLC', 'sourceSettings': {'loop': True, 'network_caching': 400, 'playback_behavior': 'always_play', 'playlist': {'hidden': False, 'selected': False, 'value': '/home/streamgaki/Desktop/Videos To Play/Highschool Batsu Clip - Ten Ten.mkv'}, 'shuffle': True, 'subtitle': 1, 'subtitle_enable': False, 'track': 1}, 'sourceType': 'vlc_source'})>
So it looks like it worked, and looking at the OBS log, that seems to be the case:
17:14:18.688: [obs-websocket] Request >> '{"sourceName": "VLC", "sourceSettings": {"playlist": {"hidden": false, "selected": false, "value": "/home/streamgaki/Desktop/Videos To Play/Highschool Batsu Clip - Ten Ten.mkv"}}, "sourceType": null, "request-type": "SetSourceSettings", "message-id": "5"}'
17:14:18.688: [obs-websocket] Response << '{"message-id":"5","sourceName":"VLC","sourceSettings":{"loop":true,"network_caching":400,"playback_behavior":"always_play","playlist":{"hidden":false,"selected":false,"value":"/home/streamgaki/Desktop/Videos To Play/Highschool Batsu Clip - Ten Ten.mkv"},"shuffle":true,"subtitle":1,"subtitle_enable":false,"track":1},"sourceType":"vlc_source","status":"ok"}'
However... checking OBS, the VLC source ends up with nothing in its playlist
Am I doing shitty code? Or is the module or OBS being silly?
When sending the message to start the stream, it seems to have caused a TypeError on my StreamStatus event
Exception in thread Thread-1:
Traceback (most recent call last):
File "C:\Users\Colin\AppData\Local\Programs\Python\Python38\lib\threading.py", line 932, in _bootstrap_inner
self.run()
File "C:\Users\Colin\Documents\_GithubRepos\PTZCamSync\PTZCamSync\lib\site-packages\obswebsocket\core.py", line 236, in run
self.core.eventmanager.trigger(obj)
File "C:\Users\Colin\Documents\_GithubRepos\PTZCamSync\PTZCamSync\lib\site-packages\obswebsocket\core.py", line 280, in trigger
if trigger is None or isinstance(data, trigger):
TypeError: isinstance() arg 2 must be a type or tuple of types
trying ws.connect() leads to above error message (python 3.6)
When triggering a scene change with a transition events are emitted for TransitionEnd and TransitionVideoEnd. These are not defined in events.py.
I've installed via pip, if that explains anything.
Is it possible for Media or VLC source to set the starting point in the media file or does the media file always play from the beginning? Kinda like the following.
'sourceSettings' : {'local_file': "path/to/file", 'start': 10.5}
I've asked the same at obs-websocket
but I haven't heard if its possible yet and figured someone here may know.
Thank you.
Hi,
I can't install obs-websocket-py.
Over pip install obs-websocket-py, I get:
Collecting obs-websocket-py
Using cached https://files.pythonhosted.org/packages/2c/82/125306f049d7517f6cbae078fe0dc4cb82df08d5a2b1018b7bbd753eadc8/obs-websocket-py-0.3.tar.gz
Complete output from command python setup.py egg_info:
Traceback (most recent call last):
File "", line 1, in
File "c:\users\pascal\appdata\local\temp\pip-install-d1x5gc\obs-websocket-py\setup.py", line 9, in
from generate_classes import generate_classes
ImportError: No module named generate_classes
----------------------------------------
Command "python setup.py egg_info" failed with error code 1 in c:\users\pascal\appdata\local\temp\pip-install-d1x5gc\obs-websocket-py\
I need the library for python2.7.
When I try it to install from a cloned git repo, I get:
Processing c:\users\pascal\downloads\obs-websocket-py-master\obs-websocket-py-master
Complete output from command python setup.py egg_info:
Traceback (most recent call last):
File "", line 1, in
File "c:\users\pascal\appdata\local\temp\pip-req-build-lh8uf8\setup.py", line 10, in
from obswebsocket import version
File "obswebsocket_init_.py", line 8, in
from .core import obsws
File "obswebsocket\core.py", line 18, in
from . import events
ImportError: cannot import name events
----------------------------------------
Command "python setup.py egg_info" failed with error code 1 in c:\users\pascal\appdata\local\temp\pip-req-build-lh8uf8\
And I installed events 0.3 with pip.
pip install events
Requirement already satisfied: events in c:\python27\lib\site-packages (0.3)
May the import of events are not correct?
Or something else?
I hope you can help.
best regards
Follow up issue for adding obs-websocket-py to PyPI (pip repository) as requested by @Palakis
Supposedly, width and height are the final sceneitem size. They return the base width and height multiplied by their scale:
// Utils.cpp:784
obs_data_set_double(data, "width", baseSourceWidth * scale.x);
obs_data_set_double(data, "height", baseSourceHeight * scale.y);
Shouldn't they be substracted by its crop values before multiplying them? Something like:
// Utils.cpp:784
obs_data_set_double(data, "width", (baseSourceWidth - crop.left - crop.right)* scale.x);
obs_data_set_double(data, "height", (baseSourceHeight - crop.top - crop.bottom) * scale.y);
(I don't know C++, maybe it's misspelled)
Saddly, I don't use obs-websocket-py anymore ๐ข... because I programed my own OBS-OSC-PythonScript 0.1. Now, I don't send OSC messages to Python and Python to Websockets... it's slow and it crashes OBS several times. I directly send OSC messages to Python script ๐.
But I've been using obs-websockets-py for a time and now, I realized that GetSceneItemProperties should be different. As I fixed that in my code, maybe you want to change in yours.
Thank you very much for your code!
Adding the two classes below to the request.py and event.py file will enable the heartbeat which was introduced lately in the obs-websocket implementation from: https://github.com/Palakis/obs-websocket/
Is it possible that you/anyone could add those classes to these files?
Kind regards,
Robert Nagtegaal
[email protected]
request.py:
class SetHeartBeat(base_classes.BaseRequest):
def __init__(self, enable):
base_classes.BaseRequest.__init__(self)
self.name = "SetHeartbeat"
self.dataout["enable"] = enable
event.py:
class Heartbeat(base_classes.BaseEvent):
def __init__(self):
base_classes.BaseEvent.__init__(self)
self.name = "Heartbeat"
self.datain["current-profile"] = None
self.datain["current-scene"] = None
self.datain["pulse"] = False
self.datain["rec-timecode"] = None
self.datain["recording"] = None
self.datain["streaming"] = None
self.datain["total-record-bytes"] = None
self.datain["total-record-frames"] = None
self.datain["total-record-time"] = None
see also: https://github.com/Elektordi/obs-websocket-py/pulls
Now that the lib have a common codebase for python 2 and 3, I should add unit tests to prevent any break of one python version while working on the other one!
Maybe it's a good idea to create to server placeholder to answer the lib with static hardcoded answers...
So - I have written a thin wrapper around this library which can be used on a command line:
https://gist.github.com/sochotnicky/101e3b2bbcdddd5db065d0ff102d3db2
For example:
$ python obs-cli.py ListSceneCollections
{
"scene-collections": [
{
"sc-name": "Demo - Share Left"
},
{
"sc-name": "Demo - Share Right"
},
{
"sc-name": "Share - WebCam"
},
{
"sc-name": "Untitled"
}
]
}
$ python obs-cli.py SetCurrentSceneCollection Untitled
{}
The way it's done it does not require changes when methods are added. I am sure there's things that do not work well - it would be nice for example if there were annotations on arguments that could be used to figure out expected argument types etc.
I was considering creating a separate repo for it & putting it there, but I figure maybe it could be more useful included here? If you'd be up for the idea - I can open a PR (it would need additional changes to setup.py etc to install the script)
running Python 3.5.2.
$ pip install obs-websocket-py
Collecting obs-websocket-py
Downloading obs-websocket-py-0.3.tar.gz
Complete output from command python setup.py egg_info:
Traceback (most recent call last):
File "", line 1, in
File "/private/var/folders/5b/r380sbgs64d9v36w3qdn27m40000gn/T/pip-build-2q0t90dj/obs-websocket-py/setup.py", line 9, in
from generate_classes import generate_classes
ImportError: No module named 'generate_classes'
Hi,
I was experimenting with your websocket lib. Tried one of the samples and it's working.
Switching scenes, listing sources, etc.
Upon trying to enable or disable a source, it seems I can turn them off but not back on?
ws.call(requests.SetSceneItemProperties(scene_name="Scene", item = "nonewsy", visible = 'true'))
time.sleep(2)
ws.call(requests.SetSceneItemProperties(scene_name="Scene", item = "nonewsy", visible = 'false'))
I've tried 0
and 1
, with scene_name or without it. The second statement works, the first one does not. Any ideas? Thanks!
At least in the current (0.4) version, it is impossible to get the mute status of an audio source, presumably due to using the wrong key when getMute() is called.
source = client.call(obswebsocket.requests.GetVolume("Line 1 (Streaming Music)"))
print source
<GetVolume request ({'source': 'Line 1 (Streaming Music)'}) called: success ({u'muted': True, u'name': u'Line 1 (Streaming Music)', u'volume': 0.20000000298023224})>
...note that the name of the key is muted
....and then:
print source.getMute()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python2.7/site-packages/obswebsocket/requests.py", line 831, in getMute
return self.datain["mute"]
KeyError: 'mute'
...note the key being used by getMute() is mute
.
This is with obs-websocket 4.6.1 on the other end.
It should be "getMonitorType", not "getMonitortype".
./obswebsocket/requests.py:2229: def getMonitortype(self):
Please consider adding a function that returns the current obs-websocket-py version information. Thank you.
Although the repository is 3.x compatible (1b97dc8) and is stated as such in the plugin README, the current version on PyPi does not have these changes.
It would be nice if you could push the latest version to PyPi so the module installed via pip is 3.x compatible ๐.
I have checked the same code on switching scenes and it has no issues, muting any source does not seem to work.
The snippet connects to obs, print success msg, and does not toggle "myname" in obs.
Example:
host = "localhost"
port = 4444
password = "1"
ws = obsws(host, port, password)
ws.connect()
try:
req = ws.call(requests.ToggleMute("myname"))
ws.disconnect()
I have added a new SysTray button "Start Procedure" to my OBS Studio which is similar to "Start Recording". However when i add it as a class to requests.py and try to access it using obs-websocket-py , i get an error saying "invalid request type" . Could you please assist as to what may be the problem? Thanks in advance.
Hello again,
I am trying to make a source move animation. However I could not find the way of setting the following parameters:
'height'
'width'
'sourceHeight'
'sourceWidth'
(Also less important/meaningless: 'itemId', 'name')
Maybe it is currently possible but I spent a lot of time trying to set 'height', 'width', 'sourceHeight' and 'sourceWidth' but I could not find the way.
On the other hand, when running the move animation (video attached) the 'ws.call' takes a lot of time between steps because of callback, so the animation it is not smooth enought. I tried to use 'ws.send' but it gives me an error. Any advice?
Thank you in advance. Best regards.
Hello Elektordi,
First of all, thank you so much for your awesome work, I really appreciate it.
Recently, obs-websocket has been updated with new features (and also will introduce some more in next release) which are not supported buy obs-websocket-py. For example CreateScene #576. I also wanted to use new feature OpenProjector but I neither could. Will be possible to use them in the future? I am learning programming and my skill is not very good right now, otherwise I would help you to do it.
Thank you for your time.
Best regards.
Running events sample with ws.disconnect()
commented out...
[elektordi@gg8 samples]$ python events.py
INFO:obswebsocket.core:Connecting...
INFO:obswebsocket.core:Connected!
OK
^C^C^C^C^C^\Quitter (core dumped)
[elektordi@gg8 samples]$
(Had to SIGKILL it to exit.)
Users are supposed to call disconnect() before exiting, but if missed it should definitely not lock the python process!!!
And maybe remove the need to generate classes...
Sorry if this does not belong here... I want to change the opacity of a filter. I read in a obs-websocket issue that somebody uses SetSourceFilterSettings:
// camera
await obs.send(
"SetSourceFilterSettings", {
sourceName: "SRC_Cam_1",
filterName: "Color Correction",
filterSettings: {
opacity: opacity
}
});
I would like to do the same with obs-websocket-py. As in Protocol says this:
filterSettings | Object | New settings. These will be merged to the current filter settings.
... I tried sending that "Object" as a dict:
(...)
ws.call(requests.SetSourceFilterSettings(sourceName='Source_001', filterName="Color Correction", filterSettings={"opacity": 50}))
... but it didn't work. In Protocol says its an "Object"... How to know what to send? Should I create that "Object" before?
I'm getting the following message
Invalid message: (Expecting value: line 1 column 1 (char 0))
When I call disconnect
on my obsws
instance. It happens because the socket closes and self.ws.recv() returns an empty string[1].
The library should probably check if self.running
is False
once again OR check if the received string is empty.
Instead it tries to JSON it.
Possible solution (the whole run
function):
def run(self):
while self.running:
try:
message = self.ws.recv()
if not self.running:
return
if not message:
raise self.core.reconnect()
result = json.loads(message)
if 'update-type' in result:
LOG.debug("Got message: %r"%(result))
obj = self.buildEvent(result)
self.core.eventmanager.trigger(obj)
elif 'message-id' in result:
LOG.debug("Got answer for id %s: %r"%(result['message-id'], result))
self.core.answers[result['message-id']] = result
else:
LOG.warning("Unknow message: %r"%(result))
except websocket.WebSocketConnectionClosedException:
if self.running:
self.core.reconnect()
except (ValueError, exceptions.ObjectError) as e:
LOG.warning("Invalid message: %s (%s)"%(message, e))
LOG.debug("RecvThread ended.")
[1] websocket.WebSocketConnectionClosedException
is only raised if you try to call recv
when the socket is already closed. It's not raised if you close the socket while you're already waiting for recv
to return - instead the recv
call will just return an empty string.
Quite likely I'm doing something wrong. Calling TransitionToProgram works, but uses whatever transition is set in OBS, not what I specify
Hello.
I have tunneled the obs websocket port (4444) using ngrok.
I am able to access obs studio remotely using http://obs-web.niek.tv/.
But im not able to connect using obs-websocket-py using a python script.
How to provide the (host, port) to this library so i can connect remotely using python.
Thanks in advance.
I'm relatively new to using the obs-websocket-py and should quickly admit that I might easily be missing something. That said, however, I've written a very simple scene change process that is as follows;
import sys
import obswebsocket
import obswebsocket.requests
def main():
client = obswebsocket.obsws("localhost", 4444)
client.connect()
scene = sys.argv[1]
response = client.call(obswebsocket.requests.SetCurrentScene(scene))
client.disconnect()
return 0
if name == "main":
main()
When I run this code I get a message box twice when I call ths procedure; one message that says "New Websocket connection /n Client [::1]:xxxxx connected" and then another message shortly after reading "Web client disconnected /n Client unknown disconnected"
Firstly, I'm wondering if there is some way to turn off or hide these messages?
I'm also wondering if I truly need to connect and disconnect as part of the scene change process. Could I, for example, connect once and then only disconnect when I'm totally done, which may be an hour or more later? I'm wonderingalso if that would help to improve the throughput of the scenechange() process as I've programmed it.
Your thoughts and suggestions are very much appreciated.
obswebsocket.requests.GetRecordingFolder() returns <GetRecordingFolder request ({}) waiting>.
obswebsocket.requests.GetRecordingFolder().getRecFolder() returns None.
Im trying to change an image position inside obs but i cant
print(ws.call(requests.GetSceneItemProperties(
'imagen',
scene_name='programacion'
)))
print(ws.call(requests.SetSceneItemProperties(
'imagen',
scene_name='programacion',
position_x=250,
position_y=300,
)))
print(ws.call(requests.GetSceneItemProperties(
'imagen',
scene_name='programacion'
)))
<GetSceneItemProperties request ({'item': 'imagen', 'scene-name': 'programacion'}) called: success ({'bounds': {'alignment': 0, 'type': 'OBS_BOUNDS_NONE', 'x': 0.0, 'y': 0.0}, 'crop': {'bottom': 0, 'left': 0, 'right': 0, 'top': 0}, 'height': 509.0, 'itemId': 11, 'locked': False, 'name': 'imagen', 'position': {'alignment': 5, 'x': 89.0, 'y': 114.0}, 'rotation': 0.0, 'scale': {'x': 1.0, 'y': 1.0}, 'sourceHeight': 509, 'sourceWidth': 1188, 'visible': True, 'width': 1188.0})>
<SetSceneItemProperties request ({'item': 'imagen', 'scene-name': 'programacion', 'position.x': 250, 'position.y': 300, 'position.alignment': None, 'rotation': None, 'scale.x': None, 'scale.y': None, 'crop.top': None, 'crop.bottom': None, 'crop.left': None, 'crop.right': None, 'visible': None, 'locked': None, 'bounds.type': None, 'bounds.alignment': None, 'bounds.x': None, 'bounds.y': None}) called: success ({})>
<GetSceneItemProperties request ({'item': 'imagen', 'scene-name': 'programacion'}) called: success ({'bounds': {'alignment': 0, 'type': 'OBS_BOUNDS_NONE', 'x': 0.0, 'y': 0.0}, 'crop': {'bottom': 0, 'left': 0, 'right': 0, 'top': 0}, 'height': 509.0, 'itemId': 11, 'locked': False, 'name': 'imagen', 'position': {'alignment': 5, 'x': 89.0, 'y': 114.0}, 'rotation': 0.0, 'scale': {'x': 1.0, 'y': 1.0}, 'sourceHeight': 509, 'sourceWidth': 1188, 'visible': True, 'width': 1188.0})>
Traceback (most recent call last):
File "./switch_scenes.py", line 25, in
print("Switching to {}".format(name))
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe9' in position 3: ordinal not in range(128)
pip install obs-websocket-py
python samples/events.py
Traceback (most recent call last):
File "/home/shawn/.virtualenvs/TEC/lib/python3.8/site-packages/obswebsocket/core.py", line 68, in connect
self.ws.connect("ws://{}:{}".format(self.host, self.port))
File "/home/shawn/.virtualenvs/TEC/lib/python3.8/site-packages/websocket/_core.py", line 222, in connect
self.sock, addrs = connect(url, self.sock_opt, proxy_info(**options),
File "/home/shawn/.virtualenvs/TEC/lib/python3.8/site-packages/websocket/_http.py", line 121, in connect
sock = _open_socket(addrinfo_list, options.sockopt, options.timeout)
File "/home/shawn/.virtualenvs/TEC/lib/python3.8/site-packages/websocket/_http.py", line 201, in _open_socket
raise err
File "/home/shawn/.virtualenvs/TEC/lib/python3.8/site-packages/websocket/_http.py", line 176, in _open_socket
sock.connect(address)
ConnectionRefusedError: [Errno 111] Connection refused
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "events.py", line 29, in <module>
ws.connect()
File "/home/shawn/.virtualenvs/TEC/lib/python3.8/site-packages/obswebsocket/core.py", line 73, in connect
raise exceptions.ConnectionFailure(str(e))
obswebsocket.exceptions.ConnectionFailure: [Errno 111] Connection refused
I'm on Pop!_OS 20.10 python3.8 as you can see.
OBS 26.1.1 which is running and recording as I run the script.
Thank you! It will be awesome to have ws access to OBS.
Awesome project. I'm making great use of this library.
I'm noticing some warnings about some events that are not recognized by obx-websocket-py but that I see documented in obx-websocket 4.8.
A two that are filling me with the most warnings are:
TransitionVideoEnd
TransitionEnd
I don't know if this is in-progress or if there's a process for adding more events to the code.
Replace wrapper in __init__.py
with imports (as seen in others libs)
It seems to be a best practice in python
Hi,
it seems that there is some confusion to the way parameters are set for SetCurrentScene.
My whole message of this issue is "PROTOCOL.md
cannot be parsed automatically".
Because given the complexity of matter it tries to declare, it needs more accurate description. PROTOCOL.md
is full of typos and doesn't represent their protocol correctly.
generate_classes.py
Even if PROTOCOL.md
was perfect, current architecture of obs-websocket-py
(particularly generate_classes.py
) doesn't support creating requests like StartStreaming
. Let's have a look at that request:
Request fields :
The 'stream' object has the following fields:
The 'settings' object has the following fields:
The 'metadata' object supports passing any string, numeric or boolean field.
Response : Error if streaming is already active, OK otherwise. No additional fields.
So there's only one field to that request. And it's an object that has (besides other fields) two more object fields - settings
and metadata
.
Plus there's this metadata
object that is unique accross protocol in sense that it can inlude arbitrary fields.
Time to look at the class generated by the generate_classes.py
:
class StartStreaming(base_classes.BaseRequest):
def __init__(self, stream, settings, type, metadata, server, key, use_auth, username, password):
base_classes.BaseRequest.__init__(self)
self.name = "StartStreaming"
self.dataout["stream"] = stream
self.dataout["settings"] = settings
self.dataout["type"] = type
self.dataout["metadata"] = metadata
self.dataout["server"] = server
self.dataout["key"] = key
self.dataout["use-auth"] = use_auth
self.dataout["username"] = username
self.dataout["password"] = password
All fields are inserted directly into request. That is wrong and doesn't work. Also all fields are required, no opportunity to skip any of them (while PROTOCOL.md
declares all of them as optional).
Doubt it. Look at the StartStopRecording
request. Its only field (stream
) is not even declared there - we're just told to look it up in another request. We'd need an AI parser to handle all these cases in PROTOCOL.md
. MOREOVER, I suspect that stream
property doesn't even belong there - it's likely for StartStopStreaming
request, just was misplaced accidentally in PROTOCOL.md
. Huh.
It's simple, we, err, handle the stuff manually.
As a part of my Python 3.5+ asyncio
-based client to obs-websocket
plugin, I tried to carefully build a usable representation of their protocol.
I provide information of all protocol types (like StreamSettings
type etc), their fields, types of their fields and their "pythonic" fields (authRequired
's pythonic one is auth_required
; use-auth
's pythonic one is use_auth
). Then I provide information of all requests, their responses and all events.
Guess what? I've failed as soon as I received a response for the GetAuthRequired
request. The fact that challenge
and salt
fields are optional (they're sent only if the auth is enabled) is mentioned in the request description, but not anywhere near the fields themselves (usually they detone such fields as "optional" explicitly).
It just confirms the fact that a maintaining is needed, you can't just convert PROTOCOL.md
to anything useful.
I've already seen a few events that don't provide their "required" fields (probably they forgot to mention those were optional, again), but I'm going to do more tests, and finally build an accurate, usable description of the protocol v4.1.
Feel free to use it. My client builds all classes during runtime, but it's still possible to use that file to build classes offline, too.
First of all, i want to ask, is compatible with ironpython? almost all libraries of python are compatible,
If it is when i try to connect to the server i get an error:
obswebsocket.exceptions.ConnectionFailure: [Errno 10044] The support for the specified socket type does not exist in this address family
You may ask. Why i'm using IronPython and not Python, the answer is simple, i need load some .DLLs and the Pythonnet lib dosnt work on python because the stupid NTFS security thing of windows
C:\Windows\system32>ipy
IronPython 2.7.9 (2.7.9.0) on .NET 4.0.30319.42000 (64-bit)
Type "help", "copyright", "credits" or "license" for more information.
import sys
import time
import logging
logging.basicConfig(level=logging.INFO)
from obswebsocket import obsws, requests
host = 'localhost'
port = 4444
password = "test"
ws = obsws(host, port, password)
ws.connect()
INFO:obswebsocket.core:Connecting...
Traceback (most recent call last):
File "", line 1, in
File "C:\Program Files\IronPython 2.7\Lib\site-packages\obswebsocket\core.py", line 72, in connect
obswebsocket.exceptions.ConnectionFailure: [Errno 10044] The support for the specified socket type does not exist in this address family
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.