Qik - это сервис стриминга (вещания) и загрузки видео с мобильных телефонов. Загруженное видео можно посмотреть на
сайте или на его
специальной версии с мобильного телефона. Доступна интеграция с другими сервисами, такими как Twitter, Facebook и другие. Клиенты для практически всех современных моделей телефонов: iPhone, Windows Mobile, Symbian, Android, Blackberry и другие.
Qik Push Engine - это механизм, который позволяет получать мгновенные оповещения о новых/изменившихся Qik-видео. Например, можно посмотреть постоянно обновляющийся список live-видео, все видео из района Новопеределкино или все видео со словом "кошка". На основе Qik Push Engine API можно построить интересные приложения, интегрированные с Qik, или добавить функциональность в уже существующие. Можно написать собственную систему нотификации, desktop-widget
или что-то еще.
Сегодня мы открываем API для работы c Qik Push Engine. Это первая ласточка в большом списке API, открывающих доступ к платформе стриминга Qik. Если вам интересно посмотреть Qik Push Engine в действии, заходите на одну из страниц примеров.
Основы работы с API
Qik Push Engine API доступно в виде набора удаленных процедур по протоколу JSON-RPC (over HTTP). В ближайшее время будет открыт REST-подобный интерфейс. Точкой входа для JSON-RPC является http://engine.qik.com/api/jsonrpc. Пока проект находится в закрытом бета-тестировании для доступа к API необходимо указать ключ разработчика, добавив параметр apikey: http://engine.qik.com/api/jsonrpc?apikey=xxxxxxx. Ключ разработчика можно получить, отправив письмо с запросом на api@qik.com.
Пример HTTP-сессии:
POST /api/jsonrpc
Host : engine.stage.qik.com
Content-Type: application/json; charset=UTF-8
Content-Length: 46
{"method": "qik.session.create", "params": []}
Ответ:
Content-Type: text/json
["a56c1603-1fbb-4140-8b35-8c36abbd8b27"]
Пример подписки на поток событий
Здесь и далее я буду использовать простую запись вызова команд, которая похожа на вызов обычных функций, опуская детали JSON-RPC взаимодействия. Итак, пусть мы хотим подписаться на список всех live-стримов, которые есть данный момент.
Первым делом создадим сессию:
qik.session.create() -> "a56c1603-1fbb-4140-8b35-8c36abbd8b27"
Подписываемся в рамках сессии на view всех публичных live-стримов, при этом указываем максимальное количество элементов во view (limit). Элементы view будут упорядочены в порядке убывания даты начала стрима (самые новые первыми):
qik.stream.subscribe\_public_live("a56c1603-1fbb-4140-8b35-8c36abbd8b27", 10) ->
[ "174/('PublicLiveStreamView', 'Stream', [('stoptime', None)], 'alllive;limit=10')", [ ... ] ]
В ответ на запрос мы получаем массив из двух элементов: первым является ключ подписки (длинная строка, начинающаяся с "174/.."). Не ищите смысла в ключе подписки, его необходимо просто сохранить, он потребуется в дальнейшем.
Вторым элементом является начальное состояние view, то есть текущий список live-стримов в нашем случае. Мы получим не больше 10 элементов (так как указали limit 10 при вызове метода qik.stream.subscribe_public_live
). Состояние view выглядит примерно следующим образом:
[
{"url": "http://qik.com/video/2158468",
"live": true,
"user_id": 340699,
"small_thumbnail_url": "http://media.qik.com/media.thumbnails.128/c8ad8fe065ad4ad7ac8491874c043eac.jpg",
"title": "Untitled", "duration": 0,
"created_at": "2009-07-11 15:56:03",
"views": 0,
"id": 2158468},
{"url": "http://qik.com/video/2158466",
"live": true,
"user_id": 340119,
"small_thumbnail_url": "http://media.qik.com/media.thumbnails.128/984c33e1ead441038f315e1fff109fc5.jpg",
"title": "Testando!",
"duration": 0, "created_at": "2009-07-11 15:55:34",
"views": 0,
"id": 2158466}
]
Смысл большинства полей очевиден, приведу лишь некоторые комментарии:
- все даты приведены в UTC;
- поле
duration
хранит длительность видео в секундах.
Так как мы подписались на live-стримы, у всех видео live == true
.
Теперь нам необходимо получать новые события для тех view, на которые мы подписались. Для этого используются HTTP long polling-запросы. Клиент отправляет запрос серверу, а сервер отправляет ответ, когда появляются события или когда истечет таймаут, если событий не появилось.
Для реализации long polling в цикле вызываем метод qik.session.get_events
, указывая желаемый таймаут (не рекомендуется использовать таймаут более 90 секунд).
qik.session.get_events("a56c1603-1fbb-4140-8b35-8c36abbd8b27", 60) ->
[ {...} ,{...} ]
В ответ мы можем получить пустой массив событий, если истек таймаут, или некоторый набор событий следующего вида:
[
{
"action": "update",
"old": {"id": 104252, "title": "Untitled", "views": 0, ...},
"obj": {"id": 104252, "title": "driving to key largo", "views": 5, ...},
"key": "175/('PublicRecentStreamView', 'Stream', [], 'allrecent;limit=50')"
},
]
В каждом событии обязательно передается следующая инормация:
-
key
- ключ подписки, это то же самое значение, которое мы получили при подписке на view, ключ позволяет отличать события для разных view в рамках одной сессии;
-
action
- действие (изменение), произошедшее с view:
-
ping
- ничего не произошло, просто view сообщает, что все хорошо :)
-
update
- элемент view изменился (как в примере выше), передается старое и новое состояние объекта в полях old
и obj
-
insert
- во view добавился новый элемент, его состояние будет записано в поле obj
-
delete
- элемент исчез из view (может быть, видео было удалено, или просто перестало удовлетворять критериям view, или ушло за границу "limit"), последнее состояние объекта будет записано в поле obj
.
В ответ на события мы можем обновить информацию на экране для пользователя, выполнить какие-либо еще действия. Но обязательно надо отправить новый запрос qik.session.get_events
, чтобы получить новые события.
В конце работы не забываем "убраться" за собой, убиваем сессию:
qik.session.destroy("a56c1603-1fbb-4140-8b35-8c36abbd8b27")
Замечания:
- В рамках одной сессии можно подписаться на произвольное количество view.
- Если это необходимо, можно авторизовать сессию от имени пользователя с помощью
qik.session.authorize
.
- Существует большое количество вспомогательных запросов, которым сессия вообще не требуется, например
qik.user.public_profile
.
- Можно отписаться от view при помощи конмады
qik.session.unsubscribe
.
Reference JS-клиент
Для демонстрации возможностей Qik Push Engine и проверки его работы был реализован легкий JavaScript-клиент. Его можно увидеть в работе на примерах, полный список которых приведен ниже.
Если вы запустите пример в Firefox с включенным Firebug, в консоли Firebug будет появляться подробная информация о выполняемых запросах к Qik Push Engine API, полученных ответах и т.п.
Исходный код клиента доступен в необфусцированном виде, со всеми комментариями. Код предоставляет по принципам public domain, то есть можете делать с ним все, что захотите - использовать в своих приложениях, модифицировать, переписывать на другие языкаи программирования и т.п.
Пробежимся быстро по компонентам JS-клиента.
Совершенно стандартный Prototype, ничего интересного.
Deferred
- это одна из основных концепций Twisted Framework (http://twistedmatrix.com). Deferred не является обязательным для взаимодействия с Qik Push Engine API, но позволяет сильно упростить сложные взаимодействия в асинхронном коде.
В качестве дополнительного материала о Deferred можно почитать про основы работы с Deferred, более сложные случаи использования Deferred, данную реализацию Deferred для Prototype, а также взглянуть на Deferred в других JS-фреймворках: MochiKit,
Dojo.
DeferredManager
- простая конструкция на основе Deferred, позволяет запускать не более N асинхронных действий в один момент времени.
Ядро клиента, объявляется namespace QikEngine
, отладочные функции, определение конфигурации, создания объекта для доступа к API и т.п.
QikEngine.API
- простая обертка JSON-RPC API Qik Push Engine, возвращающая Deferred
в качестве результата любого обращения к API. Через Deferred
же отправляются ошибки и результаты выполнения методов.
QikEngine.Session
- класс, оборачивающий понятие сессии, создание, уничтожение, авторизация в рамках сессии.
QikEngine.Events
- получение новых событий с помощью HTTP long polling, технология, похожая на BOSH/Comet. Распределение событий подписчикам (конкретным view).
QikEngine.View
- абстрактный класс, представляющий view на стороне клиента. Обслуживание обновлений, отображение в элементах HTML, обработка событий и т.п. Списки элементов хранятся прямо в DOM-контейнере в виде HTML-узлов.
Потомки QikEngine.View
для реализации конкретных view: QikEngine.PublicUserStreamView
, QikEngine.PublicRecentStreamsView
и т.д.
Очень простой интерфейс между данными, полученными из Qik Push Engine (например, информацией о стримах) и HTML-элементами. Адаптация данных, например, перевод дат из UTC в локальный формат, форматирование значений и т.п.
QikEngine.UserCache
- механизм загрузки информации о пользователях (по их ID). Использует DeferredManager
для ограничения количества параллельных запросов.
Что делать дальше?
- смотрите описание API;
- пишите письмо на api@qik.com, расскажите о своем проекте и получайте ключ для доступа к API.
Полный список примеров
Во всех примерах списки видео обновляются автоматически при внесении изменений на сайте или с мобильного телефона, например, если открою доступ Васе к моему приватному видео, он тут же увидит это видео в списке моих стримов и т.п.