Миниатюры отсутствуют для наших внешних вставок при использовании topic-thumbnails

Мы запускаем форум для нашего продукта, внешние встраиваемые элементы которого уже корректно отображаются через OneBox после разрешения Iframe с нашего домена.

Прямая ссылка на встраиваемый элемент аккуратно преобразуется в результат нашего oEmbed-эндпоинта.

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

Нужно ли нам добавить интеграцию в lib/onebox/engine?

Стоит отметить, что поведение по умолчанию в целом работает сегодня, за исключением поддержки наших динамических встраиваемых элементов. Мы хотели бы загружать JS вместо Iframe. Признаём, что существует альтернативное решение — например, динамически изменять размер iframe с помощью JS, но мы не планируем реализовывать это в общем виде для oEmbed в ближайшем будущем.

Я знаком с темой Использование изображений onebox для миниатюр тем - #20 от david, однако она не помогла мне в моём случае.

После обсуждения с командой Discourse по электронной почте я обновляю информацию здесь.

Главное открытие заключается в том, что миниатюры не загружаются, если ссылка, превращающаяся в onebox, рендерится как iframe.

Это означает, что ссылка:

https://app.everviz.com/embed/N0dDTJaOQ

может отображать миниатюру или нет в зависимости от того, разрешены ли iframes с данного домена (настройка allowed iframes). Решение состоит в том, чтобы каким-то образом внедрить iframe в пост. Я создал плагин, который делает это и устанавливает display: none для изображения, чтобы предотвратить его отображение в посте.

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

  1. Для всех общих onebox-ов: незаметно загружать и скрывать изображение рядом с ними, если существует get_oembed.thumbnail_url.
  2. Что, вероятно, является лучшим решением: добавить общую поддержку извлечения get_oembed.thumbnail_url и связывания его с постом, без включения его в область cooked.

Релевантные места:

  1. https://oembed.com/
  2. discourse/lib/onebox/engine at main · discourse/discourse · GitHub
  3. discourse/lib/onebox/engine/standard_embed.rb at main · discourse/discourse · GitHub

Меня не совсем устраивает такое модальное поведение, то есть включена ли настройка allowed iframes или нет. Было бы здорово, если бы Discourse извлекал и использовал все свойства из конечной точки oembed при первом отправлении запроса GET к ней.

Обновление

У меня возникла идея использовать API плагинов на стороне клиента для загрузки изображения в пост.

api.decorateCooked($elem => {
    $elem[0].querySelectorAll('.my-iframe')
    .forEach(function (iframe) {
      
      //работа
      
      iframe.insertAdjacentElement('beforebegin', thumbnail);
    });
  
  }, {id: 'unique_string'});

Однако Discourse ничего не обнаруживает.

Похоже, происходит одно из двух:

  1. Мы опоздали, и Discourse уже выполнил получение и генерацию миниатюр.
  2. В нашем изображении отсутствуют некоторые атрибуты, из-за чего механизм генерации миниатюр его не замечает.

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

Вы пробовали это? Написание специфичного onebox для вашего случая может позволить вам предоставить изображение onebox для обработанного поста? Тогда миниатюры будут работать автоматически.

Обратите внимание, что, насколько я знаю, onebox для YouTube представляют собой статический контент на сайте, пока вы не нажмёте кнопку воспроизведения, после чего отображается iframe. Контент, представленный до нажатия, включает изображение, которое затем используется для создания миниатюры. Очевидно, что Discourse не может читать содержимое из iframe, поэтому этот подход является хорошим решением.

Замечаю, что в вашем примере в тегах заголовка присутствует og:image, что идеально.


Моя рекомендация — отказаться от JavaScript здесь и перейти к разработке на Rails.

Единственным недостатком этого будет то, что ваше изображение останется статичным до пересборки поста, при условии, что целевое изображение также обновлено. Таким образом, если вы надеетесь отображать динамически изменяющуюся миниатюру, возможно, придётся проявить ещё больше креативности.

Привет, Роберт, спасибо за ответ!

Написание плагина стало моей первой задачей, и это сработало великолепно — неважно, поместил ли я его в lib/onebox/engine или как отдельный плагин. Однако есть нюанс: мы используем хостинговый план, где плагины, понятно, не разрешены на многопользовательских тарифах, поэтому разработка на Rails отпадает.

Остаются три варианта:

  1. Запуск собственного экземпляра
  2. Создание решения на стороне клиента, если это сработает
  3. Отправить PR в основную ветку Discourse

Чтобы сформулировать вопрос: я не уверен, примут ли такой вклад, особенно если он загружает изображение лишь для того, чтобы скрыть его. Как мне это узнать?

Возможно, я добился некоторого прогресса в этом вопросе. Рассматривая:

api.composerBeforeSave

Чей обратный вызов обрабатывается в composer.js. Оттуда мы видим, что методы createPost и editPost вызывают getCookedHtml, который по сути просто возвращает innerHTML следующего элемента:

const editorPreviewNode = document.querySelector(
  "#reply-control .d-editor-preview"
);

Это означает, что если бы мы изменили этот селектор, возможно, смогли бы внедрить HTML, эквивалентный обычной загрузке изображения. Однако, похоже, что изменение editorPreviewNode.innerHTML не приводит к каким-либо изменениям.

Почему так происходит, или что можно изменить в composerBeforeSave, чтобы добиться похожего результата?

В целом это звучит разумно. Мы, вероятно, были бы открыты к принятию PR в ядро для движка onebox для everviz.com (или аналогичных сервисов визуализации). Однако я бы избегал вставки и скрытия изображения внутри cooked-части поста — есть более лёгкий вариант. Пост-процессор Discourse будет искать загрузку по следующим элементам:

Так что, возможно, стоит добавить миниатюру в виде ссылки под iframe? Вы можете оставить её видимой или скрыть, используя класс, например, “hidden”.

Привет, Penar, спасибо за ответ.

Использование

  <div class="everviz-box">
   #{get_oembed.html}
   <a class="hidden" href="https://app.everviz.com/thumbnails/#{match[:uuid]}.png"></a>
  </div>

в качестве моего метода to_html даёт следующий вывод:

  <div class="...">
    <iframe
      ...
    ></iframe>
    <a class="hidden" href="https://app.everviz.com/thumbnails/[...].png" rel="nofollow ugc noopener"></a>
  </div>

Прямая ссылка на изображение выдаёт:

<a href="https://app.everviz.com/thumbnails/[...].png" target="_blank" rel="noopener" class="onebox">
   <img src="//localhost:3000/uploads/default/original/1X/[...].png"
        style="aspect-ratio: 690 / 459;" loading="lazy">
</a>

Это создаёт впечатление, что движок image_onebox.rb запускается на вводе только тогда, когда изображение ссылается вне контекста другого движка onebox.

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

Было бы приемлемо в данном случае создать PR с добавлением и скрытием изображения? Или необходимо предпринять что-то более сложное?

Не уверен, что правильно понимаю, это не должно проходить через движок onebox изображений.

Не работает ли это:

<a class="hidden" href="https://app.everviz.com/thumbnails/[...].png" rel="nofollow ugc noopener"></a>

То есть, если в первом сообщении темы в столбце обработанного контента присутствует такой код, будет ли изображение распознано как миниатюра после обработки?

Приносим извинения за путаницу: вывод выглядел похоже на изображение, сгенерированное движком onebox.

Предложенная ссылка (правильно дополненная UUID) не работает. Не работает и это изображение, которое я взял из Google (и которое здесь используется как якорная ссылка). Если вставка HTML-кода эквивалентна выводу onebox, это объясняет наши результаты.

https://static-cse.canva.com/blob/1031184/1600w-wK95f3XNRaM.jpg

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

Альтернативой здесь может быть добавление в ядро чего-то похожего на то, что рекомендовал @merefield, но обернутого в универсальный onebox для лениво загружаемых iframes. Возможно, добавить новое настройку сайта lazy_loaded_iframes, и onebox изначально будет выводить изображение из тега OG (которое должно быть захвачено миниатюрами), а при клике небольшой скрипт JS заменит изображение на правильный iframe (по аналогии с заменой iframe YouTube).

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