Такие сервисы, как Zapier и IFTTT, наряду с веб-перехватчиками, являются воплощением того, как Интернет развивался за последние 2,5 десятилетия. Первоначальная модель клиент-сервер была заменена или, что правильнее, замаскирована более децентрализованным подходом.

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

Для этого есть Zap.

Все начинается с хука Zapier, который запускается после публикации видео на моем канале. Оказывается, для этого случая уже есть шаблон zap (он есть почти для каждого соединения API-to-API), и довольно просто связать его с Contentful, чтобы составить черновик записи:

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

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

Склеивание всего вместе с помощью веб-хуков и функций Firebase

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

Мы можем предоставить функцию общедоступному URL-адресу, если воспользуемся модулем https:

exports.convertContentfulVideo = functions.https.onRequest((req, res) => {
    if (!req.headers.authorization || req.headers.authorization !== `Basic ${functions.config().basic_auth.password}`) {

    res.sendStatus(403);

  } else {
      // ...
  }
}

Сначала мы проверяем, является ли это авторизованным запросом. Мы делаем это, проверяя заголовок Basic Auth на соответствие паролю, хранящемуся в переменных env firebase.

Установить их довольно просто:

> firebase functions:config:set basic_auth.password="<base64-encoded-string>"

После этого вы можете получить к нему доступ, как показано выше. Затем в ветке else мы выполняем нашу работу:

Сначала нам нужно вручную разобрать запрос, потому что Contentful отправляет забавный Content-Type (не application/json)

const parsedEntry = JSON.parse(req.rawBody.toString('utf-8'));

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

let contentfulEntry;
if (parsedEntry.sys.contentType.sys.id === 'video' && parsedEntry.fields.transcript === undefined) {
  const id = parsedEntry.sys.id;

  client.getSpace(functions.config().contentful.space_id)
    .then((space) => space.getEntry(id))
    .then((entry) => {

      contentfulEntry = entry;

      const title = entry.fields.title['en-US'];
      const transcriptURL = `https://raw.githubusercontent.com/znibbles/${parameterize(title.split('|')[0].trim().toLowerCase())}/master/transcripts/${parameterize(title.split('|')[1].trim().toLowerCase())}.md`;

      return fetch(transcriptURL);
    })

После того, как у нас есть стенограмма, мы продолжаем цепочку обещаний форматировать продолжительность, которая изначально была в формате ISO-8601, в удобочитаемый формат и сокращать заголовок:

.then(res => res.text())
    .then(transcript => {

      const durationISO8601 = contentfulEntry.fields.duration['en-US'];

      contentfulEntry.fields.duration['en-US'] = moment.utc(moment.duration(durationISO8601).asMilliseconds()).format('mm:ss');
      contentfulEntry.fields.transcript = {
        'en-US': transcript
      };
      contentfulEntry.fields.title['en-US'] = contentfulEntry.fields.title['en-US'].split('|')[1].trim();

      return contentfulEntry.update();
    })

После этого мы повторно публикуем запись и заканчиваем:

.then(entry => entry.publish())
    .then(entry => res.sendStatus(200))
    .catch(reason => {
      console.error(reason);
      return res.sendStatus(500);
    });

} else {
  console.log('no video or already processed');
  res.sendStatus(422);
}

Чтобы активировать эту функцию, мы регистрируем веб-хук на Contentful, который запускает его после публикации записи.

После этого я получаю расшифровку на месте:

И преобразованная продолжительность:

Подводя итоги

Таким образом, процесс публикации в его нынешнем виде состоит из следующих шагов:

  1. Публикуйте видео на YouTube, используя специально отформатированный заголовок
  2. Отредактируйте запись Contentful, созданную Zapier: прикрепите ее к плейлисту. Это единственный шаг, который необходимо выполнить вручную, как упоминалось выше. Поскольку я публикую видео только раз в неделю или две, я считаю это приемлемым и использую его как гарантию качества с моей стороны.
  3. Нажмите «Опубликовать» и увидите, как произойдет волшебство.