python

Пишем плагин для XBMC с собственным интерфейсом: часть III — API и микро-фреймворк

  • среда, 5 ноября 2014 г. в 02:10:40
http://habrahabr.ru/post/194380/

Вступление


Это 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»:
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, где микро-фреймворк используется для создания окна входа на сайт:

Окно входа на ex.ua



Подробнее с PyXBMCt можно познакомиться по ссылкам ниже (английский язык).

PyXBMCt QuickStart Guide.

Автоматически сгенерированная документация по классам и методам PyXBMCt.

Репозиторий PyXBMCt на Github.

Тема на официальном форуме XBMC (Kodi).

Плагин, демонстрирующий возможности PyXBMCt (скриншот под спойлером ниже).

Скриншот PyXBMCt Demo



Конечно, интерфейс плагина, созданный на базе PyXBMCt, уступает по возможностям и «украшательствам» интерфейсу на базе XML-скина. Однако во многих случаях его возможностей вполне достаточно, и те, кто знакомы с «настольными» GUI-фреймворками, в частности PyQt/PySide, могут освоить PyXBMCt очень быстро.

Заключение


На этом я заканчиваю цикл статей, посвященных написанию плагинов для XBMC (Kodi). К сожалению, в силу ряда обстоятельств 3-я часть выходит со значительным запозданием, но, как говорится, «лучше поздно, чем никогда».

Предыдущие статьи


Подробная анатомия простого плагина для XBMC.
Пишем плагин для XBMC с собственным интерфейсом: часть I — теория и простейший пример.
Пишем плагин для XBMC с собственным интерфейсом: часть II — диалоги и украшателства.