Add docker compose support. Migrate to new version of tools call

This commit is contained in:
yborisovp 2025-09-29 22:26:35 +03:00
parent a7eeff23c1
commit f951b4b7f3
11 changed files with 1675 additions and 586 deletions

63
.dockerignore Normal file
View file

@ -0,0 +1,63 @@
# Git
.git
.gitignore
# Docker
Dockerfile
docker-compose.yml
.dockerignore
# Environment files
.env
.env.*
env.example
# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
# Virtual environments
venv/
env/
ENV/
# IDE
.vscode/
.idea/
*.swp
*.swo
*~
# OS
.DS_Store
Thumbs.db
# Logs
*.log
# Documentation
README.md
*.md
# Temporary files
*.tmp
*.temp

6
.env Normal file
View file

@ -0,0 +1,6 @@
# Telegram Bot Token
# Получите токен у @BotFather в Telegram
TELEGRAM_BOT_TOKEN=8263227899:AAESDG7RgctgI0a2oKHgM_2WeriiBcd3OZA
# Часовой пояс (опционально)
TZ=Europe/Moscow

33
Dockerfile Normal file
View file

@ -0,0 +1,33 @@
# Используем официальный Python образ
FROM python:3.11-slim
# Устанавливаем рабочую директорию
WORKDIR /app
# Устанавливаем системные зависимости
RUN apt-get update && apt-get install -y \
wget \
&& rm -rf /var/lib/apt/lists/*
# Копируем файл зависимостей
COPY requirements.txt .
# Устанавливаем Python зависимости
RUN pip install --no-cache-dir -r requirements.txt
# Копируем код приложения
COPY code/ ./code/
COPY data/ ./data/
# Создаем директории для базы данных
RUN mkdir -p db
# Устанавливаем рабочую директорию для запуска
WORKDIR /app/code
# Открываем порт (если потребуется для мониторинга)
EXPOSE 8000
# Команда запуска
CMD ["python", "bot.py"]

View file

@ -30,13 +30,47 @@ Y.Calendarkin — некоммерческий проект, предназна
## 🚀 Установка и запуск
### Предварительные требования
### 🐳 Запуск с Docker (Рекомендуется)
1. **Клонируйте репозиторий:**
```bash
git clone <repository-url>
cd y.calendarkin
```
2. **Создайте файл с переменными окружения:**
```bash
cp env.example .env
```
3. **Настройте переменные окружения:**
- Откройте файл `.env`
- Замените `your_bot_token_here` на токен вашего бота от [@BotFather](https://t.me/BotFather)
4. **Запустите бота:**
```bash
docker-compose up -d
```
5. **Проверьте логи:**
```bash
docker-compose logs -f
```
6. **Остановите бота:**
```bash
docker-compose down
```
### 📦 Локальная установка
#### Предварительные требования
```bash
pip install -r requirements.txt
```
### Настройка
#### Настройка
1. Создайте нового бота через [@BotFather](https://t.me/BotFather)
2. Получите токен и добавьте его в `config.py`:
@ -51,7 +85,7 @@ TOKEN = "your_bot_token_here"
mkdir -p data/icals db
```
### Запуск
#### Запуск
```bash
cd code
@ -100,9 +134,23 @@ y.calendarkin/
│ ├── icals/ # Загруженные календари
│ └── photo_edit_alarm.jpg
├── db/ # База данных SQLite
├── Dockerfile # Docker образ
├── docker-compose.yml # Docker Compose конфигурация
├── .dockerignore # Исключения для Docker
├── env.example # Пример переменных окружения
└── requirements.txt
```
### Управление данными
```bash
# Создание резервной копии базы данных
docker cp y-calendarkin-bot:/app/db ./backup/
# Восстановление базы данных
docker cp ./backup/db y-calendarkin-bot:/app/
```
## 📊 База данных
Проект использует две основные таблицы:

View file

@ -1,7 +1,8 @@
import logging, config, sql, asyncio, wget, os
from aiogram import Bot, Dispatcher, executor, types
from aiogram.types import ParseMode
from aiogram import Bot, Dispatcher, types, F
from aiogram.enums import ParseMode
from aiogram.filters import Command, or_f
from datetime import datetime, time
from script import text_ical, message_form, dt_now, delta_time
@ -10,7 +11,7 @@ from script import text_ical, message_form, dt_now, delta_time
logging.basicConfig(level=logging.INFO)
bot = Bot(token=config.TOKEN)
dp = Dispatcher(bot)
dp = Dispatcher()
# инициализируем соединение с БД
du = sql.Users('../db/users.db')
@ -18,17 +19,16 @@ dc = sql.Clock('../db/clock.db')
# ПРИВЕТСТВЕННОЕ СООБЩЕНИЕ
@dp.message_handler(commands=['start', 'help'])
@dp.message(or_f(Command('start'), Command('help')))
async def helps(message: types.Message):
tg_id = int(message.chat.id)
if not du.user_exists(tg_id):
du.add_user(tg_id)
buttons = [types.InlineKeyboardButton(text="КОМАНДЫ", callback_data="com"),
types.InlineKeyboardButton(text="АВТОР", callback_data="auth")]
keyboard = types.InlineKeyboardMarkup(row_width=2)
keyboard.add(*buttons)
keyboard = types.InlineKeyboardMarkup(inline_keyboard=[
[types.InlineKeyboardButton(text="КОМАНДЫ", callback_data="com"),
types.InlineKeyboardButton(text="АВТОР", callback_data="auth")]
])
await message.answer(text="<b>Я.Календаркин</b> - бот для оповещения о событиях из <b>Яндекс.Календаря</b>. "
"Для начала работы вам нужно всего лишь прислать в чат ссылку экспорта календаря в "
@ -38,7 +38,7 @@ async def helps(message: types.Message):
parse_mode=ParseMode.HTML, reply_markup=keyboard)
@dp.callback_query_handler(text="auth")
@dp.callback_query(F.data == "auth")
async def author(call: types.CallbackQuery):
await call.message.answer(text='*| АВТОР |*\n\n*>>* Этот бот не коммерческий проект, для упрощенного получения '
'уведомлений о событиях в Яндекс.Календаре. Не многим этот бот будет полезен, но '
@ -48,7 +48,7 @@ async def author(call: types.CallbackQuery):
parse_mode=ParseMode.MARKDOWN)
@dp.callback_query_handler(text="com")
@dp.callback_query(F.data == "com")
async def commands(call: types.CallbackQuery):
await call.message.answer(text='<b>| КОМАНДЫ |</b>\n\n'
'<b>/help</b> - вспомогательная функция для уточнения работы команд\n'
@ -59,11 +59,11 @@ async def commands(call: types.CallbackQuery):
'<b>/get_alarm</b> - информация о времени на которое настроены оповещения\n'
'<b>/edit_alarm</b> - изменение времени оповещений\n'
'<b>/stop_alarm</b> - команда, отключающая второе оповещение о событии',
parse_mode=types.ParseMode.HTML)
parse_mode=ParseMode.HTML)
# КОМАНДЫ
@dp.message_handler(commands=['list'])
@dp.message(Command('list'))
async def check_list(message: types.Message):
user_id = du.get_user_id(int(message.chat.id))
@ -88,7 +88,7 @@ async def check_list(message: types.Message):
await message.answer("Для отображения событий вы должны прислать ical-ссылку на календарь!")
@dp.message_handler(commands=['notif'])
@dp.message(Command('notif'))
async def notif_up(message: types.Message):
user_id = du.get_user_id(int(message.chat.id))
@ -103,7 +103,7 @@ async def notif_up(message: types.Message):
await message.answer("Для взаимодействия с событиями вы должны прислать ical-ссылку на календарь!")
@dp.message_handler(commands=['daily'])
@dp.message(Command('daily'))
async def daily_up(message: types.Message):
user_id = du.get_user_id(int(message.chat.id))
@ -118,7 +118,7 @@ async def daily_up(message: types.Message):
await message.answer("Для взаимодействия с событиями вы должны прислать ical-ссылку на календарь!")
@dp.message_handler(commands=['moment'])
@dp.message(Command('moment'))
async def start_up(message: types.Message):
user_id = du.get_user_id(int(message.chat.id))
@ -133,7 +133,7 @@ async def start_up(message: types.Message):
await message.answer("Для взаимодействия с событиями вы должны прислать ical-ссылку на календарь!")
@dp.message_handler(commands=['get_alarm'])
@dp.message(Command('get_alarm'))
async def start_up(message: types.Message):
user_id = du.get_user_id(int(message.chat.id))
@ -161,7 +161,7 @@ async def start_up(message: types.Message):
await message.answer("Для того, чтобы получить таймеры, вы должны прислать ical-ссылку на свой календарь!")
@dp.message_handler(commands=['edit_alarm'])
@dp.message(Command('edit_alarm'))
async def start_up(message: types.Message):
user_id = du.get_user_id(int(message.chat.id))
@ -174,7 +174,7 @@ async def start_up(message: types.Message):
await message.answer("Для того, чтобы изменить таймеры, вы должны прислать ical-ссылку на свой календарь!")
@dp.message_handler(commands=['stop_alarm'])
@dp.message(Command('stop_alarm'))
async def daily_up(message: types.Message):
user_id = du.get_user_id(int(message.chat.id))
@ -190,7 +190,7 @@ async def daily_up(message: types.Message):
# ЗАГРУЗКА ССЫЛКИ
@dp.message_handler(content_types=['text'])
@dp.message(F.text)
async def downloading_file_ics(message: types.Message):
user_id = du.get_user_id(int(message.chat.id))
@ -314,8 +314,13 @@ async def update(wait_for):
os.rename(f'../data/icals/{str(user_id)}_new.ics', f'../data/icals/{str(user_id)}.ics')
async def main():
# Создаем задачи для фоновых процессов
asyncio.create_task(alarm(60)) # ПРОВЕРКА КАЖДУЮ 1 МИНУТУ
asyncio.create_task(update(780)) # ПРОВЕРКА КАЖДУЮ 13 МИНУТУ
# Запускаем бота
await dp.start_polling(bot, skip_updates=True)
if __name__ == '__main__':
loop = asyncio.get_event_loop()
loop.create_task(alarm(60)) # ПРОВЕРКА КАЖДУЮ 1 МИНУТУ
loop.create_task(update(780)) # ПРОВЕРКА КАЖДУЮ 13 МИНУТУ
executor.start_polling(dp, skip_updates=True)
asyncio.run(main())

View file

@ -1 +1,7 @@
TOKEN = "**********:***************************"
import os
# Получаем токен из переменной окружения
TOKEN = os.getenv('TELEGRAM_BOT_TOKEN')
if not TOKEN:
raise ValueError("TELEGRAM_BOT_TOKEN environment variable is required")

File diff suppressed because it is too large Load diff

Binary file not shown.

Binary file not shown.

37
docker-compose.yml Normal file
View file

@ -0,0 +1,37 @@
services:
calendarkin-bot:
build: .
container_name: y-calendarkin-bot
restart: unless-stopped
environment:
# Токен Telegram бота (обязательно)
- TELEGRAM_BOT_TOKEN=${TELEGRAM_BOT_TOKEN}
# Дополнительные переменные окружения (опционально)
- TZ=Europe/Moscow
volumes:
# Монтируем директорию с базами данных для сохранения данных
- ./db:/app/db
# Монтируем директорию с календарями
- ./data:/app/data
# Логирование
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
# Ограничения ресурсов
deploy:
resources:
limits:
memory: 512M
reservations:
memory: 256M
# Создаем именованные тома для данных (опционально)
volumes:
db_data:
ical_data:

7
env.example Normal file
View file

@ -0,0 +1,7 @@
# Telegram Bot Token
# Получите токен у @BotFather в Telegram
TELEGRAM_BOT_TOKEN=your_bot_token_here
# Часовой пояс (опционально)
TZ=Europe/Moscow