Вступление
Это III часть цикла статей, посвященных написанию плагинов для XBMC с собственным интерфейсом. В предыдущих частях (часть I и часть II) я рассказал об основных принципах создания интерфейса плагинов XBMC и дал несколько простых примеров. В этой части я хочу совсем кратко рассказать о различных API для взаимодействия с XBMC, продемонстрировать написанный мною микро-фреймворк, упрощающий компоновку интерфейса.
Дополнение от 3.11.14: во время написания первых двух частей я пообещал вскоре написать 3-ю часть статьи. Но, к сожалению, жизнь вносит свои коррективы, и написание 3-й части пришлось отложить до лучших времен. Теперь я постараюсь исполнить обещанное, хоть и не в полной мере: рассказ о микро-фреймворке будет несколько упрощенным.
API
Рассказ о написании плагинов для XBMC был бы неполным без хотя бы краткого рассказа о различных API, обеспечивающих взаимодействие плагинов с XBMC. До сих пор в статьях речь шла об API для создания интерфейса, но ведь плагинам нужно выполнять и другие задачи: получение информации о медиафайлах, управление проигрыванием и т. п. Для выполнения этих задач в XBMC существует 3 основных API: Python API, встроенные функции (built-ins) и протокол JSON-RPC. Далее совсем кратко поговорим о каждом из них.
Python API
Набор из 5 модулей Python: xbmc, xbmcgui, xbmcplugin, xbmcaddon, xbmcvfs для взаимодействия с XBMC. Модули написаны на C++, используя Python-C API (SWIG). Ниже их краткий обзор:
xbmc — общее взаимодействие с XBMC;
xbmcgui — взаимодействие с GUI;
xbmcplugin — организация плагинов-источников контента;
xbmcaddon — доступ к различным параметрам плагинов (настройки, языковые файлы и т. п.);
xbmcvfs — работа с файловой системой.
Встроенные функции (builtins)
Набор команд для управления XBMC. Для вызова встроенных функций не обязательно писать программный код: их можно, к примеру, привязать к кнопке пульта или клавиатуры путем редактирования соответствующего конфигурационного файла. Перечень встроенных функций можно найти здесь.
Для вызова встроенных функций из скриптов на Питоне существует функция xbmc.executebuiltin().
Протокол JSON-RPC
Протокол для локального и удаленного управления XBMC на базе JSON-RPC. Обеспечивает широкие возможности взаимодействия с XBMC, включая двухсторонний обмен информацией. В последнем примере данной статьи протокол JSON-RPC используется для получения информации о последних добавленных в медиатеку фильмах. Подробнее о протоколе JSON-RPC в XBMC можно почитать здесь.
Для локального управления и обмена информацией по протоколу JSON-RPC используется функция xbmc.executeJSONRPC(). Кроме того, в состав стандартной библиотеки Питона входит модуль json, упрощающий обработку строк JSON.
Удаленное взаимодействие с XBMC на других компьютерах можно осуществлять при помощи модуля urllib2 стандартной библиотеки.
Возможности этих API частично пересекаются, и одну и ту же операцию нередко можно выполнить разными способами.
Примечание: вплоть до версии 11.0 в XBMC также был Web-API, который позволял управлять XBMC при помощи команд в URL-encoded нотации. Однако, начиная с версии 12.0, он был убран в силу избыточности, поскольку JSON-RPC обеспечивает намного большие возможности.
PyXBMCt — микрофреймворк для упрощения компоновки интерфейса плагинов
Как видно из предыдущих частей данного цикла статей, API для создания интерфейса плагинов на базе классов Window/WindowDialog и потомков класса Control не очень удобен: приходится оперировать абсолютными координатами, и графическое оформление интерфейса полностью возлагается на разработчика.
Идея создания микро-фреймоврка, который бы упростил создание интефейса плагинов (естественно, в пределах возможностей XBMC Python API), родилась у меня в ходе написания собственного плагина для закачки субтитров. В XBMC до версии 13.0 плагины субтитров были полностью автономными скриптами, и создание интерфейса возлагалось на разработчика. К слову, в версии 13.0 архитектуру плагинов субтитров полностью поменяли, и теперь они работают аналогично плагинам-источникам контента, а за интерфейс отвечает базовый код XBMC (кстати, с 14-й версии медиацентр будет называться Kodi).
Чтобы не возиться с абсолютными координатами элементов интерфейса, я написал wrapper вокруг классов Window/WindowDialog/Control, реализующий подобие менеджера геометрии Grid, и украсил всё это дело текстурами, взятыми с дефолтного скина XBMC — Confluence. Получилось неплохо, и я решил сделать на базе этого полноценный микро-фреймворк. В качестве образца был взят PyQt, поэтому фреймоврк получил название PyXBMCt.
Фреймворк предлагает 4 базовых класса-контерйнера и 9 готовых к использованию виджетов, или, как они называются в XBMC, контролов. За размещение контролов на экране отвечает менеджер геометрии Grid, и интерактивные контролы связываются с с функциями/методами аналогично механизму сигналов-слотов в PyQt. Те, кто знаком с PyQt/PySide, должны освоить PyXBMCt в два счета.
Для наглядности рассмотрим совсем простой пример.
Микро-фреймворк PyXBMCt присутствует в официальном репозитории XBMC/Kodi, поэтому, чтобы воспользоваться им, нужно добавить в раздел файла addon.xml вашего плагина (подробнее об архитектуре плагинов см. здесь) следующую строку:
<import addon="script.module.pyxbmct" version="1.1.4"/>
Теперь при установке вашего плагина из репозитория или файла ZIP микро-фреймворк подтянется из официального репозитория автоматически. Кроме того, в Kodi 14.0 «Helix» наконец-то появилась возможность устанавливать служебные плагины вручную, и плагин PyXBMCt можно установить заранее самому.
В качестве простейшего примера, естественно, возьмем «Hello World»:
# -*- coding: utf-8 -*-
# Импортируем модуль PyXBMCt.
import pyxbmct.addonwindow as pyxbmct
class MyWindow(pyxbmct.AddonDialogWindow):
def __init__(self, title=''):
# Вызываем конструктор базового класса.
super(MyWindow, self).__init__(title)
# Устанавливаем ширину и высоту окна, а также разрешение сетки (Grid):
# 2 строки и 3 столбца.
self.setGeometry(350, 150, 2, 3)
# Создаем текстовую надпись.
label = pyxbmct.Label('This is a PyXBMCt window.', alignment=pyxbmct.ALIGN_CENTER)
# Помещаем надпись в сетку.
self.placeControl(label, 0, 0, columnspan=3)
# Создаем кнопку.
button = pyxbmct.Button('Close')
# Помещаем кнопку в сетку.
self.placeControl(button, 1, 1)
# Устанавливаем начальный фокус на кнопку.
self.setFocus(button)
# Связываем кнопку с методом.
self.connect(button, self.close)
# Связываем клавиатурное действие с методом.
self.connect(pyxbmct.ACTION_NAV_BACK, self.close)
# Создаем экземпляр окна.
window = MyWindow('Hello, World!')
# Выводим созданное окно.
window.doModal()
# Принудительно удаляем экземпляр окна после использования.
del window
Если всё сделано правильно, на экране появится такое окошко с кнопкой:
Теперь, подробный разбор. Для отображения номеров строк используйте текстовый редактор с соответствующей функцией, например Notepad++. Думаю, те, кто знаком с PyQt/PySide или с другими «взрослыми» GUI-фреймворками, сразу поймут, что к чему, поэтому очевидные вещи пропускаю.
Строка 13: метод self.setGeometry() задает ширину и высоту окна, а также разрешение координатной сетки родительского окна, в которой размещаются контролы. Принцип полностью аналогичен компоновщику QtGui.QGridLayout. По умолчанию окно помещается в центр экрана, но при желании можно задать точные координаты окна в виде дополнительных параметров этого метода.
Строка 17: метод self.placeControl() помещает выбранный контрол в координатную сетку. Как и в настоящем QtGui.QGridLayout, контрол может занимать несколько строк и столбцов.
Строка 23: метод setFocus() устанавливает начальный фокус на выбранный контрол. При наличии любых интерактивных контролов этот метод является обязательным, иначе вы просто не сможете управлять своим плагином с клавиатуры/пульта.
При наличии нескольких интерактивных контролов также нужно настроить правила навигации между ними (см. предыдущие части).
Строки 25 и 27: метод self.connect() связывает контрол или числовой код клавиатурного события с функцией/методом. Естественно, здесь используется ссылка на функцию (без круглых скобок ()), а не вызов функции. Также здесь можно использовать lambda — всё как в настоящем PyQt.
Связать можно только те контролы, которые генерируют событие при их активации: это Button, RadioButton и List. Другие контролы не генерируют событий, и связывать их бесполезно.
Числовые коды событий, генерируемых органами управления (клавиатурой, мышью, джойстиком и т. п.) можно найти здесь. PyXBMCt включает символьные имена для часто используемых событий.
Числовой код ACTION_PREVIOUS_MENU или 10 (по умолчанию — клавиша ESC на клавиатуре) всегда связан с методом close(), закрывающим окно, и переназначить его нельзя. Это сделано для того, чтобы окно плагина всегда можно было закрыть.
Строка 35: после использования экземпляр окна принудительно удаляется (вызывается деструктор экземпляра окна и всех объектов, связанных с ним). Дело здесь в том, что Garbage Collector почему-то не удаляет объекты классов xbmcgui после завершения работы плагина, что может приводить к утечкам памяти. Поэтому открытые окна на базе xbmcgui/PyXBMCt нужно удалять из памяти принудительно.
Практический пример использования PyXBMCt можно увидеть в моем плагине ex.ua.alternative, где микро-фреймворк используется для создания окна входа на сайт:
Подробнее с PyXBMCt можно познакомиться по ссылкам ниже (английский язык).
Автоматически сгенерированная документация по классам и методам PyXBMCt.
Репозиторий PyXBMCt на Github.
Тема на официальном форуме XBMC (Kodi).
Плагин, демонстрирующий возможности PyXBMCt (скриншот под спойлером ниже).
Конечно, интерфейс плагина, созданный на базе PyXBMCt, уступает по возможностям и «украшательствам» интерфейсу на базе XML-скина. Однако во многих случаях его возможностей вполне достаточно, и те, кто знакомы с «настольными» GUI-фреймворками, в частности PyQt/PySide, могут освоить PyXBMCt очень быстро.
Заключение
На этом я заканчиваю цикл статей, посвященных написанию плагинов для XBMC (Kodi). К сожалению, в силу ряда обстоятельств 3-я часть выходит со значительным запозданием, но, как говорится, «лучше поздно, чем никогда».
Предыдущие статьи
Подробная анатомия простого плагина для XBMC.
Пишем плагин для XBMC с собственным интерфейсом: часть I — теория и простейший пример.
Пишем плагин для XBMC с собственным интерфейсом: часть II — диалоги и украшателства.
Автор: Roman_V_M