Profile Image

Samvadah bot

@samvadah

import os import datetime import pytz import json import logging from telegram import InlineKeyboardButton, InlineKeyboardMarkup, Update from telegram.ext import Application, CommandHandler, CallbackQueryHandler, MessageHandler, filters, ContextTypes from telethon.sync import TelegramClient # --- Configuration --- # It's highly recommended to use environment variables for sensitive data BOT_TOKEN = os.environ.get("BOT_TOKEN", "YOUR_BOT_TOKEN") API_ID = int(os.environ.get("API_ID", "YOUR_API_ID")) API_HASH = os.environ.get("API_HASH", "YOUR_API_HASH") SESSION_NAME = "telegram_bot_session" SOURCE_CHANNELS = { 'samvadah': 'samvadah', 'ramdootah': 'ramdootah' } USER_DATA_FILE = "user_data.json" AVOID_MESSAGE_ID = 8793 # The ID of the specific message to avoid from samvadah VAKYABHYAS_START_DATE = datetime.datetime(2024, 2, 8, tzinfo=pytz.UTC) # --- Logging --- logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO) logger = logging.getLogger(__name__) # --- User Data Management --- def get_default_user_config(): """Returns the default configuration for a new user.""" return { "daily_dose": True, "news_radio": True, "custom_hashtags": { "#Gita": {"count": 1, "time": "05:00"}, "#Quote": {"count": 1, "time": "10:00"}, "#Subhashitam": {"count": 1, "time": "12:00"}, "#Vakyabhyas": {"count": 1, "time": "14:00"}, "#Celebrating_Sanskrit": {"count": 1, "time": "15:00"}, "#Sanskritlessons": {"count": 1, "time": "16:00"}, "#hasya": {"count": 1, "time": "17:00"}, "#Viloma_Kavya": {"count": 1, "time": "18:00"} }, "news_filter": { "avoid_hashtags": { "#Akashvani": True, "#AkashVani_Text": True, "#Sudharma": True, "#Vruttantah": True, "#newsinsanskrit": True, "#newsaudio": True, "#saptahiki": True, "#mannkibaat": True, "#Panchangam": True, "#Career": True }, "avoid_youtube": True, "avoid_pdfs": True # New setting }, "timezone": "UTC", "state": None # To manage conversation state, e.g., 'awaiting_timezone' } def load_user_data(): try: with open(USER_DATA_FILE, "r") as f: return json.load(f) except (FileNotFoundError, json.JSONDecodeError): return {} def save_user_data(data): with open(USER_DATA_FILE, "w") as f: json.dump(data, f, indent=4) user_data = load_user_data() # --- Telethon Client --- # Using a context manager for the client is better for production client = TelegramClient(SESSION_NAME, API_ID, API_HASH) # --- Bot Handlers --- async def start(update: Update, context: ContextTypes.DEFAULT_TYPE): user_id = str(update.effective_chat.id) if user_id not in user_data: logger.info(f"New user or chat: {user_id}") user_data[user_id] = get_default_user_config() save_user_data(user_data) await show_main_menu(update, context) async def show_main_menu(update: Update, context: ContextTypes.DEFAULT_TYPE): """Displays the main menu.""" user_id = str(update.effective_chat.id) config = user_data.get(user_id, get_default_user_config()) keyboard = [ [InlineKeyboardButton(f"Daily dose {'✓' if config['daily_dose'] else '✗'}", callback_data='toggle_daily_dose')], [InlineKeyboardButton(f"News and radio {'✓' if config['news_radio'] else '✗'}", callback_data='toggle_news_radio')], [InlineKeyboardButton("Customise", callback_data='customise')], [InlineKeyboardButton(f"Time Zone ({config['timezone']})", callback_data='set_timezone')] ] reply_markup = InlineKeyboardMarkup(keyboard) text = "Welcome! Manage your content subscriptions below." if update.callback_query: await update.callback_query.edit_message_text(text, reply_markup=reply_markup) else: await update.message.reply_text(text, reply_markup=reply_markup) async def button_callback(update: Update, context: ContextTypes.DEFAULT_TYPE): """Parses all button presses.""" query = update.callback_query await query.answer() user_id = str(query.message.chat_id) # Simple Toggles if query.data == 'toggle_daily_dose': user_data[user_id]['daily_dose'] = not user_data[user_id]['daily_dose'] save_user_data(user_data) await show_main_menu(update, context) elif query.data == 'toggle_news_radio': user_data[user_id]['news_radio'] = not user_data[user_id]['news_radio'] save_user_data(user_data) await show_main_menu(update, context) # TODO: Add handlers for 'customise', 'set_timezone', and deeper menus # This part can get very complex with many states and callbacks. # For now, this structure is ready to be expanded. # --- Content Forwarding Logic --- async def fetch_and_forward_ramdootah(context: ContextTypes.DEFAULT_TYPE): """Checks ramdootah and forwards new messages based on user preferences.""" logger.info("Job started: fetch_and_forward_ramdootah") # In a real app, you'd store the ID of the last message forwarded per channel # to avoid sending duplicates. For example, in a simple file or database. last_id = 0 # Placeholder async with client: channel_entity = await client.get_entity(SOURCE_CHANNELS['ramdootah']) # Get recent messages, newer than the last one we processed messages = await client.get_messages(channel_entity, min_id=last_id, limit=20) if not messages: logger.info("No new messages from ramdootah.") return for message in reversed(messages): # Process oldest to newest for user_id, config in user_data.items(): if not config.get("news_radio", False): continue # --- Filtering Logic --- should_forward = True msg_text = message.text.lower() if message.text else "" filters = config.get("news_filter", {}) # 1. Filter by PDF if filters.get("avoid_pdfs", False) and message.document and 'application/pdf' in message.document.mime_type: should_forward = False logger.info(f"Skipping PDF for user {user_id}") # 2. Filter by YouTube if should_forward and filters.get("avoid_youtube", False) and ("youtube.com" in msg_text or "youtu.be" in msg_text): should_forward = False logger.info(f"Skipping YouTube link for user {user_id}") # 3. Filter by Hashtags if should_forward: for hashtag, is_avoided in filters.get("avoid_hashtags", {}).items(): if is_avoided and hashtag.lower() in msg_text: should_forward = False logger.info(f"Skipping message with hashtag {hashtag} for user {user_id}") break if should_forward: try: # This command forwards the message with the original channel's name. await context.bot.forward_message( chat_id=user_id, from_chat_id=f"@{SOURCE_CHANNELS['ramdootah']}", message_id=message.id ) except Exception as e: logger.error(f"Failed to forward message {message.id} to {user_id}: {e}") # Update last processed message ID here # last_id = message.id # TODO: Implement the scheduled 'fetch_and_forward_samvadah' job. # This would be more complex, as it needs to run for each user based on their # custom hashtag times and timezones. A simple daily job is not enough. # You would need a job that runs every minute, checks all users, and sees if # any scheduled post is due. def main(): """Start the bot.""" application = Application.builder().token(BOT_TOKEN).build() # Handlers application.add_handler(CommandHandler("start", start)) application.add_handler(CallbackQueryHandler(button_callback)) # --- Jobs --- job_queue = application.job_queue # Check for news from ramdootah every hour # Note: IST is UTC+5:30. The range 6AM-11PM IST corresponds to approx 00:30-17:30 UTC. # A simpler approach is to run it every hour and just forward if there's anything new. job_queue.run_repeating(fetch_and_forward_ramdootah, interval=3600, first=10) logger.info("Bot started and polling.") application.run_polling() if __name__ == '__main__': main()

Public Last updated: 2025-11-02 10:38:31 AM