Привет! И так, новый день и новая интересная задачка.
В этот раз один из моих постоянных клиентов обратился ко мне с вопросом, можно ли как-то Zoom-встречу конвертировать в автовебинар на Bizon365. В теории можно всё, а как на практике?
Что у нас есть, а что нужно?
Прежде чем дать внятный ответ на вопрос, нужно было понять, по какому пути идти и что в конечном итоге нужно сделать. И так, для автовеба нужно не много: видео и сценарий. С видео всё более менее ясно-понятно, записываем предстоящую конференцию, скачиваем видео с облака Zoom или с забираем с папочки на диске, заливаем на YouTube и в общем-то готово.
С сценарием все же основной вопрос. В целом Zoom умеет отдавать комментарии написанные в чате во время конференции в текстовом формате. Это конечно далеко не сценарий, но в общем-то хоть что-то, от чего можно отталкиваться. В общем я решил попробовать решить эту задачу.
Так что там с комментариями?
В итоге мы провели Zoom-встречу и я запросил необходимую выгрузку видео с комментариями. Комментарии, к слову, можно было скачать еще во время конференции, но я не успел и эксперт завершил конференцию быстрее, чем я успел что-то оттуда скачать. Однако это не проблема, все эти комментарии в любом случае сохраняются в облаке Zoom, собственно оттуда мне их скачали и отправили вместе с видео. Давайте взглянем, что в итоге есть в нашем файле:
Здесь мы видим, что у нас есть время, есть имя человека участвующего в конференции и собственно сам комментарий. Более подробно о структуре я расскажу дальше. А пока нужно взглянуть, а что нам в итоге нужно получить? Для этого зайдем в Bizon365, перейдем в редактор сценария любого вебинара и экспортируем оттуда сценарий. Откроем его и посмотри, из чего он состоит.
На скрине выше теперь понятно, в каком виде должен быть сценарий, что бы он был принят сервисом Bizon365. На самом деле это простой формат JSON, ничего собственно нового. Значит нам нужно по сути привести обычный текстовый вид с конференции Zoom в JSON-формат понятный Bizon-у.
Разбираемся с форматом сценария для Bizon365
Приведем JSON сценарий в более читабельный вид и сразу же становится понятно, что по сути сценарий состоит из двух ключевых секций: первая секция, по сути секция метаданных, в которой указано приложение, которое сгенерировало сценарий (свойство app), формат файла-сценарий (свойство format), свойство room которое содержит системное название вебинарной комнаты и свойство data которое содержит непосредственно сценарий. На скриншоте это свойство между синим прямоугольником и оранжевым, оставил его так, так как к метаданным оно не относится, но сценарием еще не является.
Вторая секция это собственно сам сценарий, который состоит из множества (массива) действий (action-в). А вот действия делятся еще на два типа: это команды и комментарии. Отличаются они только непосредственно значением свойства action и параметрами в поле data. Более ничем. И для простоты понимания, будем разделять так, что все объекты action в которых выставлен в значении post — комментарий, всё, что не post — команды. В оранжевом блоке как раз команда. Она отвечает за запуск самой трансляции, только не путайте с открытием комнаты. Вебинарная комната может быть открыта по расписанию, например в 18:00 MSK, а вот эфир может начаться спустя, например, 5 минут после открытия комнаты. Зеленый же блок, наоборот, — простой комментарий. В его action так и указано — post, username (логично) это имя пользователя, который этот комментарий пишет. Свойство role — означает права пользователя в чате. Может быть пустым, может быть guest, а может быть и moder, если комментарий был отправлен кем-то из сотрудников. Поле massage тоже думаю не сложно догадаться зачем. Теперь переходим к свойству timeshift. Его я преднамеренно оставил напоследок, здесь есть что обсудить.
Согласование timeshift
Так вот, свойство timeshift не что иное, как время относительно открытия комнаты (!), когда должно быть выполнено то или иное действие (action). Это значение времени указано в мс (миллисекундах) с момента открытия комнаты, это важно. В целом ничего страшного или сложного в этом нет, но именно параметр timeshit (дословно смещение времени) как раз основа основ любого сценария на Bizon365. Но если мы вернемся к файлу с комментариями Zoom, то там совершенно другой формат времени и отсчет там ведется, по всей видимости, от серверного времени Zoom и это еще и не Московское время.
Как видно на скриншоте выше, формат времени кардинально отличается. В формате Zoom время указывается по шаблону ЧЧ:ММ:СС, в то время как в Bizon, как я и писал выше, указано во первых не время, а смещение времени, а во вторых в миллисекундах.
Решение же задачи в общем-то не сложное, мы просто приведем время Zoom в миллисекунды используя формулу:
время в мс = (часы * 60 * 60 * 1000) + (минуты * 60 * 1000) +(секунды * 1000)
Затем запишем значение в миллисекундах первого комментария, затем от каждого последующего комментария будем вычитать значение первого. Таким образом первый комментарий станет нашей точкой отсчета от которого мы и будем дальше рассчитывать timeshift.
Реализация конвертера
Естественно разбирался я со всеми этими форматами явно не для того, что бы высчитывать всё вручную или через Excel. Ну во первых, если бы мне пришлось считать вручную и готовить необходимый формат тоже ручками, то явно не стал бы таким заниматься, так как это бы стоило совершенно неприличных денег для такой задачи, да и вылилось бы в несколько часов рабочего времени в лучшем случае. А может и дней. Через Excel, полагаю, посчитать временные сдвиги кое как можно было бы, но в формат JSON табличные процессор не переведет (наверное), рисковать я так тоже не стал. А по тому я расчехлил покрывшуюся пылью Microsoft Visual Studio 2019 и решил вспомнить былые времена, когда я занимался разработкой софта под Windows Desktop. Вот собственно под «винду» я программку и напишу. Всё что мне нужно, это распарсить (разобрать) формат комментариев с конференции и перевести в формат понимаемый Bizon365 попутно пересчитав значение времени. Не так и сложно. Весь код напишу на своем любимом языке .NET C#
Первым делом, нужно будет считать файл построчно.
Считанные данные с комментариями я отправляю на обработку в фоновый процесс (что бы окошко не тормозило) в предпоследней строчке. Обработкой строки комментария Zoom будет заниматься функция ProcessData, её я в потоке и выполняю.
Обработка строки заключается в том, что бы разбить строку на составляющие части, а затем провести обработку каждого блока строки комментария.
Если в программе Notepad++ включить отображение всех символов, то можно заметить такие оранжевые стрелочки между столбцами. Эти стрелки не что иное как графическое представление ASCII символа \t, что эквивалентно нажатию на кнопку Tab на клавиатуре. Символы CR LF аналогично служебные и означают обычный перенос на новую строку. Этот перенос нам уже не нужен, так мы выполняли построчное чтение, а вот по символу \t мы выполним функцию Split, которая разрежет одну строку на 3 разных столбца. Это как раз и происходи в 145 строке на скриншоте с кодом выше. В результате мы получаем массив из 3 строк, в нулевом элементе массива (в большинстве языков программирования нумерация массивов начинается с нуля) у нас хранится время. Это значение мы передадим в функцию GetMs которая переводит «время Zoom» в миллисекунды.
В этой функции все тоже просто, используя функцию Split по символу двоеточия я выделил в разные элементы массива значения часов минут и секунд. Затем сконвертировал строку в число (это очень важный нюанс) и затем просто произвел расчет по формуле выше.
Дальше рассчитываем время и заполняем объект для нашего комментария с учетом того, первый это был коммент или нет.
На скриншоте выше как я и писал, для первого комментария мы устанавливаем нулевое смещение (или пользовательское, введённое в интерфейсе программы), это значение запоминается в переменной basems. Затем каждый новый комментарий обрабатываем аналогичным образом, получая его значение в мс и отнимая от него первоначальное.
В конце работы программы просто до заполняем метаданные и выполняем процедуру сериализации которая из нашего внутреннего объекта сделает его текстовое описание как раз в формате JSON. Это описание мы и сохраняем при нажатии на кнопку в интерфейсе. В общей сложности на написание программы ушло около полутора часов (нет, серьезно, я эту статью дольше писал!) и в итоге получился отличный конвертер который в состоянии выполнить поставленную передо мной задачу за вразумительный срок. А при необходимости повторить такую конвертацию у меня под рукой уже будет готовый инструмент.
Тестирование конвертера
После написания программки я засел за монтаж видео. Ничего страшного, просто убрать лишние моменты. В общем видео смонтировано и загружено на YouTube. Пора проверить конвертер в действии. Для этого создадим комнату в Bizon365 и скопируем её системный ID.
Далее переходим на вкладку Трансляции/Автовебинар, выбираем там автовеб и нажимаем на редактирование сценария.
А затем просто импортируем сценарий который сконвертировала утилита Zoom2Bizon.
Ну и собственно скриншот с успешным импортом сконвертированного сценария =)
Вместо итога
Вот такая не особо хитрая программка получилась в итоге, плюс в мой инструментарий и плюс еще один очень интересный пример работы с нестандартной задачей. Как не крути, а наличие нужных инструментов под рукой или возможность эти самые инструменты создавать, позволяет забирать в работу очень интересные и сложные задачи. К тому же очень сильно облегчает рабочие будни. Мне даже сложно представить, сколько времени может занять такая конвертация вручную, особенно ввиду специфического синтаксиса самого JSON. А так вместе с написанием программы и монтажом, на всё про все я потратил около 3х часов времени. С учетом того, что мой компьютер совершенно не тянет даже простые функции видеомонтажа, то разработка инструмента заняла меньшую часть рабочего времени.
Ну а если кому нужен такой конвертер, нужно решить специфическую задачу или разработать инструмент под ваш запрос, обязательно пишите мне.
Спасибо за внимание!