import tkinter as tk from tkinter import ttk, messagebox from telethon import TelegramClient, events, sync from telethon.tl.functions.contacts import GetContactsRequest, ImportContactsRequest, DeleteContactsRequest, GetLocatedRequest, AddContactRequest from telethon.tl.types import InputPeerUser, InputPeerEmpty, UserStatusOffline, UserStatusRecently, UserStatusLastMonth, UserStatusLastWeek, InputGeoPoint from datetime import datetime, timedelta, timezone import asyncio import time import threading from tkintermapview import TkinterMapView # Ваши данные из my.telegram.org api_id = APP_ID api_hash = 'APP_HASH' phone_number = '+70000000' # Создаем клиент Telegram (вне функции main) client = TelegramClient("read_client", api_id=api_id, api_hash=api_hash, device_model="iPhone 55 Pro", system_version="IOS 100.1") # Время задержки между запросами к API Telegram delay_seconds = 1 # Ваш часовой пояс (в секундах) timezone_offset = 3 * 60 * 60 class App(tk.Tk): def __init__(self): super().__init__() self.title("Поиск пользователей Telegram") self.geometry("1024x800") # --- Разделение окна на фреймы --- top_frame = tk.Frame(self) top_frame.pack(side=tk.TOP, fill=tk.BOTH, expand=True) map_frame = tk.Frame(top_frame) map_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) input_frame = ttk.LabelFrame(top_frame, text="Координаты") input_frame.pack(side=tk.RIGHT, padx=10, pady=10, fill=tk.Y) results_frame = tk.Frame(self) results_frame.pack(fill=tk.BOTH, expand=True) # --- Конец разделения --- # Карта OpenStreetMap self.map_widget = TkinterMapView(map_frame, width=600, height=400, corner_radius=0) self.map_widget.pack(expand=True, fill=tk.BOTH) # --- Фрейм для координат и кнопки --- self.latitude = tk.StringVar(value="55.63729") self.longitude = tk.StringVar(value="37.88502") self.radius = tk.StringVar(value="500") latitude_fl = float(self.latitude.get()) longitude_fl = float(self.longitude.get()) self.map_widget.set_position(latitude_fl, longitude_fl) # Москва self.map_widget.set_zoom(18) # Маркер на карте self.marker = None # Обработчик клика по карте self.bind('', self.on_map_click) ttk.Label(input_frame, text="Широта:").grid(row=0, column=0, padx=5, pady=5) ttk.Entry(input_frame, textvariable=self.latitude).grid(row=0, column=1, padx=5, pady=5) ttk.Label(input_frame, text="Долгота:").grid(row=1, column=0, padx=5, pady=5) ttk.Entry(input_frame, textvariable=self.longitude).grid(row=1, column=1, padx=5, pady=5) ttk.Label(input_frame, text="Радиус поиска:").grid(row=2, column=0, padx=5, pady=5) ttk.Entry(input_frame, textvariable=self.radius).grid(row=2, column=1, padx=5, pady=5) ttk.Button(input_frame, text="Начать поиск", command=self.start_search).grid(row=3, column=0, columnspan=2, padx=5, pady=10) # --- Конец фрейма --- # --- Таблица для вывода результатов --- self.results_table = ttk.Treeview(results_frame, columns=("ID", "Расстояние", "Username", "Имя", "Фамилия", "Дата онлайна"), show="headings") self.results_table.heading("ID", text="ID") self.results_table.heading("Расстояние", text="Расстояние (м)") self.results_table.heading("Username", text="Username") self.results_table.heading("Имя", text="Имя") self.results_table.heading("Фамилия", text="Фамилия") self.results_table.heading("Дата онлайна", text="Дата онлайна") self.results_table.column("ID", width=100) self.results_table.column("Расстояние", width=100) self.results_table.column("Username", width=150) self.results_table.column("Имя", width=150) self.results_table.column("Фамилия", width=150) self.results_table.column("Дата онлайна", width=150) self.results_table.pack(fill=tk.BOTH, expand=True) # --- Конец таблицы --- def on_map_click(self, event): # Получаем координаты клика latitude = self.map_widget.get_position()[0] longitude = self.map_widget.get_position()[1] # Удаляем старый маркер, если он есть if self.marker: self.map_widget.delete(self.marker) # Создаем маркер на карте self.marker = self.map_widget.set_marker(latitude, longitude, text="Выбранное место") # Обновляем поля ввода self.latitude.set(str(latitude)) self.longitude.set(str(longitude)) def start_search(self): try: latitude = float(self.latitude.get()) longitude = float(self.longitude.get()) except ValueError: messagebox.showerror("Ошибка", "Неверный формат координат.") return # Очищаем таблицу перед новым поиском for item in self.results_table.get_children(): self.results_table.delete(item) # Запускаем асинхронную функцию поиска в отдельном потоке threading.Thread(target=self.run_search, args=(latitude, longitude), daemon=True).start() def run_search(self, latitude, longitude): try: asyncio.run(self.search_users(latitude, longitude)) except Exception as e: messagebox.showerror("Ошибка", f"Произошла ошибка: {e}") finally: messagebox.showinfo("Информация", "Поиск завершен.") async def search_users(self, latitude, longitude): # Подключаемся к Telegram await client.connect() client.session.save() # Авторизация if not await client.is_user_authorized(): await client.send_code_request(phone_number) # Введите код, полученный в Telegram me = await client.sign_in(phone_number, input('Введите код авторизации: ')) else: me = await client.get_me() try: users = await client(GetLocatedRequest( geo_point=InputGeoPoint( lat=latitude, long=longitude, accuracy_radius=100 ), self_expires=10 )) except Exception as e: messagebox.showerror("Ошибка", f"Ошибка при получении местоположений пользователей: {e}") await client.disconnect() return # print(users.stringify()) # Сохранение сырого ответа with open("raw_georequest.txt", "w", encoding="utf-8") as f2: f2.write(users.stringify()) for user in users.updates[0].peers: if hasattr(user, 'peer') and hasattr(user.peer, 'user_id'): await self.get_user_info(user) # Отключаемся от Telegram await client.disconnect() async def get_user_info(self, user): user_id = user.peer.user_id distance = user.distance if distance <= int(self.radius.get()): # Не дальше 600 метров await asyncio.sleep(delay_seconds) try: full_user = await client.get_entity(user_id) except Exception as e: messagebox.showerror("Ошибка", f"Ошибка при получении информации о пользователе {user_id}: {e}") return date_online_str = '' date_online = None last_month = datetime.now() - timedelta(days=30) last_week = datetime.now() - timedelta(days=7) if isinstance(full_user.status, UserStatusRecently): date_online_str = 'online' else: if isinstance(full_user.status, UserStatusLastMonth): date_online = last_month if isinstance(full_user.status, UserStatusLastWeek): date_online = last_week if isinstance(full_user.status, UserStatusOffline): date_online = full_user.status.was_online if date_online: date_online = date_online.replace(tzinfo=timezone.utc) + timedelta(seconds=timezone_offset) date_online_str = date_online.strftime("%d.%m.%Y %H:%M") # Добавление информации о пользователе в таблицу self.results_table.insert("", tk.END, values=( user_id, distance, full_user.username, full_user.first_name, full_user.last_name, date_online_str )) # Сохранение информации о пользователе в файл (по желанию) with open("nearby_users.txt", "a", encoding="utf-8") as f: f.write(f"ID: {user_id}, Имя пользователя: {full_user.username}, Имя: {full_user.first_name}, Фамилия: {full_user.last_name}, Дата онлайна: {date_online_str}\n") # Добавление пользователя в контакты (с задержкой) try: result = await client(AddContactRequest( id=user_id, first_name=full_user.first_name if full_user.first_name else "", last_name=full_user.last_name if full_user.last_name else "", phone=full_user.phone if full_user.phone else "", )) except Exception as e: messagebox.showerror("Ошибка", f"Ошибка при добавлении пользователя в контакты: {e}") if __name__ == "__main__": app = App() app.mainloop()