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.