Как я создал Telegram-бота для хранения файлов и чуть не стал библиотекарем

в 12:15, , рубрики: python, Интерактивные клавиатуры, облачное хранилище, обмен файлами, Разработка ботов, файловая система, хранение файлов

Или история о том, как я превратил свой Telegram в файловую систему и почему мой компьютер теперь обижается на меня.


Всем привет! Сегодня я расскажу вам о том, как из обычного скучного дня вырос проект, который превратил мой Telegram в персональную файловую систему. Если вы когда-нибудь хотели почувствовать себя системным администратором в мессенджере или просто ищете способ спрятать файлы от самого себя, то эта статья для вас.

Предыстория

Всё началось с того, что мой жесткий диск стал напоминать шкаф с несвежими носками: места мало, найти ничего нельзя, и где-то там спрятан подарок от прошлого Нового года, а хранить все файлы в "избранных" это как-то фу-фу-фу. Я люблю искать нестандартные решения обычных проблем. Решение пришло само собой - перенести всё в облако! Но где найти такое место, чтобы и доступ был всегда под рукой, и чтобы никто не догадался заглянуть, и оно было БЕСПЛАТНОЕ? Конечно же, Telegram!

Идея бота

Цель была проста - создать бота, который позволит сохранять файлы, организовывать их по папкам и при необходимости делиться ими с другими пользователями. И всё это с минимальными затратами усилий (и максимальными затратами времени). Ведь кто сказал, что хранение файлов должно быть скучным?

Архитектура проекта

Проект состоит из нескольких основных модулей:

  • config.py: файл конфигурации (здесь хранится токен бота).

  • utils/: вспомогательные функции для работы с данными и навигацией.

  • handlers/: обработчики команд, сообщений и колбэков.

  • bot.py: основной файл для запуска бота.

  • requirements.txt: зависимости проекта.

Давайте подробнее рассмотрим каждый компонент.


Файл config.py

Начнём с простого. Здесь мы храним конфигурацию бота и основные настройки.

# config.py
BOT_TOKEN = "ВАШ_ТОКЕН_ОТ_TELEGRAM"
DATA_FILE = 'user_data.json'

Не забудьте заменить "ВАШ_ТОКЕН_ОТ_TELEGRAM" на реальный токен, который можно получить у @BotFather. Файл DATA_FILE используется для хранения данных пользователей. **Почему JSON? Потому что зачем заморачиваться с базой данных, когда можно оставить всё на честном слове и JSON-файле? Ведь кто вообще использует базы данных для Telegram-ботов в 2024 году? (Спойлер: все, кроме меня.)


Вспомогательные модули

utils/data_manager.py

Этот модуль отвечает за загрузку и сохранение данных пользователей.

# utils/data_manager.py
import json
import os
from config import DATA_FILE

def load_data():
    if not os.path.exists(DATA_FILE):
        return {"users": {}, "shared_folders": {}}
    with open(DATA_FILE, 'r', encoding='utf-8') as file:
        return json.load(file)

def save_data(data):
    with open(DATA_FILE, 'w', encoding='utf-8') as file:
        json.dump(data, file, ensure_ascii=False, indent=4)

def init_user(data, user_id):
    if user_id not in data["users"]:
        data["users"][user_id] = {
            "current_path": [],
            "structure": {
                "folders": {},
                "files": []
            },
            "file_mappings": {}  # Сопоставление short_id и file_id
        }

Использование JSON-файла вместо базы данных — это как хранить семейные реликвии в картонной коробке. Надёжно? Возможно нет. Зато быстро и без лишних сложностей!

utils/navigation.py

Функции для навигации по файловой структуре.

# utils/navigation.py
def navigate_to_path(structure, path):
    current = structure
    for folder in path:
        current = current["folders"][folder]
    return current

Эта функция — наш проводник по виртуальному файловому лабиринту. Без неё мы бы заблудились в трёх соснах... то есть, в трёх папках.

utils/keyboards.py

Генерация клавиатур для навигации по папкам и файлам.

# utils/keyboards.py
from telebot import types
import uuid
import logging

logger = logging.getLogger(__name__)

def generate_markup(current, path, shared_key=None):
    markup = types.InlineKeyboardMarkup()

    # Кнопка "Вверх", если мы не в корне
    if path:
        callback_data = "up" if not shared_key else f"shared_up:{shared_key}"
        markup.add(types.InlineKeyboardButton("⬆️ Вверх", callback_data=callback_data))

    # Кнопки для папок
    for folder in current["folders"]:
        callback_data = f"folder:{folder}" if not shared_key else f"shared_folder:{shared_key}:{folder}"
        markup.add(types.InlineKeyboardButton(f"📁 {folder}", callback_data=callback_data))

    # Кнопки для файлов
    for idx, file in enumerate(current["files"], start=1):
        display_name = {
            "text": f"📝 Текст {idx}",
            "document": f"📄 Документ {idx}",
            "photo": f"🖼️ Фото {idx}",
            "video": f"🎬 Видео {idx}",
            "audio": f"🎵 Аудио {idx}"
        }.get(file["type"], f"📁 Файл {idx}")

        short_id = file.get("short_id")
        if not short_id:
            logger.error(f"Файл без short_id: {file}")
            continue

        callback_data = f"file:{short_id}" if not shared_key else f"shared_file:{shared_key}:{short_id}"
        markup.add(types.InlineKeyboardButton(display_name, callback_data=callback_data))

    # Кнопка "Вернуть Все"
    callback_data = "retrieve_all" if not shared_key else f"shared_retrieve_all:{shared_key}"
    markup.add(types.InlineKeyboardButton("📤 Вернуть Все", callback_data=callback_data))

    return markup

Здесь мы создаем интерактивные клавиатуры, которые позволяют пользователю легко навигировать по своей файловой системе. И, конечно же, кнопку "Вернуть Все", потому что кто не любит получить всё и сразу? Хотя, честно говоря, я не уверен, что кто-то действительно хочет заспамить свой чат сотней файлов, но зачем ограничивать возможности?


Обработчики

handlers/command_handlers.py

Здесь начинается веселье! Этот файл отвечает за обработку команд, которые пользователь отправляет боту. Например, создание папок, переход между ними и даже доступ к публичным папкам (в случае, если вы решили поделиться своими секретными рецептами борща).

Обработчики команд, таких как /start, /mkdir, /cd, /up, /getmydata, /share и /access.

# handlers/command_handlers.py
from telebot import types
from telebot.types import Message
from utils.data_manager import load_data, save_data, init_user
from utils.navigation import navigate_to_path
from utils.keyboards import generate_markup
import uuid
import telebot

def register_command_handlers(bot: telebot.TeleBot):
    @bot.message_handler(commands=['start'])
    def handle_start(message: Message):
        user_id = str(message.chat.id)
        data = load_data()
        init_user(data, user_id)
        save_data(data)
        bot.send_message(message.chat.id, "Добро пожаловать! Вот что я умею:nn"
                                          "/mkdir <имя_папки> - Создать новую папкуn"
                                          "/cd <имя_папки> - Перейти в папкуn"
                                          "/up - Вернуться на уровень вышеn"
                                          "/getmydata - Показать содержимое текущей папкиn"
                                          "/share - Сделать текущую папку публичнойn"
                                          "/access <ключ> - Получить доступ к публичной папке по ключу")

Команда /mkdir

Создаёт новую папку в текущей директории.

    @bot.message_handler(commands=['mkdir'])
    def handle_mkdir(message: Message):
        user_id = str(message.chat.id)
        data = load_data()
        init_user(data, user_id)

        try:
            _, folder_name = message.text.split(maxsplit=1)
        except ValueError:
            bot.reply_to(message, "Укажите имя папки. Пример: /mkdir НоваяПапка")
            return

        current = navigate_to_path(data["users"][user_id]["structure"], data["users"][user_id]["current_path"])
        if folder_name in current["folders"]:
            bot.reply_to(message, "Папка с таким именем уже существует.")
        else:
            current["folders"][folder_name] = {"folders": {}, "files": []}
            save_data(data)
            bot.reply_to(message, f"Папка '{folder_name}' создана.")

Здесь мы используем функцию navigate_to_path, чтобы попасть в текущую директорию пользователя, и затем добавляем новую папку в структуру. Потому что почему бы не сделать свою собственную файловую систему прямо в Telegram?

Команда /cd

Позволяет перемещаться между папками.

    @bot.message_handler(commands=['cd'])
    def handle_cd(message: Message):
        user_id = str(message.chat.id)
        data = load_data()
        init_user(data, user_id)

        try:
            _, folder_name = message.text.split(maxsplit=1)
        except ValueError:
            bot.reply_to(message, "Укажите имя папки. Пример: /cd МояПапка")
            return

        current = navigate_to_path(data["users"][user_id]["structure"], data["users"][user_id]["current_path"])
        if folder_name in current["folders"]:
            data["users"][user_id]["current_path"].append(folder_name)
            save_data(data)
            bot.reply_to(message, f"Перешли в папку '{folder_name}'.")
        else:
            bot.reply_to(message, "Папка не найдена.")

Пользователь может перемещаться по своей файловой структуре, как в терминале, только без возможности удалить системные файлы (хотя кто знает...).

Команда /up

Возвращает на уровень выше в файловой структуре.

    @bot.message_handler(commands=['up'])
    def handle_up(message: Message):
        user_id = str(message.chat.id)
        data = load_data()
        init_user(data, user_id)

        if data["users"][user_id]["current_path"]:
            popped = data["users"][user_id]["current_path"].pop()
            save_data(data)
            bot.reply_to(message, f"Вернулись из папки '{popped}'.")
        else:
            bot.reply_to(message, "Вы уже в корневой папке.")

Похож на команду cd .. в терминале, только тут не нужно помнить, сколько уровней подняться.

Команда /getmydata

Показывает содержимое текущей папки.

    @bot.message_handler(commands=['getmydata'])
    def handle_getmydata(message: Message):
        user_id = str(message.chat.id)
        data = load_data()
        init_user(data, user_id)

        current = navigate_to_path(data["users"][user_id]["structure"], data["users"][user_id]["current_path"])

        markup = generate_markup(current, data["users"][user_id]["current_path"])

        try:
            bot.send_message(message.chat.id, "Ваша папочная структура:", reply_markup=markup)
        except telebot.apihelper.ApiTelegramException as e:
            bot.send_message(message.chat.id, f"Ошибка при отправке клавиатуры: {str(e)}")

Теперь можно увидеть, что у вас внутри Telegram — папки, файлы и, конечно же, кнопки для навигации. Сделаем немного интерактивности в своём файловом хранилище.

Команды /share и /access

Позволяют делать папку публичной и получать доступ к публичным папкам по ключу.

    @bot.message_handler(commands=['share'])
    def handle_share(message: Message):
        user_id = str(message.chat.id)
        data = load_data()
        init_user(data, user_id)

        current_path = data["users"][user_id]["current_path"]
        structure = data["users"][user_id]["structure"]

        # Навигация до текущей папки
        try:
            current = navigate_to_path(structure, current_path)
        except KeyError:
            bot.reply_to(message, "Текущая папка не существует.")
            return

        # Генерация уникального ключа
        unique_key = uuid.uuid4().hex

        # Сохранение связи ключа с пользователем и путем
        data["shared_folders"][unique_key] = {
            "user_id": user_id,
            "path": current_path.copy()
        }

        save_data(data)

        # Отправка ключа пользователю
        bot.reply_to(message, f"Папка успешно сделана публичной.nВаш ключ для доступа: `{unique_key}`nИспользуйте команду /access <ключ> чтобы получить доступ.", parse_mode="Markdown")
    @bot.message_handler(commands=['access'])
    def handle_access(message: Message):
        user_id = str(message.chat.id)
        data = load_data()
        init_user(data, user_id)

        try:
            _, access_key = message.text.split(maxsplit=1)
        except ValueError:
            bot.reply_to(message, "Пожалуйста, укажите ключ доступа. Пример: /access <ключ>")
            return

        shared = data.get("shared_folders", {}).get(access_key)
        if not shared:
            bot.reply_to(message, "Неверный или несуществующий ключ доступа.")
            return

        owner_id = shared["user_id"]
        path = shared["path"]

        # Проверка, существует ли пользователь и папка
        if owner_id not in data["users"]:
            bot.reply_to(message, "Владелец папки не существует.")
            return

        owner_structure = data["users"][owner_id]["structure"]
        try:
            shared_folder = navigate_to_path(owner_structure, path)
        except KeyError:
            bot.reply_to(message, "Папка не найдена.")
            return

        # Генерация клавиатуры для публичной папки
        markup = generate_markup(shared_folder, path, shared_key=access_key)

        try:
            bot.send_message(message.chat.id, "Содержимое публичной папки:", reply_markup=markup)
        except telebot.apihelper.ApiTelegramException as e:
            bot.send_message(message.chat.id, f"Ошибка при отправке клавиатуры: {str(e)}")

handlers/message_handlers.py

Обрабатывает все сообщения, которые не являются командами: текст, фото, документы, видео и аудио.

# handlers/message_handlers.py
from telebot.types import Message
from utils.data_manager import load_data, save_data, init_user
from utils.navigation import navigate_to_path
import telebot
import uuid  # Для генерации уникальных short_id
import logging

logger = logging.getLogger(__name__)

def register_message_handlers(bot: telebot.TeleBot):
    @bot.message_handler(content_types=['text', 'photo', 'document', 'video', 'audio'])
    def handle_message(message: Message):
        user_id = str(message.chat.id)
        data = load_data()
        init_user(data, user_id)

        # Проверяем, что это не команда
        if message.content_type == 'text' and message.text.startswith('/'):
            return

        current = navigate_to_path(data["users"][user_id]["structure"], data["users"][user_id]["current_path"])

        if message.content_type == 'text':
            # Сохраняем текст как файл типа 'text'
            current["files"].append({"type": "text", "content": message.text})
            save_data(data)
            bot.reply_to(message, "Текстовое сообщение сохранено в текущей папке.")
        elif message.content_type == 'document':
            # Сохраняем документ
            file_id = message.document.file_id
            short_id = uuid.uuid4().hex[:8]
            current["files"].append({"type": "document", "file_id": file_id, "file_name": message.document.file_name, "short_id": short_id})
            data["users"][user_id]["file_mappings"][short_id] = file_id
            save_data(data)
            bot.reply_to(message, "Документ сохранён в текущей папке.")
        # Аналогично для фото, видео и аудио
        elif message.content_type == 'photo':
            file_id = message.photo[-1].file_id
            short_id = uuid.uuid4().hex[:8]
            current["files"].append({"type": "photo", "file_id": file_id, "short_id": short_id})
            data["users"][user_id]["file_mappings"][short_id] = file_id
            save_data(data)
            bot.reply_to(message, "Фото сохранено в текущей папке.")
        elif message.content_type == 'video':
            file_id = message.video.file_id
            short_id = uuid.uuid4().hex[:8]
            current["files"].append({"type": "video", "file_id": file_id, "short_id": short_id})
            data["users"][user_id]["file_mappings"][short_id] = file_id
            save_data(data)
            bot.reply_to(message, "Видео сохранено в текущей папке.")
        elif message.content_type == 'audio':
            file_id = message.audio.file_id
            short_id = uuid.uuid4().hex[:8]
            current["files"].append({"type": "audio", "file_id": file_id, "short_id": short_id})
            data["users"][user_id]["file_mappings"][short_id] = file_id
            save_data(data)
            bot.reply_to(message, "Аудио сохранено в текущей папке.")

Мы генерируем short_id для каждого файла, чтобы потом можно было их легко идентифицировать и получать. Это как собственная система штрих-кодов, только без сканера и очередей в супермаркете.


handlers/callback_handlers.py

Этот файл отвечает за обработку всех нажатий на кнопки. Да-да, тех самых кнопок, которые вы видите в сообщениях от бота. Здесь мы пытаемся не сойти с ума, разбирая callback_data и понимая, что же пользователь хотел сделать.

# handlers/callback_handlers.py
from telebot.types import CallbackQuery
from utils.data_manager import load_data, save_data, init_user
from utils.navigation import navigate_to_path
from utils.keyboards import generate_markup
import telebot
import logging

logger = logging.getLogger(__name__)

def register_callback_handlers(bot: telebot.TeleBot):
    @bot.callback_query_handler(func=lambda call: True)
    def handle_callback(call: CallbackQuery):
        user_id = str(call.message.chat.id)
        data = load_data()
        init_user(data, user_id)

        if call.data == "up":
            # Код для перехода на уровень выше
            if data["users"][user_id]["current_path"]:
                popped = data["users"][user_id]["current_path"].pop()
                bot.answer_callback_query(call.id, f"Вернулись из папки '{popped}'.")
            else:
                bot.answer_callback_query(call.id, "Вы уже в корневой папке.")
        elif call.data.startswith("folder:"):
            # Код для перехода в другую папку
            folder_name = call.data.split(":", 1)[1]
            current = navigate_to_path(data["users"][user_id]["structure"], data["users"][user_id]["current_path"])
            if folder_name in current["folders"]:
                data["users"][user_id]["current_path"].append(folder_name)
                bot.answer_callback_query(call.id, f"Перешли в папку '{folder_name}'.")
            else:
                bot.answer_callback_query(call.id, "Папка не найдена.")
        elif call.data.startswith("file:"):
            # Код для получения файла по short_id
            short_id = call.data.split(":", 1)[1]
            file_info = None
            for file in navigate_to_path(data["users"][user_id]["structure"], data["users"][user_id]["current_path"])["files"]:
                if file.get("short_id") == short_id:
                    file_info = file
                    break
            if not file_info:
                bot.answer_callback_query(call.id, "Файл не найден.")
                return
            # Отправляем файл
            try:
                if file_info["type"] == "text":
                    bot.send_message(call.message.chat.id, file_info["content"])
                elif file_info["type"] == "document":
                    bot.send_document(call.message.chat.id, file_info["file_id"])
                elif file_info["type"] == "photo":
                    bot.send_photo(call.message.chat.id, file_info["file_id"])
                elif file_info["type"] == "video":
                    bot.send_video(call.message.chat.id, file_info["file_id"])
                elif file_info["type"] == "audio":
                    bot.send_audio(call.message.chat.id, file_info["file_id"])
                bot.answer_callback_query(call.id, "Файл отправлен.")
            except Exception as e:
                logger.error(f"Ошибка при отправке файла: {e}")
                bot.answer_callback_query(call.id, f"Ошибка при отправке файла: {str(e)}")
        elif call.data == "retrieve_all":
            # Код для получения всех файлов в текущей папке
            current = navigate_to_path(data["users"][user_id]["structure"], data["users"][user_id]["current_path"])
            try:
                for file in current["files"]:
                    if file["type"] == "text":
                        bot.send_message(call.message.chat.id, f"Текст: {file['content']}")
                    elif file["type"] == "document":
                        bot.send_document(call.message.chat.id, file["file_id"])
                    elif file["type"] == "photo":
                        bot.send_photo(call.message.chat.id, file["file_id"])
                    elif file["type"] == "video":
                        bot.send_video(call.message.chat.id, file["file_id"])
                    elif file["type"] == "audio":
                        bot.send_audio(call.message.chat.id, file["file_id"])
                    else:
                        bot.send_message(call.message.chat.id, "Неизвестный тип файла.")
                bot.answer_callback_query(call.id, "Все файлы отправлены.")
            except Exception as e:
                logger.error(f"Ошибка при отправке файлов: {e}")
                bot.answer_callback_query(call.id, f"Ошибка при отправке файлов: {str(e)}")
        else:
            bot.answer_callback_query(call.id, "Неизвестная команда.")

        # Обновляем папочную структуру после действия, если это необходимо
        if call.data.startswith("folder:") or call.data == "up":
            current = navigate_to_path(data["users"][user_id]["structure"], data["users"][user_id]["current_path"])
            markup = generate_markup(current, data["users"][user_id]["current_path"])
            try:
                bot.edit_message_reply_markup(chat_id=call.message.chat.id,
                                              message_id=call.message.message_id,
                                              reply_markup=markup)
            except telebot.apihelper.ApiTelegramException as e:
                if "message is not modified" in str(e):
                    # Игнорируем ошибку, если сообщение не изменилось
                    pass
                else:
                    logger.error(f"Ошибка обновления клавиатуры: {e}")
                    bot.send_message(call.message.chat.id, f"Ошибка обновления клавиатуры: {str(e)}")

        save_data(data)

Здесь мы используем callback_data, чтобы понять, какую кнопку нажал пользователь, и выполнить соответствующее действие. Это как выбирать приключение в книге, только с кнопками и без возможности проиграть (почти).


Основной файл bot.py

Это мозг нашего бота. Здесь мы инициализируем бота, регистрируем обработчики и запускаем его.

# bot.py
import telebot
import config
from handlers.command_handlers import register_command_handlers
from handlers.callback_handlers import register_callback_handlers
from handlers.message_handlers import register_message_handlers
import time
import requests
import logging

# Настройка логирования
logging.basicConfig(
    level=logging.DEBUG,  # Для максимального количества информации в логах
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler("bot.log"),  # Запись логов в файл
        logging.StreamHandler()          # И вывод в консоль, чтобы всё сразу видеть
    ]
)

logger = logging.getLogger(__name__)

def start_bot():
    bot = telebot.TeleBot(config.BOT_TOKEN)

    # Регистрация обработчиков
    register_command_handlers(bot)
    register_callback_handlers(bot)
    register_message_handlers(bot)

    # Запуск бота с обработкой возможных исключений
    while True:
        try:
            logger.info("Бот запущен и ожидает обновлений...")
            bot.infinity_polling(timeout=60, long_polling_timeout=60)
        except requests.exceptions.ReadTimeout:
            logger.warning("Превышено время ожидания. Перезапуск...")
            time.sleep(5)
        except Exception as e:
            logger.error(f"Произошла ошибка: {e}")
            time.sleep(5)

if __name__ == "__main__":
    start_bot()

Мы настраиваем логирование в bot.py, чтобы потом, когда бот внезапно перестанет работать, можно было долго и мучительно искать причину. А пока что наслаждаемся бесконечным циклом while True, который заставляет бота работать круглосуточно, как ночной сторож.


Демонстрация работы бота

Что ж, теория теорией, но давайте посмотрим, как это работает на практике. Я решил испытать бота и задокументировать этот процесс.

Создание папки и сохранение файлов

Сначала я запустил бота и ввёл команду /start. Бот приветливо рассказал мне о своих возможностях.

Как я создал Telegram-бота для хранения файлов и чуть не стал библиотекарем - 1

Скриншот 1. Приветственное сообщение бота после команды /start.

Далее я решил создать новую папку:

/mkdir Документы

Бот ответил, что папка успешно создана.

Как я создал Telegram-бота для хранения файлов и чуть не стал библиотекарем - 2

Скриншот 2. Создание новой папки Документы.

Перехожу в эту папку:

/cd Документы
Как я создал Telegram-бота для хранения файлов и чуть не стал библиотекарем - 3

Скриншот 3. Переход в папку Документы.

Теперь сохраняю в неё файл в формате txt:

1.txt

Бот подтверждает, что файл сохранен.

Как я создал Telegram-бота для хранения файлов и чуть не стал библиотекарем - 4

Скриншот 4. Сохранение файла в текущую папку.

Просмотр содержимого папки

Чтобы увидеть, что находится в текущей папке, использую команду:

/getmydata

Бот отправляет мне клавиатуру с кнопками для навигации.

Как я создал Telegram-бота для хранения файлов и чуть не стал библиотекарем - 5

Скриншот 5. Просмотр содержимого папки Документы с интерактивной клавиатурой.

Получение сохранённого файла

Нажимаю на кнопку с названием моего файла, и бот отправляет мне его содержимое.

Как я создал Telegram-бота для хранения файлов и чуть не стал библиотекарем - 6

Скриншот 6. Получение сохранённого файла.

Делимся папкой с другом

Решил поделиться папкой с другом. Использую команду:

/share

Бот выдаёт мне уникальный ключ доступа.

Как я создал Telegram-бота для хранения файлов и чуть не стал библиотекарем - 7

Скриншот 7. Получение ключа доступа для публичной папки.

Друг вводит команду:

/access <уникальный_ключ>

И получает доступ к моей папке.

Как я создал Telegram-бота для хранения файлов и чуть не стал библиотекарем - 8

Скриншот 8. Друг получает доступ к публичной папке и видит её содержимое.

Получение всех файлов сразу

Друг решает получить все файлы из моей папки и нажимает кнопку "📤 Вернуть Все". Бот отправляет ему все сохранённые файлы.

Скриншот 9: Получение всех файлов из публичной папки.


Запуск бота

Чтобы запустить бота, выполните следующие шаги:

  1. Установите зависимости:

    pip install -r requirements.txt
    
  2. Создайте файл config.py с вашим токеном:

    BOT_TOKEN = "ВАШ_ТОКЕН_ОТ_TELEGRAM"
    DATA_FILE = 'user_data.json'
    
  3. Запустите бота:

    python bot.py
    

Если всё прошло успешно, бот должен начать работать, и вы сможете воспользоваться всеми его замечательными (и не очень) функциями. Если бот вдруг перестанет отвечать, не паникуйте — скорее всего, он решил взять перерыв (или вы допустили какую-то ошибку в коде, что тоже вполне возможно).


Заключение

Если вы хотите улучшить бота, вот несколько идей:

  • Реализовать поиск по файлам и папкам.

  • Добавить поддержку стикеров и голосовых сообщений.

  • Оптимизировать хранение данных (использовать базу данных вместо JSON-файла).


Спасибо, что дочитали до конца! Надеюсь, эта статья была для вас полезной. А я пойду разбираться, почему мой бот внезапно перестал отвечать на команды.

Полный исходный код бота доступен на GitHub: GitHub - tg_file_bot_3000

Автор: ruinik

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js