fix gif embeds in shuttle mode
This commit is contained in:
parent
478c025754
commit
e9b87042e1
5 changed files with 20 additions and 92 deletions
|
|
@ -691,7 +691,6 @@ class BackupReader:
|
|||
def __init__(self, backup_path: str | Path):
|
||||
self.backup_path = Path(backup_path)
|
||||
self.guild: BackupGuild | None = None
|
||||
self.role_map: Dict[int, str] = {}
|
||||
|
||||
# Internal caches populated by start()
|
||||
self._categories: List[BackupCategory] = []
|
||||
|
|
@ -724,7 +723,6 @@ class BackupReader:
|
|||
if roles_file.exists():
|
||||
roles_data = json.loads(roles_file.read_text(encoding="utf-8"))
|
||||
self._roles = [BackupRole(r) for r in roles_data]
|
||||
self.role_map = {r.id: r.name for r in self._roles}
|
||||
logger.info(f"[Backup] Loaded {len(self._roles)} roles")
|
||||
|
||||
# 3. Structure -> categories + channels
|
||||
|
|
|
|||
|
|
@ -61,14 +61,6 @@ class DiscordReader:
|
|||
|
||||
self.guild: discord.Guild | None = None
|
||||
self.client: discord.Client | None = None
|
||||
self.role_map: Dict[int, str] = {}
|
||||
self.channel_name_map: Dict[int, str] = {}
|
||||
# Session-level caches to avoid redundant fetch calls
|
||||
self._roles_cache: list[discord.Role] | None = None
|
||||
self._channels_cache: list[discord.abc.GuildChannel] | None = None
|
||||
self._categories_cache: list[discord.CategoryChannel] | None = None
|
||||
self._emojis_cache: list[discord.Emoji] | None = None
|
||||
self._stickers_cache: list[discord.GuildSticker] | None = None
|
||||
|
||||
def _create_client(self):
|
||||
intents = discord.Intents.default()
|
||||
|
|
@ -86,6 +78,7 @@ class DiscordReader:
|
|||
await self.client.login(self.token)
|
||||
|
||||
# Use fetch methods specifically to bypass dependency on gateway cache
|
||||
# fetch_guild initializes the guild object needed for subsequent API calls
|
||||
try:
|
||||
logger.info(f"Fetching guild {self.server_id}...")
|
||||
self.guild = await self.client.fetch_guild(self.server_id)
|
||||
|
|
@ -93,32 +86,9 @@ class DiscordReader:
|
|||
except discord.Forbidden:
|
||||
logger.error(f"403 Forbidden: Missing Access to fetch guild {self.server_id}.")
|
||||
raise
|
||||
|
||||
# Pre-fetch roles via API - Handle Forbidden gracefully
|
||||
try:
|
||||
roles = await self.guild.fetch_roles()
|
||||
self.role_map = {r.id: r.name for r in roles}
|
||||
self._roles_cache = [r for r in roles if not r.is_default()]
|
||||
except discord.Forbidden:
|
||||
logger.warning("403 Forbidden: Missing Access to fetch roles. Continuing without role mapping.")
|
||||
self.role_map = {}
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to fetch roles: {e}")
|
||||
self.role_map = {}
|
||||
|
||||
# Pre-fetch channels via API
|
||||
try:
|
||||
channels = await self.guild.fetch_channels()
|
||||
self.channel_name_map = {c.id: c.name for c in channels}
|
||||
self._channels_cache = [c for c in channels if not isinstance(c, discord.CategoryChannel)]
|
||||
self._categories_cache = [c for c in channels if isinstance(c, discord.CategoryChannel)]
|
||||
logger.debug(f"Pre-fetched {len(self.channel_name_map)} channels")
|
||||
except discord.Forbidden:
|
||||
logger.warning("403 Forbidden: Missing Access to fetch channels. Continuing without channel name mapping.")
|
||||
self.channel_name_map = {}
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to fetch channels: {e}")
|
||||
self.channel_name_map = {}
|
||||
logger.error(f"Failed to fetch guild {self.server_id}: {e}")
|
||||
raise
|
||||
|
||||
async def validate(self) -> Dict[str, Any]:
|
||||
"""Validates the token, server ID, intents, and permissions."""
|
||||
|
|
@ -180,40 +150,27 @@ class DiscordReader:
|
|||
async def get_categories(self):
|
||||
if not self.guild:
|
||||
return []
|
||||
if self._categories_cache is not None:
|
||||
return self._categories_cache
|
||||
categories = await self.guild.fetch_channels()
|
||||
self._categories_cache = [c for c in categories if isinstance(c, discord.CategoryChannel)]
|
||||
return self._categories_cache
|
||||
return [c for c in categories if isinstance(c, discord.CategoryChannel)]
|
||||
|
||||
async def get_roles(self):
|
||||
"""Returns all roles in the server (excluding @everyone)."""
|
||||
if not self.guild:
|
||||
return []
|
||||
if self._roles_cache is not None:
|
||||
return self._roles_cache
|
||||
roles = await self.guild.fetch_roles()
|
||||
# Filter out default @everyone role which cannot typically be created
|
||||
self._roles_cache = [r for r in roles if not r.is_default()]
|
||||
return self._roles_cache
|
||||
return [r for r in roles if not r.is_default()]
|
||||
|
||||
async def get_emojis(self):
|
||||
"""Returns all custom emojis in the server."""
|
||||
if not self.guild:
|
||||
return []
|
||||
if self._emojis_cache is not None:
|
||||
return self._emojis_cache
|
||||
self._emojis_cache = await self.guild.fetch_emojis()
|
||||
return self._emojis_cache
|
||||
return await self.guild.fetch_emojis()
|
||||
|
||||
async def get_stickers(self):
|
||||
"""Returns all custom stickers in the server."""
|
||||
if not self.guild:
|
||||
return []
|
||||
if self._stickers_cache is not None:
|
||||
return self._stickers_cache
|
||||
self._stickers_cache = await self.guild.fetch_stickers()
|
||||
return self._stickers_cache
|
||||
return await self.guild.fetch_stickers()
|
||||
|
||||
async def get_members(self):
|
||||
"""Returns all members in the server."""
|
||||
|
|
@ -230,11 +187,9 @@ class DiscordReader:
|
|||
if not self.guild:
|
||||
return []
|
||||
|
||||
if self._channels_cache is None:
|
||||
channels = await self.guild.fetch_channels()
|
||||
self._channels_cache = [c for c in channels if not isinstance(c, discord.CategoryChannel)]
|
||||
all_channels = [c for c in channels if not isinstance(c, discord.CategoryChannel)]
|
||||
|
||||
all_channels = self._channels_cache
|
||||
if category_id:
|
||||
all_channels = [c for c in all_channels if c.category_id == category_id]
|
||||
return all_channels
|
||||
|
|
@ -284,11 +239,6 @@ class DiscordReader:
|
|||
client = self.client
|
||||
self.client = None # Atomic clear
|
||||
self.guild = None
|
||||
self._roles_cache = None
|
||||
self._channels_cache = None
|
||||
self._categories_cache = None
|
||||
self._emojis_cache = None
|
||||
self._stickers_cache = None
|
||||
if client:
|
||||
try:
|
||||
await client.close()
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ from src.core.utils import resolve_discord_links
|
|||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
def clean_mentions(content: str, guild, user_mentions=None, role_mentions=None, role_map=None, emoji_map=None, channel_map=None, discord_channel_map=None, state=None, target_server_id=None) -> str:
|
||||
def clean_mentions(content: str, guild, user_mentions=None, role_mentions=None, emoji_map=None, channel_map=None, state=None, target_server_id=None) -> str:
|
||||
if not content or not guild:
|
||||
return content
|
||||
|
||||
|
|
@ -47,10 +47,6 @@ def clean_mentions(content: str, guild, user_mentions=None, role_mentions=None,
|
|||
if role and role.name:
|
||||
return f"`@{role.name}`"
|
||||
|
||||
# 4. Try provided role map
|
||||
if role_map and rid in role_map:
|
||||
return f"`@{role_map[rid]}`"
|
||||
|
||||
return match.group(0)
|
||||
|
||||
def replace_channel(match):
|
||||
|
|
@ -61,13 +57,8 @@ def clean_mentions(content: str, guild, user_mentions=None, role_mentions=None,
|
|||
return f"<#{channel_map[str(cid)]}>"
|
||||
|
||||
# 2. Fallback to name in backticks
|
||||
# Try metadata map first (robust)
|
||||
if discord_channel_map and cid in discord_channel_map:
|
||||
return f"`#{discord_channel_map[cid]}`"
|
||||
|
||||
# Try cache
|
||||
channel = guild.get_channel(cid)
|
||||
return f"`{channel.name}`" if channel else f"<#{cid}>"
|
||||
return f"`#{channel.name}`" if channel else f"<#{cid}>"
|
||||
|
||||
def replace_emoji(match):
|
||||
animated = match.group(1) == "a"
|
||||
|
|
@ -196,10 +187,8 @@ async def migrate_messages(
|
|||
msg.guild,
|
||||
msg.mentions,
|
||||
msg.role_mentions,
|
||||
context.discord_reader.role_map,
|
||||
context.state.emoji_map,
|
||||
context.state.channel_map,
|
||||
context.discord_reader.channel_name_map,
|
||||
state=context.state,
|
||||
target_server_id=context.fluxer_writer.community_id
|
||||
)
|
||||
|
|
@ -229,10 +218,8 @@ async def migrate_messages(
|
|||
msg.guild,
|
||||
snapshot.mentions if hasattr(snapshot, 'mentions') else None,
|
||||
snapshot.role_mentions if hasattr(snapshot, 'role_mentions') else None,
|
||||
context.discord_reader.role_map,
|
||||
context.state.emoji_map,
|
||||
context.state.channel_map,
|
||||
context.discord_reader.channel_name_map,
|
||||
state=context.state,
|
||||
target_server_id=context.fluxer_writer.community_id
|
||||
)
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ from src.core.utils import resolve_discord_links
|
|||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
def clean_mentions(content: str, guild, user_mentions=None, role_mentions=None, role_map=None, emoji_map=None, channel_map=None, discord_channel_map=None, state=None, target_server_id=None) -> str:
|
||||
def clean_mentions(content: str, guild, user_mentions=None, role_mentions=None, emoji_map=None, channel_map=None, state=None, target_server_id=None) -> str:
|
||||
if not content or not guild:
|
||||
return content
|
||||
|
||||
|
|
@ -47,10 +47,6 @@ def clean_mentions(content: str, guild, user_mentions=None, role_mentions=None,
|
|||
if role and role.name:
|
||||
return f"`@{role.name}`"
|
||||
|
||||
# 4. Try provided role map
|
||||
if role_map and rid in role_map:
|
||||
return f"`@{role_map[rid]}`"
|
||||
|
||||
return match.group(0)
|
||||
|
||||
def replace_channel(match):
|
||||
|
|
@ -61,13 +57,8 @@ def clean_mentions(content: str, guild, user_mentions=None, role_mentions=None,
|
|||
return f"<#{channel_map[str(cid)]}>"
|
||||
|
||||
# 2. Fallback to name in backticks
|
||||
# Try metadata map first (robust)
|
||||
if discord_channel_map and cid in discord_channel_map:
|
||||
return f"`#{discord_channel_map[cid]}`"
|
||||
|
||||
# Try cache
|
||||
channel = guild.get_channel(cid)
|
||||
return f"`{channel.name}`" if channel else f"<#{cid}>"
|
||||
return f"`#{channel.name}`" if channel else f"<#{cid}>"
|
||||
|
||||
def replace_emoji(match):
|
||||
animated = match.group(1) == "a"
|
||||
|
|
@ -204,10 +195,8 @@ async def migrate_messages(
|
|||
msg.guild,
|
||||
msg.mentions,
|
||||
msg.role_mentions,
|
||||
context.discord_reader.role_map,
|
||||
context.state.emoji_map,
|
||||
context.state.channel_map,
|
||||
context.discord_reader.channel_name_map,
|
||||
state=context.state,
|
||||
target_server_id=context.stoat_writer.community_id
|
||||
)
|
||||
|
|
@ -233,10 +222,8 @@ async def migrate_messages(
|
|||
msg.guild,
|
||||
snapshot.mentions if hasattr(snapshot, 'mentions') else None,
|
||||
snapshot.role_mentions if hasattr(snapshot, 'role_mentions') else None,
|
||||
context.discord_reader.role_map,
|
||||
context.state.emoji_map,
|
||||
context.state.channel_map,
|
||||
context.discord_reader.channel_name_map,
|
||||
state=context.state,
|
||||
target_server_id=context.stoat_writer.community_id
|
||||
)
|
||||
|
|
|
|||
|
|
@ -337,7 +337,13 @@ class StoatWriter:
|
|||
# Stoat requires SendableEmbed objects, not raw dicts
|
||||
stoat_embeds = []
|
||||
if embeds:
|
||||
for e in embeds:
|
||||
for raw_embed in embeds:
|
||||
# Normalize embed to dict (handles both live discord.Embed and backup dicts)
|
||||
if hasattr(raw_embed, "to_dict"):
|
||||
e = raw_embed.to_dict()
|
||||
else:
|
||||
e = raw_embed
|
||||
|
||||
# Convert integer color to hex string if present
|
||||
color = None
|
||||
if e.get("color"):
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue