Skip to content

Instantly share code, notes, and snippets.

@SpiritCroc
Last active September 4, 2020 14:08
Show Gist options
  • Save SpiritCroc/2905c50887a9de5790d790a943b15c0b to your computer and use it in GitHub Desktop.
Save SpiritCroc/2905c50887a9de5790d790a943b15c0b to your computer and use it in GitHub Desktop.
#!/usr/bin/env python3
# A script to set room-specific display names for your Matrix (-> https://matrix.org) account
# for all your joined rooms, depending on whether the room members are personal contacts or not.
# Requires the matrix-nio library.
#
# Before execution, adapt at least following values:
# - MY_HOMESERVER
# - MY_MX_ID
# - PERSONAL_SERVERS
# - PERSONAL_CONTACTS
# - PERSONAL_DISPLAY_NAME
# - DEFAULT_DISPLAY_NAME
import asyncio
import getpass
from colorama import Fore, Style
from nio import AsyncClient, MatrixRoom, RoomGetStateEventError
# Change these
MY_HOMESERVER = "https://myhomeserver.com"
MY_MX_ID = "@mxid:myhomeserver.com"
# All users in personal servers are automatically regarded as personal contacts
PERSONAL_SERVERS = [
"myhomeserver.com"
]
PERSONAL_CONTACTS = [
MY_MX_ID,
"@friend1:friend1-homeserver.org",
"@friend2:friend2-hs.com",
# + automatically include all from PERSONAL_SERVERS
]
# Name to use in rooms where only personal contacts are (except empty rooms)
PERSONAL_DISPLAY_NAME = "My name for personal contacts"
# Default display name
DEFAULT_DISPLAY_NAME = "My name for the rest of the internet"
# Names not included here are assumed manually set and will not be touched
MANAGED_DISPLAY_NAMES = [
PERSONAL_DISPLAY_NAME,
DEFAULT_DISPLAY_NAME,
]
SCRIPT_DEVICE_ID = "RENAMERSCR"
VERBOSE = False
class PlannedRename:
def __init__(self, room_id, room_name, old_name, new_name, old_avatar, new_avatar):
self.room_id = room_id
self.room_name = room_name
self.old_name = old_name
self.new_name = new_name
self.old_avatar = old_avatar
self.new_avatar = new_avatar
async def main():
client = AsyncClient(MY_HOMESERVER, MY_MX_ID, SCRIPT_DEVICE_ID)
passwd = getpass.getpass("Password: ")
await client.login(passwd)
# Sync fetches rooms
await client.sync()
planned_renames = []
max_room_name_len = 0
for room in client.rooms.values():
room_id = room.room_id
max_room_name_len = max(max_room_name_len, len(room.display_name))
myroomnick = room.user_name(MY_MX_ID)
myavatarurl = room.avatar_url(MY_MX_ID)
nick_change_allowed = myroomnick in MANAGED_DISPLAY_NAMES
print("ROOM {} {} {}".format(room.display_name, room_id, myroomnick if nick_change_allowed else (Fore.MAGENTA + myroomnick + Style.RESET_ALL)))
if not nick_change_allowed:
print(" => skip")
continue
member_response = await client.joined_members(room_id = room_id)
members = member_response.members
if len(members) <= 1:
print(" Ignore: {} members".format(len(members)))
room_is_personal = True
for member in members:
member_name = member.display_name
member_id = member.user_id
whitelisted = False
for allowed_server in PERSONAL_SERVERS:
if member_id.count(":") == 1 and member_id.endswith(":{}".format(allowed_server)):
whitelisted = True
break
if not whitelisted:
whitelisted = member_id in PERSONAL_CONTACTS
if VERBOSE:
print(" {} {} {}".format("ok" if whitelisted else "--", member_name, member_id))
room_is_personal = room_is_personal and whitelisted
if room_is_personal:
new_name = PERSONAL_DISPLAY_NAME
else:
new_name = DEFAULT_DISPLAY_NAME
# TODO support avatar changes
if myroomnick == new_name:
print(" => keep {}".format(myroomnick))
else:
print(f" => {Fore.YELLOW}{myroomnick}{Style.RESET_ALL} -> {Fore.CYAN}{new_name}{Style.RESET_ALL}")
planned_renames.append(PlannedRename(room_id=room_id, room_name=room.display_name, old_name=myroomnick, new_name=new_name, old_avatar=myavatarurl, new_avatar=myavatarurl))
print("-"*42)
print("Planned renames:")
room_format = "{{:<{}}}".format(max_room_name_len)
for pr in planned_renames:
room_name = room_format.format(pr.room_name)
print(f"{room_name} | {pr.old_name} -> {pr.new_name}")
print("-"*42)
input("Enter to rename")
for pr in planned_renames:
room_id = pr.room_id
# Compare https://github.com/matrix-org/matrix-react-sdk/blob/7c4a84aae0b764842fadd38237c1a857437c4f51/src/SlashCommands.tsx#L274
# https://github.com/matrix-org/matrix-doc/blob/8eb1c531442093d239ab35027d784c4d9cfc8ac9/specification/client_server_api.rst#L1975
# https://github.com/matrix-org/matrix-doc/blob/9281d0ca13c39b83b8bbba184c8887d3d4faf045/event-schemas/schema/m.room.member
# https://github.com/matrix-org/matrix-doc/blob/370ae8b9fe873b3ce061e4a8dbd7cf836388d640/event-schemas/examples/m.room.member
# https://github.com/poljar/matrix-nio/blob/41636f04c14ffede01cf31abc309615b16ac949b/nio/client/async_client.py#L1570
# TODO support avatar changes
content = {
"membership": "join",
"displayname": pr.new_name
#"avatar_url": pr.new_avatar
}
print(f"{pr.room_name}: {content}")
result = await client.room_put_state(room_id = room_id, event_type = "m.room.member", content = content, state_key = MY_MX_ID)
if VERBOSE:
print(result)
await client.logout()
await client.close()
asyncio.get_event_loop().run_until_complete(main())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment