Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ jobs:
run: bin/rails db:test:prepare test:system

- name: Keep screenshots from failed system tests
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
if: failure()
with:
name: screenshots
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,4 @@
# Ignore key files for decrypting credentials and more.
/config/*.key

/DEPLOY.md
71 changes: 71 additions & 0 deletions DEPLOY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# Деплой на сервер (Docker Compose)

Ниже — самый простой способ задеплоить этот бот на VPS (Ubuntu/Debian) через Docker.

## 1) Подготовка сервера

Установи Docker и Compose:

```bash
sudo apt-get update
sudo apt-get install -y docker.io docker-compose-plugin
sudo usermod -aG docker $USER
newgrp docker
```

## 2) Подготовка проекта на сервере

Склонируй репозиторий:

```bash
git clone <your-repo-url> video-link-bot
cd video-link-bot
```

## 3) Секреты (env)

Создай файл `.env` рядом с `docker-compose.prod.yml`:

```bash
cat > .env <<'EOF'
TELEGRAM_BOT_TOKEN=__PUT_TOKEN_HERE__
DATABASE_PASSWORD=__PUT_DB_PASSWORD_HERE__
RAILS_MASTER_KEY=__PUT_MASTER_KEY_HERE__
EOF
```

Где взять `RAILS_MASTER_KEY`:
- локально: `cat config/master.key` (НЕ коммить в git)

## 4) Запуск

Собрать и поднять сервисы:

```bash
docker compose -f docker-compose.prod.yml --env-file .env up -d --build
```

Проверить логи:

```bash
docker compose -f docker-compose.prod.yml --env-file .env logs -f --tail=200 bot
docker compose -f docker-compose.prod.yml --env-file .env logs -f --tail=200 app
```

Остановить:

```bash
docker compose -f docker-compose.prod.yml --env-file .env down
```

## Что будет запущено

- `db` — Postgres
- `app` — Rails (порт 80) + Solid Queue внутри Puma (`SOLID_QUEUE_IN_PUMA=true`)
- `bot` — отдельный процесс, который запускает `rake bot:start` (long polling)

## Примечания

1) Для TikTok метаданных используется `yt-dlp` — он устанавливается внутри Docker-образа.
2) Если хочешь HTTPS и домен — проще всего поставить перед контейнером Caddy/Nginx или перейти на Kamal.

2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ WORKDIR /rails

# Install base packages
RUN apt-get update -qq && \
apt-get install --no-install-recommends -y curl libjemalloc2 libvips postgresql-client && \
apt-get install --no-install-recommends -y curl libjemalloc2 libvips postgresql-client yt-dlp && \
ln -s /usr/lib/$(uname -m)-linux-gnu/libjemalloc.so.2 /usr/local/lib/libjemalloc.so && \
rm -rf /var/lib/apt/lists /var/cache/apt/archives

Expand Down
96 changes: 96 additions & 0 deletions app/bots/bot_messages.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# Тексты сообщений бота — вынесены в отдельный модуль для удобства правок
module BotMessages
WELCOME = <<~TEXT.freeze
🎬 *Video Downloader Bot*

Я могу помочь вам скачать видео с популярных платформ!

📋 *Поддерживаемые платформы:*
• YouTube 🎥
• Instagram 📸
• TikTok 🎵

✨ *Просто отправьте мне ссылку на видео!*

📌 *Примеры ссылок:*
• https://youtube.com/watch?v=...
• https://instagram.com/p/...
• https://tiktok.com/@.../video/...

📝 *Доступные команды:*
/help - Справка
/supported - Поддерживаемые платформы
/stats - Статистика
TEXT

HELP = <<~TEXT.freeze
ℹ️ *Как пользоваться ботом:*

1. *Отправьте ссылку* на видео с YouTube, Instagram или TikTok
2. Бот *проанализирует* ссылку
3. Получите *информацию о видео* и опцию скачивания

⚠️ *Ограничения:*
• Максимальный размер файла: 50MB
• До 10 запросов в час
• Некоторые видео могут быть недоступны

🔒 *Конфиденциальность:*
Ваши ссылки хранятся временно и удаляются через 24 часа.
TEXT

SUPPORTED = <<~TEXT.freeze
📋 *Подробно о поддерживаемых платформах:*

*YouTube* 🎥
• Поддерживаются обычные видео
• Короткие видео (Shorts)
• Плейлисты (первое видео)

*Instagram* 📸
• Посты с видео (Reels, IGTV)
• Истории (если публичные)
• Не поддерживаются: приватные аккаунты

*TikTok* 🎵
• Все публичные видео
• С музыкой и эффектами
• Без водяных знаков (где возможно)

🚀 *Просто отправьте ссылку!*
TEXT

UNKNOWN_COMMAND = "❌ Неизвестная команда. Используйте /help"
ERROR_GENERIC = "⚠️ Произошла ошибка. Попробуйте позже."
PROCESSING = "⏳ Обрабатываю ссылку...\n\n🔗 %{url}"

def self.stats(requests)
<<~TEXT
📊 *Ваша статистика:*

Всего запросов: #{requests.count}
Успешно: #{requests.completed.count}
В обработке: #{requests.processing.count}
Не удалось: #{requests.failed.count}

⏰ *Последние запросы:*
#{recent_requests_summary(requests)}
TEXT
end

def self.recent_requests_summary(requests)
recent = requests.order(created_at: :desc).limit(5)
recent.map do |req|
"• #{req.platform_name}: #{req.status_name} (#{time_ago(req.created_at)})"
end.join("\n")
end

def self.time_ago(time)
minutes = ((Time.current - time) / 60).to_i
if minutes < 60
"#{minutes} мин назад"
else
"#{(minutes / 60).to_i} ч назад"
end
end
end
Loading
Loading