support for lottie json stickers
This commit is contained in:
parent
c60ad506df
commit
cae47b697c
5 changed files with 123 additions and 15 deletions
|
|
@ -18,6 +18,8 @@ def setup_logging():
|
|||
level=level,
|
||||
handlers=handlers
|
||||
)
|
||||
# Suppress PIL debug logs which are very noisy during Lottie conversion
|
||||
logging.getLogger('PIL').setLevel(logging.INFO)
|
||||
|
||||
def relaunch_in_terminal():
|
||||
"""Detects if running without a terminal on Linux and relaunches in one."""
|
||||
|
|
|
|||
|
|
@ -5,3 +5,6 @@ rich # Terminal formatting and rich text
|
|||
textual # Terminal UI framework
|
||||
PyYAML # YAML parsing and serialization
|
||||
pydantic # Data validation using Python type hints
|
||||
lottie # Lottie file manipulation and conversion
|
||||
Pillow # Image processing (required for GIF rendering)
|
||||
cairosvg # SVG rendering (required for Lottie conversion)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import discord
|
||||
import logging
|
||||
from typing import AsyncGenerator, Dict, Any
|
||||
from typing import AsyncGenerator, Dict, Any, Union
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -227,9 +227,44 @@ class DiscordReader:
|
|||
"""Downloads a Discord emoji into memory."""
|
||||
return await emoji.read()
|
||||
|
||||
async def download_sticker(self, sticker: discord.GuildSticker) -> bytes:
|
||||
async def download_sticker(self, sticker: Union[discord.GuildSticker, discord.StickerItem]) -> bytes:
|
||||
"""Downloads a Discord sticker into memory."""
|
||||
return await sticker.read()
|
||||
logger.debug(f"Attempting to download sticker: {getattr(sticker, 'name', 'unknown')} (type: {type(sticker)})")
|
||||
|
||||
# 1. Try directly reading
|
||||
if hasattr(sticker, 'read'):
|
||||
try:
|
||||
return await sticker.read()
|
||||
except Exception as e:
|
||||
logger.debug(f"Direct read failed for sticker: {e}")
|
||||
|
||||
# 2. Try converting to full sticker (only for StickerItem)
|
||||
if hasattr(sticker, 'to_sticker'):
|
||||
try:
|
||||
logger.debug(f"Attempting to_sticker() for {getattr(sticker, 'name', 'unknown')}")
|
||||
full_sticker = await sticker.to_sticker()
|
||||
if hasattr(full_sticker, 'read'):
|
||||
return await full_sticker.read()
|
||||
except Exception as e:
|
||||
logger.debug(f"to_sticker fallback failed: {e}")
|
||||
|
||||
# 3. Try downloading from URL as last resort
|
||||
url = getattr(sticker, 'url', None)
|
||||
if url:
|
||||
try:
|
||||
import aiohttp
|
||||
logger.debug(f"Attempting URL download for sticker from {url}")
|
||||
async with aiohttp.ClientSession() as session:
|
||||
async with session.get(str(url)) as resp:
|
||||
if resp.status == 200:
|
||||
return await resp.read()
|
||||
else:
|
||||
logger.debug(f"URL download failed with status {resp.status}")
|
||||
except Exception as e:
|
||||
logger.debug(f"URL download failed for sticker: {e}")
|
||||
|
||||
logger.warning(f"Failed to download sticker {getattr(sticker, 'name', 'unknown')} after all attempts")
|
||||
return b""
|
||||
|
||||
async def download_attachment(self, attachment: discord.Attachment) -> bytes:
|
||||
"""Downloads a Discord attachment into memory."""
|
||||
|
|
|
|||
|
|
@ -1,8 +1,17 @@
|
|||
import asyncio
|
||||
import logging
|
||||
import re
|
||||
import json
|
||||
import io
|
||||
from typing import Callable, Awaitable, Dict, Any
|
||||
|
||||
try:
|
||||
from lottie.objects import Animation
|
||||
from lottie.exporters.gif import export_gif
|
||||
HAS_LOTTIE = True
|
||||
except ImportError:
|
||||
HAS_LOTTIE = False
|
||||
|
||||
from src.core.base import MigrationContext
|
||||
from src.core.utils import resolve_discord_links
|
||||
|
||||
|
|
@ -242,18 +251,43 @@ async def migrate_messages(
|
|||
sticker_data = await context.discord_reader.download_sticker(s)
|
||||
if sticker_data:
|
||||
# Use format to determine extension
|
||||
ext = getattr(s, 'format', 'png')
|
||||
if hasattr(ext, 'name'): # discord.py StickerFormat enum
|
||||
ext = ext.name
|
||||
format_val = getattr(s, 'format', 'png')
|
||||
logger.debug(f"Sticker {getattr(s, 'name', 'unknown')} format_val type: {type(format_val)}, value: {format_val}")
|
||||
|
||||
# Handle Lottie (json)
|
||||
if hasattr(format_val, 'name'): # discord.py StickerFormat enum
|
||||
ext = format_val.name.lower()
|
||||
elif isinstance(format_val, int):
|
||||
# Map common StickerFormat values if it's an int
|
||||
format_map = {1: 'png', 2: 'apng', 3: 'lottie', 4: 'gif'}
|
||||
ext = format_map.get(format_val, 'png')
|
||||
else:
|
||||
ext = str(format_val).lower()
|
||||
|
||||
logger.debug(f"Determined sticker extension: {ext}")
|
||||
|
||||
# Handle Lottie (json) -> Convert to GIF
|
||||
if ext == 'lottie':
|
||||
ext = 'json'
|
||||
if HAS_LOTTIE:
|
||||
try:
|
||||
logger.debug(f"Converting Lottie sticker {s.name} to GIF...")
|
||||
lottie_data = json.loads(sticker_data)
|
||||
animation = Animation.load(lottie_data)
|
||||
output = io.BytesIO()
|
||||
export_gif(animation, output)
|
||||
sticker_data = output.getvalue()
|
||||
ext = 'gif'
|
||||
logger.debug(f"Successfully converted Lottie sticker {s.name} to GIF")
|
||||
except Exception as conv_err:
|
||||
logger.error(f"Failed to convert Lottie sticker {s.name} to GIF: {conv_err}")
|
||||
ext = 'json' # Fallback to json if conversion fails
|
||||
else:
|
||||
logger.warning(f"Lottie library not available, sending sticker {s.name} as raw JSON")
|
||||
ext = 'json'
|
||||
|
||||
filename = f"sticker_{s.name}_{s.id}.{ext}"
|
||||
files.append({"filename": filename, "data": sticker_data})
|
||||
stats["attachments"] += 1
|
||||
logger.debug(f"Added sticker {s.name} as attachment")
|
||||
logger.debug(f"Added sticker {s.name} as attachment (extension: {ext})")
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to download sticker {getattr(s, 'name', 'unknown')}: {e}")
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,17 @@
|
|||
import asyncio
|
||||
import logging
|
||||
import re
|
||||
import json
|
||||
import io
|
||||
from typing import Callable, Awaitable, Dict, Any
|
||||
|
||||
try:
|
||||
from lottie.objects import Animation
|
||||
from lottie.exporters.gif import export_gif
|
||||
HAS_LOTTIE = True
|
||||
except ImportError:
|
||||
HAS_LOTTIE = False
|
||||
|
||||
from src.core.base import MigrationContext
|
||||
from src.core.utils import resolve_discord_links
|
||||
|
||||
|
|
@ -245,18 +254,43 @@ async def migrate_messages(
|
|||
sticker_data = await context.discord_reader.download_sticker(s)
|
||||
if sticker_data:
|
||||
# Use format to determine extension
|
||||
ext = getattr(s, 'format', 'png')
|
||||
if hasattr(ext, 'name'): # discord.py StickerFormat enum
|
||||
ext = ext.name
|
||||
format_val = getattr(s, 'format', 'png')
|
||||
logger.debug(f"Sticker {getattr(s, 'name', 'unknown')} format_val type: {type(format_val)}, value: {format_val}")
|
||||
|
||||
# Handle Lottie (json)
|
||||
if hasattr(format_val, 'name'): # discord.py StickerFormat enum
|
||||
ext = format_val.name.lower()
|
||||
elif isinstance(format_val, int):
|
||||
# Map common StickerFormat values if it's an int
|
||||
format_map = {1: 'png', 2: 'apng', 3: 'lottie', 4: 'gif'}
|
||||
ext = format_map.get(format_val, 'png')
|
||||
else:
|
||||
ext = str(format_val).lower()
|
||||
|
||||
logger.debug(f"Determined sticker extension: {ext}")
|
||||
|
||||
# Handle Lottie (json) -> Convert to GIF
|
||||
if ext == 'lottie':
|
||||
ext = 'json'
|
||||
if HAS_LOTTIE:
|
||||
try:
|
||||
logger.debug(f"Converting Lottie sticker {s.name} to GIF...")
|
||||
lottie_data = json.loads(sticker_data)
|
||||
animation = Animation.load(lottie_data)
|
||||
output = io.BytesIO()
|
||||
export_gif(animation, output)
|
||||
sticker_data = output.getvalue()
|
||||
ext = 'gif'
|
||||
logger.debug(f"Successfully converted Lottie sticker {s.name} to GIF")
|
||||
except Exception as conv_err:
|
||||
logger.error(f"Failed to convert Lottie sticker {s.name} to GIF: {conv_err}")
|
||||
ext = 'json' # Fallback to json if conversion fails
|
||||
else:
|
||||
logger.warning(f"Lottie library not available, sending sticker {s.name} as raw JSON")
|
||||
ext = 'json'
|
||||
|
||||
filename = f"sticker_{s.name}_{s.id}.{ext}"
|
||||
files.append({"filename": filename, "data": sticker_data})
|
||||
stats["attachments"] += 1
|
||||
logger.debug(f"Added sticker {s.name} as attachment")
|
||||
logger.debug(f"Added sticker {s.name} as attachment (extension: {ext})")
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to download sticker {getattr(s, 'name', 'unknown')}: {e}")
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue