inspect_jitsi package#
Subpackages#
- inspect_jitsi.sync package
- inspect_jitsi.xmpp package
Submodules#
Module contents#
Tools for inspecting a running Jitsi Meet deployment.
- class inspect_jitsi.DiagnosisResult(ws_domain, config_js_reachable=False, discovered_hosts=None, xmpp_domain_tried=None, domain_recognized=None, sasl_mechanisms=None, anonymous_login_ok=None, error=None)[source]
Bases:
objectWhat's needed to read a Jitsi room's occupancy.
As found by JitsiConference.diagnose().
Example:
DiagnosisResult( ws_domain="meet.example.com", config_js_reachable=True, discovered_hosts={ "domain": "meet.jitsi", "muc": "muc.meet.jitsi", "anonymousdomain": None, }, xmpp_domain_tried="meet.jitsi", domain_recognized=True, sasl_mechanisms=["ANONYMOUS"], anonymous_login_ok=True, error=None, )
- __annotations__ = {'anonymous_login_ok': 'bool | None', 'config_js_reachable': 'bool', 'discovered_hosts': 'dict[str, str | None] | None', 'domain_recognized': 'bool | None', 'error': 'str | None', 'sasl_mechanisms': 'list[str] | None', 'ws_domain': 'str', 'xmpp_domain_tried': 'str | None'}
- __dataclass_fields__ = {'anonymous_login_ok': Field(name='anonymous_login_ok',type='bool | None',default=None,default_factory=<dataclasses._MISSING_TYPE object>,init=True,repr=True,hash=None,compare=True,metadata=mappingproxy({}),kw_only=False,_field_type=_FIELD), 'config_js_reachable': Field(name='config_js_reachable',type='bool',default=False,default_factory=<dataclasses._MISSING_TYPE object>,init=True,repr=True,hash=None,compare=True,metadata=mappingproxy({}),kw_only=False,_field_type=_FIELD), 'discovered_hosts': Field(name='discovered_hosts',type='dict[str, str | None] | None',default=None,default_factory=<dataclasses._MISSING_TYPE object>,init=True,repr=True,hash=None,compare=True,metadata=mappingproxy({}),kw_only=False,_field_type=_FIELD), 'domain_recognized': Field(name='domain_recognized',type='bool | None',default=None,default_factory=<dataclasses._MISSING_TYPE object>,init=True,repr=True,hash=None,compare=True,metadata=mappingproxy({}),kw_only=False,_field_type=_FIELD), 'error': Field(name='error',type='str | None',default=None,default_factory=<dataclasses._MISSING_TYPE object>,init=True,repr=True,hash=None,compare=True,metadata=mappingproxy({}),kw_only=False,_field_type=_FIELD), 'sasl_mechanisms': Field(name='sasl_mechanisms',type='list[str] | None',default=None,default_factory=<dataclasses._MISSING_TYPE object>,init=True,repr=True,hash=None,compare=True,metadata=mappingproxy({}),kw_only=False,_field_type=_FIELD), 'ws_domain': Field(name='ws_domain',type='str',default=<dataclasses._MISSING_TYPE object>,default_factory=<dataclasses._MISSING_TYPE object>,init=True,repr=True,hash=None,compare=True,metadata=mappingproxy({}),kw_only=False,_field_type=_FIELD), 'xmpp_domain_tried': Field(name='xmpp_domain_tried',type='str | None',default=None,default_factory=<dataclasses._MISSING_TYPE object>,init=True,repr=True,hash=None,compare=True,metadata=mappingproxy({}),kw_only=False,_field_type=_FIELD)}
- __dataclass_params__ = _DataclassParams(init=True,repr=True,eq=True,order=False,unsafe_hash=False,frozen=False,match_args=True,kw_only=False,slots=False,weakref_slot=False)
- __dict__ = mappingproxy({'__module__': 'inspect_jitsi.xmpp.diagnosis', '__firstlineno__': 22, '__annotations__': {'ws_domain': 'str', 'config_js_reachable': 'bool', 'discovered_hosts': 'dict[str, str | None] | None', 'xmpp_domain_tried': 'str | None', 'domain_recognized': 'bool | None', 'sasl_mechanisms': 'list[str] | None', 'anonymous_login_ok': 'bool | None', 'error': 'str | None'}, '__doc__': 'What\'s needed to read a Jitsi room\'s occupancy.\n\nAs found by `JitsiConference.diagnose()`.\n\nExample::\n\n DiagnosisResult(\n ws_domain="meet.example.com",\n config_js_reachable=True,\n discovered_hosts={\n "domain": "meet.jitsi",\n "muc": "muc.meet.jitsi",\n "anonymousdomain": None,\n },\n xmpp_domain_tried="meet.jitsi",\n domain_recognized=True,\n sasl_mechanisms=["ANONYMOUS"],\n anonymous_login_ok=True,\n error=None,\n )\n\n', 'config_js_reachable': False, 'discovered_hosts': None, 'xmpp_domain_tried': None, 'domain_recognized': None, 'sasl_mechanisms': None, 'anonymous_login_ok': None, 'error': None, 'to_dict': <function DiagnosisResult.to_dict>, '__static_attributes__': (), '__dict__': <attribute '__dict__' of 'DiagnosisResult' objects>, '__weakref__': <attribute '__weakref__' of 'DiagnosisResult' objects>, '__dataclass_params__': _DataclassParams(init=True,repr=True,eq=True,order=False,unsafe_hash=False,frozen=False,match_args=True,kw_only=False,slots=False,weakref_slot=False), '__dataclass_fields__': {'ws_domain': Field(name='ws_domain',type='str',default=<dataclasses._MISSING_TYPE object>,default_factory=<dataclasses._MISSING_TYPE object>,init=True,repr=True,hash=None,compare=True,metadata=mappingproxy({}),kw_only=False,_field_type=_FIELD), 'config_js_reachable': Field(name='config_js_reachable',type='bool',default=False,default_factory=<dataclasses._MISSING_TYPE object>,init=True,repr=True,hash=None,compare=True,metadata=mappingproxy({}),kw_only=False,_field_type=_FIELD), 'discovered_hosts': Field(name='discovered_hosts',type='dict[str, str | None] | None',default=None,default_factory=<dataclasses._MISSING_TYPE object>,init=True,repr=True,hash=None,compare=True,metadata=mappingproxy({}),kw_only=False,_field_type=_FIELD), 'xmpp_domain_tried': Field(name='xmpp_domain_tried',type='str | None',default=None,default_factory=<dataclasses._MISSING_TYPE object>,init=True,repr=True,hash=None,compare=True,metadata=mappingproxy({}),kw_only=False,_field_type=_FIELD), 'domain_recognized': Field(name='domain_recognized',type='bool | None',default=None,default_factory=<dataclasses._MISSING_TYPE object>,init=True,repr=True,hash=None,compare=True,metadata=mappingproxy({}),kw_only=False,_field_type=_FIELD), 'sasl_mechanisms': Field(name='sasl_mechanisms',type='list[str] | None',default=None,default_factory=<dataclasses._MISSING_TYPE object>,init=True,repr=True,hash=None,compare=True,metadata=mappingproxy({}),kw_only=False,_field_type=_FIELD), 'anonymous_login_ok': Field(name='anonymous_login_ok',type='bool | None',default=None,default_factory=<dataclasses._MISSING_TYPE object>,init=True,repr=True,hash=None,compare=True,metadata=mappingproxy({}),kw_only=False,_field_type=_FIELD), 'error': Field(name='error',type='str | None',default=None,default_factory=<dataclasses._MISSING_TYPE object>,init=True,repr=True,hash=None,compare=True,metadata=mappingproxy({}),kw_only=False,_field_type=_FIELD)}, '__replace__': <function _replace>, '__hash__': None, '__init__': <function DiagnosisResult.__init__>, '__repr__': <function DiagnosisResult.__repr__>, '__eq__': <function DiagnosisResult.__eq__>, '__match_args__': ('ws_domain', 'config_js_reachable', 'discovered_hosts', 'xmpp_domain_tried', 'domain_recognized', 'sasl_mechanisms', 'anonymous_login_ok', 'error')})
- __eq__(other)
Return self==value.
- __firstlineno__ = 22
- __hash__ = None
- __init__(ws_domain, config_js_reachable=False, discovered_hosts=None, xmpp_domain_tried=None, domain_recognized=None, sasl_mechanisms=None, anonymous_login_ok=None, error=None)
- __match_args__ = ('ws_domain', 'config_js_reachable', 'discovered_hosts', 'xmpp_domain_tried', 'domain_recognized', 'sasl_mechanisms', 'anonymous_login_ok', 'error')
- __module__ = 'inspect_jitsi.xmpp.diagnosis'
- __replace__(**changes)
- __repr__()
Return repr(self).
- __static_attributes__ = ()
- __weakref__
list of weak references to the object
- config_js_reachable: bool = False
- ws_domain: str
- class inspect_jitsi.JitsiConference(conference_url, nick=None, *, name=None, anonymous_domain=None, muc_domain=None, timeout=10)[source]
Bases:
objectA Jitsi Meet conference (room), joined anonymously as an observer.
Use as an async context manager:
async with JitsiConference(conference_url, "probe") as conference: print(await conference.get_participants())
or call
open()/close()directly.diagnose()andis_created()can be called standalone, without opening the conference, to check what's needed to join at all and whether there's anyone to join in the first place.- async __aenter__()[source]
- Return type:
Self
- __dict__ = mappingproxy({'__module__': 'inspect_jitsi.xmpp.conference', '__firstlineno__': 50, '__doc__': 'A Jitsi Meet conference (room), joined anonymously as an observer.\n\nUse as an async context manager::\n\n async with JitsiConference(conference_url, "probe") as conference:\n print(await conference.get_participants())\n\nor call :meth:`open`/:meth:`close` directly. :meth:`diagnose` and\n:meth:`is_created` can be called standalone, without opening the\nconference, to check what\'s needed to join at all and whether there\'s\nanyone to join in the first place.\n', '__init__': <function JitsiConference.__init__>, 'room': <property object>, 'nick': <property object>, 'name': <property object>, 'open': <function JitsiConference.open>, 'close': <function JitsiConference.close>, 'get_participants': <function JitsiConference.get_participants>, 'is_created': <function JitsiConference.is_created>, 'diagnose': <function JitsiConference.diagnose>, '_probe_stream': <function JitsiConference._probe_stream>, '__aenter__': <function JitsiConference.__aenter__>, '__aexit__': <function JitsiConference.__aexit__>, '__static_attributes__': ('_anonymous_domain', '_connection', '_muc_domain', 'conference_url', 'timeout'), '__dict__': <attribute '__dict__' of 'JitsiConference' objects>, '__weakref__': <attribute '__weakref__' of 'JitsiConference' objects>, '__annotations__': {}})
- __firstlineno__ = 50
- __init__(conference_url, nick=None, *, name=None, anonymous_domain=None, muc_domain=None, timeout=10)[source]
- __module__ = 'inspect_jitsi.xmpp.conference'
- __static_attributes__ = ('_anonymous_domain', '_connection', '_muc_domain', 'conference_url', 'timeout')
- __weakref__
list of weak references to the object
- async diagnose()[source]
Probe the server and report what's needed to read this room's occupancy.
Unlike
open(), this never joins the room - it checks whether /config.js was readable, which internal domains it advertises, whether the XMPP domain is actually served over the WebSocket endpoint, which SASL mechanisms it offers, and whether anonymous login succeeds (i.e. whether a token/JWT is required).- Return type:
- async get_participants()[source]
Return the participants currently known to be in the conference.
- Return type:
- async is_created()[source]
Return whether this room currently exists, without joining it.
Jitsi's MUC returns a forbidden disco#info error for a room that exists (disco is restricted to occupants) but item-not-found for one that hasn't been created yet (or was destroyed once everyone left) - this tells the two apart without joining.
- Raises:
inspect_jitsi.xmpp.JitsiConnectionError – the XMPP connection failed or was lost (refused, dropped, timed out, or an unparseable server response) - not raised for a room that simply doesn't exist, which is reported as False.
- Return type:
- property nick: str
The MUC nickname this conference is (or will be) joined under.
- property room: str
The room name, e.g. "SomeRoomName".
- exception inspect_jitsi.JitsiConnectionError[source]
Bases:
ConnectionErrorTalking to a Jitsi deployment's XMPP endpoint failed or was lost.
Covers everything below the room-existence/participant-roster level - the WebSocket connection being refused, dropped, or timing out, and a server response this hand-rolled client can't parse - as well as the protocol-level rejections (stream errors, failed SASL, a failed MUC join) this module raises as it negotiates a session. Catch this (or the plain ConnectionError it subclasses) instead of guessing at every stdlib/websockets exception a live XMPP session might raise.
- __firstlineno__ = 126
- __module__ = 'inspect_jitsi.xmpp.connection'
- __static_attributes__ = ()
- __weakref__
list of weak references to the object
- class inspect_jitsi.JitsiXmppConnection(conference_url, nick=None, *, name=None, anonymous_domain=None, muc_domain=None, timeout=10)[source]
Bases:
objectAn anonymous XMPP/MUC connection, joined to one Jitsi Meet room.
Connects over the WebSocket endpoint the Jitsi web client itself uses, joins the room's MUC under the given nickname (disclosing name as its XEP-0172 display name, if given - no display name is disclosed by default), and keeps a live roster of the other participants (updated as they join/leave for as long as the connection stays open).
Use as an async context manager:
async with JitsiXmppConnection(conference_url, "probe") as conn: print(await conn.get_participant_count())
or call
open()/close()directly.- async __aenter__()[source]
- Return type:
Self
- __annotations__ = {'_occupant_jid': 'str | None', '_participants': 'dict[str, Participant]', '_reader_task': 'asyncio.Task | None', '_ws': 'websockets.ClientConnection | None', 'error': 'Exception | None', 'room_created': 'bool | None'}
- __dict__ = mappingproxy({'__module__': 'inspect_jitsi.xmpp.connection', '__firstlineno__': 332, '__doc__': 'An anonymous XMPP/MUC connection, joined to one Jitsi Meet room.\n\nConnects over the WebSocket endpoint the Jitsi web client itself uses,\njoins the room\'s MUC under the given nickname (disclosing `name` as its\nXEP-0172 display name, if given - no display name is disclosed by\ndefault), and keeps a live roster of the other participants (updated as\nthey join/leave for as long as the connection stays open).\n\nUse as an async context manager::\n\n async with JitsiXmppConnection(conference_url, "probe") as conn:\n print(await conn.get_participant_count())\n\nor call :meth:`open`/:meth:`close` directly.\n', '__init__': <function JitsiXmppConnection.__init__>, 'ws': <property object>, 'open': <function JitsiXmppConnection.open>, '_read_loop': <function JitsiXmppConnection._read_loop>, '_handle_presence': <function JitsiXmppConnection._handle_presence>, 'close': <function JitsiXmppConnection.close>, 'other_participants': <function JitsiXmppConnection.other_participants>, 'get_participants': <function JitsiXmppConnection.get_participants>, 'get_participant_count': <function JitsiXmppConnection.get_participant_count>, '__aenter__': <function JitsiXmppConnection.__aenter__>, '__aexit__': <function JitsiXmppConnection.__aexit__>, '__static_attributes__': ('_anonymous_domain', '_focus_seen', '_joined', '_muc_domain', '_occupant_jid', '_participants', '_reader_task', '_ws', 'changed', 'conference_url', 'ended', 'error', 'name', 'nick', 'room', 'room_closed', 'room_created', 'timeout', 'ws_domain'), '__dict__': <attribute '__dict__' of 'JitsiXmppConnection' objects>, '__weakref__': <attribute '__weakref__' of 'JitsiXmppConnection' objects>, '__annotations__': {'_ws': 'websockets.ClientConnection | None', '_occupant_jid': 'str | None', '_participants': 'dict[str, Participant]', '_reader_task': 'asyncio.Task | None', 'error': 'Exception | None', 'room_created': 'bool | None'}})
- __firstlineno__ = 332
- __init__(conference_url, nick=None, *, name=None, anonymous_domain=None, muc_domain=None, timeout=10)[source]
- __module__ = 'inspect_jitsi.xmpp.connection'
- __static_attributes__ = ('_anonymous_domain', '_focus_seen', '_joined', '_muc_domain', '_occupant_jid', '_participants', '_reader_task', '_ws', 'changed', 'conference_url', 'ended', 'error', 'name', 'nick', 'room', 'room_closed', 'room_created', 'timeout', 'ws_domain')
- __weakref__
list of weak references to the object
- _participants: dict[str, Participant]
- async _read_loop()[source]
Continuously update the roster from incoming presence stanzas.
Waits without a timeout - a quiet room is normal here; a dead connection is detected by the WebSocket's own keepalive pings.
- Return type:
- _reader_task: Task | None
- _ws: ClientConnection | None
- changed
Set whenever the roster changes or the connection ends. Callers clear it themselves after they've looked at the new state.
- ended
Set once the background reader stops (room closed or connection lost).
- async get_participant_count()[source]
Return the number of participants currently in the room.
- Return type:
- async get_participants()[source]
Return the participants currently known to be in the room.
- Return type:
- async open()[source]
Connect, authenticate anonymously, and join the room's MUC.
If the room doesn't exist yet and this deployment restricts room creation to privileged users, this still succeeds - room_created is set to False and the room is treated as empty (no participants), rather than raising.
- Return type:
- other_participants()[source]
The participants known to be in the room, in the order they joined.
Not counting this connection itself. Synchronous, unlike
get_participants().- Return type:
- room_closed
the MUC removed us (room destroyed, we were kicked) or jicofo, the conference focus, left it.
- Type:
True once the room is known to be over
- room_created: bool | None
Whether the room existed to join. None before open().
False means the room didn't exist yet (or was destroyed once everyone left) and this deployment restricts room creation to privileged users (jicofo) - not a genuine failure, just an empty room: open() still succeeds, with no participants.
- property ws: ClientConnection
The underlying WebSocket connection.
None before
open()is called and afterclose()- accessing it in either state is a bug, so it raises instead of silently returning None.
- class inspect_jitsi.Participant(jid, nick, name=None, role=None, affiliation=None, real_jid=None, occupant_id=None)[source]
Bases:
objectOne occupant of a room, parsed from their MUC presence stanza.
- __annotations__ = {'affiliation': 'str | None', 'jid': 'str', 'name': 'str | None', 'nick': 'str', 'occupant_id': 'str | None', 'real_jid': 'str | None', 'role': 'str | None'}
- __dataclass_fields__ = {'affiliation': Field(name='affiliation',type='str | None',default=None,default_factory=<dataclasses._MISSING_TYPE object>,init=True,repr=True,hash=None,compare=True,metadata=mappingproxy({}),kw_only=False,_field_type=_FIELD), 'jid': Field(name='jid',type='str',default=<dataclasses._MISSING_TYPE object>,default_factory=<dataclasses._MISSING_TYPE object>,init=True,repr=True,hash=None,compare=True,metadata=mappingproxy({}),kw_only=False,_field_type=_FIELD), 'name': Field(name='name',type='str | None',default=None,default_factory=<dataclasses._MISSING_TYPE object>,init=True,repr=True,hash=None,compare=True,metadata=mappingproxy({}),kw_only=False,_field_type=_FIELD), 'nick': Field(name='nick',type='str',default=<dataclasses._MISSING_TYPE object>,default_factory=<dataclasses._MISSING_TYPE object>,init=True,repr=True,hash=None,compare=True,metadata=mappingproxy({}),kw_only=False,_field_type=_FIELD), 'occupant_id': Field(name='occupant_id',type='str | None',default=None,default_factory=<dataclasses._MISSING_TYPE object>,init=True,repr=True,hash=None,compare=True,metadata=mappingproxy({}),kw_only=False,_field_type=_FIELD), 'real_jid': Field(name='real_jid',type='str | None',default=None,default_factory=<dataclasses._MISSING_TYPE object>,init=True,repr=True,hash=None,compare=True,metadata=mappingproxy({}),kw_only=False,_field_type=_FIELD), 'role': Field(name='role',type='str | None',default=None,default_factory=<dataclasses._MISSING_TYPE object>,init=True,repr=True,hash=None,compare=True,metadata=mappingproxy({}),kw_only=False,_field_type=_FIELD)}
- __dataclass_params__ = _DataclassParams(init=True,repr=True,eq=True,order=False,unsafe_hash=False,frozen=True,match_args=True,kw_only=False,slots=False,weakref_slot=False)
- __delattr__(name)
Implement delattr(self, name).
- __dict__ = mappingproxy({'__module__': 'inspect_jitsi.xmpp.participant', '__firstlineno__': 31, '__annotations__': {'jid': 'str', 'nick': 'str', 'name': 'str | None', 'role': 'str | None', 'affiliation': 'str | None', 'real_jid': 'str | None', 'occupant_id': 'str | None'}, '__doc__': 'One occupant of a room, parsed from their MUC presence stanza.', 'name': None, 'role': None, 'affiliation': None, 'real_jid': None, 'occupant_id': None, 'from_presence': <classmethod(<function Participant.from_presence>)>, 'to_dict': <function Participant.to_dict>, 'to_json': <function Participant.to_json>, '__static_attributes__': (), '__dict__': <attribute '__dict__' of 'Participant' objects>, '__weakref__': <attribute '__weakref__' of 'Participant' objects>, '__dataclass_params__': _DataclassParams(init=True,repr=True,eq=True,order=False,unsafe_hash=False,frozen=True,match_args=True,kw_only=False,slots=False,weakref_slot=False), '__dataclass_fields__': {'jid': Field(name='jid',type='str',default=<dataclasses._MISSING_TYPE object>,default_factory=<dataclasses._MISSING_TYPE object>,init=True,repr=True,hash=None,compare=True,metadata=mappingproxy({}),kw_only=False,_field_type=_FIELD), 'nick': Field(name='nick',type='str',default=<dataclasses._MISSING_TYPE object>,default_factory=<dataclasses._MISSING_TYPE object>,init=True,repr=True,hash=None,compare=True,metadata=mappingproxy({}),kw_only=False,_field_type=_FIELD), 'name': Field(name='name',type='str | None',default=None,default_factory=<dataclasses._MISSING_TYPE object>,init=True,repr=True,hash=None,compare=True,metadata=mappingproxy({}),kw_only=False,_field_type=_FIELD), 'role': Field(name='role',type='str | None',default=None,default_factory=<dataclasses._MISSING_TYPE object>,init=True,repr=True,hash=None,compare=True,metadata=mappingproxy({}),kw_only=False,_field_type=_FIELD), 'affiliation': Field(name='affiliation',type='str | None',default=None,default_factory=<dataclasses._MISSING_TYPE object>,init=True,repr=True,hash=None,compare=True,metadata=mappingproxy({}),kw_only=False,_field_type=_FIELD), 'real_jid': Field(name='real_jid',type='str | None',default=None,default_factory=<dataclasses._MISSING_TYPE object>,init=True,repr=True,hash=None,compare=True,metadata=mappingproxy({}),kw_only=False,_field_type=_FIELD), 'occupant_id': Field(name='occupant_id',type='str | None',default=None,default_factory=<dataclasses._MISSING_TYPE object>,init=True,repr=True,hash=None,compare=True,metadata=mappingproxy({}),kw_only=False,_field_type=_FIELD)}, '__replace__': <function _replace>, '__hash__': <function Participant.__hash__>, '__init__': <function Participant.__init__>, '__repr__': <function Participant.__repr__>, '__eq__': <function Participant.__eq__>, '__setattr__': <function Participant.__setattr__>, '__delattr__': <function Participant.__delattr__>, '__match_args__': ('jid', 'nick', 'name', 'role', 'affiliation', 'real_jid', 'occupant_id')})
- __eq__(other)
Return self==value.
- __firstlineno__ = 31
- __hash__()
Return hash(self).
- __init__(jid, nick, name=None, role=None, affiliation=None, real_jid=None, occupant_id=None)
- __match_args__ = ('jid', 'nick', 'name', 'role', 'affiliation', 'real_jid', 'occupant_id')
- __module__ = 'inspect_jitsi.xmpp.participant'
- __replace__(**changes)
- __repr__()
Return repr(self).
- __setattr__(name, value)
Implement setattr(self, name, value).
- __static_attributes__ = ()
- __weakref__
list of weak references to the object
- classmethod from_presence(presence)[source]
Build a Participant from a MUC <presence/> stanza.
- Return type:
- jid: str
The MUC occupant JID, e.g. "room@muc.example.com/<nick-resource>".
- nick: str
The MUC nickname - the resourcepart of jid.
- occupant_id: str | None = None
Stable per-session anonymous id (XEP occupant-id), if disclosed.
Unlike jid/nick, this stays the same for one occupant across the conference even where the MUC nick is a random per-join identifier - useful for telling "still the same person" from "someone new".
- inspect_jitsi.diagnose_jitsi_access(conference_url, timeout=10)[source]
Probe a Jitsi deployment and report what's needed to read occupant counts.
See
inspect_jitsi.xmpp.JitsiConference.diagnose()for details.- Return type:
- async inspect_jitsi.discover_hosts(domain, timeout=10)[source]
Read
https://<domain>/config.jsto find the real XMPP/MUC domains.A Jitsi deployment's internal domain names often differ from the public hostname (e.g. docker-jitsi-meet defaults to "meet.jitsi" internally). Returns a dict with keys "domain", "muc", "anonymousdomain" - any of which may be None if not found.
- inspect_jitsi.get_participant_count(conference_url, nick=None, name=None, anonymous_domain=None, muc_domain=None, timeout=10)[source]
Return the number of participants currently in a Jitsi Meet room.
- Parameters:
conference_url (
str) – e.g. "https://meet.example.com/SomeRoomName".nick (
str|None) – the MUC nickname to join under. Random if not given.name (
str|None) – the display name (XEP-0172) to disclose when joining. No display name is disclosed if not given.anonymous_domain (
str|None) – override the XMPP domain used for stream/login. Auto-discovered from the site's /config.js if not given.muc_domain (
str|None) – override the MUC component domain (e.g. "muc.meet.jitsi" or "conference.example.com"). Auto-discovered if not given.timeout (
float) – seconds to wait for each network step.
- Return type:
- Returns:
Number of people already in the room, not counting this probe (0 if the room is empty).
- Raises:
inspect_jitsi.xmpp.JitsiConnectionError – the XMPP connection failed or was lost (refused, dropped, timed out, or an unparseable server response).
- inspect_jitsi.get_participants(conference_url, nick=None, name=None, anonymous_domain=None, muc_domain=None, timeout=10)[source]
Return the participants currently in a Jitsi Meet room.
- Parameters:
conference_url (
str) – e.g. "https://meet.example.com/SomeRoomName".nick (
str|None) – the MUC nickname to join under. Random if not given.name (
str|None) – the display name (XEP-0172) to disclose when joining. No display name is disclosed if not given.anonymous_domain (
str|None) – override the XMPP domain used for stream/login. Auto-discovered from the site's /config.js if not given.muc_domain (
str|None) – override the MUC component domain (e.g. "muc.meet.jitsi" or "conference.example.com"). Auto-discovered if not given.timeout (
float) – seconds to wait for each network step.
- Return type:
- Returns:
The participants already in the room, not counting this probe (empty if the room is empty).
- Raises:
inspect_jitsi.xmpp.JitsiConnectionError – the XMPP connection failed or was lost (refused, dropped, timed out, or an unparseable server response).
- inspect_jitsi.is_room_created(conference_url, anonymous_domain=None, muc_domain=None, timeout=10)[source]
Return whether a Jitsi Meet room currently exists, without joining it.
- Parameters:
conference_url (
str) – e.g. "https://meet.example.com/SomeRoomName".anonymous_domain (
str|None) – override the XMPP domain used for stream/login. Auto-discovered from the site's /config.js if not given.muc_domain (
str|None) – override the MUC component domain (e.g. "muc.meet.jitsi" or "conference.example.com"). Auto-discovered if not given.timeout (
float) – seconds to wait for each network step.
- Raises:
inspect_jitsi.xmpp.JitsiConnectionError – the XMPP connection failed or was lost (refused, dropped, timed out, or an unparseable server response) - not raised for a room that simply doesn't exist, which is reported as False.
- Return type:
- async inspect_jitsi.monitor_conference(conference_url, *, nick=None, name=None, anonymous_domain=None, muc_domain=None, timeout=60, connect_timeout=10, create=False, stay=False)[source]
Yield the room's state whenever it changes, until the room is closed.
A room that does not exist is not joined (joining could create it): a single state with
status.openfalse is yielded instead, unlesscreateis set.- Parameters:
conference_url (
str) – e.g. "https://meet.example.com/SomeRoomName".nick (
str|None) – the MUC nickname to join under. Random if not given.name (
str|None) – the display name (XEP-0172) to disclose when joining.anonymous_domain (
str|None) – override the XMPP domain. Auto-discovered if not given.muc_domain (
str|None) – override the MUC domain. Auto-discovered if not given.timeout (
float) – seconds to keep trying to reconnect after the connection is lost, before giving up. 0 disables reconnecting.connect_timeout (
float) – seconds to wait for each network step.create (
bool) – join the room even if it does not exist, which creates it on deployments that let anyone create rooms. Otherwise the existence of the room is checked before every join.stay (
bool) – keep monitoring when nobody else is in the room. Otherwise the room counts as closed - and the monitor leaves it - as soon as the monitor is the only one left in it.
- Raises:
ValueError – the conference URL cannot be parsed.
inspect_jitsi.xmpp.JitsiConnectionError – the first connection failed, or the connection was lost and could not be re-established within
timeoutseconds.
- Return type:
AsyncIterator[dict[str,Any]]
- inspect_jitsi.monitor_room(conference_url, nick=None, name=None, anonymous_domain=None, muc_domain=None, timeout=60, connect_timeout=10, create=False, stay=False)[source]
Yield the state of a Jitsi Meet room whenever it changes, until it is closed.
This is what
inspect-jitsi monitorprints, one dict per JSON line:for state in monitor_room("https://meet.example.com/SomeRoomName"): print(state["status"], len(state["participants"]))
Each dict has the keys
room,participants(a list, in the order they joined) andstatus(openandattempts). The first one is yielded once connected; the last one hasstatus["open"]false. Reconnecting after a lost connection only increasesstatus["attempts"].- Parameters:
conference_url (
str) – e.g. "https://meet.example.com/SomeRoomName".nick (
str|None) – the MUC nickname to join under. Random if not given.name (
str|None) – the display name (XEP-0172) to disclose when joining. No display name is disclosed if not given.anonymous_domain (
str|None) – override the XMPP domain used for stream/login. Auto-discovered from the site's /config.js if not given.muc_domain (
str|None) – override the MUC component domain. Auto-discovered if not given.timeout (
float) – seconds to keep trying to reconnect after the connection is lost, before giving up. 0 disables reconnecting.connect_timeout (
float) – seconds to wait for each network step.create (
bool) – join the room even if it does not exist, which creates it on deployments that let anyone create rooms. Otherwise a room that does not exist is reported as closed, without joining it.stay (
bool) – keep monitoring when nobody else is in the room. Otherwise the room counts as closed - and the monitor leaves it - as soon as the monitor is the only one left in it.
- Raises:
ValueError – the conference URL cannot be parsed.
inspect_jitsi.xmpp.JitsiConnectionError – the first connection failed, or the connection was lost and could not be re-established within
timeoutseconds.
- Return type: