Add show color and notes params

This commit is contained in:
Speng Reb 2026-05-31 22:50:04 +02:00
parent 952440bb05
commit 7f7c10d02c
5 changed files with 35 additions and 2 deletions

View file

@ -181,6 +181,7 @@ Show endpoints manage scheduled playlist runs. They support bot Bearer auth and
```python
shows = bot.list_shows() # rank >= MOD
public_shows = bot.list_public_shows() # read-only public schedule
show = bot.get_show(show_id) # rank >= MOD
payload = {
@ -195,6 +196,8 @@ payload = {
{"type": "yt", "id": "dQw4w9WgXcQ", "pos": "end"}
],
"status": "scheduled",
"notes": "<p>Special guest this week.</p>",
"color": "#22AAEE",
}
created = bot.create_show(payload) # rank >= MOD
@ -215,6 +218,8 @@ Create/update payload constraints:
- `conflict_mode`: `force` | `skip`
- `playlist`: required non-empty array of media entries with `type`, `id`, and optional `pos` (`next` | `end`)
- `status`: `draft` | `scheduled` | `paused` | `completed` | `failed` | `canceled` (`running` is internal)
- `notes`: optional `string | null` (rich HTML allowed; expected max input length 20000 chars before sanitize)
- `color`: optional `string | null`, must match `^#[0-9A-Fa-f]{6}$` when provided
Action payload schema:

View file

@ -4,8 +4,8 @@ build-backend = "setuptools.build_meta"
[project]
name = "veretube-bot"
version = "0.1.4"
description = "Python bot library for veretube sync channels"
version = "0.1.5"
description = "Python bot library for veretube/sync v4.0 channels"
readme = "README.md"
license = "MIT"
requires-python = ">=3.10"

View file

@ -1,4 +1,5 @@
import urllib.parse
import re
import requests
@ -122,6 +123,8 @@ class BotAPI:
# ── Shows ─────────────────────────────────────────────────────────────────
_SHOW_COLOR_RE = re.compile(r"^#[0-9A-Fa-f]{6}$")
def _validate_show_payload(self, payload: dict) -> None:
timezone = payload.get("timezone")
if not isinstance(timezone, str) or not timezone.strip():
@ -143,6 +146,20 @@ class BotAPI:
if status is not None and status not in {"draft", "scheduled", "paused", "completed", "failed", "canceled"}:
raise ValueError("status must be one of: draft, scheduled, paused, completed, failed, canceled")
notes = payload.get("notes")
if notes is not None:
if not isinstance(notes, str):
raise ValueError("notes must be a string or null")
if len(notes) > 20000:
raise ValueError("notes must be at most 20000 characters")
color = payload.get("color")
if color is not None:
if not isinstance(color, str):
raise ValueError("color must be a string or null")
if not self._SHOW_COLOR_RE.fullmatch(color):
raise ValueError("color must match /^#[0-9A-Fa-f]{6}$/")
playlist = payload.get("playlist")
if not isinstance(playlist, list) or not playlist:
raise ValueError("playlist is required and must be a non-empty list")
@ -159,6 +176,10 @@ class BotAPI:
"""List channel shows. Requires rank >= MOD."""
return self._request("GET", "/shows")
def list_public_shows(self) -> list:
"""List public show schedule. Read-only."""
return self._request("GET", "/shows/public")
def get_show(self, show_id: int | str) -> dict:
"""Get a single show by id. Requires rank >= MOD."""
return self._request("GET", f"/shows/{show_id}")

View file

@ -250,6 +250,9 @@ class AsyncBot:
async def list_shows(self) -> list:
return await asyncio.to_thread(self.api.list_shows)
async def list_public_shows(self) -> list:
return await asyncio.to_thread(self.api.list_public_shows)
async def get_show(self, show_id: int | str) -> dict:
return await asyncio.to_thread(self.api.get_show, show_id)

View file

@ -330,6 +330,10 @@ class Bot:
"""List scheduled shows. Requires rank >= MOD."""
return self.api.list_shows()
def list_public_shows(self) -> list:
"""List public scheduled shows. Read-only."""
return self.api.list_public_shows()
def get_show(self, show_id: int | str) -> dict:
"""Get a single show by id. Requires rank >= MOD."""
return self.api.get_show(show_id)