No último ano, os podcasts começaram a fazer parte do cotidiano de muitas pessoas. Contando com a entrada de expoentes da chamada grande mídia, o formato tem crescido em popularidade. Com isso, é comum que as pessoas procurem indicações de programas para ouvir, geralmente vindas de amigos ou de alguém cujo trabalho admiram. Sendo assim, não seria legal poder responder à pergunta "E aí, quais podcasts você tem escutado?" dos nossos amigos com um único link?
A maneira mais comum de compartilhar listas de feeds é usando arquivos no padrão OPML (Outline Processor Markup Language). A funcionalidade de exportar e compartilhar o OPML com a lista de podcasts - que grande parte dos aplicativos possui - certamente é suficiente para usuários intermediários de tecnologia. Porém, seria útil que as pessoas pudessem simplesmente visualizar a lista de forma amigável, sem precisar importá-la no seu aplicativo. Para isso, nada melhor que uma simples página web.
Pensando nesse tipo de necessidade, criei um pequeno plugin para Pelican que basicamente lê um arquivo OPML e gera uma lista dos feeds em formato HTML para ser inserida em páginas do site. A abordagem utilizada foi a mais "ingênua" possível. Por enquanto, implementei apenas o suficiente para ler os arquivos gerados pelo Pocket Casts , aplicativo de podcasts que uso atualmente. Optei por não utilizar nenhuma biblioteca pronta para lidar com o formato OPML porque 1) não queria adicionar dependências extras além do Pelican e 2) queria aprender um pouco sobre como lidar com arquivos XML. Para isso, o uso da popular biblioteca lxml foi o caminho escolhido.
Lendo arquivos XML com lxml
A biblioteca lxml pode ser instalada via pip:
$ pip install lxml
Após a instalação, o primeiro passo foi aprender como ler arquivos XML usando o lxml. Para fazer o parse de um arquivo que contém uma estrutura XML, usamos o método parse() o módulo lxml.etree. O método recebe um arquivo (ou objeto file-like) aberto e retorna um objeto do tipo ElementTree. Outra opção é passar diretamente uma string com o caminho do arquivo.
from lxml import etree # opção 1 f = open("arquivo.xml", "r") tree = etree.parse(f) f.close() # opção 2 tree = etree.parse("arquivo.xml")
Uma vez que já temos o nosso ElementTree carregado com a estrutura do XML, precisamos obter o nó inicial (root) para percorrer a estrutura a partir dele. Para isso, vamos usar o método getroot(). No nosso caso específico - arquivos que seguem a especificação OPML - o elemento do XML que nos interessa é o <outline>. Sendo assim, podemos usar o método iter() do elemento inicial para encontrar todas as ocorrências de <outline> que partem dele. Por fim, usamos o método get() para obter o valor dos atributos que nos interessam, que no caso são o text e xmlUrl, e armazená-los em alguma estrutura. No exemplo abaixo, os atributos são armazenados em uma lista de tuplas:
root = tree.getroot() elements = [] for e in root.iter("outline"): text = e.get("text") url = e.get("xmlUrl") elements.append((text, url))
Com os dados em mãos, é possível então montar strings em diferentes formatos de saída.
Criando um plugin para Pelican
Após conseguir a leitura e transformação do OPML, o passo seguinte foi aprender como funciona um plugin do Pelican, para que eu pudesse transformar meu script em algo que pudesse ser usado para formatar automaticamente a página do site.
Um plugin do Pelican consiste em módulo que possui uma função chamada register(). Essa função é responsável por registrar as funções que serão executadas pelo Pelican para executar a lógica do plugin. Isso é feito conectando cada uma delas a signals, que são sinais emitidos pelo Pelican em cada etapa da geração do site. Segue um exemplo retirado da própria documentação do Pelican:
import logging from pelican import signals log = logging.getLogger(__name__) def test(sender): log.debug("%s initialized !!", sender) def register(): signals.initialized.connect(test)
O código completo com os detalhes da implementação está disponível em https://github.com/rodrigoamaral/pelican-opml e contribuições são muito bem vindas!