El tema de incrustación necesita algo de amor

Hoy me acordé de esto después de hacer clic en el botón “Mostrar publicación completa” para Introducing Discourse AI. La publicación completa que se muestra en Discourse no tiene todas las imágenes ni muchos encabezados. Para aumentar la confusión, se muestran los subtítulos de las imágenes, pero sin sus imágenes asociadas.

Podría ser posible solucionar el problema en Meta para su blog (¿Ghost?) ajustando la configuración del sitio allowed embed selectors de Meta: Configuring allowed embed selectors. Por experiencia pasada, sé que obtener esta configuración puede ser un proceso complicado. Si intentas ajustarla, presta mucha atención a los resultados.

Discourse tiene mucho potencial para funcionar como un sistema de comentarios para publicaciones externas, pero para hacer un buen trabajo en esto, hacer clic en el botón “Mostrar publicación completa” debe extraer de manera confiable todos los elementos de la publicación externa. Creo que el problema es que el gem Readability de Ruby que se utiliza para analizar publicaciones externas no está diseñado para el trabajo que Discourse está haciendo con él. Tampoco se mantiene activamente: GitHub - cantino/ruby-readability: Port of arc90's readability project to Ruby.

3 Me gusta

Sí, en este punto, o nos movemos a otra cosa que lo haga un poco mejor o simplemente cambiamos la estrategia de incrustación para hacer que el Mostrar publicación completa sea un Leer publicación completa que sea un enlace simple a la publicación original. Después de todo, puede ser inútil luchar contra todos los posibles problemas de incrustación en cada sitio web.

4 Me gusta

@sam acabo de arreglar esto, échale un vistazo.

3 Me gusta

Nos estamos preparando para lanzar nuestro blog en Ghost y utilizar las integraciones de Ghost > Discourse. ¡Muy contentos de ver este cambio!

4 Me gusta

Las imágenes ahora se están cargando. No soy muy bueno en los acertijos de “encuentra las diferencias”, pero todavía veo algunas diferencias:

  • Falta el título Temas semánticamente relacionados
  • Falta el título Sentimiento de la comunidad
  • Falta una lista desordenada en la sección Proveedores de módulos
  • Falta el título Instalar Discourse AI en tu comunidad

Idealmente, la indicación “Regístrate en nuestro boletín” debería excluirse de la publicación incrustada.

La capacidad de citar fácilmente la publicación incrustada parece importante. Pensando en eso ahora, no estoy seguro de cuál es el comportamiento esperado cuando se hace clic en los botones “expandir/contraer” y “ir a la publicación” para las citas de una publicación incrustada.

Es un problema complicado. Debería ser tan simple como sanear el HTML que está contenido en el elemento article o main de una publicación, pero sospecho que aún habría problemas con ese enfoque. Por ejemplo, requeriría un manejo especial para evitar la duplicación del elemento h1 de una publicación de blog si el header existe dentro del article.

1 me gusta

Creo que todo esto está sucediendo también en readability.js, esta es la vista de lectura de Firefox:

<h2 id="installing-discourse-ai-on-your-community">
      <strong>Installing Discourse AI on your community</strong>
    </h2>

Veré si hay una manera fácil de solucionar esto…

No estoy seguro de esto… pero si realmente, realmente queremos hacer eso, podemos agregar .discourse-newsletter-signup a blocked_embed_selectors

4 Me gusta

Sí, readablity.js se basa en el mismo código que GitHub - cantino/ruby-readability: Port of arc90's readability project to Ruby, por lo que probablemente se esté utilizando la misma lógica para eliminar esos elementos. Sin embargo, readablity.js generalmente hace un mejor trabajo que Ruby Readability.

La llamada a la acción (CTA) del correo electrónico es confusa porque la entrada de correo electrónico se elimina de la publicación incrustada. Técnicamente, no estoy seguro de que la CTA deba estar dentro del article.

1 me gusta

Solo haciendo un seguimiento de esto, ya que estoy de acuerdo con @simon en que esto debería reconsiderarse en algún momento.

Una buena parte de las solicitudes de soporte para el plugin WP Discourse son en realidad problemas de rastreo de legibilidad de alguna forma u otra.

Creo que eso resume mi instinto sobre esto.

Dicho esto, no tengo una gran solución en este momento además de esta.

Pero estoy interesado en contribuir a una solución mejor que el status quo, ya que reduciría la carga de trabajo de soporte de WP Discourse.

1 me gusta

Sí que miran los problemas, pero son lentos para solucionarlos…

Configurar MiniRacer para que envuelva la legibilidad no es muy difícil… Hice un prototipo de esto.

Es posible que podamos pasar a esta implementación, pero también ya hemos divergido, por lo que terminaríamos renunciando a características.

No es un problema fácil de resolver.

2 Me gusta

Sí, justo, sin embargo, siento que será un juego interminable de “topo ciego”. Siempre habrá alguna versión de:

La publicación en mi sitio web se ve como X y cuando hago clic en “Mostrar publicación completa” se ve como Y y quiero que sean idénticas.

Supongo que mi pregunta más profunda es si hay un beneficio real para esta funcionalidad, que nunca será perfecta, sobre

Al convertirlo en un botón de “Mostrar publicación completa”, la gente espera una fidelidad que Discourse nunca podrá ofrecer por completo. Mi preocupación es más la gestión de las expectativas.

Supongo que lo que pides es la eliminación de la función de incrustación. No estoy seguro de estar de acuerdo. Creo que los sitios que incrustan contenido muy desordenado deberían usar esta simple forma de “enlace al original”. Sin embargo, los sitios que incrustan contenido mejor estructurado pueden hacer uso del modo lector, a pesar de ser imperfecto.

1 me gusta

No necesariamente. Digo que se necesita una mejor gestión de las expectativas.

El 99% de las personas que administran un sitio web no sabrán si su HTML es lo suficientemente semántico como para ser analizado fácilmente por una gema como “readability”, o incluso si eso es lo que determina cómo funciona la función. La suposición predeterminada de los usuarios es que hay un problema “en Discourse” (o más a menudo en el plugin WP Discourse) cuando no hay una fidelidad del 100% entre la publicación en su sitio y el contenido que aparece cuando el usuario hace clic en “Mostrar publicación completa”.

Hacer que una opción como tener una llamada a la acción “Leer publicación completa” sea fácil de habilitar, y quizás la predeterminada, ayudaría, creo.

2 Me gusta

Lo que quise decir con esto es que Ruby Readability es “una herramienta para extraer el contenido legible principal de una página web”. Para el caso de un sitio que publica publicaciones en Discourse, creo que es seguro asumir que el contenido legible principal de la página web se conoce y puede definirse mediante un selector CSS externo. Por ejemplo, article, .entry-content, .post, etc.

El tipo de herramienta que imagino simplemente permitiría a los sitios definir un selector externo para el contenido de sus publicaciones, y luego sanearía el HTML que estuviera contenido dentro de ese selector. Una versión un poco más sofisticada permitiría a los sitios definir selectores internos que quisieran excluir de Discourse.

En mi sitio de WordPress tengo una publicación con marcado completamente estándar. Me gustaría publicar todo lo que está dentro del div .entry-content en Discourse. Casi funciona, pero no puedo averiguar cómo configurar la opción allowed embed selector en Discourse para importar los elementos de lista de la publicación. Este es el tipo de problema con el que he visto que luchan los sitios. Sin poder ejecutar Rails.cache.clear, es realmente difícil de configurar.

Publicar la publicación como un onebox es una solución razonable para esto.

Editar: la opción debug es útil para comprender lo que está sucediendo: GitHub - cantino/ruby-readability: Port of arc90's readability project to Ruby. Para el caso de las listas excluidas en mi publicación de WordPress:

Se limpia condicionalmente ul#. con peso 0 y puntuación de contenido 0 porque tiene demasiados enlaces para su peso (0).

Sin embargo, es una lista perfectamente legítima.

Una característica muy solicitada con los embeds expandidos es permitir que los videos de Youtube aparezcan en el contenido expandido. Evitar que esto suceda está codificado en la gema: ruby-readability/lib/readability.rb at master · cantino/ruby-readability · GitHub. No estoy seguro de si vale la pena hacer un PR para poder anular esa lista con una opción.

2 Me gusta

No me voy a entusiasmar demasiado con esto, pero estuve usando Nokogiri para otra cosa durante el fin de semana. Es algo adictivo. Pensé en echar un vistazo al código de incrustación mientras Nokogiri estaba fresco en mi mente.

Mi interés en esto es que me gustaría ver que Discourse se use más ampliamente en sitios de noticias y blogs. Si eso sucediera, puedo imaginar que los nuevos propietarios de sitios se frustren con la funcionalidad de incrustación actual. Aquí hay una idea para mejorarla:

Agregue dos nuevos atributos opcionales al modelo EmbeddableHost:

  • target_selector: el selector CSS externo que contiene el contenido que se va a incrustar
  • exclude_selectors: una lista de selectores CSS que se excluirán del contenido seleccionado por target_selector.

Se debe agregar un botón “Configurar” a cada fila de Host Incrustable en la página Admin / Incrustación. Hacer clic en ese botón abre una página similar a la página Correos electrónicos / Resumen de vista previa.

La página Configurar Host tendría un formulario con campos para ingresar la configuración target_selector y exclude_selectors del host, y un campo de URL que permitiría probar los valores proporcionados contra una página web específica. La prueba esencialmente solo ejecutaría TopicEmbed.parse_html con los valores target_selector y exclude_selectors proporcionados, y luego mostraría los resultados.


Los cambios en el código parse_html son fáciles de probar. Aquí hay un enfoque posible. Tenga en cuenta que este código es solo una prueba de concepto:

editado en topic_embed.rb (discourse/app/models/topic_embed.rb at main · discourse/discourse · GitHub)

###########################################################################
    # `target_selector` y `exclude_selectors` idealmente se encontrarían en el registro `EmbeddableHost` del dominio
    # estas configuraciones particulares se usaron para probar contra 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
      # recurrir a Readability si `target_selector` no está configurado para el host
      read_doc = Readability::Document.new(html, opts)
    end
    ###########################################################################

Para probar sin crear una nueva clase, aquí hay un método básico article_content agregado a la clase TopicEmbed:

  def self.article_content(html, target_selector, exclude_selectors = [])
    doc = Nokogiri::HTML(html)
    # eliminar comentarios y etiquetas de script
    doc.xpath('//comment()').each { |i| i.remove }
    doc.css("script, style").each { |i| i.remove }

    # obtener el NodeSet para el target_selector
    # tal vez recurrir a Readability aquí si el conjunto devuelto está vacío
    selected_nodes = doc.css(target_selector)

    # excluir nodos
    unless exclude_selectors.empty?
      selected_nodes.css(*exclude_selectors).each do |node|
        node.remove
      end
    end

    # tratar con tamaños de imagen, podría necesitar mejoras
    selected_nodes.css('img').each do |img|
      img.remove_attribute('width')
      img.remove_attribute('height')
    end

    # solo por si acaso, permitir iframes si su fuente está permitida
    # usar `[data-sanitized="true"]` para evitar que los iframes sean eliminados en el paso remove_empty_nodes
    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

    # eliminar nodos 'p' y 'div' vacíos
    selected_nodes.css('p', 'div').each do |node|
      node.remove if node.content.strip.empty? && !node.at_css('iframe[data-sanitized="true"]')
    end

    # convertir los nodos a una cadena y devolver un objeto con un método `content`
    content = selected_nodes.to_s
    OpenStruct.new(content: content)
  end

Estoy bastante seguro de que solo tomaría un poco de ajuste en varios dominios para que funcione correctamente. Los resultados que he estado obteniendo para BBS son buenos hasta ahora.

El objetivo es crear algo que los propietarios de sitios puedan entender y configurar fácilmente por sí mismos. Con este enfoque, cuanto más específico sea el target_selector, más fácil será configurar el exclude_selectors. Por ejemplo, para un sitio de WordPress, si se seleccionara .entry-content como target_selector, no se requeriría ninguna configuración adicional. Si los propietarios del sitio quisieran obtener más que el HTML básico de .entry-content, podrían averiguar cómo hacerlo en la página Configurar Host.

El único problema real que puedo ver es para los hosts con HTML muy inconsistente. Ese caso podría manejarse manteniendo Ruby Readability como respaldo.