Pular para o conteúdo
Development

Construindo um backfill de sindicação de blog

Por Victor Da Luz
railsrubymediumdev-logblog-manager

Eu venho construindo um app Rails, o blog-manager, para rastrear e sindicar posts entre o vdaluz.com, o Medium, e o LinkedIn. Depois de deixar a integração com o Medium principal funcionando, esbarrei num problema prático: 72 posts já existiam no Medium, mas meu banco de dados local não sabia nada sobre eles. Tudo estava com medium_status: not_imported. Antes de escrever qualquer código novo de publicação, eu precisava sincronizar o estado local.

O beco sem saída do RSS

Minha primeira tentativa usou o feed RSS em medium.com/feed/@vdaluz. O serviço Medium::PublishedBackfill fazia polling nele e combinava posts por URL ou título. Funcionou, mas só retornava 10 posts. O Medium limita o RSS público a 10 itens. Eu tinha 72.

Indo mais fundo com GraphQL

O Medium tem uma API GraphQL não documentada em medium.com/_/graphql. Sessões logadas podem consultar latestPostsConnection(type: POST_TYPE_PUBLIC), paginada via cursor. Usei uma sessão de navegador já logada no Medium para rodar queries autenticadas e paginar por todos os 72 posts em três requisições (25+25+22).

A resposta me dava o id, title, firstPublishedAt, e previewImage.id de cada post; exatamente o que eu precisava para o backfill.

Combinação de títulos e pegadinhas de Unicode

Combinei posts com registros locais em duas camadas: primeiro por medium_url (posts já vinculados), depois por título normalizado. A segunda camada esbarrou num problema inesperado: o Medium guarda apóstrofos como aspas curvas Unicode (U+2019), enquanto meu frontmatter em markdown usa apóstrofos ASCII retos (U+0027). Títulos como “What’s Next” com aspa curva não combinavam com “What’s Next” com aspa reta.

O fix foi uma função de normalização que converte aspas curvas para retas antes da comparação. Depois disso, 69 dos 72 posts combinaram sem problema. As 3 falhas eram posts bem antigos, com títulos substancialmente diferentes entre as plataformas.

A armadilha do stdin do kamal

Escrevi um script Rails runner para fazer as atualizações e tentei rodá-lo via bin/kamal app exec --reuse "bin/rails runner -" < script.rb. Ele saiu com código 0, levou uns 6 segundos, e não fez absolutamente nada. O script rodou, mas com stdin vazio; o app exec do kamal não encaminha o stdin do shell que chamou para dentro do container.

O fix: scp do script para o host, docker cp para dentro do container, depois docker exec diretamente. Óbvio em retrospecto, chato de descobrir.

Hero images no vdaluz.com

Com hero_image_url preenchido para 69 posts (URLs do CDN do Medium), o próximo passo era colocar essas imagens no site Astro do vdaluz.com. Baixei todas as 82 imagens (72 publicadas + 14 agendadas, menos 4 sobreposições), gerei variantes .webp, adicionei o frontmatter heroImage nos arquivos markdown correspondentes, e atualizei três templates do Astro para renderizá-las: banner em largura total nas páginas de post, thumbnail nos cards de listagem, thumbnail nos cards de leitura relacionada.

O campo heroImage já estava conectado às meta tags de OG. Só não estava sendo renderizado visualmente em lugar nenhum. Foi uma observação de uma linha que virou uma atualização de três templates.

O que está no banco agora

Depois do backfill: 69 posts com medium_status: published, 14 com medium_status: scheduled (raspados da interface do Medium), 2 sem match (divergências antigas de título). O serviço DraftCreator já lê hero_image_url ao montar drafts do Medium, então novos posts vão incluir suas hero images automaticamente assim que essa coluna estiver preenchida.

Leitura relacionada

Você também pode achar útil

Proton

Proton VPN

VPN comercial com filtragem NetShield e interruptor de desligamento automático.

Como parceiro da Proton, ganho com compras qualificadas dos serviços de privacidade e segurança da Proton (Pass, Mail, VPN, Drive).

Saiba mais
RackNerd

RackNerd VPS

Hospedagem VPS econômica para serviços leves que funcionam continuamente.

Como afiliado da RackNerd, ganho com compras qualificadas.

Saiba mais
Airalo

eSIM Airalo

eSIM de dados local para viagens - sem necessidade de trocar um SIM físico.

Este é meu link de indicação da Airalo. Você recebe um desconto no seu primeiro eSIM e eu ganho crédito da Airalo para o meu.

Saiba mais