import logging from dataclasses import dataclass from typing import List, Optional import discord log = logging.getLogger(__name__) @dataclass class Target: target_id: int target_type: str # "guild" | "group_dm" | "dm" name: str async def resolve_friend(client: discord.Client, friend_id: int) -> discord.User: """Fetch the target user object so we can display who the script is actually reacting to (helps catch a wrong/typo'd friend_id early).""" user = client.get_user(friend_id) if user is None: user = await client.fetch_user(friend_id) return user async def discover_targets( client: discord.Client, friend: discord.User, manual_guild_ids: Optional[List[int]] = None ) -> List[Target]: friend_id = friend.id targets: List[Target] = [] guild_ids_seen = set() try: profile = await friend.profile(with_mutual_guilds=True, with_mutual_friends=False, with_mutual_friends_count=False) for mutual in (profile.mutual_guilds or []): guild = client.get_guild(mutual.id) name = guild.name if guild else f"Unknown Guild {mutual.id}" targets.append(Target(mutual.id, "guild", name)) guild_ids_seen.add(mutual.id) except discord.NotFound: log.warning( "No mutual guild/friend relationship visible for user %s " "(profile lookup requires already being friends or sharing a server). " "Relying on manual_guild_ids and group DMs only.", friend_id, ) except discord.HTTPException: log.warning("Mutual-guilds profile lookup failed; falling back to manual_guild_ids only", exc_info=True) for guild_id in (manual_guild_ids or []): if guild_id in guild_ids_seen: continue guild = client.get_guild(guild_id) name = guild.name if guild else f"Manual Guild {guild_id}" targets.append(Target(guild_id, "guild", name)) guild_ids_seen.add(guild_id) try: dm_channel = friend.dm_channel or await friend.create_dm() targets.append(Target(dm_channel.id, "dm", f"DM with {friend}")) except discord.HTTPException: log.warning("Failed to open the 1:1 DM channel with %s", friend, exc_info=True) for channel in client.private_channels: if isinstance(channel, discord.GroupChannel) and any(u.id == friend_id for u in channel.recipients): name = channel.name or ", ".join(u.name for u in channel.recipients) targets.append(Target(channel.id, "group_dm", name)) return targets