Глобальные методы UI
PotokSDK.ui — рендер, HUD, плеер, навигация, регистрация.
ui.render()
Заголовок раздела «ui.render()»ui.render(component, slotId?) — компиляция разметки и отправка хосту. slotId — проекция в слот; без него — экран песочницы.
Уведомления HUD
Заголовок раздела «Уведомления HUD»Метод ui.showHUD(type: string, message: string) вызывает кратковременный системный баннер в углу экрана. Поддерживаемые типы: “success”, “error”, “info”, “warning”.
Запуск Видеоплеера
Заголовок раздела «Запуск Видеоплеера»ui.playVideo(playbackInfo) — полноэкранный плеер. Поля playbackInfo:
ui.playVideo({ streamUrl: "http://example.com/video.m3u8", streamType: "m3u8", title: "Название фильма", season: 1, episode: 3, torrentHash: "abc123def456", fileIndex: "0", audios: [ { id: "ru", name: "Русский дубляж", url: "http://example.com/video_ru.m3u8" }, { id: "en", name: "Английский оригинал", url: "http://example.com/video_en.m3u8" } ], headers: { "User-Agent": "PotokPlayer" }, providerId: "my-torrents", voice: "dub", subtitles: [ { id: "ru-vtt", src: "http://example.com/subs_ru.vtt", label: "Русские", language: "ru", isDefault: true, format: "vtt", name: "Русские", srclang: "ru", url: "http://example.com/subs_ru.vtt" } ], session: { keepaliveUrl: "http://example.com/session/keepalive", stopUrl: "http://example.com/session/stop", intervalSec: 30, hash: "abc123def456", file: "0", statusUrl: "http://example.com/session/status", statusIntervalSec: 5 }, duration: 7200, introStart: 0, introEnd: 90, outroStart: 7080, outroEnd: 7200, thumbnails: { urlTemplate: "http://example.com/thumbs/{time}.jpg", intervalSec: 5 }, requiresBuffering: false});Селектор Серий
Заголовок раздела «Селектор Серий»Метод ui.showEpisodeSelector(config) вызывает системное всплывающее окно для выбора сезонов и серий, разработанное специально для сериалов.
ui.showEpisodeSelector({ title: "Имя сериала", seasons: [ { id: 1, seasonNumber: 1, season_number: 1, episodes: [ { id: 101, episodeNumber: 1, episode_number: 1, name: "Серия 1", stillPath: "https://image.tmdb.org/t/p/w500/example.jpg", still_path: "https://image.tmdb.org/t/p/w500/example.jpg", airDate: "2011-04-17", air_date: "2011-04-17", overview: "Описание серии" } ] } ], episodes: [ { id: "s01e01", season: 1, episode: 1, rawSeason: 1, rawEpisode: 1, title: "Серия 1", fileName: "Show.S01E01.mkv", stillPath: "https://image.tmdb.org/t/p/w500/example.jpg", airDate: "2011-04-17", isWatched: false, sizeLabel: "1.2 GB", audios: [ { id: "ru", name: "Русский дубляж", url: "http://example.com/s01e01_ru.m3u8" }, { id: "en", name: "Английский оригинал", url: "http://example.com/s01e01_en.m3u8" } ], url: "http://example.com/s01e01.m3u8" } ], seasonsLoading: false, isSaving: false, tmdbSeasonsCount: 8, onPlay: (ep, audioId) => { console.log("Playing:", ep.season, ep.episode, audioId); }, onStartEditing: () => { console.log("Editing started"); }, onApplyOverride: (seasonNum, epNum) => { console.log("Override applied:", seasonNum, epNum); }, onClose: () => { console.log("Selector closed"); }});Навигация
Заголовок раздела «Навигация»ui.navigateTo(to, state?) — переход в раздел хоста (/settings, /library, …):
ui.navigateTo("/settings");ui.navigateTo("/library", { filter: "watchlist" });Темы оформления
Заголовок раздела «Темы оформления»Кастомные темы и акцент:
ui.registerThemes(themes)— регистрация Theme[] на хосте.ui.setAccentTheme(themeId)— переключение акцента.
Свой CSS (injectHostCss)
Заголовок раздела «Свой CSS (injectHostCss)»Внедрение или замена глобального стиля в хосте для переоформления любого встроенного компонента. Требует разрешение custom-css.
ui.injectHostCss(id, css) — добавить или заменить глобальный CSS-слой; он идёт после стилей приложения и выигрывает при равной специфичности.- Тот же id заменяет слой; пустая строка удаляет его.
- Сочетается с .style(‘my-class’) у компонента для точного таргетинга.
- Кнопка настроек и менеджер расширений остаются видимыми — плагин не заблокирует сам себя.
// Свой класс на компонентеconst card = Card().style("my-hero-card").child(Text("Featured"));ui.render(card);
// Стилизуем его глобально + перекрашиваем встроенный классui.injectHostCss("cards", ` .my-hero-card { border-radius: 1.5rem; box-shadow: 0 8px 24px rgba(0,0,0,.4); } .media-card-overlay { background: linear-gradient(to top, #000, transparent) !important; }`);
// Тот же id заменяет слой; пустая строка — удаляетui.injectHostCss("cards", "");Мутации блоков ui.block()
Заголовок раздела «Мутации блоков ui.block()»Метод ui.block(blockName) возвращает билдер для декларативного изменения существующих блоков интерфейса хоста. Через element(id) можно скрыть, отредактировать, вставить до/после или заменить элемент; append/prepend добавляют разметку; apply() отправляет мутации хосту.
- element(id).hide() — скрывает элемент блока.
- element(id).edit(props) — изменяет свойства элемента.
- element(id).before(ui) / after(ui) / replace(ui) — вставка или замена разметки.
- append(ui) / prepend(ui) — добавляет разметку в начало или конец блока.
- apply() — регистрирует накопленные мутации на хосте.
ui.onBlockContextUpdate()
Заголовок раздела «ui.onBlockContextUpdate()»Метод ui.onBlockContextUpdate(callback) подписывает плагин на обновления контекста активного блока интерфейса. Коллбек получает (blockName, context) при смене данных экрана (например, при переходе к другому фильму). Возвращает функцию отписки.
Регистрация в системе
Заголовок раздела «Регистрация в системе»Регистрация в хосте:
| Функция API | Описание |
|---|---|
registerPlugin(meta) |
Метаданные плагина (id, name, version). Вызывать первой при загрузке. |
registerSource(config) |
Регистрирует плагин как поисковый провайдер (источник медиа-потоков). Хост обращается к зарегистрированному источнику при поиске видеофайлов. |
registerSlotContribution(config) |
Регистрирует графический вклад в указанный интерфейсный слот (например, в кнопки действий или под описание медиафайла). |
onSettingsChanged(callback) |
Подписывает плагин на интерактивное изменение полей формы его настроек на хосте в реальном времени. В коллбек передаются (key, value, currentSettings). |
updateSettingsForm(updates) |
Отправляет команду хосту обновить значения полей формы настроек в реальном времени (например, для автозаполнения пресетов, сброса или валидации). Принимает объект обновлений { updates }. |
Детальное описание registerSlotContribution
Заголовок раздела «Детальное описание registerSlotContribution»Вклад UI в слот. Хост вызывает render при монтировании экрана.
Поля config:
-
id (string) — id вклада, как в slots манифеста.
-
slotName(string) —media-actions,details-bottom,extension-page, … -
render(props) (function) — возвращает { label, icon?, layout }.
-
label (string) — Название/подпись для вклада.
-
icon (string, опционально) — Имя иконки Lucide.
-
layout (
UIComponent) — Дерево UI компонентов (создается с помощью билдеровCard(),VStack(),Button() и т.д.).
Easy Plugin
Заголовок раздела «Easy Plugin»Кнопка трейлера в media-actions, блок в details-bottom:
Структура
Заголовок раздела «Структура»my-easy-plugin/├── manifest.json # Метаданные и объявление слотов└── index.js # Исполняемый JS код плагинаmanifest.json
Заголовок раздела «manifest.json»{ "id": "my-easy-plugin", "name": "Простой Просмотрщик", "version": "1.0.0", "description": "Добавляет кнопку просмотра трейлера и блок в деталях", "permissions": ["ui-notifications"], "slots": [ { "id": "trailer-action-button", "slotName": "media-actions", "title": "Кнопка Трейлера" }, { "id": "extra-details-info", "slotName": "details-bottom", "title": "Блок Информации" } ]}index.js
Заголовок раздела «index.js»import { PotokSDK } from 'potok-sdk';
PotokSDK.registerPlugin({ id: "my-easy-plugin", name: "Простой Просмотрщик"});
PotokSDK.registerSlotContribution({ id: "trailer-action-button", slotName: "media-actions", render(props) { const { Button } = PotokSDK.ui.components; return { label: "Смотреть Трейлер", icon: "play", layout: Button("Смотреть Трейлер") .variant("primary") .onClick(() => { PotokSDK.ui.playVideo({ streamUrl: "http://example.com/video.m3u8", streamType: "m3u8", title: "Название фильма", season: 1, episode: 3, torrentHash: "abc123def456", fileIndex: "0", audios: [ { id: "ru", name: "Русский дубляж", url: "http://example.com/video_ru.m3u8" }, { id: "en", name: "Английский оригинал", url: "http://example.com/video_en.m3u8" } ], headers: { "User-Agent": "PotokPlayer" }, providerId: "my-torrents", voice: "dub", subtitles: [ { id: "ru-vtt", src: "http://example.com/subs_ru.vtt", label: "Русские", language: "ru", isDefault: true, format: "vtt", name: "Русские", srclang: "ru", url: "http://example.com/subs_ru.vtt" } ], session: { keepaliveUrl: "http://example.com/session/keepalive", stopUrl: "http://example.com/session/stop", intervalSec: 30, hash: "abc123def456", file: "0", statusUrl: "http://example.com/session/status", statusIntervalSec: 5 }, duration: 7200, introStart: 0, introEnd: 90, outroStart: 7080, outroEnd: 7200, thumbnails: { urlTemplate: "http://example.com/thumbs/{time}.jpg", intervalSec: 5 }, requiresBuffering: false }); }) }; }});
PotokSDK.registerSlotContribution({ id: "extra-details-info", slotName: "details-bottom", render(props) { const { Card, VStack, Text, Badge, HStack } = PotokSDK.ui.components; return { label: "Дополнительно", icon: "info", layout: Card() .title("Рекомендовано плагином") .subtitle(`Кинопоиск ID: ${props.mediaId}`) .child( VStack() .spacing(8) .child(Text(`Вы просматриваете страницу "${props.title}". Этот блок встроил кастомный плагин.`).variant("secondary")) .child( HStack() .spacing(6) .child(Badge("Качество 1080p").color("success")) .child(Badge("Лицензия").color("info")) ) ) }; }});