mirror of
https://github.com/Spengreb/sync.git
synced 2026-06-09 23:02:05 +00:00
Add example python bot for making shows
This commit is contained in:
parent
03922e8484
commit
e3dd961430
3 changed files with 171 additions and 0 deletions
32
examples/python-show-bot/README.md
Normal file
32
examples/python-show-bot/README.md
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
# Python Show Bot Example
|
||||||
|
|
||||||
|
Uses `veretube-bot==0.1.4` with `AsyncBot` and the built-in Shows API helpers.
|
||||||
|
|
||||||
|
## Setup
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd examples/python-show-bot
|
||||||
|
python3 -m venv .venv
|
||||||
|
source .venv/bin/activate
|
||||||
|
pip install -r requirements.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
Set environment variables:
|
||||||
|
|
||||||
|
- `BOT_TOKEN` (required)
|
||||||
|
- `CHANNEL` (required)
|
||||||
|
- `SOCKET_URL` (default: `http://localhost:1337`)
|
||||||
|
- `API_BASE` (default: `http://localhost:8080/api/v1`)
|
||||||
|
- `SHOW_TIMEZONE` (default: `UTC`, must be valid IANA timezone)
|
||||||
|
|
||||||
|
Run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python bot.py
|
||||||
|
```
|
||||||
|
|
||||||
|
## Chat Commands
|
||||||
|
|
||||||
|
- `!shows` - list shows
|
||||||
|
- `!mkshow` - create a demo show
|
||||||
|
- `!runshow <id>` - run a show immediately
|
||||||
116
examples/python-show-bot/bot.py
Normal file
116
examples/python-show-bot/bot.py
Normal file
|
|
@ -0,0 +1,116 @@
|
||||||
|
"""
|
||||||
|
Veretube Python Show Bot example (veretube-bot 0.1.4)
|
||||||
|
|
||||||
|
Commands in chat:
|
||||||
|
!shows -> list existing shows
|
||||||
|
!mkshow -> create an example show scheduled ~2 minutes from now
|
||||||
|
!show <id> -> inspect a show from API
|
||||||
|
!runshow <id> -> trigger immediate run of a show
|
||||||
|
"""
|
||||||
|
|
||||||
|
from datetime import datetime, timedelta, timezone
|
||||||
|
import asyncio
|
||||||
|
import os
|
||||||
|
|
||||||
|
from veretube_bot import AsyncBot, BotAPIError
|
||||||
|
|
||||||
|
BOT_TOKEN = os.getenv("BOT_TOKEN", "TOKEN_HERE")
|
||||||
|
CHANNEL = os.getenv("CHANNEL", "CHANNEL_NAME_HERE")
|
||||||
|
SOCKET_URL = os.getenv("SOCKET_URL", "http://localhost:1337")
|
||||||
|
API_BASE = os.getenv("API_BASE", "http://localhost:8080/api/v1")
|
||||||
|
SHOW_TIMEZONE = os.getenv("SHOW_TIMEZONE", "UTC")
|
||||||
|
|
||||||
|
bot = AsyncBot(
|
||||||
|
token=BOT_TOKEN,
|
||||||
|
channel=CHANNEL,
|
||||||
|
socket_url=SOCKET_URL,
|
||||||
|
api_url=API_BASE,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def create_example_show_payload() -> dict:
|
||||||
|
# Schedule a couple minutes in the future to make testing easy.
|
||||||
|
scheduled_for = datetime.now(timezone.utc) + timedelta(minutes=2)
|
||||||
|
|
||||||
|
return {
|
||||||
|
"name": f"Python Demo Show {scheduled_for.strftime('%H:%M:%S')}",
|
||||||
|
"scheduled_for": scheduled_for.isoformat(),
|
||||||
|
"timezone": SHOW_TIMEZONE,
|
||||||
|
"recurrence": "none",
|
||||||
|
"fill_mode": "append",
|
||||||
|
"conflict_mode": "force",
|
||||||
|
"start_playback": False,
|
||||||
|
"status": "scheduled",
|
||||||
|
"playlist": [
|
||||||
|
{"type": "yt", "id": "dQw4w9WgXcQ", "pos": "end"},
|
||||||
|
{"type": "yt", "id": "9bZkp7q19f0", "pos": "end"},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
@bot.on("chatMsg")
|
||||||
|
async def on_chat(data):
|
||||||
|
msg = (data.get("msg") or "").strip()
|
||||||
|
|
||||||
|
if msg == "!shows":
|
||||||
|
try:
|
||||||
|
shows = await bot.list_shows()
|
||||||
|
except BotAPIError as err:
|
||||||
|
await bot.send_message(f"shows error: {err}")
|
||||||
|
return
|
||||||
|
|
||||||
|
if not shows:
|
||||||
|
await bot.send_message("No shows configured")
|
||||||
|
return
|
||||||
|
|
||||||
|
summary = ", ".join([f"#{s['id']} {s['name']} ({s['status']})" for s in shows[:4]])
|
||||||
|
await bot.send_message(f"Shows: {summary}")
|
||||||
|
|
||||||
|
elif msg == "!mkshow":
|
||||||
|
try:
|
||||||
|
show = await bot.create_show(create_example_show_payload())
|
||||||
|
persisted = await bot.get_show(show["id"])
|
||||||
|
await bot.send_message(
|
||||||
|
f"Created show #{persisted['id']} status={persisted.get('status')} "
|
||||||
|
f"scheduled_for={persisted.get('scheduled_for')} timezone={persisted.get('timezone')}"
|
||||||
|
)
|
||||||
|
except BotAPIError as err:
|
||||||
|
await bot.send_message(f"create show error: {err}")
|
||||||
|
|
||||||
|
elif msg.startswith("!runshow "):
|
||||||
|
parts = msg.split()
|
||||||
|
if len(parts) != 2 or not parts[1].isdigit():
|
||||||
|
await bot.send_message("Usage: !runshow <show_id>")
|
||||||
|
return
|
||||||
|
|
||||||
|
show_id = int(parts[1])
|
||||||
|
try:
|
||||||
|
result = await bot.show_action(show_id, "run")
|
||||||
|
await bot.send_message(f"Show #{result['id']} run action complete, status={result['status']}")
|
||||||
|
except BotAPIError as err:
|
||||||
|
await bot.send_message(f"run show error: {err}")
|
||||||
|
|
||||||
|
elif msg.startswith("!show "):
|
||||||
|
parts = msg.split()
|
||||||
|
if len(parts) != 2 or not parts[1].isdigit():
|
||||||
|
await bot.send_message("Usage: !show <show_id>")
|
||||||
|
return
|
||||||
|
|
||||||
|
show_id = int(parts[1])
|
||||||
|
try:
|
||||||
|
show = await bot.get_show(show_id)
|
||||||
|
await bot.send_message(
|
||||||
|
f"Show #{show['id']}: status={show.get('status')} "
|
||||||
|
f"scheduled_for={show.get('scheduled_for')} timezone={show.get('timezone')}"
|
||||||
|
)
|
||||||
|
except BotAPIError as err:
|
||||||
|
await bot.send_message(f"show lookup error: {err}")
|
||||||
|
|
||||||
|
|
||||||
|
@bot.on("changeMedia")
|
||||||
|
async def on_media(data):
|
||||||
|
title = data.get("title", "(unknown)")
|
||||||
|
await bot.send_message(f"Now playing: {title}")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
asyncio.run(bot.run())
|
||||||
23
examples/python-show-bot/requirements.txt
Normal file
23
examples/python-show-bot/requirements.txt
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
aiohappyeyeballs==2.6.2
|
||||||
|
aiohttp==3.13.5
|
||||||
|
aiosignal==1.4.0
|
||||||
|
async-timeout==5.0.1
|
||||||
|
attrs==26.1.0
|
||||||
|
bidict==0.23.1
|
||||||
|
certifi==2026.5.20
|
||||||
|
charset-normalizer==3.4.7
|
||||||
|
frozenlist==1.8.0
|
||||||
|
h11==0.16.0
|
||||||
|
idna==3.15
|
||||||
|
multidict==6.7.1
|
||||||
|
propcache==0.5.2
|
||||||
|
python-engineio==4.13.1
|
||||||
|
python-socketio==5.16.1
|
||||||
|
requests==2.33.1
|
||||||
|
simple-websocket==1.1.0
|
||||||
|
typing_extensions==4.15.0
|
||||||
|
urllib3==2.7.0
|
||||||
|
veretube-bot==0.1.4
|
||||||
|
websocket-client==1.9.0
|
||||||
|
wsproto==1.3.2
|
||||||
|
yarl==1.24.2
|
||||||
Loading…
Add table
Reference in a new issue