Загрузка данных


#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
STALCRAFT Auction Bot - Улучшенная версия с удобной настройкой
"""

import sys
import os
import json
import time
import threading
import tkinter as tk
from tkinter import ttk, messagebox

# Проверка и установка зависимостей
def install_package(package):
    import subprocess
    subprocess.check_call([sys.executable, "-m", "pip", "install", package])

try:
    import pyautogui
    import pytesseract
    from PIL import ImageGrab, Image
    import keyboard
except ImportError as e:
    print(f"Устанавливаю зависимости...")
    install_package("pyautogui")
    install_package("pytesseract")
    install_package("Pillow")
    install_package("keyboard")
    print("Зависимости установлены. Перезапустите программу.")
    sys.exit(1)

class Config:
    def __init__(self):
        self.search_text = ""
        self.max_price = 100000
        self.pages_count = 3
        self.use_pages = True
        self.test_mode = True
        self.auto_buy = False
        
        # Координаты
        self.coords = {
            'input': {'x': 0, 'y': 0},
            'refresh': {'x': 0, 'y': 0},
            'slider': {'x': 0, 'y': 0},
            'ok': {'x': 0, 'y': 0}
        }
        
        # OCR области
        self.ocr_areas = {
            'prices': {'x1': 0, 'y1': 0, 'x2': 0, 'y2': 0},
            'buy_btn': {'x1': 0, 'y1': 0, 'x2': 0, 'y2': 0},
            'pages': {'x1': 0, 'y1': 0, 'x2': 0, 'y2': 0}
        }
        
        self.ocr_lang = 'rus'
        self.ocr_scale = 200
        self.ocr_attempts = 3
        self.confidence_threshold = 70
        
    def save(self, filename='config.json'):
        try:
            with open(filename, 'w', encoding='utf-8') as f:
                json.dump(self.__dict__, f, indent=4, ensure_ascii=False)
            return True
        except:
            return False
            
    def load(self, filename='config.json'):
        try:
            if os.path.exists(filename):
                with open(filename, 'r', encoding='utf-8') as f:
                    data = json.load(f)
                    for key, value in data.items():
                        if hasattr(self, key):
                            setattr(self, key, value)
                return True
        except:
            pass
        return False

class CoordinatePicker:
    """Класс для выбора координат и областей на экране"""
    
    def __init__(self, root):
        self.root = root
        self.result = None
        self.running = False
        self.start_x = 0
        self.start_y = 0
        
    def pick_coordinate(self, callback):
        """Выбор одной координаты кликом"""
        self.root.iconify()
        time.sleep(0.5)
        
        # Создаем прозрачное окно для захвата клика
        picker = tk.Toplevel(self.root)
        picker.attributes('-fullscreen', True)
        picker.attributes('-alpha', 0.3)
        picker.configure(bg='black')
        picker.focus_set()
        
        # Инструкция
        label = tk.Label(picker, text="КЛИКНИТЕ ЛЕВОЙ КНОПКОЙ МЫШИ\nв нужном месте для установки координаты",
                        font=('Arial', 24, 'bold'),
                        fg='white', bg='black',
                        wraplength=800)
        label.place(relx=0.5, rely=0.1, anchor='center')
        
        # Переменная для результата
        result = {'x': 0, 'y': 0}
        
        def on_click(event):
            result['x'] = event.x_root
            result['y'] = event.y_root
            picker.destroy()
            self.root.deiconify()
            callback(result['x'], result['y'])
        
        def on_key(event):
            if event.keysym == 'Escape':
                picker.destroy()
                self.root.deiconify()
                callback(None, None)
        
        picker.bind('<Button-1>', on_click)
        picker.bind('<Key>', on_key)
        
        # Ждем закрытия окна
        self.root.wait_window(picker)
    
    def pick_area(self, callback):
        """Выбор области двумя кликами (левый верхний и правый нижний угол)"""
        self.root.iconify()
        time.sleep(0.5)
        
        # Создаем прозрачное окно
        picker = tk.Toplevel(self.root)
        picker.attributes('-fullscreen', True)
        picker.attributes('-alpha', 0.2)
        picker.configure(bg='black')
        picker.focus_set()
        
        # Инструкция
        label = tk.Label(picker, 
                        text="КЛИКНИТЕ ЛЕВОЙ КНОПКОЙ МЫШИ\nв ЛЕВОМ ВЕРХНЕМ УГЛУ области\n\n"
                             "Затем кликните в ПРАВОМ НИЖНЕМ УГЛУ области\n\n"
                             "Нажмите ESC для отмены",
                        font=('Arial', 20, 'bold'),
                        fg='white', bg='black',
                        wraplength=800)
        label.place(relx=0.5, rely=0.1, anchor='center')
        
        # Canvas для рисования прямоугольника
        canvas = tk.Canvas(picker, bg='white', highlightthickness=0)
        canvas.place(relx=0, rely=0, relwidth=1, relheight=1)
        
        # Переменные
        points = []
        rect = None
        
        def on_click(event):
            nonlocal rect, points
            
            x, y = event.x_root, event.y_root
            points.append((x, y))
            
            if len(points) == 2:
                # Вторая точка - завершаем
                x1, y1 = points[0]
                x2, y2 = points[1]
                
                # Убираем прямоугольник
                if rect:
                    canvas.delete(rect)
                
                # Сохраняем результат
                result = {
                    'x1': min(x1, x2),
                    'y1': min(y1, y2),
                    'x2': max(x1, x2),
                    'y2': max(y1, y2)
                }
                
                picker.destroy()
                self.root.deiconify()
                callback(result)
                
            else:
                # Первая точка - рисуем прямоугольник
                if rect:
                    canvas.delete(rect)
                rect = canvas.create_rectangle(x-5, y-5, x+5, y+5, outline='red', width=3)
        
        def on_motion(event):
            nonlocal rect
            if len(points) == 1:
                # Обновляем прямоугольник при движении мыши
                if rect:
                    canvas.delete(rect)
                x1, y1 = points[0]
                x2, y2 = event.x_root, event.y_root
                rect = canvas.create_rectangle(x1, y1, x2, y2, outline='red', width=2, fill='red', stipple='gray25')
        
        def on_key(event):
            if event.keysym == 'Escape':
                picker.destroy()
                self.root.deiconify()
                callback(None)
        
        picker.bind('<Button-1>', on_click)
        picker.bind('<Motion>', on_motion)
        picker.bind('<Key>', on_key)
        
        # Ждем закрытия окна
        self.root.wait_window(picker)

class OCRSimple:
    def __init__(self, config):
        self.config = config
        
    def extract_prices(self, image):
        """Извлечение цен из изображения"""
        try:
            # Масштабирование
            if self.config.ocr_scale != 100:
                scale = self.config.ocr_scale / 100
                width = int(image.width * scale)
                height = int(image.height * scale)
                image = image.resize((width, height), Image.Resampling.LANCZOS)
            
            # Конфиг для Tesseract
            custom_config = f'--psm 6 -c tessedit_char_whitelist=0123456789 '
            
            # Распознавание
            data = pytesseract.image_to_data(
                image,
                lang=self.config.ocr_lang,
                config=custom_config,
                output_type=pytesseract.Output.DICT
            )
            
            prices = []
            for i, text in enumerate(data['text']):
                text = text.strip()
                if text:
                    try:
                        conf = int(data['conf'][i])
                        if conf >= self.config.confidence_threshold:
                            clean = ''.join(filter(str.isdigit, text))
                            if clean and len(clean) >= 4:
                                price = int(clean)
                                if 1000 <= price <= 10000000:
                                    prices.append({
                                        'price': price,
                                        'confidence': conf,
                                        'bbox': (
                                            data['left'][i],
                                            data['top'][i],
                                            data['width'][i],
                                            data['height'][i]
                                        )
                                    })
                    except:
                        continue
            
            return prices
        except Exception as e:
            print(f"OCR ошибка: {e}")
            return []
    
    def find_text(self, image, keywords):
        """Поиск текста в изображении"""
        try:
            data = pytesseract.image_to_data(
                image,
                lang=self.config.ocr_lang,
                output_type=pytesseract.Output.DICT
            )
            
            for i, text in enumerate(data['text']):
                text_lower = text.lower().strip()
                for keyword in keywords:
                    if keyword in text_lower:
                        return {
                            'text': text,
                            'bbox': (
                                data['left'][i],
                                data['top'][i],
                                data['width'][i],
                                data['height'][i]
                            )
                        }
            return None
        except:
            return None

class AuctionBot:
    def __init__(self, config):
        self.config = config
        self.ocr = OCRSimple(config)
        self.running = False
        self.purchases = 0
        self.spent = 0
        self.status = "Готов"
        
        pyautogui.FAILSAFE = True
        pyautogui.PAUSE = 0.2
    
    def start(self):
        if self.running:
            return
        
        if not self.config.search_text:
            self.status = "Ошибка: не указан товар"
            return
        
        for key, coord in self.config.coords.items():
            if coord['x'] == 0 and coord['y'] == 0:
                self.status = f"Ошибка: не настроена координата {key}"
                return
        
        for key, area in self.config.ocr_areas.items():
            if area['x1'] == area['x2'] or area['y1'] == area['y2']:
                self.status = f"Ошибка: не настроена область {key}"
                return
        
        self.running = True
        self.status = "Запущен"
        
        thread = threading.Thread(target=self._run)
        thread.daemon = True
        thread.start()
    
    def stop(self):
        self.running = False
        self.status = "Остановлен"
    
    def _run(self):
        while self.running:
            try:
                self.status = "Ввод товара..."
                if not self._input_text():
                    time.sleep(2)
                    continue
                
                self.status = "Обновление списка..."
                if not self._refresh():
                    time.sleep(2)
                    continue
                
                self.status = "Поиск лотов..."
                if self._search_lots():
                    continue
                
                time.sleep(1)
                
            except Exception as e:
                self.status = f"Ошибка: {str(e)[:30]}"
                time.sleep(3)
    
    def _input_text(self):
        try:
            coords = self.config.coords['input']
            pyautogui.click(coords['x'], coords['y'])
            time.sleep(0.3)
            
            pyautogui.hotkey('ctrl', 'a')
            time.sleep(0.1)
            pyautogui.press('delete')
            time.sleep(0.1)
            
            pyautogui.write(self.config.search_text)
            time.sleep(0.2)
            return True
        except:
            return False
    
    def _refresh(self):
        try:
            coords = self.config.coords['refresh']
            pyautogui.click(coords['x'], coords['y'])
            time.sleep(2)
            return True
        except:
            return False
    
    def _search_lots(self):
        if self._check_page():
            return True
        
        for step in range(80, 401, 80):
            if not self.running:
                return False
            
            self._scroll(step)
            if self._check_page():
                return True
        
        if self.config.use_pages:
            for page in range(2, self.config.pages_count + 1):
                if not self.running:
                    return False
                
                if self._switch_page(page):
                    if self._check_page():
                        return True
        
        return False
    
    def _check_page(self):
        try:
            area = self.config.ocr_areas['prices']
            screenshot = ImageGrab.grab(bbox=(
                area['x1'], area['y1'],
                area['x2'], area['y2']
            ))
            
            prices = self.ocr.extract_prices(screenshot)
            
            if not prices:
                return False
            
            valid = [p for p in prices if p['price'] <= self.config.max_price]
            
            if not valid:
                return False
            
            best = min(valid, key=lambda x: x['price'])
            
            self.status = f"Найден лот: {best['price']:,}"
            
            if self.config.test_mode:
                return False
            
            if self.config.auto_buy:
                return self._buy(best)
            
            return False
            
        except Exception as e:
            print(f"Ошибка проверки: {e}")
            return False
    
    def _buy(self, price_data):
        try:
            area = self.config.ocr_areas['prices']
            bbox = price_data['bbox']
            
            click_x = area['x1'] + bbox[0] + bbox[2] // 2
            click_y = area['y1'] + bbox[1] + bbox[3] // 2
            
            pyautogui.click(click_x, click_y)
            time.sleep(0.5)
            
            if not self._click_buy_button():
                return False
            
            coords = self.config.coords['ok']
            pyautogui.click(coords['x'], coords['y'])
            time.sleep(0.5)
            
            self.purchases += 1
            self.spent += price_data['price']
            self.status = f"Куплено за {price_data['price']:,}"
            
            return True
            
        except Exception as e:
            print(f"Ошибка покупки: {e}")
            return False
    
    def _click_buy_button(self):
        try:
            area = self.config.ocr_areas['buy_btn']
            screenshot = ImageGrab.grab(bbox=(
                area['x1'], area['y1'],
                area['x2'], area['y2']
            ))
            
            result = self.ocr.find_text(screenshot, ['выкупить', 'купить', 'выкуп', 'лот'])
            
            if result:
                bbox = result['bbox']
                click_x = area['x1'] + bbox[0] + bbox[2] // 2
                click_y = area['y1'] + bbox[1] + bbox[3] // 2
                
                pyautogui.click(click_x, click_y)
                return True
            
            return False
            
        except:
            return False
    
    def _scroll(self, steps):
        try:
            coords = self.config.coords['slider']
            pyautogui.moveTo(coords['x'], coords['y'])
            pyautogui.mouseDown()
            pyautogui.moveTo(coords['x'], coords['y'] + steps, duration=0.3)
            pyautogui.mouseUp()
            time.sleep(0.5)
        except:
            pass
    
    def _switch_page(self, page):
        try:
            area = self.config.ocr_areas['pages']
            screenshot = ImageGrab.grab(bbox=(
                area['x1'], area['y1'],
                area['x2'], area['y2']
            ))
            
            custom_config = '--psm 6 -c tessedit_char_whitelist=0123456789'
            data = pytesseract.image_to_data(
                screenshot,
                config=custom_config,
                output_type=pytesseract.Output.DICT
            )
            
            for i, text in enumerate(data['text']):
                if text.strip() == str(page):
                    bbox = (
                        data['left'][i],
                        data['top'][i],
                        data['width'][i],
                        data['height'][i]
                    )
                    
                    click_x = area['x1'] + bbox[0] + bbox[2] // 2
                    click_y = area['y1'] + bbox[1] + bbox[3] // 2
                    
                    pyautogui.click(click_x, click_y)
                    time.sleep(1.5)
                    return True
            
            return False
            
        except:
            return False
    
    def get_stats(self):
        return {
            'purchases': self.purchases,
            'spent': self.spent,
            'status': self.status,
            'running': self.running
        }

class MainWindow:
    def __init__(self):
        self.root = tk.Tk()
        self.root.title("STALCRAFT Auction Bot")
        self.root.geometry("700x800")
        self.root.resizable(False, False)
        
        # Конфиг и бот
        self.config = Config()
        self.config.load()
        self.bot = AuctionBot(self.config)
        self.picker = CoordinatePicker(self.root)
        
        # Переменные для GUI
        self.coord_labels = {}
        self.area_labels = {}
        
        self._create_ui()
        self._update_status()
        
        self.root.protocol("WM_DELETE_WINDOW", self._on_close)
    
    def _create_ui(self):
        main = ttk.Frame(self.root, padding="10")
        main.pack(fill=tk.BOTH, expand=True)
        
        # Заголовок
        ttk.Label(main, text="STALCRAFT AUCTION BOT", 
                 font=('Arial', 16, 'bold')).pack(pady=(0, 10))
        
        # Основные настройки
        basic = ttk.LabelFrame(main, text="Основные настройки", padding="10")
        basic.pack(fill=tk.X, pady=5)
        
        # Товар
        row1 = ttk.Frame(basic)
        row1.pack(fill=tk.X, pady=2)
        ttk.Label(row1, text="Товар:", width=12).pack(side=tk.LEFT)
        self.search_var = tk.StringVar(value=self.config.search_text)
        ttk.Entry(row1, textvariable=self.search_var, width=30).pack(side=tk.LEFT, padx=5)
        
        # Цена
        row2 = ttk.Frame(basic)
        row2.pack(fill=tk.X, pady=2)
        ttk.Label(row2, text="Макс. цена:", width=12).pack(side=tk.LEFT)
        self.price_var = tk.StringVar(value=str(self.config.max_price))
        ttk.Entry(row2, textvariable=self.price_var, width=15).pack(side=tk.LEFT, padx=5)
        
        # Страницы
        row3 = ttk.Frame(basic)
        row3.pack(fill=tk.X, pady=2)
        ttk.Label(row3, text="Страниц:", width=12).pack(side=tk.LEFT)
        self.pages_var = tk.StringVar(value=str(self.config.pages_count))
        ttk.Entry(row3, textvariable=self.pages_var, width=8).pack(side=tk.LEFT, padx=5)
        
        self.use_pages_var = tk.BooleanVar(value=self.config.use_pages)
        ttk.Checkbutton(row3, text="Использовать страницы", 
                       variable=self.use_pages_var).pack(side=tk.LEFT, padx=10)
        
        # Координаты (улучшенная настройка)
        coord_frame = ttk.LabelFrame(main, text="Координаты (кликните для установки)", padding="10")
        coord_frame.pack(fill=tk.X, pady=5)
        
        coord_items = [
            ("Поле ввода", "input", "Кликните на поле ввода товара"),
            ("Обновить", "refresh", "Кликните на кнопку 'Обновить'"),
            ("Ползунок", "slider", "Кликните на ползунок прокрутки"),
            ("ОК", "ok", "Кликните на кнопку 'ОК' подтверждения")
        ]
        
        for i, (label, key, hint) in enumerate(coord_items):
            row = ttk.Frame(coord_frame)
            row.pack(fill=tk.X, pady=2)
            
            ttk.Label(row, text=f"{label}:", width=12).pack(side=tk.LEFT)
            
            coords = self.config.coords[key]
            self.coord_labels[key] = tk.StringVar(
                value=f"X={coords['x']} Y={coords['y']}" if coords['x'] != 0 else "Не установлена"
            )
            ttk.Label(row, textvariable=self.coord_labels[key], width=18).pack(side=tk.LEFT, padx=5)
            
            ttk.Button(row, text="Кликнуть", 
                      command=lambda k=key, h=hint: self._set_coord(k, h)).pack(side=tk.LEFT, padx=2)
        
        # OCR области (улучшенная настройка)
        ocr_frame = ttk.LabelFrame(main, text="OCR области (выделите область)", padding="10")
        ocr_frame.pack(fill=tk.X, pady=5)
        
        ocr_items = [
            ("Цены", "prices", "Выделите область с ценами на аукционе"),
            ("Кнопка выкупа", "buy_btn", "Выделите область кнопки 'Выкупить лот'"),
            ("Страницы", "pages", "Выделите область с номерами страниц")
        ]
        
        for i, (label, key, hint) in enumerate(ocr_items):
            row = ttk.Frame(ocr_frame)
            row.pack(fill=tk.X, pady=2)
            
            ttk.Label(row, text=f"{label}:", width=12).pack(side=tk.LEFT)
            
            area = self.config.ocr_areas[key]
            if area['x1'] == 0 and area['x2'] == 0:
                display = "Не установлена"
            else:
                display = f"({area['x1']},{area['y1']}) → ({area['x2']},{area['y2']})"
            
            self.area_labels[key] = tk.StringVar(value=display)
            ttk.Label(row, textvariable=self.area_labels[key], width=25).pack(side=tk.LEFT, padx=5)
            
            ttk.Button(row, text="Выделить", 
                      command=lambda k=key, h=hint: self._set_area(k, h)).pack(side=tk.LEFT, padx=2)
        
        # Управление
        control = ttk.Frame(main)
        control.pack(pady=10)
        
        ttk.Label(control, text="Режим:").pack(side=tk.LEFT, padx=5)
        self.mode_var = tk.StringVar(value="ТЕСТ" if self.config.test_mode else "ВКЛ")
        mode_combo = ttk.Combobox(control, textvariable=self.mode_var,
                                 values=['ТЕСТ', 'ВКЛ'], width=8, state='readonly')
        mode_combo.pack(side=tk.LEFT, padx=5)
        
        ttk.Button(control, text="Проверить OCR", 
                  command=self._test_ocr).pack(side=tk.LEFT, padx=5)
        
        self.start_btn = ttk.Button(control, text="▶ ЗАПУСК", 
                                   command=self._start_bot)
        self.start_btn.pack(side=tk.LEFT, padx=5)
        
        self.stop_btn = ttk.Button(control, text="■ СТОП", 
                                  command=self._stop_bot, state='disabled')
        self.stop_btn.pack(side=tk.LEFT, padx=5)
        
        # Статус
        status_frame = ttk.LabelFrame(main, text="Статус", padding="5")
        status_frame.pack(fill=tk.X, pady=5)
        
        self.status_var = tk.StringVar(value="Готов")
        ttk.Label(status_frame, textvariable=self.status_var, font=('Arial', 10)).pack()
        
        self.stats_var = tk.StringVar(value="Покупок: 0 | Потрачено: 0")
        ttk.Label(status_frame, textvariable=self.stats_var, font=('Arial', 9)).pack()
        
        # Сохранение
        save_frame = ttk.Frame(main)
        save_frame.pack(pady=10)
        
        ttk.Button(save_frame, text="Сохранить настройки", 
                  command=self._save_config).pack(side=tk.LEFT, padx=5)
        
        ttk.Button(save_frame, text="Загрузить настройки", 
                  command=self._load_config).pack(side=tk.LEFT, padx=5)
    
    def _set_coord(self, key, hint):
        """Установка координаты через клик"""
        # Показываем подсказку
        messagebox.showinfo("Настройка координаты", 
            f"Наведите мышь на элемент '{key}' и кликните левой кнопкой\n\n{hint}\n\nНажмите ESC для отмены")
        
        def callback(x, y):
            if x is not None and y is not None:
                self.config.coords[key]['x'] = x
                self.config.coords[key]['y'] = y
                self.coord_labels[key].set(f"X={x} Y={y}")
                messagebox.showinfo("Успех", f"Координата {key} установлена!\nX={x} Y={y}")
            else:
                messagebox.showinfo("Отмена", "Настройка отменена")
        
        self.picker.pick_coordinate(callback)
    
    def _set_area(self, key, hint):
        """Установка OCR области выделением"""
        messagebox.showinfo("Настройка OCR области", 
            f"Выделите область '{key}'\n\n{hint}\n\n"
            f"1. Кликните в ЛЕВОМ ВЕРХНЕМ углу\n"
            f"2. Кликните в ПРАВОМ НИЖНЕМ углу\n"
            f"Нажмите ESC для отмены")
        
        def callback(result):
            if result:
                self.config.ocr_areas[key] = result
                self.area_labels[key].set(
                    f"({result['x1']},{result['y1']}) → ({result['x2']},{result['y2']})"
                )
                messagebox.showinfo("Успех", f"Область {key} установлена!")
            else:
                messagebox.showinfo("Отмена", "Настройка отменена")
        
        self.picker.pick_area(callback)
    
    def _test_ocr(self):
        """Тест OCR"""
        area = self.config.ocr_areas['prices']
        if area['x1'] == area['x2'] or area['y1'] == area['y2']:
            messagebox.showwarning("Ошибка", "Сначала настройте область цен!")
            return
        
        try:
            screenshot = ImageGrab.grab(bbox=(
                area['x1'], area['y1'],
                area['x2'], area['y2']
            ))
            
            prices = self.bot.ocr.extract_prices(screenshot)
            
            result = "=== РЕЗУЛЬТАТЫ OCR ТЕСТА ===\n\n"
            result += f"Область: {area['x1']},{area['y1']} → {area['x2']},{area['y2']}\n"
            result += f"Язык: {self.config.ocr_lang}\n"
            result += f"Масштаб: {self.config.ocr_scale}%\n\n"
            
            if prices:
                result += f"Найдено цен: {len(prices)}\n\n"
                for p in prices[:10]:  # Показываем первые 10
                    result += f"{p['price']:,}  — {p['confidence']}%\n"
                
                if len(prices) > 10:
                    result += f"... и еще {len(prices) - 10} цен\n"
                
                valid = [p for p in prices if p['price'] <= self.config.max_price]
                if valid:
                    best = min(valid, key=lambda x: x['price'])
                    result += f"\nПодходящих: {len(valid)}\n"
                    result += f"Минимальная цена: {best['price']:,}"
                else:
                    result += f"\nПодходящих: 0\n"
                    result += f"Макс. цена: {self.config.max_price:,}"
            else:
                result += "❌ Цены не найдены!\n\n"
                result += "Возможные проблемы:\n"
                result += "1. Неправильно настроена область\n"
                result += "2. Некорректные параметры OCR\n"
                result += "3. Tesseract не установлен\n"
                result += "4. Плохое качество изображения"
            
            messagebox.showinfo("Тест OCR", result)
            
        except Exception as e:
            messagebox.showerror("Ошибка", f"Ошибка теста: {e}")
    
    def _start_bot(self):
        # Обновляем настройки
        self.config.search_text = self.search_var.get()
        try:
            self.config.max_price = int(self.price_var.get())
            self.config.pages_count = int(self.pages_var.get())
        except:
            messagebox.showerror("Ошибка", "Некорректное значение!")
            return
        
        self.config.use_pages = self.use_pages_var.get()
        self.config.test_mode = self.mode_var.get() == "ТЕСТ"
        self.config.auto_buy = self.mode_var.get() == "ВКЛ"
        
        self.bot.start()
        
        self.start_btn.config(state='disabled')
        self.stop_btn.config(state='normal')
    
    def _stop_bot(self):
        self.bot.stop()
        self.start_btn.config(state='normal')
        self.stop_btn.config(state='disabled')
    
    def _save_config(self):
        self.config.search_text = self.search_var.get()
        try:
            self.config.max_price = int(self.price_var.get())
            self.config.pages_count = int(self.pages_var.get())
        except:
            pass
        
        self.config.use_pages = self.use_pages_var.get()
        self.config.test_mode = self.mode_var.get() == "ТЕСТ"
        self.config.auto_buy = self.mode_var.get() == "ВКЛ"
        
        if self.config.save():
            messagebox.showinfo("Успех", "Настройки сохранены в config.json!")
        else:
            messagebox.showerror("Ошибка", "Не удалось сохранить настройки!")
    
    def _load_config(self):
        if self.config.load():
            # Обновляем GUI
            self.search_var.set(self.config.search_text)
            self.price_var.set(str(self.config.max_price))
            self.pages_var.set(str(self.config.pages_count))
            self.use_pages_var.set(self.config.use_pages)
            self.mode_var.set("ТЕСТ" if self.config.test_mode else "ВКЛ")
            
            # Обновляем координаты
            for key, coords in self.config.coords.items():
                if coords['x'] != 0 or coords['y'] != 0:
                    self.coord_labels[key].set(f"X={coords['x']} Y={coords['y']}")
                else:
                    self.coord_labels[key].set("Не установлена")
            
            # Обновляем OCR области
            for key, area in self.config.ocr_areas.items():
                if area['x1'] != 0 or area['x2'] != 0:
                    self.area_labels[key].set(
                        f"({area['x1']},{area['y1']}) → ({area['x2']},{area['y2']})"
                    )
                else:
                    self.area_labels[key].set("Не установлена")
            
            messagebox.showinfo("Успех", "Настройки загружены!")
        else:
            messagebox.showwarning("Ошибка", "Не удалось загрузить настройки!")
    
    def _update_status(self):
        try:
            stats = self.bot.get_stats()
            self.status_var.set(stats['status'])
            self.stats_var.set(f"Покупок: {stats['purchases']} | Потрачено: {stats['spent']:,}")
        except:
            pass
        
        self.root.after(1000, self._update_status)
    
    def _on_close(self):
        self.bot.stop()
        self.config.save()
        self.root.destroy()

if __name__ == "__main__":
    try:
        # Проверка Tesseract
        try:
            pytesseract.get_tesseract_version()
            print("Tesseract найден")
        except Exception as e:
            print(f"Tesseract не найден: {e}")
            messagebox.showwarning("Предупреждение", 
                "Tesseract OCR не найден!\n\n"
                "Установите Tesseract OCR:\n"
                "1. Скачайте: https://github.com/UB-Mannheim/tesseract/wiki\n"
                "2. Установите в C:\\Program Files\\Tesseract-OCR\\\n"
                "3. Перезапустите программу")
        
        app = MainWindow()
        app.root.mainloop()
        
    except Exception as e:
        print(f"Ошибка: {e}")
        import traceback
        traceback.print_exc()
        input("Нажмите Enter для выхода...")