Такие сервисы, как 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, который запускает его после публикации записи.
После этого я получаю расшифровку на месте:
И преобразованная продолжительность:
Подводя итоги
Таким образом, процесс публикации в его нынешнем виде состоит из следующих шагов:
- Публикуйте видео на YouTube, используя специально отформатированный заголовок
- Отредактируйте запись Contentful, созданную Zapier: прикрепите ее к плейлисту. Это единственный шаг, который необходимо выполнить вручную, как упоминалось выше. Поскольку я публикую видео только раз в неделю или две, я считаю это приемлемым и использую его как гарантию качества с моей стороны.
- Нажмите «Опубликовать» и увидите, как произойдет волшебство.