"""Sticker management utilities for Telegram bot.""" import logging from typing import List, Optional, Tuple, Dict, Any from telegram import InlineKeyboardMarkup, InlineKeyboardButton, Update from telegram.ext import ContextTypes from telegram.constants import StickerFormat from database import db from image_processor import process_image_for_sticker, validate_image logger = logging.getLogger(__name__) async def check_owner(update: Update) -> bool: """Check if user is the bot owner.""" from config import OWNER_ID user_id = update.effective_user.id return user_id == OWNER_ID async def check_premium_status(update: Update, context: ContextTypes.DEFAULT_TYPE) -> bool: """Check if user has Telegram Premium.""" user_id = update.effective_user.id # Get current user info from Telegram try: chat = await context.bot.get_chat(user_id) is_premium = bool(getattr(chat, 'is_premium', False)) # Update database await db.update_premium_status(user_id, is_premium) return is_premium except Exception as e: logger.error(f"Error checking premium status: {e}") # Fallback to cached status cached = await db.get_premium_status(user_id) return cached if cached is not None else False def get_main_menu_keyboard() -> InlineKeyboardMarkup: """Generate main menu keyboard.""" keyboard = [ [InlineKeyboardButton("➕ Neues Stickerpaket", callback_data="create_set")], [InlineKeyboardButton("📥 Existierendes hinzufügen", callback_data="add_existing")], [InlineKeyboardButton("📦 Meine Stickerpakete", callback_data="list_sets")], [InlineKeyboardButton("❓ Hilfe", callback_data="help")], ] return InlineKeyboardMarkup(keyboard) def get_set_action_keyboard(set_name: str) -> InlineKeyboardMarkup: """Generate keyboard for set actions.""" keyboard = [ [InlineKeyboardButton("➕ Sticker hinzufügen", callback_data=f"add_sticker:{set_name}")], [InlineKeyboardButton("🗑 Sticker löschen", callback_data=f"delete_sticker:{set_name}")], [InlineKeyboardButton("🏷 Emoji ändern", callback_data=f"change_emoji:{set_name}")], [InlineKeyboardButton("✏️ Paket umbenennen", callback_data=f"rename_set:{set_name}")], [InlineKeyboardButton("🗑 Paket löschen", callback_data=f"delete_set:{set_name}")], [InlineKeyboardButton("⬅️ Zurück", callback_data="back_to_menu")], ] return InlineKeyboardMarkup(keyboard) async def get_user_sets_keyboard(user_id: int) -> Tuple[Optional[InlineKeyboardMarkup], str]: """Generate keyboard with user's sticker sets.""" sets = await db.get_user_sticker_sets(user_id) if not sets: return None, "📭 Du hast noch keine Stickerpakete." keyboard = [] for s in sets: display_name = s['set_title'][:30] if s['set_title'] else s['set_name'] keyboard.append([InlineKeyboardButton( f"📦 {display_name}", callback_data=f"select_set:{s['set_name']}" )]) keyboard.append([InlineKeyboardButton("⬅️ Zurück", callback_data="back_to_menu")]) text = f"📦 **Deine Stickerpakete** ({len(sets)} total)\\n\\nWähle ein Paket:" return InlineKeyboardMarkup(keyboard), text async def create_sticker_set( update: Update, context: ContextTypes.DEFAULT_TYPE, name: str, title: str, sticker_file, emoji: str = "🤖" ) -> Tuple[bool, str]: """Create a new sticker set with automatic image processing.""" try: user_id = update.effective_user.id bot_username = context.bot.username set_name = f"{name}_by_{bot_username}" # Download the file file_obj = await sticker_file.download_as_bytearray() file_bytes = bytes(file_obj) # Validate image is_valid, error_msg = await validate_image(file_bytes) if not is_valid: return False, f"Invalid image: {error_msg}" # Process image for sticker format processed_image = await process_image_for_sticker(file_bytes) if not processed_image: return False, "Failed to process image. Please ensure it's a valid image file (PNG, JPG, WebP) and under 10MB." # Create sticker input with processed image from telegram import InputSticker sticker = InputSticker( sticker=processed_image, format=StickerFormat.STATIC, emoji_list=[emoji] ) # Create sticker set await context.bot.create_new_sticker_set( user_id=user_id, name=set_name, title=title, stickers=[sticker] ) # Track in database await db.add_sticker_set(user_id, set_name, title) return True, set_name except Exception as e: logger.error(f"Error creating sticker set: {e}") return False, str(e) async def add_sticker_to_set( update: Update, context: ContextTypes.DEFAULT_TYPE, set_name: str, sticker_file, emoji: str = "🤖" ) -> bool: """Add a sticker to existing set with automatic image processing.""" try: # Download and process the file file_obj = await sticker_file.download_as_bytearray() file_bytes = bytes(file_obj) # Validate image is_valid, error_msg = await validate_image(file_bytes) if not is_valid: logger.error(f"Invalid image for sticker: {error_msg}") return False # Process image for sticker format processed_image = await process_image_for_sticker(file_bytes) if not processed_image: logger.error("Failed to process image for sticker") return False from telegram import InputSticker sticker = InputSticker( sticker=processed_image, format=StickerFormat.STATIC, emoji_list=[emoji] ) await context.bot.add_sticker_to_set( user_id=update.effective_user.id, name=set_name, sticker=sticker ) return True except Exception as e: logger.error(f"Error adding sticker: {e}") return False async def add_video_sticker_to_set( update: Update, context: ContextTypes.DEFAULT_TYPE, set_name: str, webm_bytes: bytes, emoji: str = "🤖" ) -> bool: """Add a video sticker (WebM) to existing set.""" try: from telegram import InputSticker sticker = InputSticker( sticker=webm_bytes, format=StickerFormat.VIDEO, emoji_list=[emoji] ) await context.bot.add_sticker_to_set( user_id=update.effective_user.id, name=set_name, sticker=sticker ) return True except Exception as e: logger.error(f"Error adding video sticker: {e}") return False async def delete_sticker_from_set(update: Update, context: ContextTypes.DEFAULT_TYPE, sticker_file_id: str) -> bool: """Delete a sticker from a set.""" try: await context.bot.delete_sticker_from_set(sticker_file_id) await db.delete_sticker(sticker_file_id) return True except Exception as e: logger.error(f"Error deleting sticker: {e}") return False async def delete_sticker_set(update: Update, context: ContextTypes.DEFAULT_TYPE, set_name: str) -> bool: """Delete a sticker set.""" try: await context.bot.delete_sticker_set(set_name) await db.delete_sticker_set(set_name) return True except Exception as e: logger.error(f"Error deleting sticker set: {e}") return False async def rename_sticker_set(update: Update, context: ContextTypes.DEFAULT_TYPE, set_name: str, new_title: str) -> bool: """Rename a sticker set title.""" try: await context.bot.set_sticker_set_title(set_name, new_title) await db.rename_sticker_set(set_name, new_title) return True except Exception as e: logger.error(f"Error renaming sticker set: {e}") return False async def change_sticker_emoji(update: Update, context: ContextTypes.DEFAULT_TYPE, sticker_file_id: str, new_emoji: str) -> bool: """Change emoji of a sticker.""" try: await context.bot.set_sticker_emoji_list(sticker_file_id, [new_emoji]) return True except Exception as e: logger.error(f"Error changing sticker emoji: {e}") return False async def add_existing_sticker_set( update: Update, context: ContextTypes.DEFAULT_TYPE, set_name: str ) -> Tuple[bool, str]: """ Add an existing sticker set to the database. Args: set_name: Name of the sticker set (e.g., "my_stickers_by_mybot") Returns: Tuple of (success, message) """ try: # Try to get sticker set from Telegram sticker_set = await context.bot.get_sticker_set(set_name) if not sticker_set: return False, "Stickerpaket nicht gefunden." # Get set info title = sticker_set.title user_id = update.effective_user.id # Check if already in database existing_sets = await db.get_user_sticker_sets(user_id) if any(s['set_name'] == set_name for s in existing_sets): return False, "Dieses Stickerpaket ist bereits in deiner Liste." # Add to database await db.add_sticker_set(user_id, set_name, title) logger.info(f"Added existing sticker set '{set_name}' to database for user {user_id}") return True, f"Stickerpaket '{title}' wurde hinzugefügt!" except Exception as e: logger.error(f"Error adding existing sticker set: {e}") return False, f"Fehler: {str(e)}\n\nPrüfe, ob der Name korrekt ist und du Zugriff auf das Paket hast." async def schedule_premium_check(context: ContextTypes.DEFAULT_TYPE): """Scheduled job to check premium status periodically.""" from config import OWNER_ID, logger try: # Check owner's premium status chat = await context.bot.get_chat(OWNER_ID) is_premium = bool(getattr(chat, 'is_premium', False)) await db.update_premium_status(OWNER_ID, is_premium) logger.info(f"Premium check completed. Owner premium status: {is_premium}") except Exception as e: logger.error(f"Error in scheduled premium check: {e}")