Incorporação de tópicos precisa de atenção

Fui lembrado disso hoje depois de clicar no botão “Mostrar Postagem Completa” para Introducing Discourse AI. A postagem completa exibida no Discourse está sem todas as imagens e muitos cabeçalhos. Para aumentar a confusão, as legendas das imagens são exibidas, mas sem suas imagens associadas.

Pode ser possível corrigir o problema no Meta para seu blog (Ghost?) ajustando a configuração do site allowed embed selectors do Meta: Configuring allowed embed selectors. Pela experiência passada, sei que obter essa configuração pode ser um processo complicado. Se você tentar ajustá-la, preste muita atenção aos resultados.

O Discourse tem muito potencial para funcionar como um sistema de comentários para postagens externas, mas para fazer um bom trabalho nisso, clicar no botão “Mostrar Postagem Completa” precisa buscar de forma confiável todos os elementos da postagem externa. Acho que o problema é que a gema Ruby Readability, usada para analisar postagens externas, não foi projetada para o trabalho que o Discourse está fazendo com ela. Ela também não está sendo ativamente mantida: GitHub - cantino/ruby-readability: Port of arc90's readability project to Ruby.

3 curtidas

Sim, neste ponto, ou mudamos para outra coisa que a torne um pouco melhor ou simplesmente alteramos a estratégia de incorporação para transformar o Show Full Post em um Read Full Post que é um link simples para o post original. Afinal, pode ser inútil lutar contra todos os possíveis problemas de incorporação em todos os sites.

4 curtidas

@sam acabei de corrigir isso, dê uma olhada.

3 curtidas

Estamos nos preparando para lançar nosso blog no Ghost e utilizar as integrações do Ghost com o Discourse. Muito feliz em ver essa mudança!

4 curtidas

As imagens agora estão sendo carregadas. Não sou muito bom em quebra-cabeças do tipo “acerte a diferença”, mas ainda vejo algumas diferenças:

  • Título Tópicos Semanticamente Relacionados ausente
  • Título Sentimento da Comunidade ausente
  • Lista não ordenada ausente na seção Provedores de Módulos
  • Título Instalando Discourse AI em sua comunidade ausente

Idealmente, o prompt “Inscreva-se em nossa newsletter” seria excluído da postagem incorporada.

Ter a capacidade de citar facilmente a postagem incorporada parece importante. Pensando nisso agora, não tenho certeza qual é o comportamento esperado quando os botões “expandir/recolher” e “ir para a postagem” são clicados para as citações de uma postagem incorporada.

É um problema complicado. Deveria ser tão simples quanto higienizar o HTML contido no elemento article ou main de uma postagem, mas suspeito que ainda haveria problemas com essa abordagem. Por exemplo, exigiria algum tratamento especial para evitar a duplicação do elemento h1 de um post de blog se o header existir dentro do article.

1 curtida

Acho que tudo isso está acontecendo também em readability.js, esta é a visualização do leitor do Firefox:

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

Vou ver se há uma maneira fácil de consertar isso…

Não tenho certeza sobre isso… mas se realmente quisermos fazer isso, podemos adicionar .discourse-newsletter-signup a blocked_embed_selectors

4 curtidas

Sim, readablity.js é baseado no mesmo código de GitHub - cantino/ruby-readability: Port of arc90's readability project to Ruby, então provavelmente a mesma lógica está sendo usada para remover esses elementos. O readablity.js geralmente faz um trabalho melhor do que o Ruby Readability.

O CTA do e-mail é confuso porque a entrada de e-mail é removida da postagem incorporada. Tecnicamente, não tenho certeza se o CTA pertence ao article.

1 curtida

Apenas dando um toque neste tópico, pois concordo com o @simon que isso deve ser repensado em algum momento.

Uma boa parte das solicitações de suporte para o plugin WP Discourse são, na verdade, problemas de rastreamento de legibilidade de alguma forma.

Acho que isso resume o meu sentimento sobre o assunto.

Dito isso, não tenho uma ótima solução no momento, além desta.

Mas estou interessado em contribuir para uma solução melhor do que o status quo, pois isso reduziria a carga de trabalho de suporte do WP Discourse.

1 curtida

Eles analisam os problemas, mas demoram para corrigi-los…

Configurar o MiniRacer para encapsular a legibilidade não é muito difícil… Fiz um protótipo disso.

É possível que possamos migrar para essa implementação, mas também já divergimos, então acabaríamos desistindo de recursos.

Este não é um problema fácil de resolver.

2 curtidas

Sim, justo, no entanto, sinto que será um jogo sem fim de “caça às toupeiras”. Sempre haverá alguma versão de:

A postagem no meu site parece X e quando clico em “Mostrar Postagem Completa”, ela parece Y e eu quero que elas sejam idênticas.

Acho que minha pergunta mais profunda é se há um benefício real para essa funcionalidade, que nunca será perfeita, em vez de

Ao torná-lo um botão “Mostrar Postagem Completa”, as pessoas esperam uma fidelidade que o Discourse nunca poderá entregar totalmente. Minha preocupação é mais com o gerenciamento de expectativas.

Acho que o que você está pedindo é a remoção do recurso de incorporação. Não tenho certeza se estou a favor. Acho que sites que incorporam conteúdo muito confuso devem usar esta forma simples de “link para o original”. No entanto, sites que incorporam conteúdos mais bem estruturados podem fazer uso do modo leitor, embora ele seja imperfeito.

1 curtida

Não necessariamente. Estou dizendo que precisa haver um melhor gerenciamento de expectativas.

99% das pessoas que administram um site não saberão se o HTML delas é suficientemente semântico para ser facilmente analisado por uma gema como a legibilidade, ou mesmo que é isso que determina como o recurso funciona. A suposição padrão dos usuários é que há um problema “no Discourse” (ou mais frequentemente no plugin WP Discourse) quando não há 100% de fidelidade entre a postagem em seu site e o conteúdo que aparece quando o usuário clica em “Mostrar Postagem Completa”.

Tornar uma opção como ter uma CTA de “Ler Postagem Completa” fácil de habilitar, e talvez o padrão, ajudaria, eu acho.

2 curtidas

O que eu quis dizer com isso é que Ruby Readability é “uma ferramenta para extrair o conteúdo legível principal de uma página da web”. Para o caso de um site que publica posts no Discourse, acho que é seguro assumir que o conteúdo legível principal da página da web é conhecido e pode ser definido por um seletor CSS externo. Por exemplo, article, .entry-content, .post, etc.

O tipo de ferramenta que estou imaginando apenas permitiria que os sites definissem um seletor externo para o conteúdo de seus posts, então sanitizaria o HTML que estava contido dentro desse seletor. Uma versão um pouco mais sofisticada permitiria que os sites definissem seletores internos que eles queriam excluir do Discourse.

No meu site WordPress, tenho um post com marcação completamente padrão. Eu gostaria de publicar tudo o que está na div .entry-content para o Discourse. Quase funciona, mas não consigo descobrir como configurar a configuração allowed embed selector no Discourse para importar os elementos de lista do post. Este é o tipo de problema que vi sites lutando. Sem poder executar Rails.cache.clear, é realmente complicado de configurar.

Publicar o post como um onebox é uma solução razoável para isso.

Editar: a opção debug é útil para descobrir o que está acontecendo: GitHub - cantino/ruby-readability: Port of arc90's readability project to Ruby. Para o caso das listas excluídas no meu post WordPress:

Condicionalmente limpo ul#. com peso 0 e pontuação de conteúdo 0 porque tem muitos links para seu peso (0).

É uma lista perfeitamente legítima, no entanto.

Um recurso muito solicitado com embeds expandidos é permitir que vídeos do YouTube apareçam no conteúdo expandido. Impedir que isso aconteça é codificado na gema: ruby-readability/lib/readability.rb at master · cantino/ruby-readability · GitHub. Não tenho certeza se vale a pena fazer um PR para poder substituir essa lista por uma opção.

2 curtidas

Não me deixarei levar muito por isso, mas estive a usar o Nokogiri para outra coisa durante o fim de semana. É meio viciante. Pensei em dar uma olhada no código de incorporação enquanto o Nokogiri estava fresco na minha mente.

Meu interesse nisso é que eu gostaria de ver o Discourse ser mais amplamente utilizado por sites de notícias e blogs. Se isso acontecesse, posso imaginar novos proprietários de sites a ficarem frustrados com a funcionalidade de incorporação atual. Aqui está uma ideia para melhorá-la:

Adicionar dois novos atributos opcionais ao modelo EmbeddableHost:

  • target_selector: o seletor CSS externo que contém o conteúdo a ser incorporado
  • exclude_selectors: uma lista de seletores CSS que devem ser excluídos do conteúdo selecionado pelo target_selector.

Um botão “Configurar” deve ser adicionado a cada linha de Host Incorporável na página Admin / Incorporação. Clicar nesse botão abre uma página semelhante à página de E-mails / Resumo de Pré-visualização.

A página Configurar Host teria um formulário com campos para inserir as configurações target_selector e exclude_selectors do host, e um campo de URL que permitiria testar os valores fornecidos contra uma página web específica. O teste essencialmente apenas executaria TopicEmbed.parse_html com os valores target_selector e exclude_selectors fornecidos, e depois exibiria os resultados.


As alterações no código parse_html são fáceis de testar. Aqui está uma abordagem possível. Note que este código é apenas uma prova de conceito:

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

###########################################################################
    # `target_selector` e `exclude_selectors` seriam idealmente encontrados no registro `EmbeddableHost` do domínio
    # estas configurações específicas foram usadas para testar 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
      # fallback para Readability se `target_selector` não estiver definido para o host
      read_doc = Readability::Document.new(html, opts)
    end
    ###########################################################################

Para testar sem criar uma nova classe, aqui está um método básico article_content adicionado à classe TopicEmbed:

  def self.article_content(html, target_selector, exclude_selectors = [])
    doc = Nokogiri::HTML(html)
    # remover comentários e tags de script
    doc.xpath('//comment()').each { |i| i.remove }
    doc.css("script, style").each { |i| i.remove }

    # obter o NodeSet para o target_selector
    # talvez usar Readability como fallback se o conjunto retornado estiver vazio
    selected_nodes = doc.css(target_selector)

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

    # lidar com tamanhos de imagem, pode precisar de melhorias
    selected_nodes.css('img').each do |img|
      img.remove_attribute('width')
      img.remove_attribute('height')
    end

    # apenas para o caso, permitir iframes se sua origem for permitida
    # usar `[data-sanitized="true"]` para evitar que iframes sejam removidos na etapa 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

    # remover nós 'p' e 'div' vazios
    selected_nodes.css('p', 'div').each do |node|
      node.remove if node.content.strip.empty? && !node.at_css('iframe[data-sanitized="true"]')
    end

    # converter os nós para uma string e retornar um objeto com um método `content`
    content = selected_nodes.to_s
    OpenStruct.new(content: content)
  end

Tenho quase certeza de que seria apenas um pouco de ajuste em vários domínios para acertar. Os resultados que tenho obtido para BBS têm sido bons até agora.

O objetivo é criar algo que os proprietários de sites possam entender e configurar facilmente por conta própria. Com esta abordagem, quanto mais específico for o target_selector, mais fácil será configurar os exclude_selectors. Por exemplo, para um site WordPress, se .entry-content fosse selecionado como target_selector, nenhuma configuração adicional seria necessária. Se os proprietários de sites quisessem obter mais do que o HTML básico .entry-content, eles poderiam descobrir como fazer isso na página Configurar Host.

O único problema real que vejo é para hosts com HTML muito inconsistente. Esse caso poderia ser resolvido mantendo o Ruby Readability como um fallback.