mediacenter-docs.github.io

Разработка дополнений (плагинов) для приложения “Медиацентр” на языке Lua

Совместимость с версией приложения указано в виде «(>=версия)».

Содержание

  1. Общие сведения
  2. Конфигурационный файл
  3. Основной модуль программы
  4. Принципы построения внутренних ссылок
  5. Формирование ответа на запрос пользователя
  6. Формирование информации об элементе списка или телепрограммы EPG
  7. Дополнительные функции Lua
    7.1. Основные функции
    7.2. Функции работы со строками
    7.3. Использование PERL совместимых регулярных выражений (>= 0.3.1)
    7.4. Функции кодирования данных
    7.5. Функции поддержки криптографии (>=0.3.1)
    7.6. Сетевые функции
    7.7. Работа с документами в JSON формате
    7.8. Работа с документам в XML формате
    7.9. Вспомогательные функции
    7.10. Функции библиотеки Zlib (>=0.3.2)
    7.11. Выполнение программ на языке Python (>=0.3.3)
  8. Общие модули Lua
  9. Пример дополнения “Лента новостей

1. Общие сведения

Дополнение представляет собой ZIP архив (упакованный стандартным способом, режим сжатия – deflate) с расширением .IMC.zip, который содержит следующие файлы:

Также архив может содержать дополнительные модули и изображения. Дополнение загружается в память при открытии архива или внутренней ссылки и выгружается при выходе из приложения. Взаимодействие между пользователем и дополнением происходит на основе принципа запрос-ответ.

Конфигурационный файл, модули и возвращаемые дополнением данные должны быть в кодировке UTF-8 (без BOM), для конвертации из одной кодировки в другую предусмотрены дополнительные функции Lua.

Модули содержат текст программы на языке Lua (версия 5.3), подробнее про язык Lua можно прочитать на следующих ресурсах:

Вернуться к содержанию Вернуться в начало раздела

2. Конфигурационный файл

Конфигурационный файл представляет собой XML документ следующего вида:

<?xml version="1.0" encoding="UTF-8"?>
<service>
<id><!-- уникальный идентификатор дополнения (только латинские буквы, точки, тире и цифры) --></id>

<!-- заголовок дополнения -->
<label>@string/label</label>

<preferences>
<!-- содержит настройки дополнения -->

  <!-- пример настройки в виде текстового поля -->
  <item name="username" label="@string/username" type="text" />

  <!-- пример настройки в виде скрытого текста -->
  <item name="password" label="@string/password" type="password" />

  <!-- пример настройки в виде скрытого текста, где данные будут храниться в зашифрованном виде (>=0.3.3) -->
  <item name="password" label="@string/password" type="password" encrypted="true" />

  <!-- пример настройки в виде выбора значения из списка -->
  <item name="quality " label="@string/quality" type="list" entries="@array/quali_entries" values="@array/quali_values" />

  <!-- где:
      name - идентификатор настройки,
      label – заголовок,
      type – тип (значения: text – строка, password – скрытая строка, list – значение из списка),
      entries (только для типа list) – ссылка на массив строк (заголовки),
      values (только для типа list) – ссылка на массив строк (значения),
      encrypted (только для типов text и password) – хранить значение в зашифрованном виде (>=0.3.3)
  -->

</preferences>

<strings>
<!-- содержит строки и массивы строк на базовом языке -->

  <!-- пример строк -->
  <string name="label">My Label</string>
  <string name="username">Username</string>
  <string name="password">Password</string>
  <string name="quality">Quality video</string>

  <!-- пример массива строк -->
  <string-array name="quali_entries">
    <item>High quality</item>
    <item>Medium quality</item>
    <item>Low quality</item>
  </string-array>

  <string-array name="quali_values">
    <item>high</item>
    <item>medium</item>
    <item>low</item>
  </string-array>

<!-- где: name - идентификатор строки или массива строк.
  Элементы настроек и заголовок могут ссылаться на строки и массив строк по идентификатору:
  ссылка на строку – @string/идентификатор
  ссылка на массив строк – @array/идентификатор
 -->
</strings>

<!-- Для добавления строк и массива строк на языке локализации
	необходимо добавить контейнер <strings-[lang]>...</strings-[lang]>,
	где lang - кодовое обозначение языка по стандарту ISO 639-1 (например: en – английский, ru – русский, de – немецкий).
	заполнение <strings-[lang]>...</strings-[lang]> осуществляется аналогично <strings>...</strings>
 -->

 <!-- пример строк и массива строк на русском языке -->
 <strings-ru>
  <string name="label">Мой заголовок</string>
  <string name="username">Пользователь</string>
  <string name="password">Пароль</string>
  <string name="quality">Качество видео</string>

  <string-array name="quali_entries">
    <item>Высокое качество</item>
    <item>Среднее качество</item>
    <item>Низкое качество</item>
  </string-array>

  <string-array name="quali_values">
    <item>high</item>
    <item>medium</item>
    <item>low</item>
  </string-array>
</strings-ru>

</service>
Вернуться к содержанию Вернуться в начало раздела

3. Основной модуль программы

-- Функция выполняемая при загрузке дополнения
function onLoad()
  print('Hello from example!')
  -- Должна вернуть 1 (иначе загрузка будет прервана и пользователю будет выдано сообщение об ошибке)
  return 1
end

-- Функция выполняемая при выгрузке дополнения (может отсутствовать в модуле)
function onUnLoad()
  print('Bye bye!!!')
end

-- Функция формирования ответа на запрос пользователя (открытие дополнения или внутренней ссылки)
function onCreate(args)
  -- Возвращает результат в виде таблицы.
  return {}
end

-- Функция формирования информации об элементе списка или телепрограммы EPG (может отсутствовать в модуле)
-- Приложение запрашивает данную информацию если указан параметр meta у элемента в списке в виде внутренней ссылки
function onMeta(args)
  -- Возвращает результат в виде таблицы.
  return {}
end

-- Функция оповещения о состоянии в режиме управляемого воспроизведения (может отсутствовать в модуле)
function onEvent(args)
  -- Обработка оповещения.
end
Вернуться к содержанию Вернуться в начало раздела

4. Принципы построения внутренних ссылок

Ссылка на контент

#[type]/[ключ1=значение1&ключ2=значение2…]

где [type] (определяет тип контента в списке, не влияет при открытии ссылки):

Аргументы ключ – значение передаются в функцию onCreate в виде значения полей таблицы.

Например:

#video/q=video&id=390182

Ссылка на изображение

#self/[полное имя файла в архиве дополнения]

Например:

#self/icon.png

Ссылка запроса дополнительной информации

#self/[ключ1=значение1&ключ2=значение2…]

Аргументы ключ – значение передаются в функцию onMeta в виде значения полей таблицы

Ссылка запроса дополнительной информации (встроенная поддержка телепрограммы)

Для встроенного механизма заполнения телепрограммы в форматах XMLTV / MediaPortal / JTV используется следующий формат:

#tv/url=[ссылка на архив с телепрограммой]&name=[название телеканала или имя файла в архиве][&shift=часовой сдвиг]

Параметр shift используется только для формата JTV.

Например:

#tv/url=https://iptvx.one/epg/epg.xml.gz&name=Bridge

Ссылка оповещения о состоянии воспроизведения

#self/[ключ1=значение1&ключ2=значение2…]

Аргументы ключ – значение передаются в функцию onEvent в виде значения полей таблицы

Вернуться к содержанию Вернуться в начало раздела

5. Формирование ответа на запрос пользователя

Для формирования ответа предназначена функция onCreate основного модуля программы. В качестве аргумента функция принимает таблицу с ключами и значениями из внутренней ссылки. Рассмотрим варианты ответа:

Показать сообщение

return {
  view = 'msgbox',  -- (>=0.3.1) Вместо 'msgbox' можно указать 'message'.
  message = 'Текст сообщения'
}

Показать сообщение об ошибке

return {
  view = 'error',
  message = 'Текст ошибки'
}

Открыть диалог ввода строки

return {
  view = 'keyword',
  message = 'Текст подсказки',
  keyword = 'Строка по умолчанию'
}

При вводе пользователем происходит переход по текущей ссылке, где аргумент keyword заменяется (добавляется) введенным значением.

Открыть диалог ввода пользователя и пароля

return {
  view = 'login',
  message = 'Текст подсказки',
  error = 'Текст ошибки',
  username = 'Пользователь по умолчанию',
  password = 'Пароль по умолчанию'
}

При вводе пользователем происходит переход по текущей ссылке, где аргументы username и password заменяются (добавляются) введенными значениями.

Открыть диалог выбора учетной записи для получения токена, зарегистрированной в системе (>=0.3.3)

return {
  view = 'token',
  scope = 'права',
  type = 'Тип учетной записи (например com.google)',
  username = 'Пользователь по умолчанию (необязателен)'
}

При выборе пользователем происходит переход по текущей ссылке, где аргумент token заменяется (добавляется) введенным значением.

Открыть настройки дополнения

return {view = 'setup'}

Обновить текущий список

return {view = 'refresh'}

Вернуться на предыдущую страницу (>=0.3.3)

return {view = 'back'}

Отменить выполнение (>=0.3.4)

return {view = 'pass'}

Открыть список элементов

return {
  -- Вид просмотра списка
  view = 'grid',
  -- где view:
  --   'simple' – простой список (маленькая иконка и заголовок)
  --   'list' – список (иконка, заголовок, описание и индикатор передачи)
  --   'grid' – значки с заголовком
  --   'grid_large' – стоп-кадр с заголовками
  --   'grid_poster' – иконки в виде обложек фильмов
  --   'annotation' – страница с описанием контента
  --   'select' – выбор из всплывающего списка

  -- Тип контента (необязателен)
  type = 'folder',
  -- где type:
  --   'folder' – каталог (рекомендуется указывать когда в списке элементов может быть только один элемент)
  --   'playlist' – плейлист (если в плейлисте только один элемент то происходит автоматический переход по ссылке элемента)
    
  -- Отображать панель подробной информации (необязателен) (>= 0.3.4)
  detailed = true,

  -- Текст подсказки, отображаемый над списком элементов (необязателен)
  message = '...',
  
  -- Идентификатор для сохранения вида просмотра список / иконки с сохранением состояния (необязателен) (>= 0.3.2)
  -- Рекомендуется указывать для плейлистов IPTV
  viewtype = 'edem',

  -- Доступен ли выбор фильтра по типу элементов списка (необязателен) (>= 0.3.2)
  -- Рекомендуется указывать для списка файлов разных типов
  filterable = true,

  -- Определяет обновление страницы при наступлении системных событий (необязателен) (>= 0.3.3)
  actions = 'media',
  -- где actions:
  --  'media' – подключение / отключение носителя информации
  --  'package' – установка / удаление приложения
  --  'connect' – подключение к сети
  --  'disconnect' – отключение от сети

  -- Оригинальное название, отображается на странице с описанием контента (необязателен)
  name = 'Mission Impossible',

  -- Ссылка на иконку, отображается в виде постера на странице с описанием контента (необязателен)
  poster = 'http://...',

  -- Сюжет, отображается на странице с описанием контента (необязателен)
  description = '...',

  -- Список характеристик, отображается на странице с описанием контента (необязателен)
  annotation = {'Жанр: Боевик', 'Год выпуска: 2012', '...'},

  -- Меню быстрого вызова, отображаемый в правой стороне над списком элементов (необязателен)
  menu = {
    {
      -- Заголовок
      title = 'Жанры',

      -- Ссылка
      mrl = '#self/q=genres',
      --или (>=0.3.1)
      url = '#self/q=genres',

      -- Ссылка на иконку (необязателен)
      image = '#self/genres.png',
      -- или (>=0.3.1)
      icon = '#self/genres.png',

      -- Тип контента для ускорения запуска просмотра (необязателен) (>=0.3.3)
      type = 'video'
      -- где type: 'video' - видео файл, 'stream' - онлайн трансляция, 'audio' - аудио файл (интернет-радио), 'photo' - файл картинки (>=0.3.4), 'text' - текстовый файл (>=0.3.4)
    }
  },

  -- Список элементов
    {
      -- Заголовок
      title = 'Планета обезьян',

      -- Ссылка
      mrl = 'http://server.com/video/appes.mp4',
      --или (>=0.3.1)
      url = 'http://server.com/video/appes.mp4',

      -- Ссылка на иконку (необязателен)
      image = 'http://server.com/images/appes.jpg',
      -- или (>=0.3.1)
      icon = 'http://server.com/images/appes.jpg',

      -- Тип контента для ускорения запуска просмотра (необязателен) (>=0.3.3)
      type = 'video',
      -- где type: 'video' - видео файл, 'stream' - онлайн трансляция, 'audio' - аудио файл (интернет-радио), 'photo' - файл картинки (>=0.3.4), 'text' - текстовый файл (>=0.3.4)

      -- Описание (необязателен)
      annotation = '...',
      -- или
      annotation = {'...', '...', '...'},

      -- Группа или категория (необязателен)
      group = 'Кино',

      -- Меню элемента списка (необязателен)
      -- Отображается в всплывающем диалоге при долгом нажатии кнопки выбора
      -- Структура аналогична меню быстрого вызова
      menu = {}

      -- Внутренняя ссылка для формирования информации об элементе списка или телепрограммы (необязателен)
      -- Для формирования результата дополнением
      meta = '#self/[key=value][&key2=value2][...]', -- аргументы keyN=valueN передаются в виде таблицы в функцию onMeta
      -- Для использования встроенного механизма заполнения телепрограммы в формате XMLTV / MediaPortal
      meta = '#tv/url=http://programtv.ru/xmltv.xml.gz&name=Bridge',
      -- Для использования встроенного механизма заполнения телепрограммы в формате JTV
      meta = '#tv/url=http://programtv.ru/jtv.zip&name=Bridge&shift=4',
      -- где:
      --  url - ссылка на источник телепрограммы
      --  name - название телеканала
      --  shift - часовой пояс телепрограммы (только для формата JTV)

      -- Размер файла или устройства хранения в байтах, отображается при просмотре в виде списка (необязателен)
      size = 1024523535,

      -- Размер свободного пространства в байтах, отображается при просмотре в виде списка (необязателен)
      free = 0,

      -- Время отступа в секундах (необязателен)
      -- Предназначен для формирования аудио плейлистов для разбивки файла по трекам
      start = 0,
        
      -- Продолжительность в секундах (необязателен) (>=0.3.4)
  	  duration = 0,

      -- Качество видео, используется для всплывающего списка (необязателен) (>=0.3.1)
      quality = '720P',

      -- HTTP заголовки, передаваемые при открытии ссылки (необязателен) (>=0.3.1)
      headers = {['User-Agent'] = 'Monkey'},

      -- Шаблон ссылки для просмотра архива телеканала (необязателен) (>=0.3.2)
      -- Доступные параметры:
      --  {utc} или {start} (>=0.3.3) – время начала в unix timestamp
      --  {lutc} – время завершения в unix timestamp
      --  {offset} – отклонение от текущей даты в секундах
      --  {timestamp} – текущее время в unix timestamp (>=0.3.3)
      -- например:
      arch = '?utc={utc}&lutc={lutc}',
      -- или для (>=0.3.3)
      ['catchup-source'] = '?begin=${start}&now=${timestamp}',
      -- или
      arch = '?offset=-{offset}',

      -- Количество дней за который доступен просмотр архива (необязателен) (>=0.3.2)
      ago = 4,
      -- или для (>=0.3.3)
      ['catchup-days'] = 4,
        
      -- Подключение внешних субтитров или звуковых дорожек (необязателен) (>=0.3.4)
      -- Примечание: работает только при просмотре в встроенном плеере.
      slaves = {
         {type = 'subtitle', url = '...'},
         {type = 'audio', url = '...'},
      },
        
      -- Отображать подробное описание элемента (необязателен) (>=0.3.4)
  	  detailed = true,
    }
}

Открыть просмотр в режиме управляемого воспроизведения

return {
  view = 'playback',

  -- Заголовок видео (необязателен)
  label = 'Планета обезьян',
  -- или (>=0.3.1)
  title = 'Планета обезьян',

  -- Ссылка на видео
  mrl = 'http://server.com/video/appes.mp4',
  -- или (>=0.3.1)
  url = 'http://server.com/video/appes.mp4',

  -- Внутренняя cсылка для запроса предыдущего видео (необязателен)
  previous = '#self/id=4571',

  -- Внутренняя cсылка для запроса следующего видео (необязателен)
  next = '#self/id=8517',

  -- Внутренняя cсылка оповещения о состоянии воспроизведения (необязателен)
  -- В функцию onEvent обработки оповещения передаются следующие аргументы:
  --   'action' - событие: 'got' - видео готово к воспроизведению, 'watched' - видео просмотрено, 'update' - обновление информации (каждые 1000мс)
  --   'time' - время воспроизведения в секундах
  --   'percent' - процент просмотренного видео
  --   'duration' - продолжительность видео в секундах
  meta = '#self/video_id=7544',

  -- Доступно позиционирование и переход к следующему видео (необязателен)
  seekable = 'true',  -- По умолчанию - 'false'

  -- Прямая ссылка на видео (необязателен)
  direct = 'true',  -- По умолчанию - 'false'

  -- HTTP заголовки, передаваемые при открытии ссылки (необязателен)
  headers = {['User-Agent'] = 'Monkey'}
}
Вернуться к содержанию Вернуться в начало раздела

6. Формирование информации об элементе списка или телепрограммы EPG

Для формирования информации об элементе или телепрограммы предназначена функция onMeta основного модуля программы. В качестве аргумента функция принимает таблицу с ключами и значениями из внутренней ссылки заданной в параметре meta у элемента списка и дополнительно параметр type.

Параметр type может принимать следующие значения:

Рассмотрим формирование результата на следующем примере с комментариями:

function onMeta(args)
  if args['type'] == 'EPG' then
    -- Список телепередач
    local t = {}
    table.insert(t, {
      title = 'Новости',    -- Название
      time1 = 1234324,      -- Время начала в формате unix timestamp. (>=0.3.1) Вместо **time1** можно указать **begin**
      time2 = 1234524,      -- Время завершения в формате unix timestamp (необязателен). (>=0.3.1) Вместо **time2** можно указать **end**
      annotation = '...',   -- (>=0.3.2) Описание (необязателен)
      group = 'Новости',    -- (>=0.3.2) Категория (необязателен)
      url = '...'           -- (>=0.3.2) Прямая ссылка на видео файл для просмотра архива телеканала (необязателен)
    })
    return t
  else
    -- Возврат информации об элементе (телеканале).
    -- Обязательно для заполнения только одно поле
    return {
      title = 'Заголовок для замены',
      annotation = 'Описание для замены',
      image = 'Ссылка на изображение для замены',   -- (>=0.3.1) Вместо **image** можно указать **icon**
      group = 'Имя группы для замены',
      size = 0,      -- Занято в байтах (необязателен)
      free = 0,      -- Свободно в байтах (необязателен)
      start = 0,     -- Время отступа в секундах (необязателен) (>=0.3.4)
      duration = 0   -- Продолжительность в секундах (необязателен) (>=0.3.4)
    }
  end
end
Вернуться к содержанию Вернуться в начало раздела

7. Дополнительные функции Lua

7.1. Основные функции

-- Вывести отладочную информацию в Log журнал
print('Starting…')

-- Загрузить модуль дополнения или общий модуль
require('video')

-- Получить значение (строка или nil) параметра среды исполнения
-- В качестве аргумента функции E может выступать:
--  'version' – версия приложения
--  'locale' – локализация
--  'tmp' – каталог временных файлов
--  'language' – язык системы по стандарту ISO 639-1
--  'country' – страна по стандарту ISO 3166-1 alpha-2
--  'model' – модель устройства
--  'vod' – есть ли поддержка M3U VOD
--  'platform' – платформа
local v = E'version'

-- Получить строку по тегу из конфигурационного файла
-- См. <label>...</label> в конфигурационном файле
local v = N'label'

-- Получить строку по идентификатору на языке системы
-- См. <string name="quality">...</string> в конфигурационном файле
local v = L'quality'

-- Получить таблицу строк по идентификатору на языке системы
-- См. <string-array name="qualities">...</string-array> в конфигурационном файле
local v = A'qualities'

-- Получить значение (строка или nil) настройки
local v = getprop('username')

-- Установить значение (строка или nil) настройки
setprop('password', 'my password here')

-- Установить значение настройки в зашифрованном виде (не будет доступен другим дополнениям) (>=0.3.3)
setprop('password', 'my password here', true)

-- Получить значение (строка или nil) системной настройки
-- Доступные системные настройки:
--   'udpxy' - использовать udpxy при просмотре IPTV multicast
--   'udpxy_server' - адрес сервера udpxy
--   'udpxy_port' - порт сервера udpxy
--   'tv' - использовать автоматическую загрузку телепрограммы
--   'source' - ссылка на источник телепрограммы
--   'timezone' - часовой пояс телепрограммы
--   'store' - количество дней хранения программы передач, где 'unlimited' - неограничено
--   'videoplayer' - проигрыватель видео: 'internal' - встроенный, 'lite' - встроенный (облегченная версия) (>=0.3.4), 'mxplayer' - MX Player, 'system' - по выбору системы
--   'streamplayer' - проигрыватель видео трансляций и IPTV: 'internal' - встроенный, 'lite' - встроенный (облегченная версия) (>=0.3.4), 'mxplayer' - MX Player, 'system' - по выбору системы
--   'surface' - использовать расширенное масштабирование
--   'scaling' - масштабирование видео: 'stretch' - растягивать, 'fit' - оригинальное соотношение сторон, 'crop' - растягивание и обрезание по высоте
--   'resumeplay' - использовать возобновление просмотра
--   'resume_limit' - не сохранять время остановки для видео меньше (мин.)
--   'highlighted' - подсвечивать текст просмотренного видео
--   'quality' - качество видео (по умолчанию)
--   'advanced' - использовать расширенную поддержку источников
--   'demo' - использовать автовоспроизведение контента из папки ICONBIT_PLAY
--   'photo_interval' - время просмотра фото (секунд)
--   'random' - воспроизводить контент из папки ICONBIT_PLAY в случайном порядке
--   'webserver' - использовать Web интерфейс
--   'webserver_port' - порт Web интерфейса
--   'services' - загружать список интернет сервисов с сервера
--   'update' - проверять наличие обновления при запуске приложения
--   'auto_app' - запускать приложение при загрузки системы: 'disable' - не использовать, 'iptv' - IPTV, 'application' - Медиацентр, 'filemanager' - Проводник

-- Cистемные настройки начиная с (>=0.3.4):
--	'dvdplayer' - проигрыватель DVD / Blu-ray образов: 'internal' - встроенный, 'system' - по выбору системы
--	'audioplayer' - аудиоплеер: 'internal' - встроенный, 'system' - по выбору системы
--	'pictureviewer' - просмотр фото: 'internal' - встроенный, 'system' - по выбору системы
--	'textviewer' - просмотр тестовых файлов: 'internal' - встроенный, 'system' - по выбору системы
--	'process_subdirectories' - Обрабатывать подкаталоги при последовательном воспроизведении
--	'subtitles_autoload' - автоматически загружать внешние субтитры
--	'subtitles_size' - размер текста субтитров
--	'subtitles_color' - цвет текста субтитров
--	'subtitles_background' - отображать фон субтитров
--	'subtitles_bold' - полужирные субтитры
--	'subtitle_text_encoding' - кодировка текста субтитров
--	'opengl' - использование OpenGL ES2: auto, on, off
--	'chroma_format' - принудительный формат цветности: RV32, RV16, YV12
--	'enable_frame_skip' - пропуск кадров
--	'file_caching' - кэш файлов (мс)
--	'network_caching' - кэш сетевых данных (мс)
--	'display_stats' - выводить отладочную информацию
local v = sysprop('source')

-- Получить значение (строка или nil) настройки другого дополнения
-- Для указания имени настройки используется следующий формат '[Идентификатор дополнения]_[Имя настройки]'
local v = sysprop('tvigle_quality')
Вернуться к содержанию Вернуться в начало раздела

7.2. Функции работы со строками

local text = 'Привет мир!'

-- Получить количество символов в UTF-8 строке
local l = utf8.len(text)

-- Получить результат (булево) проверки строки на пустое значение
local v = utf8.empty(text)

-- Получить копию подстроки, где start – позиция первого символа (нумерация начинается с 1), length – количество символов
local v = utf8.sub(text, 8, 3)

-- Получить результат (число) сравнения 2-х строк, где: text1 < text2 тогда -1, если text1 = text2 тогда 0 иначе 1
local v = utf8.compare(text, '213');

-- Получить результат (число) сравнения 2-х строк без учета регистра, где: text1 < text2 тогда -1, если text1 = text2 тогда 0 иначе 1
local v = utf8.casecompare(text, '213');

-- Получить результат (число) сравнения 2-х строк без учета регистра, где: text1 < text2 тогда -1, если text1 = text2 тогда 0 иначе 1
local v = utf8.casecompare(text, '213');

-- Получить строку на основании неограниченного перечисления кодов символов
local v = utf8.char(65, 66, 67)

-- Получить копию строки, где символы приведены в нижний регистр
local v = utf8.lower(text)

-- Получить копию строки, где символы приведены в верхний регистр
local v = utf8.upper(text)

-- Получить копию строки без пробелов в начале и конце строки
local v = utf8.trim(text)

-- Получить декодированное представление UTF-8 строки
local v = utf8.trim('Hello \ufe00\u007f')

-- Получить результат (булево) проверки строки на UTF-8 кодировку
local v = utf8.assert(text)

-- Обход строки по символам с помощью функции utf8.chars
for position, char in utf8.chars(text) do
  print(position, char)
end

-- Обход строки по кодам символов с помощью функции utf8.codes
for position, code in utf8.codes(text) do
  print(position, code, utf8.char(code))
end

-- Обход многострочного текста по строкам с помощью функции utf8.lines
for i, line in utf8.lines(text) do
  print(ш, line)
end

-- Получить копию строки, где символы из кодировки 'WINDOWS-1251' преобразованы в 'UTF-8'
local v = iconv(text, 'WINDOWS-1251', 'UTF-8')
Вернуться к содержанию Вернуться в начало раздела

7.3. Использование PERL совместимых регулярных выражений

Кроме стандартных функций Lua для работы с регулярными выражениями доступны расширенные функции PERL (>= 0.3.1). Среди основных особенностей расширенных функций можно выделить полную поддержку кодировки UTF-8 и более широкий язык регулярных выражений.

Внимание: при получении результата следует учитывать тот факт, что первое значение — строка, полное совпадение с регулярным выражением.

local pattern = 'v=([0-9]+)'
local text = 'This is v=5, but any v=10'
local replace = '\\1=v'

-- Получить объект регулярного выражения pattern
local x = pcre.compile(pattern)

-- Получить первое захваченное совпадение в строке text с объектом регулярного выражения (количество значений зависит от выражения pattern)
local v = x:exec(text)

-- Получить все захваченные совпадения в строке text с объектом регулярного выражения (количество значений зависит от выражения pattern)
for _, v in x:gexec(text) do
  print(v)
end

-- Получить первое захваченное совпадение в строке text с регулярным выражением pattern (количество значений зависит от выражения pattern)
local v = pcre.match(text, pattern)

-- Получить все захваченные совпадения в строке text с регулярным выражением pattern (количество значений зависит от выражения pattern)
for _, v in pcre.gmatch(text, pattern) do
  print(v)
end

-- Получить копию строки text, где все найденные совпадения с регулярным выражением pattern заменены на значение replace (для подстановки значений выражения используется формат «\N», где N – номер значения)
local v = pcre.gsub(text, pattern, replace)
Вернуться к содержанию Вернуться в начало раздела

7.4. Функции кодирования данных

local text = 'username:password'
local array = {text, 'Hello World!'}

-- Получить закодированное значение строки по методу BASE64
local data = base64.encode(text)

-- Получить декодированное значение строки по методу BASE64
local v = base64.decode(data)

-- Получить MD5 хеш в виде hex строки
local v = md5.sum(text)

-- Получить MD5 хеш в виде hex строки из неопределенного количества данных
local t = md5.init()
for _, v in ipairs(array) do
  t:append(v)
end
local v = t:finish()

-- Получить SHA1 хеш в виде hex строки
local v = sha1.sum(text)

-- Получить SHA1 хеш в виде hex строки из неопределенного количества данных
local t = sha1.init()
for _, v in ipairs(array) do
  t:append(v)
end
local v = t:finish()

-- Получить расшифрованный текст для flash плеера uppod
uppod_decode(text, 'хеш 1', 'хеш 2')
Вернуться к содержанию Вернуться в начало раздела

7.5. Функции поддержки криптографии

Доступно в (>=0.3.1).

local data = 'Hello World!'
local digest = 'SHA512'
local cipher = 'AES-256-CBC'
local password = '12345'
local iv
local size = 32

-- Получить список (table) доступных алгоритмов шифрования
local ciphers = crypto.list('ciphers')

-- Получить список (table) доступных хеш алгоритмов
local digests = crypto.list('digests')

-- Получить представление данных в виде hex строки
local text = bin2hex(data)

-- Получить данные из hex строки
local b = hex2bin(text)

-- Получить хеш data по алгоритму digest
local b = crypto.digest(digest, data)

-- Получить размер хеш в байтах по алгоритму digest
local l = crypto.digest_size(digest)

-- Получить зашифрованные данные из data по алгоритму cipher
local packed = crypto.encrypt(cipher, data, password, iv)
-- или
local packed = openssl_encrypt(cipher, data, password, iv)

-- Получить расшифрованные данные из packed по алгоритму cipher
local unpacked = crypto.decrypt(cipher, packed, password, iv)
-- или
local unpacked = openssl_decrypt(cipher, packed, password, iv)

-- Получить размер ключа для алгоритма шифрования cipher
local l = crypto.key_length(cipher)

-- Получить размер iv для алгоритма шифрования cipher
local l = crypto.cipher_iv_length(cipher)

-- Получить случайный набор байт размером size в виде бинарной строки
local b = crypto.random_bytes(size)
-- или
local b = openssl_random_bytes(size)

-- Получить псевдослучайный набор байт размером size в виде бинарной строки
local b = crypto.random_pseudo_bytes(size)
-- или
local b = openssl_random_pseudo_bytes(size)
Вернуться к содержанию Вернуться в начало раздела

7.6. Сетевые функции

Общие функции

-- Получить список сетевых интефейсов (>=0.3.2)
local irf = os.interfaces()
for _, v in ipairs(irf) do
  -- v['name'] - Идентификатор (строка)
  -- v['addr'] - IP адрес (строка)
  -- v['hwaddr'] - MAC адрес (строка)
  -- v['bitmask'] - Маска подсети (число)
  -- v['loopback'] - Это обратная петля (булево)
  -- v['private'] - Это частная сеть (булево)
  -- v['connected'] - Соединение установлено (булево)
  -- v['wireless'] - Это беспроводная сеть (булево)
end

Работа с сокетами

local hostname = 'yandex.ru'
local port = 80
local timeout = 30
local size = 8192

-- Получить объект сокета для TCP соединения
local s = socket.tcp()

-- Получить объект сокета для SSL соединения
local s = socket.tcp(1)

-- Установить соединение с сервером hostname:port с ожиданием timeout и сохранить результат соединения connected (булево)
local connected = s:connect(hostname, port, timeout)

-- Прочитать данные из сокета размером size байт (по умолчанию 4096 байт) и сохранить результат в виде строки
local text = s:read(size)

-- Отправить данные через сокет
s:write('Custom data')

-- Получить результат проверки (булево) установки соединения с сервером
local r = s:connected()

Работа по протоколу HTTP

local url = 'https://yandex.ru/?q=abracadabra'
local headers = {Referrer = 'https://yandex.ru/'}
local postfields = 'q=abracadabra'
local responses = {}
local filename = '/sdcard/page.html'

-- Получить содержимое (строка без обработки) интернет страницы по методу GET
local x = http.get(url)
-- с использованием HTTP заголовков headers
local x = http.get(url, headers)
-- с использованием HTTP заголовков headers и получением ответа сервера в responses (код и заголовки)
local x = http.get(url, headers, responses)
-- Примечание 1: При ошибке соединения с сервером возникает исключение и прекращение выполнения программы (чтобы перехватить исключение используйте функцию pcall)
-- Примечание 2: Код ответа сервера сохраняется под ключом http_code в переменной responses

-- Получить содержимое (строка) интернет страницы по методу GET с декодированием по алгоритму, полученному в заголовке «Content-Encoding». (>=0.3.2)
local x = http.getz(url)
-- Возможные аргументы аналогичны функции http.get

-- Получить содержимое (строка без обработки) интернет страницы по методу POST
local x = http.post(url)
-- с использованием HTTP заголовков headers
local x = http.post(url, headers)
-- с использованием HTTP заголовков headers и данными postfields
local x = http.post(url, headers, postfields)
-- с использованием HTTP заголовков headers, данными postfields и получением ответа сервера в responses (код и заголовки)
local x = http.post(url, headers, postfields, responses)

-- Получить содержимое (строка) интернет страницы по методу POST с декодированием по алгоритму, полученному в заголовке «Content-Encoding». (>=0.3.2)
local x = http.postz(url)
-- Возможные аргументы аналогичны функции http.post

-- Загрузить файл из сетевого источника url в filename (полный путь для сохранения файла) и сохранить размер файла в filesize (>=0.3.1)
local filesize = http.download(url, filename)

-- Получить параметры строки запроса в виде таблицы
local opts = http.decode('name=user&value=kukareku')

-- Получить строку параметров запроса на основании таблицы
local query = http.encode({name = 'user', value = 'kukareku'})

-- Получить раскодированное значение URL строки
local v = urldecode('ku+ka+re+ku')

-- Получить кодированное представление URL строки
local v = urlencode(v)
-- с исключением символов строки '@#'
local v = urlencode(v, '@#')

-- Получить параметры URL адреса в виде таблицы, где:
--   'scheme' – протокол
--   'folder' - каталог
--   'domain' – домен
--   'username' – пользователь
--   'password' – пароль
--   'hostname' – имя сервера
--   'port' – порт
--   'path' – путь
--   'query' – строка параметров.
local x = urlsplit(url)
print(x['hostname'])

-- Пример загрузки страницы и вывода всех заголовков и содержимого в журнал
local responses = {}
local x = http.get('https://yandex.ru/,q=abracadabra', {Referrer = 'https://yandex.ru/'}, responses)
for k, v in pairs(responses) do
  print(k, v)
end
print(x)
Вернуться к содержанию Вернуться в начало раздела

7.7. Работа с документами в JSON формате

-- Получить представление JSON текста в виде таблицы
local x = json.decode('[1,2,3,4,5]')

-- Получить представление таблицы в виде JSON текста (>=0.3.1)
local text = json.encode(x)
-- Примечание: текст, используемый в функции json.decode может не совпадать с текстом, полученным в последствии функцией json.encode в виду особенностей порядка расположения элементов в таблице на языке Lua.

-- Пример
local x = json.decode('[1,2,3,4,5]')
for k, v in pairs(x) do
  print(k, v)
end
Вернуться к содержанию Вернуться в начало раздела

7.8. Работа с документам в XML формате

local url = 'http://www.vesti.ru/export/videos.rss?cid=1'
local charset = 'UTF-8'
local text = [[
  <responses>
    <element>1</element>
    <element>2</element>
    <element myattr="Three">3</element>
  </responses>
]]

-- Получить объект XML из url источника
local x = xml.load(url)

-- Получить объект XML из url источника c использованием кодировки текста charset
local x = xml.load(url, charset)

-- Получить объект XML из строки text c использованием кодировки текста charset
local x = xml.parse(text)

-- Получить количество элементов в заданной иерархии
-- Формат:
--  count (name1[[,index1][,name2[,index2]][,…],nameN)
--  где: name1, name2, ..., nameN - имена тегов. Если index не задан, то берется первый элемент
local count = x:count('responses', 'element')

-- Получить текстовое значение элемента в заданной иерархии
-- Формат:
--  value (name1[[,index1][,name2[,index2]][,…],nameN[,indexN])
--  где: name1, name2, ..., nameN - имена тегов. Если index не задан, то берется первый элемент
local v = x:value('responses', 'element')
local v = x:value('responses', 'element', 3)

-- Получить текстовое значение атрибута элемента в заданной иерархии
-- Формат:
--  attribute (name1[[,index1][,name2[,index2]][,…],nameN[,indexN],attr)
--  где: name1, name2, ..., nameN - имена тегов, attr - имя аттрибута. Если index не задан, то берется первый элемент
local v = x:attribute('responses', 'element', 3, 'myattr')

-- Получить итератор обхода по элементам в заданной иерархии (>=0.3.1)
-- Формат:
--  rows (name1[[,index1][,name2[,index2]][,…],nameN[,indexN])
--  где: name1, name2, ..., nameN - имена тегов. Если index не задан, то берется первый элемент
for row in x:rows('responses', 'element') do
  print(row:value())
end

-- Получить итератор обхода по элементам в заданной иерархии с индексом (>=0.3.1)
-- Формат:
--  irows (name1[[,index1][,name2[,index2]][,…],nameN[,indexN])
--  где: name1, name2, ..., nameN - имена тегов. Если index не задан, то берется первый элемент
for index, row in x:irows('responses', 'element') do
  print(index, row:value())
end
Вернуться к содержанию Вернуться в начало раздела

7.9. Вспомогательные функции

-- Получить файл из источника в виде строки. В качестве источника может выступать локальный файл или URL адрес (поддерживаются протоколы HTTP / HTTPS / FTP / SMB)
local x = util.download('ftp://ftp.gnu.org/pub/information.txt')

-- Получить список файлов и папок в заданном локальном или сетевом каталоге в виде таблицы (аналогично формируемому списку дополнением)
local x = util.ls('ftp://ftp.gnu.org/')

-- Получить размер локального файла
local size = os.filesize('/sdcard/test.m3u')

-- Получить информацию о занятом и свободном пространстве на локальном диске в виде таблицы
local stat = os.statfs('/sdcard')
-- где:
--  stat['total'] - всего
--  stat['used'] - занято
--  stat['free'] - свободно
--  stat['percent'] - процент занятого

-- Получить путь для сохранения файла во временном каталоге
local cachefile = os.cache('pl_list.txt')

-- Получить список пакетов в виде строки через запятую, установленных в системе (>=0.3.1)
local x = os.packages()
Вернуться к содержанию Вернуться в начало раздела

7.10. Функции библиотеки Zlib

Доступно в (>=0.3.2).

-- Метод кодирования deflate (по умолчанию)
zlib.ENCODING_DEFLATE

-- Метод кодирования gzip
zlib.ENCODING_GZIP

-- Без сжатия
zlib.NO_COMPRESSION

-- Быстрое сжатие
zlib.BEST_SPEED

-- Лучшее сжатие
zlib.BEST_COMPRESSION

local value = 'Hello World!'
local encoding = zlib.ENCODING_GZIP
local level = zlib.BEST_COMPRESSION

-- Получить сжатые данные value по методу кодирования encoding (необязателен) с уровнем сжатия level от 0 до 9 (необязателен)
local x = zlib.deflate (value, encoding, level)

-- Получить распакованные данные x по методу кодирования encoding (необязателен)
local unpacked = zlib.inflate(x, encoding)

-- Получить хеш (число) значения value по алгоритму adler32
local adler32 = zlib.adler32(value)
-- с продолжением подсчета
local adler32 = zlib.adler32(value, adler32)

-- Получить хеш (число) значения value по алгоритму crc32
local crc32 = zlib.crc32(value)
-- с продолжением подсчета
local crc32 = zlib.crc32(value, crc32)
Вернуться к содержанию Вернуться в начало раздела

7.11. Выполнение программ на языке Python

Доступно в (>=0.3.3). Используется CPython 3.7 с предустановленными библиотеками: Cryptodome.

-- Информация о версии и сборке интерпретатора CPython (строка)
python._VERSION

-- Путь к местонаждению библиотеки интерпретатора CPython (строка)
python._PATH

local path = '/sdcard/youtube-dl'
local args = {'--help'}
local run_name = '__main__'

-- Выполнить файл или модуль (включая zip) path с параметрами командной строки args (необязателен) и именем run_name (необязателен)
local r, x, e = python.execute(path, args, run_name)
-- где:
--  r - выполненое успешно без ошибок (булево)
--  x - строка стандартного вывода (stdout)
--  e - строка вывода ошибок (stderr)

-- Выполнить простой файл с параметрами командной строки args (необязателен)
local r, x, e = python.file('/sdcard/test.py', args)
-- r, x, e аналогично функции python.execute

-- Выполнить текст программы с параметрами командной строки args (необязателен)
local r, x, e = python.string('import sys; print(sys.argv)', args)
-- r, x, e аналогично функции python.execute

local name = 'youtube_dl'

-- Подключить модуль по локальному пути path под именем name и сохранить результат в r (булево)
local r = python.import(name, path)
if r then
  print('Модуль успешно подключен')
end

-- Проверить подключен ли модуль под именем name и сохранить результат в r (булево)
local r = python.imported(name)
if r then
  print('Модуль уже подключен')
end

-- Получить объект нового интерпритатора Python
local interp = python.interp()

-- Использование объекта интерпритатора аналогично функциям python.*
local r, x, e = interp:execute(path, args, run_name)
local r, x, e = interp:file('/sdcard/test.py', args)
local r, x, e = interp:string('import sys; print(sys.argv)', args)
local r = interp:import(name, path)
local r = interp:imported(name)
Вернуться к содержанию Вернуться в начало раздела

8. Общие модули Lua

Любое дополнение может использовать функционал общих модулей приложения. На данный момент существуют следующие модули:

Общий модуль video

-- Подключить общий модуль video
require('video')

local t = {}
local url = 'https://www.youtube.com/watch?v=7fdshje78'
local label = 'Мое видео'
local titles = {'youtube' = 'Trailer'}

-- Добавить ссылку url к воспроизведению в список элементов под заголовком label с шаблоном замены заголовка titles (необязателен)
addvideo(t, url, label, titles)
-- Примечание 1: url может ссылаться на сериал популярного хостинга тогда формируется список всех серий иначе добавляется элемент «Смотреть»
-- Примечание 2: titles в данном примере реализует замену заголовка элемента на 'Trailer' при содержании строки 'youtube' в url
-- Примечание 3: перед выполнением данной функции рекомендуется заполнить свойство 'ref' в таблице t (полный адрес интернет страницы).
-- Примечание 4: при формировании списка генерирует внутренние ссылки с параметром q = 'play', соответственно в дополнении должна быть реализована обработка данного параметра с использованием функции video.

-- Вернуть данные для запуска воспроизведения видео
return video(url, args)
-- Примечание: args – таблица дополнительных свойств ()
-- Пример загрузки интернет страницы, вывода всех ссылок и их воспроизведение (если возможно)

-- Подключим общий модуль video
require('video')

BASE_URL = '<адрес страницы>'

function onLoad()
  return 1
end

function onCreate(args)
  local t = { }
  if args['q'] == 'play' then
    -- Если пользователя выбрал ссылку то попробуем её воспроизвести
    return video(args['url'], args)
  else
    -- Иначе загрузим страницу по адресу BASE_URL и выведем все ссылки страницы
    local t = {view = 'simple', type = 'folder'}
    local x = http.get(BASE_URL)
    for url in string.gmatch(x, '"(http.-)"') do
      addvideo(t, url, url)
    end
    return t
  end
end

Общий модуль parser

-- Подключить общий модуль parser
require('parser')

local text = '   <caption>Option</caption>  '
local pattern = '(.+)'
local patterns = {'(.+)', '<(.-)>', '<caption>(.-)</caption>'}

-- Получить копию строки без пустот, тегов и других специальных символов
local v = tolazy(text)

-- Получить совпадение (string.match) с регулярным выражением pattern строки text и последующим использованием функции tolazy
local v = parse_match(text, pattern)

-- Получить массив (таблица) совпадений заданных в массиве (таблица) шаблонов patterns строки text
local v = parse_array(text, patterns)

local t = {}
local data = '{"playlist":[{"file":"http://server.com/filename.mp4"}]}'

-- Заполнить список элементов на основании JSON плейлиста
parse_playlist(t, data)
Вернуться к содержанию Вернуться в начало раздела