1

Тема: Туториал: Написание подкастов

Создание подкастов

Как выглядит то, о чём будет идти речь:

  • - Папка;
  • - Подкаст;
  • - Папка подкаста (обычно для группировки созданных ссылок);
  • - Динамическая папка;
  • - Медиа-ресурс (отображается в программе в окне справа);

Совет: если вам что-то непонятно, то попробуйте оставить понимание этого на потом. Возможно, прочитав далее, в другом разделе или в дальнейших примерах, встретите ответ на свой вопрос.

В программе "Домашний медиа-сервер" есть папка "Подкасты", куда можно добавить элемент "Подкаст" или папку, содержащую сколько угодно таких элементов (папок и подкастов). Элемент "Подкаст" отличается от простой папки тем, что его можно обновить, нажав на нём в программе на компьютере правой клавишей мышки или зайдя при навигации на устройстве в папку "Обновить подкаст". В общем случае, назначение такого подкаста - создание внутри своей папки списка элементов, например ссылок на видео , музыкальные композиции или фотографии (смотря для какого раздела вы пишете подкаст: Фильмы, Музыка или Фото).

В программе Домашний медиа-сервер подкаст может создавать список элементов двумя способами:

  1. Автоматически из RSS фида
  2. В специально написанном скрипте

В случае создания списка из RSS фида, там всё достаточно просто. В поле "Ссылка" подкаста нужно указать ссылку на RSS feed. При обновлении такого подкаста будут созданы все элементы такой ленты. В простейшем случае, если в элементах фида прямые ссылки на видео, то этим всё и заканчивается. Подкаст готов. Например, в поле "Ссылка" подкаста вставить http://feeds.reuters.com/reuters/video/quickcut/rss/mp4/, убедиться, что "Режим чтения списка ресурсов" выставлен в Стандартный (RSS), все скрипты выключены - то при обновлении подкаста увидим список видео, которые можем включить на просмотр.

В реальной жизни всё немного сложнее. Потому как даже в новостных лентах очень редко есть прямые ссылки на видео файлы или медиа ресурсы (как в примере выше). Обычно ссылка ведёт на страницу новости или сайта, где расположено видео. Так что приходиться включать использование скриптов и перед отдачей реальной ссылки на медиа-ресурс телевизору или другому устройству воспроизведения (медиаплееру), нужно обычно загружать страницу по ссылке, указанной в элементе подкаста, и оттуда каким-то образом получать реальную ссылку на медиа файл или поток (если это вещание).

Поэтому ниже будет рассказано о скриптах и их использовании.

Для использования скриптов в подкасте нужно их включить. Для этого нужно зайти в свойства подкаста, т.е. на самом подкасте нажать правой клавишей мышки и выбрать "Изменить название" или на папке, содержащую подкасты (наследующие эти скрипты), и выбрать "Изменить название/Настройки". В появившемся окне внизу нужно выбрать вкладку "Скрипты", установить "Режим чтения списка ресурсов" в значение Специальный (скрипт) и включить те скрипты, которые хотим использовать.


Рис.1 Окно свойств подкаста

Выше, на картинке (Рис.1) изображено окно, где включено использование скриптов. Вот некоторые пояснения к тому, что мы там можем увидеть.

  • "Режим чтения списка ресурсов" - режим, в котором будет работать подкаст:

    • Стандартный (RSS) - режим, для формирования списка ресурсов НЕ используется скрипт чтения списка ресурсов. Список ресурсов берётся из ленты RSS, ссылка которой указана в поле "Ссылка" подкаста.

    • Специальный (скрипт) - для формирования списка ресурсов (например, списка видео, музыкальных файлов или фото) будет использоваться скрипт "Скрипт чтения списка ресурсов (Alt + 2)". Где мы уже программно будем создавать элементы списка и будет создано только то, что мы сами укажем.

    • Наследовать - режим будет унаследован от папки, которая содержит данный подкаст.

  • "Скрипт создания подкаст-лент (Alt + 1)" - Есть только у папок и запускается на выполнение только интерактивно, через нажатие правой клавишей мышки на папке и выборе "Создать ленты подкастов" (пункт будет виден только у тех папок, у которых включён данный скрипт). Используется, в основном, для создания внутри этой папки списка самих подкастов.

  • "Скрипт чтения списка ресурсов (Alt + 2)" - Запускается на выполнение, когда вы обновляете подкаст через "Обновить подкаст". Используется для создания ссылок на видео (медиа-ресурсы).

  • "Скрипт чтения дополнительных свойств RSS (Alt + 3)" - может использоваться дополнительно к режиму чтения списка ресурсов "Стандартный (RSS)". В данной статье не рассматривается и как его использовать я пока не знаю.

  • "Скрипт получения ссылки на ресурс (Alt + 4)" - Запускается на выполнение, когда происходит запуск ссылки медиа-ресурса. Например, запуск фильма на просмотр (на телевизоре или медиаплеере запустили фильм) или музыкальной композиции. Используется для получения реальной ссылки на ресурс. Потому как часто ссылка медиа-ресурса ведёт на страницу фильма или видео, а в данном скрипте получают ссылку на сам видео файл и присваивают это значение переменной MediaResourceLink.

Указанные в скобках сочетания клавиш (Alt+2, Alt+4) - для быстрого доступа к скриптам (редактирование), при их наличии в подкасте. Обращаю внимание, что скрипт открывается тот, который используется, т.е. возможно унаследованный, если таковое стоит в настройках. Но для начального создания подкаста данные сочетания не сработают, потому как их (скрипты) нужно сначала ввести и сохранить.

Написание скриптов

Далее будет подразумеваться, что вы знакомы с каким-либо языком программирования (неважно, Pascal, C, JavaScript, хоть PHP или любым другим) и будут даны только отличия в синтаксисе и особенности использования в данной программе. Тут самого обучения программированию как такового нет, но будет объяснено как можно применить знания программирования для написания подкастов.

Для ввода скриптов в подкаст, в окне свойств подкаста нужно сначала включить их использование (Рис.1), а потом нажать на кнопку редактирования скрипта (стоит сразу за пунктом "Включен"). Откроется окно редактирования и отладки скрипта:


Рис.2 Окно редактирования скрипта

В открывшемся окне редактирования скрипта справа можно выдвинуть панель справочника функций, классов, переменных. Данная панель поможет увидеть какие есть в нашем распоряжении классы или функции, чем мы можем пользоваться в нашем скрипте. Под полем редактирования скрипта слева выбирается Язык синтаксиса, который мы будем использовать. Правее - кнопки, которые помогут нам проверить, запустить или отладить наш скрипт. Довольно удобно и круто, что в программе, в окне редактирования скрипта есть даже отладчик. Пусть простой, но с ним можно пошагово проверить выполнение и посмотреть текущие значения переменных.

К сожалению, забудьте про использование клавиши Tab. И если редактируете скрипт в другом редакторе где были табы в начале строк или копируете текст скрипта откуда-то где была табуляция, то после вставки такого текста в редактор, готовьтесь к неадекватному отображению текста и его редактированию. Сдвиг строки табуляцией может не происходить и удаление символа может происходить не там, где вы ожидаете - отображение каретки начинает врать относительно настоящей позиции.

Перед сохранением скрипта, обязательно запускайте проверку синтаксиса.

По поводу языка скриптов.

В программе Домашний медиа-сервер как движок для скриптов используется FastScript. У него есть масса ограничений и специфических свойств. Но для простых задач он вполне может подойти. Плохое и единственное описание находится тут. Если кому-то очень не хватает мощи настоящих языков программирования, жить не может без фреймворков, настоящего ООП или аллергия на Pascal - те идут обсуждать. А тем, кто считает, что если язык программирования умеет получать значение из ячейки и класть в неё, арифметические действия и битовый сдвиг, то с помощью этого языка можно сделать всё - значит добро пожаловать ниже.

Использование выбранного синтаксиса тут не значит, что можно использовать все возможности данного языка. Нельзя создавать классы, но можно создавать объекты из существующих встроенных классов и которые добавил сам автор программы (они перечислены справа в справочнике классов). Не все типы переменных возможно объявить, только те, которые заложены в FastScript (например, нет указателей - pointers). Нет операторов Include и проч. Как и программа, FastScript написана на Pascal (Delphi) и многие объекты и функции идут именно оттуда. Значение неустановленных объектов равно не NULL, а паскалевскому Nil. Есть и некоторые другие особенности. Их всех я даже не знаю.

Общие положения написания кода в программе Домашний медиа-сервер

В скрипте должна быть главная процедура, которая первая запускается в скрипте. Она может вызывать другие объявленные процедуры или функции, которые должны быть объявлены ранее неё. Это означает, что если у вас будет несколько процедур, то главная должна быть самой последней. Главная процедура в PascalScript объявляется так:

begin

end.

в C++Script и JScript объявляется так:

{

}

До использования FastScript в данной программе я практически не был знаком с языком Pascal, поэтому для себя выбрал более привычный язык синтаксиса C++Script и буду приводить примеры в основном на нём. Но если вам более близок другой синтаксис, то можете использовать PascalScript или JScript. Для начала, я буду дублировать некоторые примеры на PascalScript и C++Script. Подозреваю, что для знающих язык Delphi, разобраться будет гораздо легче. Но даже не знающих его - тоже не так уж трудно.

Кратко, чем они отличаются. Пример простенькой программы на PascalScript:

var
  sMsg: String; // Объявляем переменную
begin
  sMsg := 'Привет!'; // Присваиваем значение
  ShowMessage(sMsg); // Выводим окно с нашим текстом
end.

Пример той-же программы на C++Script:

string sMsg; // Объявляем переменную
{
  sMsg = 'Привет!'; // Присваиваем значение
  ShowMessage(sMsg); // Выводим окно с нашим текстом
}

Пример той-же программы на JScript:

{
  msg = 'Привет!'; // А, даже тип объявлять не обязательно...
  ShowMessage(msg); // Выводим окно с нашим текстом
}

Примеры с объявлением дополнительных функций:

var
  gsMsg: String; // Объявляем переменные
  gnMyNum: Integer;

// Объявляем функцию для сложения двух чисел
function GetMyNumber(n1, n2: Integer): Integer; Begin
  Result := n1 + n2;
end;

// ГЛАВНАЯ ПРОЦЕДУРА
begin
  gnMyNum := GetMyNumber(1, 2); // Вызов нашей выше объявленной функции
  gsMsg   := 'Получилось число: ' + IntToStr(gnMyNum); // Формируем строку сообщения
  ShowMessage(gsMsg);           // Показываем сообщение
end.

Пример той-же программы на C++Script:

string gsMsg; // Объявляем переменные
int gnMyNum;

// Объявляем функцию для сложения двух чисел
int GetMyNumber(int n1, int n2) {
  return n1 + n2;
}

// ГЛАВНАЯ ПРОЦЕДУРА
{
  gnMyNum = GetMyNumber(1, 2); // Вызов нашей выше объявленной функции
  gsMsg   = 'Получилось число: ' + IntToStr(gnMyNum); // Формируем строку сообщения
  ShowMessage(gsMsg);          // Показываем сообщение
}

Как видите всё очень просто и всё отличается только некоторым оформлением: объявлением, присвоением := на просто =, начало и конец блоков begin и end заменяются на { и }, некоторыми другими чисто синтаксическими вещами.

Отладка скриптов

Для отладки скрипта, его пошагового выполнения, можно поставить точку остановки (breakpoint), например, на строке gsMsg = 'Получилось число: ' + IntToStr(gnMyNum); путём нажатия F5 или кликнув мышкой слева поля редактирования. Запустив скрипт на выполнение, программа остановиться на точке останова. Можно нажать Ctrl-F7, в появившемся окне вставить имя переменной и посмотреть её значение. Пошаговое выполнение команд - F8.


Рис.3 Пример отладки скрипта и просмотра значения переменной по Ctrl-F7

Также в окне вычисления выражения можно нажать на кнопку с картинкой , это добавит имя переменной (или выражения) в таблицу списка выражений справа. В этой таблице при отладке можно следить за текущими значениями переменных. Удалить строку из таблицы можно встав на неё и нажав Ctrl-Del.

Встроенные переменные

В программе Домашний медиа-сервер есть встроенные переменные, которые уже содержат соответствующие значения. Список доступных переменных также можно посмотреть справа в окне справочника. Некоторые переменные доступны только в определённых скриптах. Вот описание некоторых:

  • Application - объект приложения TApplication, в контексте которого выполняется скрипт (предназначение мне не ясно);
  • CurrentMediaItem - текущий элемент списка медиа-ресурсов при интерактивном запуске (из программы);
  • DebugMode - содержит True, если скрипт запущен в отладчике;
  • IsWine - содержит True, если программа Домашний медиа-сервер запущена в Linux под Wine;
  • ServiceMode - содержит True, если скрипт выполняется в папке "Сервис"? (неизвестно, это предположение);
  • InteractiveMode - содержит True, если скрипт выполняется в интерактивном режиме (запущен из программы на компьютере);
  • FolderItem - текущий подкаст или папка, где исполняется скрипт (доступна только в скрипте чтения списка ресурсов или в скрипте создания подкаст-лент);
  • PodcastItem - текущий медиа-ресурс, который запущен на воспроизведение (доступна только в скрипте получения ссылки на ресурс);
  • MediaResourceLink - после завершения скрипта должна содержать реальную ссылку на видео, аудио или фото файл, как результат работы скрипта (доступна только в скрипте получения ссылки на ресурс);
  • gsUserVariable1 ... gsUserVariable5 - пользовательские глобальные переменные, которые сохраняют значение после завершения скрипта. Могут использоваться для передачи данных между разными скриптами.

  • Группа "Параметры медиа-ресурса" содержит список переменных, которые хранят значения параметров текущего медиа-ресурса и зависят от контекста исполнения. В скрипте чтения списка ресурсов это параметры подкаста, в скрипте получения ссылки на ресурс это параметры самого запускаемого медиа-ресурса. Вот несколько основных переменных:

    • mpTitle - название;
    • mpFilePath - значение поля "Ссылка" подкаста или медиа-ресурса;
    • mpComment - комментарий;
    • mpPodcastParameters - объединённое значение полей "Дополнительные параметры подкаста", начиная с текущего элемента и вверх - родительских папок. В основном, используется для проверки в скрипте дополнительно установленных ключей для подкаста;
    • mpPodcastAuthorizationUserName - Унаследованное значение поля "Имя пользователя", если включена авторизация в подкасте или папке, содержащий данный подкаст;
    • mpPodcastAuthorizationPassword - Унаследованное значение поля "Пароль", если включена авторизация в подкасте или папке, содержащий данный подкаст;
  • Группа "Параметры настройки" это переменные, которые содержат текущие значения настроек программы или устройства. Например:
    • cfgTranscodingScreenHeight - Высота кадра (которая казана в настройках устройства)
    • cfgTranscodingScreenWidth - Ширина кадра (которая казана в настройках устройства)
    • ...

Предназначение системных переменных ExceptionClassName и ExceptionMessage мне пока не известно (например, при возникновении исключения в них не было информации).

Если вы в скрипте меняете значение переменных параметров настройки или подкаста - это действует только в текущем исполняющемся скрипте. Например, если вы смените значение mpTitle, то это не поменяет название подкаста в базе программы, это просто сменит значение переменной.

Описание типов и классов тоже можно посмотреть в справочнике справа. Например видим, что переменная FolderItem имеет тип THmsScriptMediaItem. Включаем в справочнике отображение классов и находим там класс THmsScriptMediaItem. И там можем посмотреть какие функции и свойства есть у данного класса, а значит и у объекта, на который ссылается данная переменная. Для примера, есть свойство ChildCount - по названию понятно, что это количество дочерних элементов. А метод DeleteChildItems удаляет дочерние элементы (полезна для очистки, перед обновлением подкаста).

Пример работы со встроенными переменными

Давайте создадим новый подкаст, для примера, новых выступлений конференции TED и назовём его "www.ted.com", на котором мы потренируемся. В поле "Ссылка" введём https://www.ted.com/talks?language=ru, режим чтения списка ресурсов включим в "Специальный (скрипт)", "Скрипт чтения списка ресурсов (Alt + 2)" в режим "Включен" и нажмём кнопку ОК, чтобы значения ссылки и наименования сохранились в программе. Теперь откроем настройки подкаста через правую кнопку мыши и заново зайдём в редактирование скрипта чтения списка ресурсов .


Рис.4 Создание нашего первого подкаста

Потом заходим в скрипт чтения списка ресурсов и вставляем следующий код (язык C++Script):

{
  ShowMessage(mpTitle+': '+mpFilePath);
}

При выполнении (запуск F9), можем увидеть следующее окно:

Рис.5 Результат выполнения примера работы с переменными

Где мы видим, что переменная mpTitle содержит строку "www.ted.com", т.е. заголовок текущего подкаста, а переменная mpFilePath содержит "https://www.ted.com/talks?language=ru" - значение ссылки подкаста.

Если тут вам всё понятно, то тогда далее, я думаю, не должно возникнуть никаких трудностей. Мы рассмотрим самые нужные и распространённые функции, узнаем и научимся работать со встроенными классами, которые нам помогут сделать всё, что нужно для создания реального подкаста.

Sony Bravia KDL-32CX523

2

Re: Туториал: Написание подкастов

Создание скрипта чтения списка ресурсов

Как правило, смысл скрипта создания списка ресурсов сводится к тому, чтобы загрузить страницу(ы) какого-то сайта, распарсить (т.е. найти в коде страницы нам нужные блоки текста) и создать по этим данным список ссылок на ресурсы (например видео).

Т.к. окончательное предназначение скрипта - создание ссылок на медиа-ресурсы, для начала, давайте научимся создавать такие ссылки. Специально для этого есть очень полезная функция HmsCreateMediaItem. В окне редактирования скрипта, на панели справа в справочнике функций в разделе "Обработка медиа-ресурсов" находим данную функцию и смотрим какие параметры она может принимать. Нажав двойным щелчком мышки на данной функции, её текст перейдёт в поле скрипта в текущую позицию. Мы можем увидеть что-то типа:

HmsCreateMediaItem(const aItemPath: string; const aFolderID: string = ''; const aFolderPath: string = ''): THmsScriptMediaItem

Тут мы видим, что в скобках перечислены параметры, которые данная функция может принимать. Указаны они в формате Pascal, т.е. идёт наименование параметра и после двоеточия тип (string - строка, integer - числовой и т.п.). После функции тоже стоит двоеточие и тип - это тип значения, который возвращает функция.

Вот список параметров, которые принимает данная функция:

  1. aItemPath - ссылка медиа-ресурса (строка);
  2. aFolderID - ItemID папки или подкаста, где будет создана ссылка (строка). ItemID - свойство объекта класса THmsScriptMediaItem (например, т.к. переменная FolderItem содержит объект текущей папки или подкаста, то можно указать FolderItem.ItemID - это значит что ссылка будет создана в текущей папке);
  3. aFolderPath - Имя подпапки (например, для группировки ссылок), которая будет создана автоматически (строка);

Третий параметр aFolderPath - строка, но после неё стоит равно и пустое значение. Если в параметрах функции установлены значения - то это значения по-умолчанию и такие параметры можно опускать, т.е. не указывать (необязательные).

Обратите внимание, что возвращает эта функция созданный объект с типом THmsScriptMediaItem. Справа в справочнике включаем отображение классов (если не включено) и находим среди них класс THmsScriptMediaItem. Вообще - это самый главный класс. Это класс любого элемента базы данных программы Домашний медиа-сервер, будь то медиа-ресурс, папка или подкаст. Но в данном случае, наша функция HmsCreateMediaItem создаёт именно медиа-ресурс. У данного класса есть индекс свойство Properties. Через указание номера свойства, можно установить или получить его значение. На самом деле это и есть параметры подкаста или медиа-ссылки, а значения номеров индекса определённых параметров перечислены в справочнике справа в разделе "Константы" -> "Идентификаторы параметров медиа-ресурса". Например:

  • Item.Properties[mpiFilePath] - это ссылка;
  • Item.Properties[mpiTitle] - название;
  • Item.Properties[mpiThumbnail] - эскиз;
  • Item.Properties[mpiTimeLength] - длительность (можно присваивать как строку вида 01:20:00.000 или как число в секундах);
  • Item.Properties[mpiYear] - год;
  • Item.Properties[mpiGenre] - жанр;
  • Item.Properties[mpiCreateDate] - дата создания;

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

Давайте напишем такой скрипт (PascalScript):

// ОБЪЯВЛЕНИЕ ПЕРЕМЕННЫХ
var
  Item: THmsScriptMediaItem; // Создаваемый элемент подкаста

// ГЛАВНАЯ ПРОЦЕДУРА
begin
  Item := HmsCreateMediaItem('http://test.da/1', FolderItem.ItemID);
  Item.Properties[mpiTitle] := 'Первая';
  Item.Properties[mpiYear ] := '1990';
  Item.Properties[mpiGenre] := 'Боевик';
  
  Item := HmsCreateMediaItem('http://test.da/2', FolderItem.ItemID);
  Item.Properties[mpiTitle] := 'Вторая';
  Item.Properties[mpiYear ] := '2000';
  Item.Properties[mpiGenre] := 'Приключения';
  
  Item := HmsCreateMediaItem('http://test.da/3', FolderItem.ItemID);
  Item.Properties[mpiTitle] := 'Третья';
  Item.Properties[mpiYear ] := '2010';
  Item.Properties[mpiGenre] := 'Драма';
  
  Item := HmsCreateMediaItem('http://test.da/4', FolderItem.ItemID);
  Item.Properties[mpiTitle] := 'Четвёртая';
  Item.Properties[mpiYear ] := '2020';
  Item.Properties[mpiGenre] := 'Фантастика';
end.

То же самое на C++Script:

// ОБЪЯВЛЕНИЕ ПЕРЕМЕННЫХ
THmsScriptMediaItem Item; // Создаваемый элемент подкаста

// ГЛАВНАЯ ПРОЦЕДУРА
{
  Item = HmsCreateMediaItem('http://test.da/1', FolderItem.ItemID);
  Item[mpiTitle] = 'Первая';
  Item[mpiYear ] = '1990';
  Item[mpiGenre] = 'Боевик';
  
  Item = HmsCreateMediaItem('http://test.da/2', FolderItem.ItemID);
  Item[mpiTitle] = 'Вторая';
  Item[mpiYear ] = '2000';
  Item[mpiGenre] = 'Приключения';
  
  Item = HmsCreateMediaItem('http://test.da/3', FolderItem.ItemID);
  Item[mpiTitle] = 'Третья';
  Item[mpiYear ] = '2010';
  Item[mpiGenre] = 'Драма';
  
  Item = HmsCreateMediaItem('http://test.da/4', FolderItem.ItemID);
  Item[mpiTitle] = 'Четвёртая';
  Item[mpiYear ] = '2020';
  Item[mpiGenre] = 'Фантастика';
}

В функии HmsCreateMediaItem вторым параметром указано значение FolderItem.ItemID - это передаётся ItemID папки, где будет создан элемент. Т.к. переменная FolderItem содержит объект текущего подкаста или папки класса THmsScriptMediaItem, то у него есть свойство ItemID и медиа-ссылка будет создана именно в текущем подкасте.

Если приведённый код выше скопировать и сохранить как текст скрипта создания ссылок на медиа-ресурсы, обновить подкаст, то справа в окне можно увидеть следующую картину:

Рис.6 Результат теста создания медиа-ссылок.

Ура, мы научились создавать подкаст. Почти. Осталось узнать ещё несколько функций, чтобы загрузить страницу, распарсить её и создать ссылки на настоящие видео-ресурсы.

Загрузка страниц сайта

Для того, чтобы загрузить страницу в программе Домашний медиа-сервер, проще всего использовать функцию HmsDownloadURL. Для этого в окне редактирования скрипта, на панели справа в справочнике функций в разделе "Интернет" находим данную функцию и смотрим какие параметры она может принимать:

HmsDownloadURL(const aURL: string; const aHeaders: string = ''; aAcceptCompressed: Boolean = False): Variant

Параметры функции:

  1. aURL - URL (адрес) страницы, которую мы хотим загрузить (строка);
  2. aHeaders - строка заголовков http протокола, разделённых символами перевода строки и каретки (0x0A + 0x0D) (необязательный параметр). Например, там можно указать, что мы типа браузер Firefox: "User-Agent: Mozilla/5.0 (X11; Linux i686; rv:2.0.1) Gecko/20100101 Firefox/4.0.1"+#10#13;
  3. aAcceptCompressed - если True, использовать сжатие GZip или Deflate при запросе (необязательный параметр);

Итак, чтобы загрузить страничку сайта мы можем выполнить команду:

sHtml = HmsDownloadURL(mpFilePath);

Которая загрузит в переменную sHtml содержимое страницы по ссылке, указанной в переменной mpFilePath. А переменная mpFilePath содержит, как мы уже знаем, ссылку указанную в настройках подкаста под полем наименования.

Давайте в нашем первом подкасте, с указанной в настройках ссылкой https://www.ted.com/talks?language=ru, напишем такой скрипт чтения списка ресурсов (язык C++Script):

// Глобальные переменные
string gsHtml; // Содержимое страницы сайта

// ГЛАВНАЯ ПРОЦЕДУРА
{
  gsHtml = HmsDownloadUrl(mpFilePath); // Загрузка страницы по ссылке
  gsHtml = gsHtml;
}

Команду gsHtml = gsHtml; мы вставили только для того, чтобы можно было поставить на неё точку останова, нажав на ней F5 или нажав мышкой левее этой строки. После запуска нашего скрипта по F9, программа остановит выполнение на нашей строке. После чего мы можем посмотреть значение переменной gsHtml в окне по Ctrl-F7.


Рис.6 Просмотр результата загрузки страницы сайта

Загрузить страничку получилось. Теперь нужно в полученном тексте страницы найти информацию о видео и создать ссылки на них. Будем использовать специальный объект для поиска блоков текста по регулярному выражению. Скажу вам честно, что даже при том, что вы научитесь писать подкасты и прекрасно будете уметь писать скрипты - думать над тем, где нужную информацию взять и какое регулярное выражение использовать в каждом конкретном случае, будет занимать основное время при создании любого подкаста.

Парсинг

Разбор текста с тем, чтобы найти нужную информацию и вычленить из неё конкретные значения нужных полей, таких как ссылка, название, длительность видео, называется общим словом "парсинг". Парсинг страницы с использованием регулярных выражений сводится к тому, чтобы сначала в тексте найти блок, содержащий информацию о видео (как минимум название и ссылку на страницу с видео), а потом в найденном блоке вычленить нужную информацию. Потом найти следующий блок и так далее.

Как понять где и что нужно искать? Всё приходит с опытом. Открываем страницу сайта https://www.ted.com/talks?language=ru в браузере. Там мы можем увидеть список новых видео выступлений, на которые мы будем создавать ссылки в подкасте.


Рис.7 Как выглядит список видео в браузере

Теперь откроем код страницы, нажав Ctrl-U (или какая там отвечает горячая клавиша вашего любимого браузера за показ содержимого страницы). Внимательно смотрим html код. Долго изучаем. Можно просто попытаться найти упоминание названия одного из видео в коде и найти те участки, которые содержат информацию о видео. В данном случае можно найти текст, где где-то после <div class='container results' id='browse-results'> перечисляется информация о каждом видео. Тут каждый блок текста, где есть нужная информация (как минимум ссылка и наименование), начинается с тега <div class='media media--sm-v'> и заканчивается закрывающимися тегами </div>.


Рис.8 Часть исходного кода страницы, где есть информация о видео

Смотрим, между какими значениями достаточно вырезать нужную информацию и пишем простейшее регулярное выражение, которое будет искать текст между двумя этими значениями: media--sm-v(.*?)meta__item. Что означает, что будет искаться блок текста между скобками (группировка), перед которым стоит media--sm-v и после которого идёт meta__item. (Внутри скобок точка означает любой символ, после неё нужно указать сколько любых символов: звёздочка - означает сколько угодно, знак вопроса - до первого совпадения следующих условий). Полностью тут описывать как работать с регулярками я не буду, об этом хорошо написано в Википедии и множестве других сайтов этому посвящённых. Также, если хотите, для создания и проверки работы регулярных выражений есть неплохой онлайн инструмент https://regex101.com/#python, где можно в "TEST STRING" вставить html код нашей странички и прям там проверить, правильно ли мы придумали и вылавливает ли наше регулярное выражение нужную инфу: https://regex101.com/r/bX0wS8/2.

Внимание! При использовании языка C++Script или JScript, в строках символ обратного слеша \ используется как экранирующий символ. Это значит, что в строках, которых мы хотим поставить знак обратного слеша, нужно ставить его двойным: \\. Будьте внимательны при переводе регулярок из PascalScript в C++Script и обратно. Например, регулярка test\(.*?)\this в PascalScript или других языках будет выглядеть в C++Script как test\\(.*?)\\this. Пятьсот тысяч раз спотыкался на этом.

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

Класс TRegExpr.

В окне редактирования скрипта в справочнике справа найдём среди классов TRegExpr и посмотрим его функции. Объекты из классов создаются вызовом конструктора Create. Там мы видим, что при вызове создания такого объекта нужно указать первый параметр - регулярное выражение, вторым параметром можно задать опции. Опции для регулярок также определены как встроенные константы. В справочнике можно включить показ встроенных констант и там в группе "Другие" все константы, начинающиеся на PCRE - это константы опций для использования в регулярных выражениях (модификаторы, как в PHP). Например, PCRE_SINGLELINE - по сути PCRE_CASELESS+PCRE_DOTALL - означает, что текст, где будет происходить поиск, будет представляться как одна строка, совпадения искаться регистронезависимо и точка в регулярном выражении будет означать по-настоящему любой символ, в том числе и перевод строк.

У класса TRegExpr есть методы:

  • Search - начать поиск в указанном тексте;
  • SearchAgain - продолжить поиск после места последнего найденного совпадения;
  • Match - получить содержимое найденного блока (группировки, т.е. содержимого между скобок в регулярке). Можно как параметр передать номер группировки, если в регулярке указано их несколько;
  • Replace - заменить найденные совпадения на указанную строку;

А также есть свойство Subject - это и есть текст, в котором происходит поиск совпадений по регулярному выражению.

Данный класс обычно используют с организацией цикла, в котором по очереди находят каждый блок текста по совпадению условиям регулярки и обрабатывают его, создавая элементы подкаста.

Вот пример такого цикла на PascalScript:

  RegEx := TRegExpr.Create('media--sm-v(.*?)meta__item', PCRE_SINGLELINE); // Создаём объект поиска блоков текста 
  If RegEx.Search(gsHtml) Then // Если нашли совпадение, запускаем цикл
    Repeat

      //... тут обрабатываем то, что получаем от RegEx.Match, т.е. найденный блок

    Until Not RegEx.SearchAgain; // Повторяем цикл пока SearchAgain возвращает True
  RegEx.Free; // Освобождаем объект из памяти

Пример цикла на C++Script:

  TRegExpr RegEx = TRegExpr.Create('media--sm-v(.*?)meta__item', PCRE_SINGLELINE); // Создаём объект поиска блоков текста 
  if (RegEx.Search(gsHtml)) do { // Если нашли совпадение, запускаем цикл do ... while

  //... тут обрабатываем то, что получаем от RegEx.Match, т.е. найденный блок

  } while (RegEx.SearchAgain()); // Повторяем цикл пока SearchAgain возвращает True
  RegEx.Free(); // Освобождаем объект из памяти

Помните, что объекты, созданные через конструктор функцию Create потом нужно не забыть удалить из памяти функцией Free. А ещё лучше, обернуть выполнение кода после создания объекта в обработку исключений try ... и в блоке finally выполнить функцию Free для созданных объектов.

Функция HmsRegExMatch

Функция HmsRegExMatch служит для нахождения в строке соответствия по условию регулярного выражения. Может принимать 5 параметров, 3 из них обязательны.

HmsRegExMatch(const aRegEx, aSubject: string; var aMatch: string; aIndex: Integer = 1; aOptions: Integer = 0): Boolean 

Возможные параметры функции:

  1. aRegEx - регулярное выражение (строка);
  2. aSubject - текст, где будет происходить поиск по регулярному выражению (строка);
  3. aMatch - переменная типа строка, куда будет занесено значение группировки (то, что между скобок) регулярного выражения в случае успешного совпадения;
  4. aIndex - номер группировки (число, по-умолчанию 1);
  5. aOptions - опции использования регулярных выражений (число, константы начинающиеся на PCRE_).

Функция возвращает True, если найдено совпадение и помещает значение группировки в переменную в третьем параметре. В случае если не найдено, значение переменной не меняется. С помощью этой функции удобно вычленять нужную информацию из текста. Например, получить значение ссылки или наименования из блока текста, который содержит информацию о видео или вырезание нужного блока из текста.

Пример использования. Пусть sText1 содержит строку <h2>Пример использования</h2><a href="http://test.me/please">Ссылка1</a>. Тогда после команды:

HmsRegExMatch('<a[^>]+href="(.*?)"', sText1, sText2);

sText2 будет содержать http://test.me/please. Тест. А после команды:

HmsRegExMatch('<a[^>]+href="(.*?)/(.*?)"', sText1, sText2, 2);

sText2 будет содержать please (потому как четвёртым параметром указано получить вторую группировку).

Функции HmsRegExMatch2 и HmsRegExMatch3 отличаются только количеством указания переменных для получения результата группировок без указания их номера.

Функция HmsHtmlToText

Функция HmsHtmlToText превращает html код в чистый текст без тегов и преобразовывает специальные сущности типа &nbsp;, &lt; и проч. в символы. Вторым параметром может быть код кодовой страницы Windows (Windows codepage). Полезна, например, после получения наименования из html избавиться от тегов и возможных html сущностей.

HmsHtmlToText(const aHtmlText: string; aCodePage: Integer = 0): string

Параметры функции:

  1. aHtmlText - преобразуемый текст (строка);
  2. aCodePage - кодовая страница (число: 1251 - Windows, 866 - DOS, 65001 - UTF-8, ...). Необязательный параметр.

Пример:

sText = HmsHtmlToText('<h2>Пример использования</h2><strong>полезной&nbsp;функции</strong>');

После выполнения команды выше, sText будет содержать текст: "Пример использования полезной функции".
Будьте внимательны, &nbsp; будет преобразован в неразрывный пробел. На вид его в тексте не отличить (хотя дизайнеры, говорят, могут). Но вот код его будет не Chr(32), а Chr(160).

Функция HmsExpandLink

Функция HmsExpandLink преобразует относительную ссылку в полную, не относительную. Например, если в тексте страницы сайта https://www.ted.com/talks?language=ru мы найдём ссылку /talks/1, то этой командой мы может её сделать полной. Допустим, переменная sLink содержит относительную ссылку /talks/1:

sLink = HmsExpandLink(sLink, 'https://www.ted.com');

После выполнения данной команды в sLink будет уже https://www.ted.com/talks/1. Если до выполнения этой команды переменная уже содержит полную ссылку, то её значение не изменится. Эта функция просто избавляет нас от лишней проверки, какая ссылка там содержится и лишних телодвижений. Потому как иногда в разных местах html кода могут встречаться ссылки как относительные, так и нет. Например, на картинки или постеры.

Внимание, замечено, что не все виды относительных ссылок она обрабатывает правильно, а только тех, которые начинаются на слеш /. А в жизни на некоторых сайтах, в редких случаях, могут начинаться без слеша или на точку со слешем ./. Да и вообще, html код страниц может быть разнообразным и не всегда соответствовать стандартам и рекомендациям W3C.

Ну всё. Вот и были рассказаны несколько функций, с помощью которых можно загрузить, распарсить загруженную страницу и получить данные для создания ссылок на медиа-ресурсы. Можно писать скрипты. Готовы? Поехали.

Sony Bravia KDL-32CX523

3

Re: Туториал: Написание подкастов

Пишем скрипт чтения списка ресурсов

Помните, что объявленные переменные внутри главной процедуры или вне её - являются глобальными. Т.е. видны во всех процедурах сразу. А переменные, объявленные внутри своей отдельной процедуре или функции - видимы только в ней.

В скрипте чтения списка ресурсов, т.к. часто этот скрипт служит именно для обновления списка ссылок, уместно в начале выполнить очистку уже ранее созданных. Поэтому начнём свой скрипт с вызова процедуры очистки дочерних элементов текущего подкаста: FolderItem.DeleteChildItems. Итак, начнём писать скрипт:

// Глобальные переменные
var
  gsHtml: String;   // Содержимое страницы сайта
  gsLink: String;   // Ссылка на видео
  gsName: String;   // Наименование видео
  gsImg : String;   // Картинка превью (эскиз)
  RegExp: TRegExpr; // Объект для поиска по регулярному выражению

// ГЛАВНАЯ ПРОЦЕДУРА
begin
  FolderItem.DeleteChildItems;          // Очищаем существующие ссылки

  gsHtml := HmsDownloadUrl(mpFilePath); // Загрузка страницы по ссылке

  // Создаём объект для поиска по регулярному выражению
  RegExp := TRegExpr.Create('media--sm-v(.*?)meta__item', PCRE_SINGLELINE);
  
  // Организовываем цикл
  If RegExp.Search(gsHtml) Then Repeat

    // Получаем данные о видео
    HmsRegExMatch('<a[^>]+href="(.*?)"', RegExp.Match, gsLink); // Ссылка
    

  Until Not RegExp.SearchAgain; // Повторять цикл пока SearchAgain возвращает True 

  RegExp.Free; // Освобождаем созданный объект из памяти

end.

Давайте поставим точку останова на строку HmsRegExMatch('<a[^>]+href="(.*?)"', RegExp.Match, gsLink); и посмотрим, что в переменной RegExp.Match:

Видим, что русский текст не отображается нормально. Это значит, что кодировка загруженной страницы не совпадает с той, в которой мы работаем. В программе Домашний медиа-сервер используется кодировка Windows-1251. А сайты очень часто отдают в кодировке Utf8. Чтобы решить эту проблему, нужно перекодировать загруженную страницу из Utf-8 в Windows-1251. Для этого есть функция HmsUtf8Decode. Сразу хочу обратить внимание и на вторую проблему. В найденном тексте есть переносы строк, поэтому в функциях HmsRegExMatch нам следует указывать опции PCRE_SINGLELINE или PCRE_DOTALL, т.к. точка в регулярных выражениях, по-умолчанию, означает любой символ кроме переноса строк и шаблон регулярки без указания этих опций не сработает на получении данных, например, о наименовании видео. Есть простой способ избежать необходимости указывать дополнительные опции в данном случае - просто убрать из текста заранее все переносы строк. Для этого есть функция HmsRemoveLinebreaks, которая просто убирает из текста все переносы.

Также мы видим, что у нас есть информация о длительности, но формат, который поддерживает программа, должен быть конкретный - это либо секунды, либо в формате '00:00:00.000'. Поэтому придётся полученную строку длительности видео немного преобразовать в нужный нам формат.

Итак, не буду вас долго мучить. Итоговый скрипт создания ссылок, в нашем случае, может быть такой.

Скрипт чтения списка ресурсов (PascalScript):

// Глобальные переменные
var
  gsUrlBase: String = 'https://www.ted.com'; // База ссылки, для создания полных ссылок из относительных

  gsHtml: String;   // Содержимое страницы сайта
  gsLink: String;   // Ссылка на видео
  gsName: String;   // Наименование видео
  gsImg : String;   // Картинка превью (эскиз)
  gsTime: String;   // Длительность видео

  gsVal : String;   // Переменная для хранения временного значения строки
  gnSec : Integer;  // Число секунд длительности видео 

  RegExp: TRegExpr; // Объект для поиска по регулярному выражению
  Item  : THmsScriptMediaItem; // Объект элемента базы данных программы 
  
// ГЛАВНАЯ ПРОЦЕДУРА
begin
  FolderItem.DeleteChildItems;           // Очищаем существующие ссылки

  gsHtml := HmsDownloadUrl(mpFilePath);  // Загрузка страницы по ссылке
  gsHtml := HmsUtf8Decode(gsHtml);       // Перекодируем текст из UTF-8
  gsHtml := HmsRemoveLinebreaks(gsHtml); // Удаляем переносы строк

  // Создаём объект для поиска по регулярному выражению
  RegExp := TRegExpr.Create('media--sm-v(.*?)meta__item', PCRE_SINGLELINE);
  
  // Организовываем цикл
  If RegExp.Search(gsHtml) Then Repeat

    // Получаем данные о видео
    HmsRegExMatch('<a[^>]+href=[''"](.*?)[''"]' , RegExp.Match, gsLink); // Ссылка
    HmsRegExMatch('(<h4.*</h4>)'                , RegExp.Match, gsName); // Наименование
    HmsRegExMatch('<img[^>]+src=[''"](.*?)[''"]', RegExp.Match, gsImg ); // Картинка
    HmsRegExMatch('duration.*?>(.*?)<'          , RegExp.Match, gsTime); // Длительность
    
    gsName := HmsHtmlToText(gsName);            // Избавляемся от html тегов в названии 
    gsLink := HmsExpandLink(gsLink, gsUrlBase); // Делаем из относительных ссылок абсолютные
    gsImg  := HmsExpandLink(gsImg , gsUrlBase);

    // Вычисляем длительность в секундах из того формата, который на сайте (m:ss)
    gnSec := 0;
    if HmsRegExMatch('(\d+):', gsTime, gsVal) then gnSec := gnSec + StrToInt(gsVal) * 60; // Минуты 
    if HmsRegExMatch(':(\d+)', gsTime, gsVal) then gnSec := gnSec + StrToInt(gsVal);      // Секунды 

    // Создаём элемент медиа-ссылки
    Item := HmsCreateMediaItem(gsLink, FolderItem.ItemID); // Создаём элемент подкаста
    Item.Properties[mpiTitle     ] := gsName; // Наименование 
    Item.Properties[mpiThumbnail ] := gsImg;  // Картинка 
    Item.Properties[mpiTimeLength] := gnSec;  // Длительность в секундах

  Until Not RegExp.SearchAgain; // Повторять цикл пока SearchAgain возвращает True 

  RegExp.Free; // Освобождаем созданный объект из памяти
end.

Скрипт чтения списка ресурсов (C++Script):

// Глобальные переменные
  string gsUrlBase = 'https://www.ted.com'; // База ссылки, для создания полных ссылок из относительных

  string gsHtml; // Содержимое страницы сайта
  string gsLink; // Ссылка на видео
  string gsName; // Наименование видео
  string gsImg ; // Картинка превью (эскиз)
  string gsTime; // Длительность видео

  string gsVal ; // Переменная для хранения временного значения строки
  int    gnSec ; // Число секунд длительности видео 

  TRegExpr RegExp;          // Объект для поиска по регулярному выражению
  THmsScriptMediaItem Item; // Объект элемента базы данных программы 
  
// ГЛАВНАЯ ПРОЦЕДУРА
{
  FolderItem.DeleteChildItems();        // Очищаем существующие ссылки

  gsHtml = HmsDownloadUrl(mpFilePath);  // Загрузка страницы по ссылке
  gsHtml = HmsUtf8Decode(gsHtml);       // Перекодируем текст из UTF-8
  gsHtml = HmsRemoveLinebreaks(gsHtml); // Удаляем переносы строк

  // Создаём объект для поиска по регулярному выражению
  RegExp = TRegExpr.Create('media--sm-v(.*?)meta__item', PCRE_SINGLELINE);
  
  // Организовываем цикл
  if (RegExp.Search(gsHtml)) do {

    // Получаем данные о видео
    HmsRegExMatch('<a[^>]+href=[\'"](.*?)[\'"]' , RegExp.Match, gsLink); // Ссылка
    HmsRegExMatch('(<h4.*</h4>)'                , RegExp.Match, gsName); // Наименование
    HmsRegExMatch('<img[^>]+src=[\'"](.*?)[\'"]', RegExp.Match, gsImg ); // Картинка
    HmsRegExMatch('duration.*?>(.*?)<'          , RegExp.Match, gsTime); // Длительность
    
    gsName = HmsHtmlToText(gsName);            // Избавляемся от html тегов в названии 
    gsLink = HmsExpandLink(gsLink, gsUrlBase); // Делаем из относительных ссылок абсолютные
    gsImg  = HmsExpandLink(gsImg , gsUrlBase);

    // Вычисляем длительность в секундах из того формата, который на сайте (m:ss)
    gnSec = 0;
    if (HmsRegExMatch('(\\d+):', gsTime, gsVal)) gnSec += StrToInt(gsVal) * 60; // Минуты 
    if (HmsRegExMatch(':(\\d+)', gsTime, gsVal)) gnSec += StrToInt(gsVal);      // Секунды 

    // Создаём элемент медиа-ссылки
    Item = HmsCreateMediaItem(gsLink, FolderItem.ItemID); // Создаём элемент подкаста
    Item[mpiTitle     ] = gsName; // Наименование 
    Item[mpiThumbnail ] = gsImg;  // Картинка 
    Item[mpiTimeLength] = gnSec;  // Длительность в секундах

  } while (RegExp.SearchAgain); // Повторять цикл пока SearchAgain возвращает True 

  RegExp.Free(); // Освобождаем созданный объект из памяти
}

Ура. Если мы сохраним данный скрипт и обновим подкаст - мы увидим список видео!

Теперь по порядку разберём текст скрипта и дадим пояснения каждой команде.

Объяснение скрипта чтения списка ресурсов (C++Script):

В самом начале объявляем переменные, которыми мы будем пользоваться в скрипте. Если переменная глобальная (видима во всех функциях), то я добавляю к началу названия букву g. Также добавляю букву типа переменной: у строковых s (string), у числовых n (numeric). Чтобы не запутаться при разрастании кода и по названию было понятно, что это за переменная.

// Глобальные переменные
  string gsUrlBase = 'https://www.ted.com'; // База ссылки, для создания полных ссылок из относительных

Переменную gsUrlBase полезно задавать там, где в коде используется функция HmsExpandLink. Она обычно задаёт значение базы адреса сайта, который мы будем парсить. Т.е. когда мы будем доставать ссылки из HTML кода страницы, которые могут оказаться относительными и эти ссылки нужно приводить к абсолютному виду. Т.к. обычно загружаем страницы с одного домена, то значение для всех таких функций можно задать в одном месте и заранее.

  string gsHtml; // Содержимое страницы сайта
  string gsLink; // Ссылка на видео
  string gsName; // Наименование видео
  string gsImg ; // Картинка превью (эскиз)
  string gsTime; // Длительность видео

  string gsVal ; // Переменная для хранения временного значения строки
  int    gnSec ; // Число секунд длительности видео 

Тут мы просто перечисляем все переменные, которые нам понадобятся. Желательно имена давать переменным таким образом, чтобы они несли смысл, для чего они предназначены. Поверьте, даже скрипт написанный вами, через пол года становиться скриптом, который написал кто-то чужой и вам потом самим свой код придётся изучать заново.

  FolderItem.DeleteChildItems();        // Очищаем существующие ссылки

FolderItem - это встроенная переменная, которая содержит объект текущего подкаста или папки. Она доступна только в скриптах создания подкаст лент или скриптах создания ссылок на медиа-ресурсы. Тип данной переменной - THmsScriptMediaItem, а значит у неё есть все свойства и методы данного класса. Вызывая метод DeleteChildItems, мы удаляем все дочерние элементы данного объекта. Это значит мы удалим все существующие ссылки в данном подкасте, ведь мы же их будем создавать заново.

  gsHtml = HmsDownloadUrl(mpFilePath);  // Загрузка страницы по ссылке
  gsHtml = HmsUtf8Decode(gsHtml);       // Перекодируем текст из UTF-8
  gsHtml = HmsRemoveLinebreaks(gsHtml); // Удаляем переносы строк

Функция HmsDownloadUrl загружает страницу по указанной ссылке и возвращает её содержимое. Переменная mpFilePath содержит значение поля "Ссылка" подкаста, т.е. в нашем случае "https://www.ted.com/talks?language=ru". После выполнения HmsDownloadUrl в переменной gsHtml будет содержаться html код загруженной страницы.

Т.к. страницы сайта, в нашем случае, отдаются сервером в кодировке Utf-8, то функцией HmsUtf8Decode мы перекодируем текст, чтобы русские наименования отражались правильно.

А функцией HmsRemoveLinebreaks мы убираем в содержимом страницы все переносы строк, чтобы при использовании далее регулярных выражений в функциях HmsRegExMatch можно было не указывать опции PCRE_SINGLELINE или PCRE_DOTALL.

  // Создаём объект для поиска по регулярному выражению
  RegExp = TRegExpr.Create('media--sm-v(.*?)meta__item', PCRE_SINGLELINE);

Создаём объект класса TRegExpr, где в параметрах указываем регулярное выражение и опции. Регулярное выражение должно быть таким, чтобы при совпадении шаблона можно было получить блок данных, который бы содержал данные о видео (ссылку, наименование, картинку). У данного класса есть метод Search, где мы в параметрах передаём текст, где будет происходить поиск. Также есть метод SearchAgain, который продолжает поиск следующего совпадения. Поэтому мы организовываем цикл, но сначала проверяем, вернул ли метод Search истину (значение True). Если вернул, то запускаем выполнение цикла с проверкой повторного поиска SearchAgain в конце цикла.

  if (RegExp.Search(gsHtml)) do {
  ...
  } while (RegExp.SearchAgain); // Повторять цикл пока SearchAgain возвращает True 

Внутри цикла объект RegExp через метод Match возвращает найденный блок текста, который был найден по шаблону регулярного выражения. И там мы можем вычленить информацию о видео: найти ссылки, получить наименование, ссылку на картинку.

    // Получаем данные о видео
    HmsRegExMatch('<a[^>]+href=[\'"](.*?)[\'"]' , RegExp.Match, gsLink); // Ссылка
    HmsRegExMatch('(<h4.*</h4>)'                , RegExp.Match, gsName); // Наименование
    HmsRegExMatch('<img[^>]+src=[\'"](.*?)[\'"]', RegExp.Match, gsImg ); // Картинка
    HmsRegExMatch('duration.*?>(.*?)<'          , RegExp.Match, gsTime); // Длительность

Функция HmsRegExMatch по регулярному выражению из переданного текста во втором параметре пытается получить значение в переменную, указанную в третьем параметре. Поэтому, в случае успеха, в переменных gsLink, gsName, gsImg, gsTime после выполнения данных команд будут значения, найденные по регулярному выражению (заданной группировкой скобками).

    gsName = HmsHtmlToText(gsName);            // Избавляемся от html тегов в названии 

Т.к. для получения наименования задано регулярное выражение получить весь текст между тегами <h4 и </h4> включая их самих (взяты в скобки), то переменная gsName будет содержать текст наименования вместе с html тегами. Для того, чтобы избавиться от тегов и получить чистое наименование, как раз и нужна функция HmsHtmlToText. Она сделает наименование чистым текстом, убрав все теги.

    gsLink = HmsExpandLink(gsLink, gsUrlBase); // Делаем из относительных ссылок абсолютные
    gsImg  = HmsExpandLink(gsImg , gsUrlBase);

Данные команды используют функцию HmsExpandLink для того, чтобы привести ссылки к абсолютному виду, т.е. начинающиеся на http, если вдруг они у нас относительные. Базу для дополнения ссылок до полных задаём вторым параметром. Переменная gsUrlBase у нас уже определена в самом начале и содержит начало ссылки с именем домена.

    // Вычисляем длительность в секундах из того формата, который на сайте (m:ss)
    gnSec = 0;
    if (HmsRegExMatch('(\\d+):', gsTime, gsVal)) gnSec += StrToInt(gsVal) * 60; // Минуты 
    if (HmsRegExMatch(':(\\d+)', gsTime, gsVal)) gnSec += StrToInt(gsVal);      // Секунды 

Командами выше, мы из переменной gsTime последовательно пробуем вычленить цифры. Сначала минуты, потом секунды. В случае удачного вычленения и получения цифр в переменную gsVal, мы увеличиваем значение gnSec соответственно значениям. Функция StrToInt конвертирует переданную строку как цифровое значение в числовой тип, а т.к. в регулярном выражении мы задали получать только цифры, мы уверены, что в переменной gsVal всегда будет число как строка. После всего, в переменной gnSec будет храниться число секунд длительности видео.

Вообще, таких преобразований может быть сколько угодно на сайте и все они будут разными в разных случаях. Всё зависит от сайта и формата данных, которые попадают в наше распоряжение. В данном случае мы сделали это так. В другом случае на другом сайте, скорее всего, нужно будет делать по-другому. Главное - получить результат в том формате, который нам нужен. В случае длительности видео, формат который мы должны получить, это либо количество секунд как числовой тип, либо строка в виде 00:00:00.000.

    // Создаём элемент медиа-ссылки
    Item = HmsCreateMediaItem(gsLink, FolderItem.ItemID); // Создаём элемент подкаста
    Item[mpiTitle     ] = gsName; // Наименование 
    Item[mpiThumbnail ] = gsImg;  // Картинка 
    Item[mpiTimeLength] = gnSec;  // Длительность в секундах

Функция HmsCreateMediaItem создаёт элемент подкаста - медиа-ссылку, где первым параметром мы передаём значение поля "Ссылка" ("Путь") нашего медиа-ресурса. Если элемент с такой ссылкой уже есть, то функция вернёт найденный объект. Вторым параметром мы задаём ItemID папки или подкаста, в которой будет создаваться ссылка. Т.к. переменная FolderItem содержит объект текущего подкаста, то указав FolderItem.ItemID мы создадим ссылку в текущем подкасте.

Функция HmsCreateMediaItem возвращает созданный объект и мы присваиваем это значение переменной Item. После чего, через указание идентификаторов свойств объекта мы устанавливаем значения параметров созданного элемента. Задаём наименование, ссылку на эскиз и устанавливаем длительность.

В самом конце, после всего цикла и когда объект для поиска блоков RegExp нам уже не нужен, мы уничтожаем данный объект, освобождая его из памяти:

  RegExp.Free(); // Освобождаем созданный объект из памяти

Вот и объяснение всего скрипта. Это был самый простой пример работы скрипта создания списка медиа-ресурсов. По нему можно понять сам принцип работы и предназначение подобного скрипта.

Sony Bravia KDL-32CX523

4

Re: Туториал: Написание подкастов

Пишем скрипт получения ссылки на ресурс

Т.к. ссылки наших видео-ресурсов - это не ссылки на файлы, которые мы могли бы отдать медиа-плееру (телевизору) на проигрывание, то нам нужно написать скрипт получения ссылки на медиа-ресурс, который бы нашёл и присвоил переменной MediaResourceLink ссылку на реальный файл видео.

Заходим в редактирование скрипта получения ссылки на ресурс и пишем там программу, которая бы загрузила страницу видео с сайта и нашла бы там реальную ссылку.

Для этого точно так же открываем страницу с видео в браузере и смотрим html код этой страницы. Очень долго изучаем. В данном случае, ближе к концу страницы можно обнаружить javascript код, который в формате json содержит ссылки на видео файлы с разными языками и качеством (идёт после <script>q("talkPage.init"). Желательно изучить несколько страниц с разными видео, чтобы найти общую картину. Например тут, в нашем случае, если есть файлы видео с русскими субтитрами - кончаются на -ru.mp4. Если с русскими субтитрами нет, то можно просто взять первую ссылку на видео, после ключевого слова "high".

Раз мы ссылки на видео нашли, осталось только придумать регулярное выражение, по которому бы можно было найти и получить нам нужную ссылку. Здесь я просто приведу уже готовые регулярные выражения без объяснения. Почему именно они такие - это вам задание на изучение регулярных выражений. Потому как у меня пока не стоит цель обучить с ними работать.

Т.к. все функции вы уже знаете, осталось написать простой код, который бы это сделал.

// Объявления переменных
var
  gsHtml: String; // Загруженная страница сайта

// ГЛАВНАЯ ПРОЦЕДУРА
begin
  gsHtml := HmsDownloadUrl(mpFilePath); // Загрузка страницы по ссылке

  If Not HmsRegExMatch('"high":"([^"]+-ru.mp4)"', gsHtml, MediaResourceLink)  // Пробуем получить ссылку на медиаресурс
    Then HmsRegExMatch('"high":"(.*?)"'         , gsHtml, MediaResourceLink); // Если не получилось, то пробуем по-другому
end.

Наш скрипт получения ссылки на ресурс на C++Script:

// ГЛАВНАЯ ПРОЦЕДУРА
{
  string gsHtml = HmsDownloadUrl(mpFilePath); // Загрузка страницы по ссылке

  if (!HmsRegExMatch('"high":"([^"]+-ru.mp4)"', gsHtml, MediaResourceLink)) // Пробуем получить ссылку на медиаресурс
       HmsRegExMatch('"high":"(.*?)"'         , gsHtml, MediaResourceLink); // Если не получилось, то пробуем по-другому
}

Все команды вам тут известны. Из вышеприведённого кода вы должны усвоить две важные вещи:

  1. Результат скрипта получения ссылки на ресурс для медиа-ссылок заносится в переменную MediaResourceLink;
  2. Код должен быть как можно более простым.

Тестовое транскодирование

Конечно, первая проверка работоспособности проходит ещё на этапе отладки скрипта, когда вы его пишете или уже написали. Но окончательная проверка работоспособности получения видео и возможность его транскодирования делается в программе, когда есть ссылки медиа-ресурса (созданы обновлением подкаста) и написан скрипт получения ссылки на медиа-ресурс.

Можно запустить тестовое транскодирование, чтобы посмотреть, реально ли ваша ссылка на медиа-ресурс является ссылкой на видео файл. В случае, если доступа по такой ссылке не будет или ссылка получена не правильно, то процесса транскодирования не будет, будут выведены ошибки. Для того, чтобы запустить тестовое транскодирование, нужно на ссылке медиа-ресурса нажать правой клавишей мышки и в появившемся окне выбрать "Тестовое транскодирование". В выпавшем далее списке устройств нужно выбрать одно, например - "Устройство по умолчанию".


Рис.9 Запуск тестового транскодирования

После этого должно появиться черное консольное окно, в котором высвечиваются параметры транскодирования и вывод сообщений о самой работе транскодера:

Рис.10 Результат тестового транскодирования

Смотрите на надписи. Если через некоторое время будет показано как на картинке выше (Рис.10), где будет идти время и показан битрейт, то значит всё в порядке и ваша видео ссылка, скорее всего, будет работать и на телевизоре (медиа-плеере).

Если выходят ошибки или транскодирования не происходит, то при отладке скрипта получения ссылки на медиа-ресурс нужно перехватить то значение, которое попадает в переменную MediaResourceLink и попытаться эту ссылку вставить в браузер. В браузере должно начаться проигрывание видео или он должен предложить скачать указанный файл. Если предлагает скачать файл - скачиваем и пытаемся проиграть в любом плеере на компьютере. Если ни скачать, ни проиграть данный файл по полученной ссылке не получается, значит мы что-то сделали не так и получившееся ссылка не является рабочей. И нужно возвращаться к изучению того, как получить реальную ссылку на файл.

Заключение первой статьи о созданием подкастов

В данной статье были даны только базовые знания о функциях и классах. Как их использовать, какие есть переменные и константы. Что из себя представляем написание подкаста. Много нюансов и уточнений были опущены специально, чтобы не мешать всё в кучу для людей, которые только знакомятся с возможностями скриптов в программе.

Более подробно и больше информации частями будет дано в следующих статьях о написании подкастов. Там будет рассмотрено создание на реальном сайте онлайн-кинотеатра со всеми трудностями (конечно не всеми - они появляются везде как уникальные), которые вас могут ожидать при создании подкаста.

Некоторые подкасты можно взять для изучения, как они написаны.

C++Sript:

PascalScript:

и другие подкасты, не помеченные [WH] (их лучше не смотреть).

Sony Bravia KDL-32CX523

5

Re: Туториал: Написание подкастов

Здравствуйте Уважаемый WendyH!Раньше на Ваших подкастах при создании ленты подкаста выскакивала простыня где наглядно можно было настроить подкаст под свои нужды,почему Вы сейчас не используете эту функцию,было очень удобно,можно ли вернуть такие настойки?Мне например неинтересна информация о фильме его рейтинге и т.д и т.п. что надо сделать чтобы не загружать лишнию информацию и не загружать сайт подкаста? *DONT_KNOW*

Skyway Droid.Использую подкасты с прямыми ссылками.Транскодированием не занимаюсь.

6

Re: Туториал: Написание подкастов

Визуальная возможность проставлять галочки очень сильно нагромождает код скрипта и имеет определённые требования к его структуре. Это было в подкастах со спец.движком, от которого я отказался в пользу простоты и понятности кода. Чтобы любой желающий мог открыть код подкаста и спокойно его прочитать и научится.
И те галочки просто управляют ключами в доп. параметрах. Просто ставит определённый ключ или убирает.
Настраивается это, обычно, под себя один раз в жизни (ну почти). Поэтому и не стал заморачиваться.

Sony Bravia KDL-32CX523

7

Re: Туториал: Написание подкастов

WendyH пишет:

Визуальная возможность проставлять галочки очень сильно нагромождает код скрипта и имеет определённые требования к его структуре. Это было в подкастах со спец.движком, от которого я отказался в пользу простоты и понятности кода. Чтобы любой желающий мог открыть код подкаста и спокойно его прочитать и научится.
И те галочки просто управляют ключами в доп. параметрах. Просто ставит определённый ключ или убирает.
Настраивается это, обычно, под себя один раз в жизни (ну почти). Поэтому и не стал заморачиваться.

Всё понятно я так и предпалогал.А в настоящих подкастах есть возможность как-то отключать загрузку информации,или тупо удалять часть скрипта отвечающего за загрузку информации?И ещё вопрос-когда будет вторая часть о написании подкастов? :mad:

Skyway Droid.Использую подкасты с прямыми ссылками.Транскодированием не занимаюсь.

8

Re: Туториал: Написание подкастов

Orenburg пишет:

Всё понятно я так и предпалогал.А в настоящих подкастах есть возможность как-то отключать загрузку информации,или тупо удалять часть скрипта отвечающего за загрузку информации?И ещё вопрос-когда будет вторая часть о написании подкастов? :mad:

Насчёт убрать информацию и прочее - зависит от подкаста. Обычно с подкастом в первом сообщении идёт описание ключей, которые можно поставить или убрать. Как правило, достаточно из дополнительных параметров убрать ключ, отвечающий за дополнительную информацию.
Например,  в подкасте Moonwalk есть описание и там для этого нужно убрать ключ --infoitems. А если добавить ключ --justlinks - то вообще будут просто ссылки на фильмы без каких-либо папок.
В подкасте HDKinoteatr.com v2 тоже есть ключ --infoitems, который можно убрать.

Насчёт второй части туториала - даже не знаю, прям стыдно. Начинал писать несколько раз и всё как-то не получалось закончить. Ну раз вы напомнили, опять возьмусь.

Sony Bravia KDL-32CX523

9

Re: Туториал: Написание подкастов

WendyH! На старом форуме я нашёл Ваш скрипт визуальной формы настроек подкаста(https://www.homemediaserver.ru/forum/viewtopic.php?f=23&t=2793)
Вы немогли бы обьяснить на пальцах как применить этот скрипт к подкасту.Что-то уменя не получилось добавить скрипт в подкаст. *DONT_KNOW*

Skyway Droid.Использую подкасты с прямыми ссылками.Транскодированием не занимаюсь.

10

Re: Туториал: Написание подкастов

Orenburg пишет:

WendyH! На старом форуме я нашёл Ваш скрипт визуальной формы настроек подкаста(https://www.homemediaserver.ru/forum/viewtopic.php?f=23&t=2793)
Вы немогли бы обьяснить на пальцах как применить этот скрипт к подкасту.Что-то уменя не получилось добавить скрипт в подкаст. *DONT_KNOW*

Этот скрипт для кодеров, которые бы могли использовать набор функций для своих подкастов. Этот скрипт нужно адаптировать под конкретный подкаст и настраивать на определённые ключи (там, где в коде P := CreateNewParam(PARAMS); далее нужно указывать какой ключ что означает и как его отображать визуально).
Тем более, что он написан на PascalScript и не для всех подкастов подойдёт (если в подкасте уже есть код по Alt+1 на другом языке).

Создайте отдельную тему с предложением, где бы вы хотели видеть подобные настройки (в каких подкастах), посмотрим что можно сделать. А то эта тема немного для других вопросов. Некоторые сообщения я потом отсюда перенесу.

Sony Bravia KDL-32CX523