トピック埋め込みに愛が必要

本日、Introducing Discourse AI の「Show Full Post」ボタンをクリックした際に、このことを思い出しました。Discourse に表示される完全な投稿には、すべての画像と多くの見出しが欠落しています。さらに混乱を招くことに、画像のキャプションは表示されますが、関連する画像はありません。

Discourse の allowed embed selectors サイト設定を調整することで、Meta の (Ghost?) ブログの問題を修正できる可能性があります: https://meta.discourse.org/t/configure-the-allowed-embed-selectors-setting/134481。過去の経験から、この設定を取得するのは難しいプロセスであることがわかっています。調整を試みる場合は、結果に細心の注意を払ってください。

Discourse は、外部投稿のコメントシステムとして機能する大きな可能性を秘めていますが、これをうまく行うためには、「Show Full Post」ボタンをクリックしたときに、外部投稿のすべての要素を確実に取得する必要があります。問題は、外部投稿の解析に使用される Ruby Readability gem が、Discourse が使用しているジョブには意図されていないことだと思います。また、活発にメンテナンスされていません: https://github.com/cantino/ruby-readability。

「いいね!」 3

はい、この時点で、何か別のものに移行して少し改善するか、あるいは Show Full Post を元の投稿への単純なリンクである Read Full Post に変更するかのどちらかです。結局のところ、すべてのウェブサイトで考えられるすべての埋め込み問題と戦うのは無意味かもしれません。

「いいね!」 4

@sam これを修正しました。確認してください。

「いいね!」 3

Ghostでブログを公開する準備をしており、GhostとDiscourseの連携機能を利用する予定です。この変更は非常に嬉しいです!

「いいね!」 4

画像が取り込まれるようになりました。「間違い探し」のようなパズルは得意ではありませんが、まだいくつかの違いが見られます。

  • Semantic Related Topics のタイトルが欠落
  • Community Sentiment のタイトルが欠落
  • Modules Providers セクションの順序なしリストが欠落
  • Installing Discourse AI on your community のタイトルが欠落

理想的には、「Sign up for our newsletter」のプロンプトは、埋め込まれた投稿から除外されるべきです。

埋め込まれた投稿を簡単に引用できる機能は重要だと思われます。今考えてみると、「展開/折りたたみ」ボタンと埋め込まれた投稿の引用の「投稿に移動」ボタンがクリックされたときの期待される動作がわかりません。

これは難しい問題です。投稿の article または main 要素に含まれる HTML をサニタイズするだけで簡単なはずですが、それでも問題が発生する可能性があります。たとえば、headerarticle 内に存在する場合にブログ投稿の h1 要素の重複を防ぐには、特別な処理が必要になります。

「いいね!」 1

これはすべてreadablity.jsでも発生していると思います。これはFirefoxのリーダービューです。

<h2>
      <strong>コミュニティへのDiscourse AIのインストール</strong>
    </h2>

これを簡単に修正できる方法があるか確認します…

これについてはよくわかりませんが、もし本当にやりたいのであれば、.discourse-newsletter-signupblocked_embed_selectorsに追加できます。

「いいね!」 4

はい、readablity.jsGitHub - cantino/ruby-readability: Port of arc90's readability project to Ruby と同じコードに基づいているため、おそらくそれらの要素を削除するために同じロジックが使用されています。ただし、readablity.js は一般的に Ruby Readability よりも優れた仕事をします。

メールのCTAは、メール入力が埋め込み投稿から削除されるため、紛らわしいです。技術的には、CTAが article の内側にあるべきかどうかはわかりません。

「いいね!」 1

これを再投稿します。@simon さんと同様に、これはいつか再考されるべきだと思います。

WP Discourse プラグインのサポートリクエストのかなりの部分は、実際には何らかの形の Readability クローリングの問題です。

これが私の直感的な意見をまとめたものです。

とはいえ、現時点ではこれ以上の良い解決策はありません。

しかし、WP Discourse のサポート作業負荷を軽減するために、現状よりも良い解決策に貢献する意欲があります。

「いいね!」 1

問題は確認していますが、修正が遅いです…

MiniRacer が readability をラップするように設定するのはそれほど難しくありません… プロトタイプを作成しました。

この実装に移行する可能性もありますが、すでに分岐しているため、機能を手放すことになります。

これは解決が容易な問題ではありません。

「いいね!」 2

ええ、もっともですが、それは終わりのない「モグラたたき」ゲームになると思います。常に次のような投稿があるでしょう。

私のウェブサイトの投稿はXのように見え、「投稿全体を表示」をクリックするとYのように見え、それらを同一にしたいのです。

この機能に、決して完璧にはならないこの機能に、真の利点があるのかどうか、それとも

「投稿全体を表示」ボタンにすることで、人々はDiscourseが決して完全に提供できない忠実度を期待します。私の懸念は、むしろ期待値の管理です。

あなたが求めているのは、埋め込み機能の削除ということでしょうか。私はそれに賛成かどうか確信が持てません。埋め込みコンテンツが非常に乱雑なサイトは、このシンプルな「元の投稿へのリンク」形式を使用すべきだと思います。しかし、より構造化されたコンテンツを埋め込んでいるサイトは、不完全ではありますが、リーダーモードを利用することができます。

「いいね!」 1

必ずしもそうではありません。より良い期待値の管理が必要だと言っているのです。

ウェブサイトを運営している人の99%は、自分のHTMLがreadabilityのようなgemによって簡単に解析できるほど十分にセマンティックであるかどうかを知りませんし、機能の動作を決定するのがそれであることさえ知りません。ユーザーのデフォルトの想定は、サイト上の投稿と「投稿全体を表示」をクリックしたときに表示されるコンテンツとの間に100%の忠実性がない場合、「Discourse」の問題(あるいはもっと頻繁にはWP Discourseプラグイン)であるということです。

「投稿全体を読む」CTAのようなオプションを簡単に有効にできるようにすること、そしておそらくデフォルトにすることが役立つと思います。

「いいね!」 2

私が言いたかったのは、Ruby Readability は「ウェブページの主要な読み取り可能なコンテンツを抽出するためのツール」であるということです。Discourse に投稿を公開するサイトの場合、ウェブページの主要な読み取り可能なコンテンツは既知であり、外部 CSS セレクターで定義できると仮定しても安全だと思います。たとえば、article.entry-content.post などです。

私が想像しているツールの種類は、サイトが投稿コンテンツの外部セレクターを定義し、そのセレクター内の HTML をサニタイズできるようにするだけです。もう少し洗練されたバージョンでは、サイトが Discourse で除外したい内部セレクターを定義できるようになります。

私の WordPress サイトでは、完全に標準的なマークアップの投稿があります。.entry-content div のすべてのものを Discourse に公開したいと思います。これはほぼ機能しますが、Discourse の allowed embed selector 設定を、投稿のリスト要素を取得するように構成する方法がわかりません。これは、サイトが苦労しているのを見てきた問題の種類です。Rails.cache.clear を実行できないと、構成は非常に困難です。

投稿をワンボックスとして公開することは、このための妥当な解決策です。

編集: debug オプションは、何が起こっているかを理解するのに役立ちます: GitHub - cantino/ruby-readability: Port of arc90's readability project to Ruby WordPress 投稿の除外されたリストの場合:

Conditionally cleaned ul#. with weight 0 and content score 0 because it has too many links for its weight (0).

しかし、それは完全に正当なリストです。

埋め込みの拡張に関する非常に要望の多い機能は、YouTube 動画を拡張コンテンツに表示できるようにすることです。それを防ぐことは、gem にハードコードされています: ruby-readability/lib/readability.rb at master · cantino/ruby-readability · GitHub PR を作成する価値があるかどうかはわかりません。

「いいね!」 2

週末に別の目的で Nokogiri を使用していましたが、あまり夢中にならないようにします。それは一種の依存性があります。Nokogiri がまだ記憶に残っているうちに、埋め込みコードを見てみることにしました。

これに興味があるのは、ニュースサイトやブログサイトで Discourse がより広く使用されるのを見たいからです。もしそうなった場合、新しいサイトの所有者が現在の埋め込み機能に不満を感じるようになる可能性があります。改善のためのアイデアをいくつか紹介します。

EmbeddableHost モデルに 2 つの新しいオプション属性を追加します。

  • target_selector: 埋め込むコンテンツを含む外側の CSS セレクター
  • exclude_selectors: target_selector によって選択されたコンテンツから除外する CSS セレクターのリスト。

管理画面の「埋め込み」ページの各埋め込みホスト行に「設定」ボタンを追加する必要があります。このボタンをクリックすると、メール / プレビュー要約ページに似たページが開きます。

ホスト設定ページには、ホストの target_selector および exclude_selectors 設定を入力するためのフィールドと、指定された値を特定の Web ページに対してテストできる URL フィールドを備えたフォームがあります。テストは基本的に、指定された target_selector および exclude_selectors 値で TopicEmbed.parse_html を実行し、結果を表示するだけです。


parse_html コードの変更は簡単にテストできます。以下に考えられるアプローチを示します。このコードは概念実証にすぎないことに注意してください。

topic_embed.rb に編集済み (discourse/app/models/topic_embed.rb at main · discourse/discourse · GitHub)

###########################################################################
    # `target_selector` と `exclude_selectors` は、理想的にはドメインの `EmbeddableHost` レコードから見つけられるべきです
    # これらの特定の の設定は boingboing.net に対するテストに使用されました
    target_selector = 'article'
    exclude_selectors = ['.article-header, .share-comments-container', '.boing-single-post-rev-content', '.next-post-list-container', '.boing-end-of-article-container-on-single-post-pages']

    if defined?(target_selector) && target_selector.present?
      read_doc = article_content(html, target_selector, exclude_selectors)
    else
      # ホストに `target_selector` が設定されていない場合は Readability にフォールバックします
      read_doc = Readability::Document.new(html, opts)
    end
    ###########################################################################

新しいクラスを作成せずにテストするには、TopicEmbed クラスに追加された基本的な article_content メソッドを次に示します。

  def self.article_content(html, target_selector, exclude_selectors = [])
    doc = Nokogiri::HTML(html)
    # コメントとスクリプトタグを削除します
    doc.xpath('//comment()').each { |i| i.remove }
    doc.css("script, style").each { |i| i.remove }

    # target_selector の NodeSet を取得します
    # 返されたセットが空の場合は、ここで Readability を使用してフォールバックする必要があるかもしれません
    selected_nodes = doc.css(target_selector)

    # ノードを除外します
    unless exclude_selectors.empty?
      selected_nodes.css(*exclude_selectors).each do |node|
        node.remove
      end
    end

    # 画像サイズを処理します。改善が必要かもしれません
    selected_nodes.css('img').each do |img|
      img.remove_attribute('width')
      img.remove_attribute('height')
    end

    # とりあえず、ソースが許可されている場合は iframe を許可します
    # remove_empty_nodes ステップで iframe が削除されるのを防ぐために `[data-sanitized="true"]` を使用します
    allowed_iframe_sources = SiteSetting.allowed_iframes.split('|')
    selected_nodes.css('iframe').each do |iframe|
      allowed = allowed_iframe_sources.any? do |allowed_source|
        iframe['src'].start_with?(allowed_source)
      end

      if allowed
        iframe['data-sanitized'] = 'true'
        iframe['width'] = '690'
        iframe['height'] = '388'
      else
        iframe.remove
      end
    end

    # 空の 'p' および 'div' ノードを削除します
    selected_nodes.css('p', 'div').each do |node|
      node.remove if node.content.strip.empty? && !node.at_css('iframe[data-sanitized="true"]')
    end

    # ノードを文字列に変換し、`content` メソッドを持つオブジェクトを返します
    content = selected_nodes.to_s
    OpenStruct.new(content: content)
  end

複数のドメインに対して少し調整するだけで、うまくいくと確信しています。これまでの BBS の結果は良好です。

目標は、サイト所有者が簡単に理解して自分で設定できるものを作成することです。このアプローチでは、target_selector が具体的であるほど、exclude_selectors を設定しやすくなります。たとえば、WordPress サイトの場合、.entry-contenttarget_selector として選択すれば、それ以上の設定は不要になります。サイト所有者が .entry-content HTML の基本以上のものを取得したい場合は、設定ホストページでその方法を見つけることができます。

唯一の実際の問題は、HTML が非常に一貫性のないホストの場合です。その場合は、Ruby Readability をフォールバックとして維持することで対処できます。