homelab/services/vk-podcast-bot/telegram_sender.py

104 lines
3.0 KiB
Python

import requests
import time
import os
from pathlib import Path
from audio_splitter import split_audio
from requests_toolbelt.multipart.encoder import MultipartEncoder, MultipartEncoderMonitor
from requests.exceptions import ConnectionError, ReadTimeout, ChunkedEncodingError
BOT_TOKEN = os.environ["TELEGRAM_TOKEN"]
CHAT_ID = os.environ["CHAT_ID"]
MAX_RETRIES = 5
def progress_callback(monitor):
percent = monitor.bytes_read / monitor.len * 100
print(f"\rUploading: {percent:5.1f}%", end="", flush=True)
def send_message(text):
url = f"https://api.telegram.org/bot{BOT_TOKEN}/sendMessage"
r = requests.post(url, data={
"chat_id": CHAT_ID,
"text": text
}, timeout=30)
if not r.ok:
print("Telegram message error:", r.text)
def upload_file(file_path, caption):
url = f"https://api.telegram.org/bot{BOT_TOKEN}/sendAudio"
for attempt in range(1, MAX_RETRIES + 1):
print(f"Connecting to Telegram (attempt {attempt}/{MAX_RETRIES})")
try:
with open(file_path, "rb") as f:
encoder = MultipartEncoder(
fields={
"chat_id": str(CHAT_ID),
"title": caption,
"audio": (file_path.name, f, "audio/mpeg"),
}
)
monitor = MultipartEncoderMonitor(encoder, progress_callback)
print("Connection established, starting upload...")
r = requests.post(
url,
data=monitor,
headers={"Content-Type": monitor.content_type},
timeout=(20, 3600) # (connect_timeout, read_timeout)
)
print("\nServer responded:", r.status_code)
if r.ok:
print("Upload success")
return True
print("Telegram API error:", r.text)
except ConnectionError:
print("\nConnection dropped by Telegram")
except ReadTimeout:
print("\nUpload timed out")
except ChunkedEncodingError:
print("\nChunked encoding error (connection reset)")
except Exception as e:
print("\nUnexpected error:", repr(e))
wait = 5 * attempt
print(f"Retrying in {wait} sec...\n")
time.sleep(wait)
return False
def send_audio(file_path, title):
parts = split_audio(Path(file_path))
for i, part in enumerate(parts, start=1):
caption = title
if len(parts) > 1:
caption = f"{title} (part {i}/{len(parts)})"
print("Uploading:", part.name)
success = upload_file(part, caption)
if not success:
return False # upload failed -> KEEP files for retry
# if we got here, ALL parts uploaded successfully -> cleanup
for part in parts:
part.unlink(missing_ok=True)
# also delete the original mp3 if we were uploading split parts
original = Path(file_path)
if len(parts) > 1 and original.exists():
original.unlink(missing_ok=True)
return True