create upload bot

This commit is contained in:
Daniil Barodkin
2026-07-11 19:19:07 +03:00
parent 80da6a1581
commit 5cdf3e66c7
12 changed files with 191 additions and 0 deletions
+21
View File
@@ -0,0 +1,21 @@
name: Deploy Music Bot
on:
push:
branches:
- main
jobs:
deploy:
runs-on: backup-runner # <-- Используем ваш label для доступа к сокету Docker
steps:
- name: Checkout Code
uses: actions/checkout@v4
- name: Build and Deploy Bot
run: |
# Запускаем сборку и деплой прямо через сокет хоста
docker compose up -d --build
- name: Clean up old images
run: docker image prune -f
+10
View File
@@ -0,0 +1,10 @@
# Default ignored files
/shelf/
/workspace.xml
# Ignored default folder with query files
/queries/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
# Editor-based HTTP Client requests
/httpRequests/
+8
View File
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="jdk" jdkName="Python 3.14" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
+6
View File
@@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<settings>
<option name="USE_PROJECT_PROFILE" value="false" />
<version value="1.0" />
</settings>
</component>
+7
View File
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Black">
<option name="sdkName" value="Python 3.14" />
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.14" project-jdk-type="Python SDK" />
</project>
+8
View File
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/auto_dj.iml" filepath="$PROJECT_DIR$/.idea/auto_dj.iml" />
</modules>
</component>
</project>
Generated
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>
+20
View File
@@ -0,0 +1,20 @@
# Берем легкий образ питона
FROM python:3.11-slim
# Устанавливаем ffmpeg (он критически нужен yt-dlp для извлечения mp3)
RUN apt-get update && \
apt-get install -y ffmpeg && \
rm -rf /var/lib/apt/lists/*
# Создаем рабочую папку
WORKDIR /app
# Копируем зависимости и устанавливаем их
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Копируем весь остальной код
COPY . .
# Запускаем бота
CMD ["python", "bot.py"]
+19
View File
@@ -0,0 +1,19 @@
{
"packages": [
"python@3.11",
"ffmpeg@latest"
],
"env": {
"VENV_DIR": ".venv"
},
"shell": {
"init_hook": [
"python -m venv $VENV_DIR",
"source $VENV_DIR/bin/activate",
"pip install -r requirements.txt"
],
"scripts": {
"start": "python bot.py"
}
}
}
+12
View File
@@ -0,0 +1,12 @@
services:
music-bot:
build: .
container_name: navidrome_bot
restart: unless-stopped
environment:
- TG_BOT_TOKEN=8849605262:AAGMJWr-02uaFI-cD4UBxg1pSB0swDH_dUc
- ADMIN_ID=812709121
- MUSIC_DIR=/music
volumes:
# Слева — путь к музыке на сервере, справа — внутри контейнера бота
- /home/redjinald/navidrome/music:/music
+71
View File
@@ -0,0 +1,71 @@
import os
import asyncio
from aiogram import Bot, Dispatcher, types, F
from aiogram.filters import Command
import yt_dlp
TOKEN = os.getenv("TG_BOT_TOKEN")
MUSIC_DIR = os.getenv("MUSIC_DIR", "./music")
# Читаем ваш ID из переменных среды (по умолчанию 0)
ADMIN_ID = int(os.getenv("ADMIN_ID", 0))
bot = Bot(token=TOKEN)
dp = Dispatcher()
def download_youtube(url: str):
ydl_opts = {
'format': 'bestaudio/best',
'postprocessors': [{
'key': 'FFmpegExtractAudio',
'preferredcodec': 'mp3',
'preferredquality': '192',
}],
'outtmpl': f'{MUSIC_DIR}/Youtube/%(uploader)s/%(title)s.%(ext)s',
'noplaylist': False,
'quiet': False
}
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
ydl.download([url])
# Создаем удобный фильтр: "сообщение от админа"
is_admin = F.from_user.id == ADMIN_ID
# --- ОБРАБОТЧИКИ ТОЛЬКО ДЛЯ ВАС (работают, если is_admin == True) ---
@dp.message(is_admin, Command("start"))
async def start_cmd(message: types.Message):
await message.reply("Привет, хозяин! Скинь ссылку на YouTube или аудиофайл, и я закину его в Navidrome.")
@dp.message(is_admin, F.text.regexp(r'https?://(?:www\.)?youtu'))
async def handle_youtube(message: types.Message):
msg = await message.reply("⏳ Начинаю скачивание...")
try:
await asyncio.to_thread(download_youtube, message.text)
await msg.edit_text("✅ Успешно скачано и добавлено в Navidrome!")
except Exception as e:
await msg.edit_text(f"❌ Ошибка:\n{str(e)[:500]}")
@dp.message(is_admin, F.audio)
async def handle_audio(message: types.Message):
msg = await message.reply("📥 Сохраняю трек...")
try:
file_name = message.audio.file_name or f"track_{message.message_id}.mp3"
destination = os.path.join(MUSIC_DIR, "Telegram", file_name)
os.makedirs(os.path.dirname(destination), exist_ok=True)
await bot.download(message.audio, destination=destination)
await msg.edit_text("✅ Трек добавлен в Navidrome!")
except Exception as e:
await msg.edit_text(f"❌ Ошибка:\n{str(e)[:500]}")
# --- ОБРАБОТЧИК ДЛЯ ЧУЖАКОВ ---
# Сработает, если ни один из верхних обработчиков не подошел (например, другой ID)
@dp.message()
async def reject_stranger(message: types.Message):
await message.reply(f"⛔ Извините, этот бот приватный.\n\nВаш Telegram ID: <code>{message.from_user.id}</code>", parse_mode="HTML")
async def main():
print("Бот запущен...")
await dp.start_polling(bot)
if __name__ == "__main__":
asyncio.run(main())
+3
View File
@@ -0,0 +1,3 @@
aiogram==3.4.1
yt-dlp==2024.3.10
mutagen