topic-thumbnails 사용 시 외부 임베드의 썸네일 누락

외부 임베드가 OneBox를 통해 이미 작동하도록 iframe 허용을 설정한 상태인我们的产品용 포럼을 출시하고 있습니다.

임베드에 대한 직접 링크는 우리의 oembed 엔드포인트의 결과물로 깔끔하게 변환됩니다.
현재 우리의 가장 큰 관심사는 토픽 목록 썸네일이 활성화되어 있을 때 썸네일이 표시되도록 하는 것입니다. 왜 썸네일이 인식되지 않는지 확실하지 않습니다.

lib/onebox/engine에 통합을 추가해야 할까요?

추가로, 현재 기본 동작은 대부분 잘 작동하지만, 동적 임베드를 지원하지 않는 점이 아쉬움입니다. 우리는 iframe 대신 JS를 로드하는 방식을 원합니다. 솔직히 이 문제를 해결하는 다른 방법, 즉 일부 JS를 사용하여 iframe의 크기를 선택적으로 조정하는 방식도 있지만, 단기적으로 oEmbed에 대해 이를 범용적으로 구현할 계획은 없습니다.

토픽 썸네일로 onebox 이미지 사용 - #20 by david에 대해 알고 있지만, 제 경우에는 도움이 되지 않는 것으로 판단됩니다.

Discourse 팀과 이메일로 몇 가지 논의한 후, 여기 업데이트를 공유합니다.

주요 발견 사항은 링크가 onebox로 변환되어 iframe으로 렌더링될 경우 썸네일이 로드되지 않는다는 것입니다.

즉, 아래 링크는

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

도메인에서 iframe이 허용되는지(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를 작성하면 cooked post에 onebox 이미지를 제공할 수 있을 것입니다. 그러면 섬네일(thumbnail)이 자동으로 작동하게 됩니다.

Youtube onebox는 플레이 버튼을 클릭할 때까지 정적인 인-사이트(in-site) 콘텐츠인 것 같습니다. 클릭하면 iframe이 표시됩니다. 클릭 전에 제공되는 콘텐츠에는 이미지가 포함되어 있으며, 이 이미지가 캡처되어 섬네일로 사용됩니다. 당연히 Discourse는 iframe에서 내용을 읽을 수 없으므로, 이 기법은 좋은 접근 방식입니다.

예제에 헤더 태그 내에 og:image가 포함되어 있는 것을 확인했습니다. 이는 완벽합니다.


여기서는 JavaScript를 피하고 Rails에서 코딩을 하도록 제안합니다.

이 방식의 유일한 단점은, 대상 이미지도 업데이트된다고 가정할 때, Post를 다시 빌드할 때까지 이미지가 정적으로 유지된다는 점입니다. 따라서 동적으로 변경되는 섬네일을 표시하길 원한다면 더 창의적인 접근이 필요할 수 있습니다.

로버트님, 답변 감사합니다!

플러그인을 작성하는 것이 제가 처음 시도한 일이었고, 이는 매우 잘 작동했습니다. lib/onebox/engine에 넣든, 별도의 플러그인으로 만들든 관계없이 말이죠. 다만 우리가 호스팅 플랜을 사용 중이라는 점이 문제입니다. 멀티 테넌트 플랜에서는 이해할 수 있는 대로 플러그인 사용이 허용되지 않아서, Rails에서 직접 개발하는 것은 불가능합니다.

그렇다면 우리에게 남은 선택지는 다음 세 가지 중 하나입니다:

  1. 자체 인스턴스 실행
  2. 작동할 수 있다면 클라이언트 측에서 해킹을 시도해 보기
  3. 메인라인 Discourse에 PR 제출

여기서 질문을 하나 드리자면, 이미지 로드 후 이를 숨기기 위한 목적이므로 이러한 기여가 받아들여질지 확신이 서지 않습니다. 어떻게 확인해 볼 수 있을까요?

이 문제에 대해 어떤 진전을 이룬 것 같습니다. 다음을 살펴보고 있습니다:

api.composerBeforeSave

이 콜백은 composer.js에서 처리됩니다. 여기서 createPost와 editPost 메서드가 getCookedHtml을 호출하는 것을 볼 수 있으며, 이는 사실상 다음 요소의 innerHTML을 반환하는 것입니다:

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

즉, 이 선택자를 수정한다면 일반적인 이미지 업로드와 동등한 HTML을 강제 삽입할 수 있을지도 모릅니다. 그러나 editorPreviewNode.innerHTML을 수정해도 아무런 변화가 나타나지 않는 것 같습니다.

왜 그런 것이며, composerBeforeSave에서 비슷한 효과를 내기 위해 무엇을 수정할 수 있을까요?

이것은 대체로 합리적으로 보입니다. everviz.com(또는 유사한 시각화 서비스)을 위한 onebox 엔진에 대한 PR을 코어에 수용하는 데 열려 있을 것입니다. 하지만 cooked 게시글에 이미지를 삽입하고 숨기는 것은 피해야 합니다. 더 가벼운 옵션이 있습니다. Discourse의 게시글 프로세서가 다음 요소에 대한 업로드를 찾습니다:

따라서 iframe 아래에 앵커로 썸네일을 추가하는 방식이 작동할 수 있습니다. 이를 표시하거나 "hidden"과 같은 클래스를 사용하여 숨길 수 있습니다.

Penar님, 답변 감사합니다.

아래 코드를 to_html 메서드로 사용했을 때 다음과 같은 출력이 생성됩니다:

  <div class="everviz-box">
   #{get_oembed.html}
   <a class="hidden" href="https://app.everviz.com/thumbnails/#{match[:uuid]}.png"></a>
  </div>
  <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(풀 리퀘스트)이 될까요? 아니면 더 복잡한 작업이 필요할까요?

정확히 무슨 말씀인지 잘 이해가 가지 않습니다. 이건 이미지 원박스 엔진을 통해 처리되지 않아야 합니다.

다음과 같은 코드가 작동하지 않는 건가요?

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

즉, 주제의 첫 게시물의 cooked 컬럼에 이 코드가 포함된 경우, 처리 후 이미지가 썸네일로 인식되는지 묻는 것입니다.

혼동을 드려 죄송합니다. 출력 결과가 이미지 원박스(onebox) 엔진과 비슷해 보였기 때문입니다.

제안된 링크(올바르게 UUID가 포함된)는 작동하지 않습니다. 구글에서 가져온 이 이미지(여기서는 앵커 태그로 작성 중)도 마찬가지입니다. HTML을 붙여 넣는 것이 원박스 출력을 생성하는 것과 동등하다면, 이는 우리의 결과를 설명할 수 있을 것입니다.

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

아, 내 실수였네. 네가 맞고, 그 접근 방식은 동작하지 않아. 썸네일을 생성할 때 우리는 다운로드된 이미지만 사용하는데, 앵커 태그로 링크된 이미지는 다운로드되지 않으니까.

여기서 대안으로 @merefield가 추천한 것과 유사한 것을 코어에 추가하되, 지연 로드되는 iframe을 위한 범용 원박서(oneboxer)로 감싸는 방법이 있을 수 있어. 예를 들어 lazy_loaded_iframes라는 새로운 사이트 설정을 추가하고, 원박이 처음에는 OG 태그의 이미지를 출력하도록 할 수 있지 (이것이 썸네일에 의해 잡히게 될 거야). 그리고 클릭 시, 약간의 JS가 이미지를 올바른 iframe으로 교체하도록 하면 돼 (유튜브 iframe 교체 방식과 유사하게).

여기서 까다로운 세부 사항 중 하나는 사용되는 이미지와 iframe의 높이가 동일해야 한다는 거야. 그렇지 않으면 게시글을 스크롤하거나 탐색할 때 원치 않는 점프가 발생할 수 있으니까.