O módulo Python projetado para baixar arquivos de determinados feeds RSS, especialmente direcionados a podcasts. Não utiliza nenhum tipo de banco de dados, mas requer um arquivo de configuração.
O script deve ser executado periodicamente. Ao iniciar, ele analisa o diretório onde armazenou os arquivos baixados anteriormente. Em seguida, ele compara esses arquivos com aqueles listados no feed RSS, identificando os arquivos ausentes e baixando-os.
Os arquivos pesquisados por padrão são mp3
.
O resultado da utilização do exemplo abaixo, em diretórios vazios, será:
dplocki@ghost-wheel:~$ python -m podcast_downloader
[2024-04-08 21:19:10] Loading configuration (from file: "~/.podcast_downloader_config.json")
[2024-04-08 21:19:15] Checking "The Skeptic Guide"
[2024-04-08 21:19:15] Last downloaded file "<none>"
[2024-04-08 21:19:15] The Skeptic Guide: Downloading file: "https://traffic.libsyn.com/secure/skepticsguide/skepticast2024-04-06.mp3" saved as "skepticast2024-04-06.mp3"
[2024-04-08 21:19:41] Checking "The Real Python Podcast"
[2024-04-08 21:19:41] Last downloaded file "<none>"
[2024-04-08 21:19:41] The Real Python Podcast: Downloading file: "https://chtbl.com/track/92DB94/files.realpython.com/podcasts/RPP_E199_03_Calvin.eef1db4d6679.mp3" saved as "[20240405] rpp_e199_03_calvin.eef1db4d6679.mp3"
[2024-04-08 21:20:04] Finished
O resultado:
dplocki@ghost-wheel:~$ tree podcasts/
podcasts/
├── RealPython
│ └── [20240405] rpp_e199_03_calvin.eef1db4d6679.mp3
└── SGTTU
└── skepticast2024-04-06.mp3
2 directories, 2 files
Instalação do PyPI:
pip install podcast_downloader
O script requer arquivo de configuração para funcionar. Após a instalação, o script pode ser executado como qualquer módulo Python:
python -m podcast_downloader
Também é possível executar o script com determinado arquivo de configuração:
python -m podcast_downloader --config my_config.json
Um exemplo de arquivo de configuração
{
"if_directory_empty" : " download_from_4_days " ,
"podcasts" : [
{
"name" : " The Skeptic Guide " ,
"rss_link" : " https://feed.theskepticsguide.org/feed/rss.aspx " ,
"path" : " ~/podcasts/SGTTU "
},
{
"rss_link" : " https://realpython.com/podcasts/rpp/feed " ,
"path" : " ~/podcasts/RealPython " ,
"file_name_template" : " [%publish_date%] %file_name%.%file_extension% "
}
]
}
Por padrão, o arquivo de configuração é colocado no diretório inicial. O nome do arquivo é: .podcast_downloader_config.json
.
O arquivo de configuração está no formato JSON. A codificação esperada é utf-8.
O caminho para o arquivo de configuração pode ser especificado pelo argumento do script.
O script substitui os valores padrão por aqueles lidos no arquivo de configuração. Eles serão sobrecarregados pelos valores fornecidos na linha de comando.
command line parameters > configuration file > default values
Propriedade | Tipo | Obrigatório? | Padrão | Observação |
---|---|---|---|---|
downloads_limit | número | não | infinidade | |
if_directory_empty | corda | não | download_último | Consulte Em caso de diretório vazio |
podcast_extensions | valor-chave | não | {".mp3": "audio/mpeg"} | Consulte Filtro de tipos de arquivo |
podcasts | subseção | sim | [] | Veja a subcategoria Podcasts |
http_headers | valor-chave | não | {"User-Agent": "podcast-downloader"} | Consulte os cabeçalhos de solicitação HTTP |
fill_up_gaps | booleano | não | falso | Consulte Baixar arquivos de lacunas |
download_delay | número | não | 0 | Consulte Atraso no download |
O segmento podcasts
é a parte do arquivo de configuração onde você fornece a matriz de objetos com o seguinte conteúdo:
Propriedade | Tipo | Obrigatório | Padrão | Observação |
---|---|---|---|---|
name | corda | sim | - | O nome do canal (use no logger) |
rss_link | corda | sim | - | A URL do feed RSS |
path | corda | sim | - | O caminho para o diretório onde os podcasts estão armazenados será baixado |
file_name_template | corda | não | %file_name%.%file_extension% | O modelo para os arquivos baixados, consulte Modelo de nome de arquivo |
disable | booleano | não | false | Este podcast será ignorado |
podcast_extensions | valor-chave | não | {".mp3": "audio/mpeg"} | O filtro de arquivo |
if_directory_empty | corda | não | download_last | Consulte Em caso de diretório vazio |
require_date | booleano | não | false | Obsoleto A data do podcast deve ser adicionada ao nome do arquivo - use o file_name_template : [%publish_date%] %file_name%.%file_extension%" |
http_headers | valor-chave | não | {"User-Agent": "podcast-downloader"} | Consulte os cabeçalhos de solicitação HTTP |
fill_up_gaps | booleano | não | falso | Consulte Baixar arquivos de lacunas |
Alguns servidores podem não gostar de como o urllib se apresenta a eles (o cabeçalho HTTP User-Agent). Isso pode levar a problemas como: urllib.error.HTTPError: HTTP Error 403: Forbidden
. É por isso que existe a possibilidade do script se passar por outra coisa: especificando os cabeçalhos HTTP durante o download dos arquivos.
Use a opção http_headers
no arquivo de configuração. O valor deve ser um objeto de dicionário onde cada cabeçalho é apresentado como um par chave-valor. A chave é o título do cabeçalho e o valor é o valor do cabeçalho.
Por padrão, o valor é: {"User-Agent": "podcast-downloader"}
. Fornecer qualquer outra coisa para http_headers
substituirá todos os valores padrão (eles não são mesclados).
Por outro lado, na subconfiguração do podcast, os http_headers
serão mesclados com os http_headers
globais. Em caso de conflito (mesmo nome de chave), o valor da subconfiguração do podcast substituirá o global.
Exemplo:
{
"http_headers" : {
"User-Agent" : " podcast-downloader "
},
"podcasts" : [
{
"name" : " Unua Podcast " ,
"rss_link" : " http://www.unuapodcast.org/feed.rss " ,
"path" : " ~/podcasts/unua_podcast " ,
"https_headers" : {
"User-Agent" : " Mozilla/5.0 "
}
},
{
"name" : " Dua Podcast " ,
"rss_link" : " http://www.duapodcast.org/feed.rss " ,
"path" : " ~/podcasts/dua_podcast " ,
"https_headers" : {
"Authorization" : " Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ== "
}
}
]
}
Neste exemplo, o Unua Podcast será baixado apenas com o cabeçalho: User-Agent: Mozilla/5.0
, e o Dua Podcast com: User-Agent: podcast-downloader
e Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
.
Quando você tem muitos arquivos para baixar de um único servidor, pode ser melhor configurar um pequeno atraso entre os downloads para evitar ser reconhecido como invasor pelo servidor. No script existe uma opção chamada download_delay
, que representa o número de segundos que o script irá esperar entre os downloads.
O valor padrão é 0
.
Notas:
O script aceita os seguintes argumentos de linha de comando:
Versão curta | Nome longo | Parâmetro | Padrão | Observação |
---|---|---|---|---|
--config | corda | ~/.podcast_downloader_config.json | A colocação do arquivo de configuração | |
--downloads_limit | número | infinidade | O número máximo de arquivos mp3 baixados | |
--if_directory_empty | corda | download_last | A abordagem geral no diretório vazio | |
--download_delay | número | 0 | O tempo de espera (segundos) entre downloads |
Use para ajustar o nome do arquivo após o download.
O valor padrão ( %file_name%.%file_extension%
) simplesmente salvará o arquivo conforme foi carregado pelo criador original. O nome do arquivo e sua extensão são baseados no link para o arquivo de podcast.
Valores do modelo:
Nome | Notas |
---|---|
%file_name% | O nome do arquivo do link, sem extensão |
%file_extension% | A extensão do arquivo, do link |
%publish_date% | A data de publicação da entrada RSS |
%title% | O título da entrada RSS |
O %publish_date%
por padrão fornece o resultado no formato YEARMMDD
. Para alterá-lo você pode fornecer o novo após os dois pontos ( :
caractere:). O script respeita os códigos do padrão C de 1989, mas o sinal de porcentagem ( %
) deve ser substituído pelo cifrão ( $
). Isso se deve à minha infeliz decisão de usar o caractere percentual como marcador do código.
O código padrão | O código do script | Notas |
---|---|---|
%Y%m%d | $Y$m$d | O valor padrão de %publish_date% |
%A | $A | Adiciona o dia da semana (configurações de idioma local) |
%x | $x | A data local representa. Atenção : em algumas configurações, o / é usado aqui, então pode causar problemas no nome do arquivo |
[%publish_date%] %file_name%.%file_extension%
[%publish_date%] %title%.%file_extension%
Os podcasts são armazenados principalmente como arquivos *.mp3
. Por padrão, o Podcast Downloader procura apenas por eles, ignorando todos os outros tipos.
Se o seu podcast suportar outros tipos de arquivos de mídia, você poderá especificar os filtros de arquivo. Forneça a extensão do arquivo (como .mp3
) e o tipo de link no próprio feed RSS (para mp3
é audio/mpeg
).
Se você não sabe o tipo do arquivo, pode procurá-lo no arquivo RSS. Procure por tags enclosure
, deve ficar assim:
< enclosure url = " https://www.vidocast.url/podcast/episode23.m4a "
length = " 14527149 "
type = " audio/x-m4a " />
Nota : o ponto na extensão do arquivo é obrigatório.
"podcast_extensions" : {
".mp3" : " audio/mpeg " ,
".m4a" : " audio/x-m4a "
}
Se um diretório de podcast estiver vazio, o script precisa saber o que fazer. Devido à falta de banco de dados, você pode:
O comportamento padrão é: download_last
O script baixará todos os episódios do feed.
Definido por download_all_from_feed
.
O script baixará apenas o último episódio do feed. Também é a abordagem padrão do script.
Definido por download_last
.
O script baixará exatamente o número determinado de episódios do feed.
Definido por download_last_n_episodes
. O n deve ser substituído por um número de episódios que você deseja baixar. Por exemplo: download_last_5_episodes
significa que os cinco episódios mais recentes serão baixados.
O script baixará todos os episódios que apareceram nos últimos n dias. Ele pode ser usado quando você estiver baixando regularmente. O número n é fornecido no valor de configuração: download_from_n_days
. Por exemplo: download_from_3_days
significa baixar todos os episódios dos últimos 3 dias.
O script irá baixar todos os episódios que aparecem após o dia do lançamento do último episódio.
O número n é o dia do episódio normal. Você pode fornecer aqui os dias da semana como palavra (o tamanho das letras é ignorado)
Dia de semana inteiro | Encurtar nome |
---|---|
Segunda-feira | seg |
Terça-feira | Terça-feira |
Quarta-feira | Quarta |
Quinta-feira | Quinta |
Sexta-feira | sex |
Sábado | Sentado |
Domingo | Sol |
Você pode fornecer o número, isso significará o dia do mês. O script aceita apenas números de 1 a 28.
Definido por download_from_
.
Exemplos:
Valor de exemplo | Significado |
---|---|
download_from_monday | Novos episódios aparecem na segunda-feira. O script irá baixar todos os episódios desde a última terça-feira (incluindo ele) |
download_from_Fri | Novos episódios aparecem na sexta-feira. O roteiro irá baixar todos os episódios desde o último sábado (incluindo ele) |
download_from_12 | Novos episódios aparecem a cada 12 dias do mês. O script irá baixar todos os episódios desde 13 meses antes |
Depois de estabelecer o arquivo totem, o script pode usá-lo para armazenar a data de sua última execução. Então, com base nesta data, o roteiro fará o download de todos os novos episódios que surgiram desde então.
Definido por download_since_last_run
. Requer estabelecer o arquivo de armazenamento por last_run_mark_file_path
.
{
"last_run_mark_file_path" : " ~/.totem.json " ,
"podcasts" : [
{
"name" : " The Skeptic Guide " ,
"rss_link" : " https://feed.theskepticsguide.org/feed/rss.aspx " ,
"path" : " ~/podcasts/SGTTU "
}
]
}
O script está lendo a data da última modificação do arquivo. A data de modificação do arquivo é atualizada pelo script.
O script reconhece o fluxo de arquivos baixados (com base nos dados do feed). Por padrão, o último arquivo baixado (de acordo com o feed) marca o início do download. Em caso de lacunas, situação em que faltam arquivos antes do último baixado, o script irá ignorá-los por padrão. Porém, existe a possibilidade de alterar esse comportamento para baixar todos os arquivos ausentes entre os já baixados. Para habilitar isso, você precisa definir o valor fill_up_gaps
como true . É importante ressaltar que o script não irá baixar arquivos antes do primeiro (de acordo com o feed), o episódio mais anterior.
Valor padrão: false
.
O script examina todos os nós de items
no arquivo RSS. O nó item
pode conter o nó enclosure
. Esses nós são usados para passar os arquivos. De acordo com a convenção, o item
único deve conter apenas um enclosure
, mas o script (como a biblioteca usada nele) pode lidar com vários arquivos anexados ao item
de podcast.
Os arquivos OPML podem ser convertidos em configuração. O arquivo de saída precisa ser ajustado (faltando o path
).
import json
import sys
import xml . etree . ElementTree as ET
def build_podcast ( node_rss ):
return {
"name" : node_rss . attrib [ "title" ],
"rss_link" : node_rss . attrib [ "xmlUrl" ],
"path" : "" ,
}
tree = ET . parse ( sys . argv [ 1 ])
podcasts = list ( map ( build_podcast , tree . findall ( "body/outline[@type='rss']" )))
result = json . dumps ({ "podcasts" : podcasts }, sort_keys = True , indent = 4 )
print ( result )
Exemplo de uso (depois de salvá-lo como opml_converter.py
):
python opml_converter.py example.opml > podcast_downloader_config.json