Проект устроен как конвейер: Telegram-канал → каталог → эфир.
1) Индексатор пробегает канал, находит аудио и GIF/MP4, читает теги и формирует playlist.json.
2) /playlist?mix=&energy= отдаёт JSON с треками и визуалами уже в нужном порядке под текущие ручки.
3) /audio/{id} и /gif/{id} запрашивают медиа в Telegram и отдают его в браузер.
Ключевой принцип: аудио не сохраняется на диск. Сервер отдаёт данные потоково (chunked) по мере получения.
Визуалы кэшируются на диск, потому что они короткие и повторяются, а кэш заметно ускоряет переключения.
Самая важная часть (то, что превращает канал в эфир):
@app.get("/audio/{message_id}")
async def audio(message_id: int):
async def gen():
async for chunk in telethon_stream_bytes(message_id):
yield chunk
return StreamingResponse(
gen(),
media_type="audio/mpeg",
headers={"Cache-Control": "no-store", "Accept-Ranges": "none"},
)
— @app.get("/audio/{message_id}")
Маршрут: GET /audio/12345 попадает сюда, {message_id} это ID сообщения с треком в Telegram.
— async def audio(message_id: int):
Асинхронный обработчик, чтобы сервер не блокировался во время загрузки/отдачи. int фиксирует тип параметра.
— async def gen(): ... yield chunk
Асинхронный генератор: читает трек из Telegram порциями (async for) и сразу отдаёт каждый кусок (yield).
— StreamingResponse(gen(), ...)
Оборачивает поток в корректный HTTP-стрим: воспроизведение может начаться до полной загрузки файла.
— media_type="audio/mpeg"
Явно задаёт Content-Type, чтобы браузер правильно воспроизводил аудио.
— headers
no-store — не кэшировать аудио. Accept-Ranges: none — без Range-запросов (перемотка/дозагрузка “с середины” не предусмотрены).
Оглавление темы 📌
Навигация по проектам канала 📍
Все проекты 🎶
#WithoutStreaming@annsFlow
💻 annFlow