{
    "api_id": "28385406",
    "api_hash": "fefea1b109f8f6b9a6205d16caba8daa",
    "session_name": "session_name",
    "json_file": "contracts.json",
    "bot_username": "@BloomSolana_bot",
    "channel_ids": [
      -1002381084695
    
  ]
}

import asyncio
import json
import re
from telethon import TelegramClient, events
from colorama import init, Fore
import datetime
import pytz
from collections import deque
import threading
from telethon.errors import PersistentTimestampOutdatedError
import pytesseract
from PIL import Image
import requests
from io import BytesIO
from telethon.tl import types

# Инициализация colorama для поддержки Windows
init(autoreset=True)

# Установите путь к исполняемому файлу Tesseract OCR (если необходимо)
pytesseract.pytesseract.tesseract_cmd = r'C:\Program Files\Tesseract-OCR\tesseract.exe'  # Убедитесь, что путь верный

# Загружаем настройки из файла config.json
def load_config():
    with open('config.json', 'r') as file:
        return json.load(file)

# Загружаем конфигурацию
config = load_config()

# Настройки из конфигурации
api_id = config['api_id']
api_hash = config['api_hash']
session_name = config['session_name']
json_file = config['json_file']
bot_username = config['bot_username']
channel_usernames = config['channel_ids']  # Список каналов для парсинга

# Создание клиента
client = TelegramClient(session_name, api_id, api_hash)

# Хранилище для последних 5 сообщений (с использованием deque для удобства)
last_5_messages = deque(maxlen=5)

# Блокировка для синхронизации доступа к данным
contracts_lock = threading.Lock()

# Хранилище для обработанных сообщений
processed_messages = set()

# Функция для загрузки обработанных сообщений из файла
def load_processed_messages():
    try:
        with open('processed_messages.json', 'r') as file:
            return set(json.load(file))  # Загружаем уже обработанные ID сообщений
    except FileNotFoundError:
        return set()  # Если файла нет, возвращаем пустое множество

# Функция для сохранения обработанных сообщений в файл
def save_processed_messages():
    with open('processed_messages.json', 'w') as file:
        json.dump(list(processed_messages), file)

# Функция для загрузки контрактов из файла JSON
def load_contracts():
    try:
        with open(json_file, 'r') as file:
            return json.load(file)
    except FileNotFoundError:
        return {}

# Функция для сохранения контрактов в JSON файл
def save_contracts(contracts):
    with open(json_file, 'w') as file:
        json.dump(contracts, file, indent=4)

# Функция для извлечения контрактов из текста
def extract_contracts(text):
    # Паттерн для поиска адресов контрактов
    pattern_address = r'\b[A-Za-z0-9]{32,44}\b'  # Регулярное выражение для поиска адресов
    pattern_url = r'https://dexscreener\\.com/solana/([A-Za-z0-9]{32,44})'
    pattern_pumpfun = r'https://pump\\.fun/coin/([A-Za-z0-9]{32,44})'
    pattern_exclude = r'^0x[A-Fa-f0-9]{40}$'  # Исключаем контракты начинающиеся с "0x"

    # Ищем все совпадения с адресами и ссылками
    addresses = re.findall(pattern_address, text)
    urls = re.findall(pattern_url, text)
    pumpfun_urls = re.findall(pattern_pumpfun, text)

    # Собираем все найденные контракты
    contracts = addresses + urls + pumpfun_urls

    # Фильтруем контракты, исключая те, что соответствуют "0x..." типу
    contracts = [contract for contract in contracts if not re.match(pattern_exclude, contract)]

    return contracts

# Функция для получения текущего времени в формате YYYY-MM-DD HH:MM:SS
def get_current_time():
    return datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')

# Функция для переподключения клиента в случае ошибок
async def safe_connect():
    try:
        if not client.is_connected():
            print(f"{Fore.CYAN}{get_current_time()} - {Fore.YELLOW}Connecting to Telegram client...")
            await client.connect()
            print(f"{Fore.CYAN}{get_current_time()} - {Fore.GREEN}Connected to Telegram client.")
    except PersistentTimestampOutdatedError:
        print(f"{Fore.CYAN}{get_current_time()} - {Fore.RED}PersistentTimestampOutdatedError occurred. Reconnecting...")
        await client.disconnect()
        await asyncio.sleep(2)  # Подождем 2 секунды перед переподключением
        await safe_connect()

# Функция для скачивания изображения и распознавания текста
def extract_contract_from_image(image_url):
    try:
        # Скачиваем изображение
        response = requests.get(image_url)
        image = Image.open(BytesIO(response.content))

        # Применяем OCR для извлечения текста с изображения
        extracted_text = pytesseract.image_to_string(image)

        # Извлекаем контракты из текста
        contracts = extract_contracts(extracted_text)

        return contracts
    except Exception as e:
        print(f"{Fore.RED}{get_current_time()} - Error extracting contract from image: {e}")
        return []

# Функция для парсинга старых сообщений за последние 7 дней
async def parse_old_messages():
    seven_days_ago = datetime.datetime.now(pytz.utc) - datetime.timedelta(days=14)
    print(f"{Fore.CYAN}{get_current_time()} - {Fore.YELLOW}Seven days ago: {Fore.WHITE}{seven_days_ago}")

    # Загружаем текущие контракты
    existing_contracts = load_contracts()

    # Перебираем каналы
    for channel in channel_usernames:
        print(f"{Fore.CYAN}{get_current_time()} - {Fore.YELLOW}Parsing messages from channel {Fore.GREEN}{channel}...")

        try:
            # Подключаемся к клиенту
            await safe_connect()

            new_contracts_count = 0
            async for message in client.iter_messages(channel, limit=10000):
                if message.text:
                    # Приводим дату сообщения к UTC
                    if message.date.tzinfo is None:
                        message_date = message.date.replace(tzinfo=pytz.utc)
                    else:
                        message_date = message.date

                    if message_date > seven_days_ago:
                        contracts = extract_contracts(message.text)
                        for contract in contracts:
                            if contract not in existing_contracts:
                                existing_contracts[contract] = {"status": "old"}
                                new_contracts_count += 1

            # Сохраняем обновленные контракты
            save_contracts(existing_contracts)

            print(f"{Fore.CYAN}{get_current_time()} - {Fore.GREEN}Finished parsing {Fore.CYAN}{channel}{Fore.GREEN}. {Fore.MAGENTA}{new_contracts_count} new contracts added.")
        except Exception as e:
            print(f"{Fore.CYAN}{get_current_time()} - {Fore.RED}Error parsing {Fore.CYAN}{channel}: {Fore.WHITE}{e}")

# Обработчик новых сообщений
sent_contracts = set()

@client.on(events.NewMessage(chats=channel_usernames))  # Убираем target_channel
async def new_message_handler(event):
    text = event.message.text
    channel_name = event.chat.username
    sender_username = None

    # Проверка на наличие sender (возможно, сообщение от бота или без username)
    if event.sender:
        sender_username = event.sender.username  # Получаем username отправителя
    else:
        print(f"{Fore.YELLOW}{get_current_time()} - Warning: Sender is None for message in {Fore.CYAN}{channel_name}")
        return  # Если отправитель не найден, пропускаем сообщение

    if text:
        # Если текст сообщения содержит контракты, обрабатываем их
        contracts = extract_contracts(text)
        if contracts:
            existing_contracts = load_contracts()
            new_contracts = [contract for contract in contracts if contract not in existing_contracts]

            if new_contracts:
                with contracts_lock:
                    existing_contracts.update({contract: {"status": "new"} for contract in new_contracts})
                    save_contracts(existing_contracts)

                # Убираем дублирующие контракты
                new_contracts_to_send = []
                for contract in new_contracts:
                    if contract not in sent_contracts:
                        new_contracts_to_send.append(contract)
                        sent_contracts.add(contract)  # Добавляем контракт в список отправленных

                if new_contracts_to_send:
                    # Отправляем только новые контракты
                    message = f"New contracts found in {channel_name}: {', '.join(new_contracts_to_send)}"
                    await client.send_message(bot_username, message)

                    print(f"{get_current_time()}{Fore.YELLOW} - Contracts from {Fore.CYAN}{channel_name}{Fore.YELLOW} sent to bot: {Fore.GREEN}{', '.join(new_contracts_to_send)}")
    
    # Обработка изображений
    if event.message.media:
        # Если сообщение содержит изображение, пытаемся извлечь из него контракты
        if isinstance(event.message.media, types.MessageMediaPhoto):
            image_url = await event.message.download()  # Скачиваем изображение
            contracts = extract_contract_from_image(image_url)
            
            if contracts:
                existing_contracts = load_contracts()
                new_contracts = [contract for contract in contracts if contract not in existing_contracts]

                if new_contracts:
                    with contracts_lock:
                        existing_contracts.update({contract: {"status": "new"} for contract in new_contracts})
                        save_contracts(existing_contracts)

                    # Убираем дублирующие контракты
                    new_contracts_to_send = []
                    for contract in new_contracts:
                        if contract not in sent_contracts:
                            new_contracts_to_send.append(contract)
                            sent_contracts.add(contract)  # Добавляем контракт в список отправленных

                    if new_contracts_to_send:
                        # Отправляем только новые контракты
                        message = f"New contracts found in image from {channel_name}: {', '.join(new_contracts_to_send)}"
                        await client.send_message(bot_username, message)

                        print(f"{get_current_time()}{Fore.YELLOW} - Contracts from image in {Fore.CYAN}{channel_name}{Fore.YELLOW} sent to bot: {Fore.GREEN}{', '.join(new_contracts_to_send)}")

# Функция запуска меню
async def menu():
    while True:
        print(f"\n{Fore.CYAN}{get_current_time()} - \n{Fore.YELLOW}1 - Parse old messages\n{Fore.YELLOW}2 - Start monitoring new messages\n{Fore.RED}3 - Exit")
        choice = input(f"{Fore.CYAN}{get_current_time()} - {Fore.YELLOW}Choose an option: ")

        if choice == '1':
            await parse_old_messages()  # Запускаем парсинг старых сообщений
        elif choice == '2':
            await safe_connect()  # Переподключаемся перед запуском мониторинга
            await client.start()
            print(f"{Fore.CYAN}{get_current_time()} - {Fore.GREEN}Monitoring started.")
            await asyncio.Event().wait()  # Блокируем выполнение потока, пока клиент работает
        elif choice == '3':
            print(f"{Fore.CYAN}{get_current_time()} - {Fore.RED}Exiting...")
            break
        else:
            print(f"{Fore.RED}Invalid choice. Please select 1, 2, or 3.")

# Основная функция
async def main():
    await menu()

if __name__ == '__main__':
    asyncio.run(main())


добавь првоерку что бы контракт отправлялся боту в телегарм только от определенных пользвателей например:
канал1-пользователь1, пользователь2