SDK для Python
SDK для Python — owncast-plugin-py позволяет создавать плагины Owncast на Python. Вы пишете обычный код на Python с декораторами. Шаг сборки превращает его в один устанавливаемый плагин, который выполняется в песочнице внутри сервера Owncast: тот же формат .ocpkg и полный набор функций, что и у JavaScript SDK, поэтому плагин на Python — полноценный равноправный аналог плагина на JS.
SDK плагинов появились в Owncast 0.3.0 и API всё ещё развивается. Если вы наткнулись на баг или у вас есть предложение, пожалуйста, создайте issue или поговорите с сообществом в чате.
Эта страница посвящена специфике Python: установка, декораторы @plugin, CLI owncast-plugin-py и тестирование. Обработчики, API, права доступа и манифест работают одинаково в обоих SDK и имеют собственные справочные страницы.
Как это соотносится со справочной документацией
Общая справочная часть называет обработчики и API в их канонической форме (camelCase). To read it as Python, apply one rule: decorators, host methods, and payload attribute access are snake_case. Raw wire dictionaries (msg.raw) and scenario JSON keep their camelCase wire names. Quick orientation:
| В справочнике | В Python |
|---|---|
| Определить обработчик | функция, декорированная @plugin.* |
Обработчик события (например, chat.message.received) | @plugin.on_chat_message |
Вызов API хоста (например, owncast.chat.sendAction) | owncast.chat.send_action(text): snake_case |
Поля полезной нагрузки (например, msg.user.displayName) | msg.user.display_name, msg.client_id. msg.raw для исходного словаря |
Результат фильтра (filter.pass()) | filter.pass_() (суффикс _: pass — ключевое слово). Также filter.modify(...) / filter.drop(reason) |
| Declare a plugin-owned custom hook | @plugin.on("my.event"). Owned as <your-slug>.my.event |
| Собрать / протестировать ваш плагин | owncast-plugin-py package / owncast-plugin-py test |
Требования
- Сервер Owncast под вашим управлением, версии 0.3.0 или новее.
- Python 3.8 или новее.
Установка
Создайте каркас проекта с помощью команды new, передав slug. uvx запускает создатель каркаса прямо из PyPI без установки чего-либо:
uvx owncast-plugin-py new my-plugin
cd my-plugin
Установите SDK, чтобы получить CLI owncast-plugin-py в PATH для шагов сборки, тестирования, запуска и упаковки:
uv tool install owncast-plugin-py # or: pip install owncast-plugin-py
Вы получите готовую к сборке директорию:
my-plugin/
├── plugin.manifest.json name, slug, version, permissions
├── README.md how to build, test, package, and install it
├── INSTRUCTIONS.md optional, rendered as a tab in the admin
├── AGENTS.md notes for AI coding agents
├── .agents/ a bundled skill for AI coding agents
├── src/plugin.py your code, with a sample handler
└── __tests__/*.test.json a sample scenario test
Написать плагин
Импортируйте plugin, owncast и filter, и регистрируйте обработчики с помощью декораторов. Каждый декоратор подписывается на одно событие. SDK формирует список подписок в манифесте на основе определённых вами обработчиков.
from owncast_plugin import plugin, owncast, filter
@plugin.on_chat_message
def greet(msg):
name = msg.user.display_name if msg.user else "someone"
owncast.chat.send(f"{name} said: {msg.body}")
@plugin.filter_chat_message
def block_spam(msg):
return filter.drop("spam") if "spam" in msg.body else filter.pass_()
The module exports five things:
plugin: реестр декораторов.@plugin.on_chat_message,@plugin.filter_chat_message,@plugin.on_stream_started,@plugin.on_tick,@plugin.on_fediverse_followи остальные соответствуют событиям времени выполнения в Справочнике обработчиков. Two take a key:@plugin.on("custom.event")declares a local custom hook that the host owns as<your-slug>.custom.event, while@plugin.on_tab_content("slug")and@plugin.on_page_content("slug")provide dynamic viewer-page HTML. For tab content, the decorator argument matches amanifest.tabsobject key. For extra page content, it matchesmanifest.extraPageContent.slug. Два не принимают ключа:@plugin.on_page_stylesи@plugin.on_page_scriptsвозвращают CSS и JavaScript, внедряемые в страницу зрителя при запросе, защищённые разрешениемui.modify.owncast: пространство имён API хоста. Имена методов —snake_case(owncast.chat.send_action,owncast.kv.get_json). Каждый вызов контролируется соответствующим разрешением, которое вы указываете в манифесте. См. Справочник API.filter: результаты фильтра, возвращаемые обработчикомfilter_chat_message:filter.pass_()(суффикс_,pass— ключевое слово Python),filter.modify(...),filter.drop(reason).auth_check: verdict helpers for the@plugin.on_auth_checkhandler of anauth.gateplugin:auth_check.ok(),auth_check.refresh(ttl=...),auth_check.deny(reason).CommandContext: what a declared command'srun()receives:.msg,.user,.command,.invoked_as,.args, and.arg_string, plusreply(text)andreply_privately(text)helpers. Import it for type hints.
Полезные нагрузки — это объекты с атрибутным доступом в snake_case поверх JSON (msg.body, msg.user.display_name, msg.client_id). Используйте msg.raw для доступа к исходному словарю. Вызовы хоста, возвращающие JSON-объекты, возвращаются как те же объекты с атрибутным доступом (owncast.server.info().name). Списки возвращаются как Python-списки.
Ещё два идиоматичных приёма Python, которые стоит знать; оба подробно документированы (с примерами на Python) на соответствующих страницах:
- Маршрутизация HTTP: плагины с
http.serveобъявляют маршруты с декораторами:@plugin.get/post/put/delete/patch(path),@plugin.route(path, methods=[...]),@plugin.on_http_request(path), и общий@plugin.on_http_request-catch-all. Обработчик возвращаетdict({status, body, headers}),str(→ 200) илиNone(→ 204). См. Работа с HTTP. - Команды чата:
plugin.commands({...})объявляет команды с псевдонимами, ограничением доступа для модераторов и ограничениями на частоту использования для каждого пользователя. Встроенная команда!helpавтоматически их перечисляет. См. Команды чата.
CLI
Установка SDK даёт вам owncast-plugin-py. Сборка и упаковка объединяют ваш исходный код и не требуют компилятора. The test, serve, and package commands fetch the prebuilt host binaries on first use (package runs its install-time load check through the test binary):
| Команда | Что она делает |
|---|---|
owncast-plugin-py new my-plugin | Создаёт каркас нового проекта плагина в ./my-plugin |
owncast-plugin-py build | Собирает src/plugin.py (без упаковки) |
owncast-plugin-py test | Собирает, затем запускает сценарии из __tests__/ |
owncast-plugin-py serve | Локальный dev-сервер (-p/--port для изменения порта, по умолчанию 8080) |
owncast-plugin-py package | Сборка + упаковка → <slug>.ocpkg: файл, который вы распространяете |
owncast-plugin-py package # produces my-plugin.ocpkg
owncast-plugin-py test
owncast-plugin-py serve # POST /_dev/chat to drive event handlers
All four run against the current directory. The positional project argument defaults to ., so inside the project you pass nothing. From elsewhere, pass the project directory: owncast-plugin-py package my-plugin. .ocpkg — единый артефакт дистрибуции. См. Упаковка и распространение, чтобы узнать, что туда входит и как устанавливать.
Ограничения, которые стоит знать
Несколько особенностей сборки Python-плагинов влияют на то, как вы их пишете. Вы импортируете owncast_plugin как обычно для поддержки редактора и для модульных тестов. Сборка позаботится обо всём остальном.
- Только чистый Python и без
pip. Шагаpip installнет: вы добавляете сторонний код, копируя его (написанный на чистом Python) исходники в ваш проект. Зависимости с C-расширениями (numpy, pandas и им подобные) не загрузятся. См. Сторонние библиотеки. Для исходящих HTTP-запросов используйтеowncast.http.fetch, а неrequests. - Не затемняйте имена стандартной библиотеки. Определение на верхнем уровне
def json(...)(или любое другое имя из stdlib) затемняет реальный модуль и может нарушить сборку, а файл модуля с именем стандартного модуля (src/json.py) игнорируется в пользу настоящего. Назовите их, например,json_response. - The entry can't use relative imports. In
src/plugin.py, import your own modules absolutely (from helpers import ...), notfrom . import helpers. Относительный импорт там приводит к ошибке сборки, хотя относительные импорты внутри модулей самого пакета работают. snake_casein the code you write, in contrast to the JS SDK's camelCase:send_action,get_json,msg.user.display_name,filter.pass_(). Raw wire dictionaries (msg.raw) and scenario JSON stay camelCase.
Сторонние библиотеки
Нет pip install и нет requirements.txt. Сторонняя библиотека работает только если она написана на чистом Python и вы копируете её исходники в src/, где она становится одним из ваших модулей.
Установка пакета в виртуальное окружение не влияет на то, что попадает в релиз, и import requests завершится неудачей во время выполнения. Чтобы использовать библиотеку, скопируйте её .py исходники в src/ (один модуль или директорию пакета) и импортируйте её.
- C-расширения никогда не работают. numpy, pandas, lxml, Pydantic v2 и всё, что содержит скомпилированный код, не загрузится.
- Вы владеете всей иерархией. Если библиотека, которую вы скопировали, импортирует другие сторонние пакеты, скопируйте и их, или выберите более простую библиотеку.
- Для исходящих HTTP-запросов используйте
owncast.http.fetch, а неrequests.
Стандартная библиотека доступна, если модуль написан на чистом Python (json, re, datetime, base64 и т.д.).
Например, пример page-content-demo требует шаблонизации Mustache. Вместо копирования пакета шаблонизатора, он содержит собственный небольшой рендерер подмножества Mustache.
Тестирование
Тесты — это сценарные файлы __tests__/*.test.json, запускаемые с помощью owncast-plugin-py test. Формат идентичен формату JS SDK, поэтому порт плагина на Python может повторно использовать тестовые сценарии версии на JS без изменений. Каждый сценарий посылает события / HTTP-запросы и проверяет наблюдаемые побочные эффекты (chatSends, записи в kv, HTTP-ответы, …).
[
{
"name": "echoes the message",
"events": [
{
"event": "chat.message.received",
"payload": { "user": { "id": "u1", "displayName": "alice" }, "body": "hi" }
}
],
"expect": { "chatSends": ["alice said: hi"] }
}
]
Полная модель данных сценария (типы шагов, состояние given, утверждения expect) представлена на странице Тестирование. Обратите внимание, что JSON сценария использует имена полей wire (camelCase: displayName, clientId), поскольку он описывает события хоста, а не ваш Python-код.
Статус
Среда выполнения, CLI owncast-plugin-py (scaffold, build, test, serve, package), полный API хоста, HTTP-маршрутизация и упаковка в .ocpkg — всё это работает уже сейчас. Все примеры плагинов на JS имеют аналоги на Python в каталоге examples/python/.
Следующие шаги
- Справочник обработчиков: каждое событие, на которое вы можете подписаться (читайте имена в виде
snake_case). - Справочник API: каждый метод
owncast.*и разрешение, которое ему требуется. - Тестирование: полная модель данных сценария.
- Упаковка и распространение: сборка
.ocpkgи его установка. - Примеры плагинов на Python: по одному на каждую функцию, каждый — полный стартовый пример, который вы можете скопировать.
- Исходники SDK: пакет
owncast-plugin-pyи набор инструментов.
Improve this page
See something missing or incorrect? Edit this page and improve the documentation for everyone.
Gabe Kangas