add conversion for stickers

This commit is contained in:
rambros 2026-03-12 00:48:26 +05:30
parent 706852e425
commit 700f8f8ec4
2 changed files with 75 additions and 13 deletions

View file

@ -257,7 +257,6 @@ async def migrate_messages(
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:
@ -265,25 +264,53 @@ async def migrate_messages(
logger.debug(f"Determined sticker extension: {ext}")
# Handle Lottie (json) -> Convert to GIF
# Fluxer: Convert animated stickers to WebP
# Lottie (json) → GIF (via lottie lib) → WebP (via Pillow)
if ext == 'lottie':
if HAS_LOTTIE:
try:
logger.debug(f"Converting Lottie sticker {s.name} to GIF...")
logger.debug(f"Converting Lottie sticker {s.name} to WebP...")
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")
gif_buf = io.BytesIO()
export_gif(animation, gif_buf)
gif_buf.seek(0)
# GIF → WebP via Pillow
from PIL import Image
img = Image.open(gif_buf)
webp_buf = io.BytesIO()
if getattr(img, 'n_frames', 1) > 1:
img.save(webp_buf, format='WEBP', save_all=True, loop=0)
else:
img.save(webp_buf, format='WEBP')
sticker_data = webp_buf.getvalue()
ext = 'webp'
logger.debug(f"Successfully converted Lottie sticker {s.name} to WebP")
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
logger.error(f"Failed to convert Lottie sticker {s.name} to WebP: {conv_err}")
ext = 'json'
else:
logger.warning(f"Lottie library not available, sending sticker {s.name} as raw JSON")
ext = 'json'
# APNG / GIF → WebP (via Pillow)
elif ext in ('apng', 'gif'):
try:
logger.debug(f"Converting {ext.upper()} sticker {s.name} to WebP...")
from PIL import Image
img = Image.open(io.BytesIO(sticker_data))
webp_buf = io.BytesIO()
if getattr(img, 'n_frames', 1) > 1:
img.save(webp_buf, format='WEBP', save_all=True, loop=0)
else:
img.save(webp_buf, format='WEBP')
sticker_data = webp_buf.getvalue()
ext = 'webp'
logger.debug(f"Successfully converted sticker {s.name} to WebP")
except Exception as conv_err:
logger.error(f"Failed to convert {ext.upper()} sticker {s.name} to WebP: {conv_err}")
# Keep original format as fallback
filename = f"sticker_{s.name}_{s.id}.{ext}"
files.append({"filename": filename, "data": sticker_data})
stats["attachments"] += 1

View file

@ -260,7 +260,6 @@ async def migrate_messages(
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:
@ -268,7 +267,8 @@ async def migrate_messages(
logger.debug(f"Determined sticker extension: {ext}")
# Handle Lottie (json) -> Convert to GIF
# Stoat: Convert animated stickers to GIF
# Lottie (json) → GIF (via lottie lib)
if ext == 'lottie':
if HAS_LOTTIE:
try:
@ -282,11 +282,46 @@ async def migrate_messages(
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
ext = 'json'
else:
logger.warning(f"Lottie library not available, sending sticker {s.name} as raw JSON")
ext = 'json'
# APNG → GIF (via Pillow, with proper frame disposal)
elif ext == 'apng':
try:
logger.debug(f"Converting APNG sticker {s.name} to GIF...")
from PIL import Image
img = Image.open(io.BytesIO(sticker_data))
gif_buf = io.BytesIO()
if getattr(img, 'n_frames', 1) > 1:
# Extract each frame onto a clean background to avoid overlap
frames = []
durations = []
for frame_idx in range(img.n_frames):
img.seek(frame_idx)
# Create fresh background and composite the frame
canvas = Image.new('RGBA', img.size, (0, 0, 0, 0))
frame = img.convert('RGBA')
canvas.paste(frame, (0, 0), frame)
# Convert to palette mode for GIF
frames.append(canvas.convert('RGBA'))
durations.append(img.info.get('duration', 100))
# Save with disposal=2 (clear frame before next)
frames[0].save(
gif_buf, format='GIF', save_all=True,
append_images=frames[1:], loop=0,
duration=durations, disposal=2, transparency=0
)
else:
img.save(gif_buf, format='GIF')
sticker_data = gif_buf.getvalue()
ext = 'gif'
logger.debug(f"Successfully converted APNG sticker {s.name} to GIF")
except Exception as conv_err:
logger.error(f"Failed to convert APNG sticker {s.name} to GIF: {conv_err}")
# Keep original apng as fallback
filename = f"sticker_{s.name}_{s.id}.{ext}"
files.append({"filename": filename, "data": sticker_data})
stats["attachments"] += 1