I think this is how you do it with slixmpp 1.8

This commit is contained in:
James Shiffer 2025-02-12 00:59:58 -08:00
parent 904c9954b5
commit 36aa7dc663
5 changed files with 46 additions and 57 deletions

8
.idea/.gitignore vendored Normal file
View File

@ -0,0 +1,8 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

View File

@ -2,15 +2,15 @@ from setuptools import setup, find_packages
setup(
name = "xmpp_discord_bridge",
version = "0.1.0",
version = "0.2.0",
url = "https://git.polynom.me/PapaTutuWawa/xmpp-discord-bridge",
author = "Alexander \"PapaTutuWawa\"",
author_email = "papatutuwawa <at> polynom.me",
author = "scoliono",
author_email = "jshiffer@linux.ucla.edu",
license = "GPLc3",
packages = find_packages(),
install_requires = [
"requests==2.27.1",
"slixmpp==1.7.1",
"slixmpp==1.8.6",
"nextcord",
"toml==0.10.2"
],

View File

@ -14,6 +14,7 @@ import slixmpp
from slixmpp import Message
from slixmpp.componentxmpp import ComponentXMPP
from slixmpp.exceptions import XMPPError, IqError
from slixmpp.types import PresenceArgs
from slixmpp.xmlstream import register_stanza_plugin
from slixmpp.jid import JID
from nextcord import Status, Embed
@ -113,6 +114,7 @@ class BridgeComponent(ComponentXMPP):
pto="%s/%s" % (muc, "Bot"),
pfrom=self._bot_jid_full)
self._logger.info("Removed all users from MUCs, disconnecting...")
# Disconnect and close
await self.disconnect()
@ -147,10 +149,17 @@ class BridgeComponent(ComponentXMPP):
else:
self._guild_map[guild][channel] = muc
self._logger.debug("Joining %s", muc)
self.plugin["xep_0045"].join_muc(muc,
self._logger.info("Joining %s", muc)
presence_options = PresenceArgs(
pfrom=self._bot_jid_full,
)
self.send_presence()
await self.plugin["xep_0045"].join_muc_wait(muc,
nick=self._bot_nick,
pfrom=self._bot_jid_full)
presence_options=presence_options,
timeout=10)
self._logger.info("Joined %s as %s", muc, self._bot_jid_full)
# Set the subject
room_config = await self.plugin["xep_0045"].get_room_config(muc,
@ -163,10 +172,10 @@ class BridgeComponent(ComponentXMPP):
if not description or description != (dchannel.topic or ""):
should_update = True
room_config.set_values({
"muc#roomconfig_roomdesc": dchannel.topic or ""
"muc#roomconfig_roomdesc": dchannel.topic or "No topic"
})
self.plugin["xep_0045"].set_subject(muc,
dchannel.topic or "",
dchannel.topic or "No subject",
mfrom=self._bot_jid_full)
if not name or name != dchannel.name:
@ -191,29 +200,20 @@ class BridgeComponent(ComponentXMPP):
vcard = self.plugin["xep_0054"].make_vcard()
vcard["PHOTO"]["TYPE"] = "image/png"
vcard["PHOTO"]["BINVAL"] = base64.b64encode(req.content)
# TODO: Replace with provided API
self.send_raw("""
<iq type="set" from="{}" to="{}">
<vCard xmlns="vcard-temp">
{}
</vCard>
</iq>
""".format(self._bot_jid_full,
muc,
str(vcard)))
await self.plugin["xep_0054"].publish_vcard(vcard)
# Aquire a webhook
wh = None
for webhook in await dchannel.webhooks():
if webhook.name == "discord-xmpp-bridge":
if webhook.name == "xmpp-bridge":
if not webhook.is_authenticated():
_logger.info("Webhook for %s has no token. Deleting and recreating" % muc)
self._logger.info("Webhook for %s has no token. Deleting and recreating" % muc)
await webhook.delete(reason="Webhook has no token. Will recreate")
else:
wh = webhook
break
if not wh:
wh = await dchannel.create_webhook(name="discord-xmpp-bridge",
wh = await dchannel.create_webhook(name="xmpp-bridge",
reason="Bridging Discord and XMPP")
self._webhooks[muc] = wh
@ -229,7 +229,7 @@ class BridgeComponent(ComponentXMPP):
jid=bare_member_jid,
ifrom=self._bot_jid_full)
self.virtual_user_join_muc(muc, member, update_state_tracking=False)
await self.virtual_user_join_muc(muc, member, update_state_tracking=False)
self._logger.info("%s is ready", muc)
self._logger.info("Bridge is ready")
@ -276,8 +276,7 @@ class BridgeComponent(ComponentXMPP):
avatar_url=self._avatars.get_avatar_url(message["from"]),
embed=embed)
except Exception as err:
self._logger.error("Webhook execution failed: %s",
err)
self._logger.error("Webhook execution failed", exc_info=err)
def virtual_user_update_presence(self, muc, uid, pshow, pstatus=None):
"""
@ -289,7 +288,7 @@ class BridgeComponent(ComponentXMPP):
pto="%s/%s" % (muc, self._virtual_muc_nicks[muc][uid]),
pfrom=self.spoof_member_jid(uid))
def virtual_user_join_muc(self, muc, member, update_state_tracking=False):
async def virtual_user_join_muc(self, muc, member, update_state_tracking=False):
"""
Makes the a puppet of member (@discord.Member) join the
MUC. Does nothing if the member is offline.
@ -313,11 +312,16 @@ class BridgeComponent(ComponentXMPP):
if self._dont_ignore_offline:
pstatus = "Offline"
self.plugin["xep_0045"].join_muc(muc,
nick=member.display_name,
pfrom=self.spoof_member_jid(member.id),
pshow=pshow,
pstatus=pstatus)
presence = PresenceArgs(
pfrom=self.spoof_member_jid(member.id),
pshow=pshow,
pstatus=pstatus
)
await self.plugin["xep_0045"].join_muc_wait(muc,
nick=self._config["general"]["discord2xmpp_name_fmt"].format(
display_name=member.display_name
),
presence_options=presence)
async def on_discord_member_join(self, member):
guild = member.guild.id
@ -328,7 +332,7 @@ class BridgeComponent(ComponentXMPP):
member.display_name)
for channel in self._guild_map[guild]:
muc = self._guild_map[guild][channel]
self.virtual_user_join_muc(muc, member, update_state_tracking=True)
await self.virtual_user_join_muc(muc, member, update_state_tracking=True)
async def on_discord_member_leave(self, member):
guild = member.guild.id
@ -376,7 +380,7 @@ class BridgeComponent(ComponentXMPP):
self._virtual_muc_users[muc].remove(after.display_name)
del self._virtual_muc_nicks[muc][after.id]
elif before.status == Status.offline and after.status != Status.offline and not self._dont_ignore_offline:
self.virtual_user_join_muc(muc, after, update_state_tracking=True)
await self.virtual_user_join_muc(muc, after, update_state_tracking=True)
else:
self.virtual_user_update_presence(muc,
after.id,
@ -544,7 +548,7 @@ def main():
logging.basicConfig(stream=sys.stdout, level=verbosity)
xmpp.connect()
xmpp.process(forever=False)
xmpp.process(forever=True)
if __name__ == "__main__":
main()

View File

@ -1,23 +0,0 @@
aiodns==3.2.0
aiohappyeyeballs==2.4.6
aiohttp==3.11.12
aiosignal==1.3.2
attrs==25.1.0
certifi==2025.1.31
cffi==1.17.1
charset-normalizer==3.4.1
frozenlist==1.5.0
idna==3.10
multidict==6.1.0
nextcord==2.6.0
propcache==0.2.1
pyasn1==0.6.1
pyasn1_modules==0.4.1
pycares==4.5.0
pycparser==2.22
requests==2.32.3
slixmpp==1.8.6
toml==0.10.2
typing_extensions==4.12.2
urllib3==2.3.0
yarl==1.18.3