Python 模組設計用於從給定的 RSS 來源下載文件,特別針對播客。它不使用任何類型的資料庫,但需要設定檔。
該腳本旨在定期運行。啟動後,它會分析先前儲存下載檔案的目錄。然後,它將這些檔案與 RSS 來源中列出的檔案進行比較,識別任何遺失的檔案並下載它們。
預設搜尋的檔案是mp3
。
在空目錄上使用下面的範例的結果將是:
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 ""
[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 ""
[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
結果:
dplocki@ghost-wheel:~$ tree podcasts/
podcasts/
├── RealPython
│ └── [20240405] rpp_e199_03_calvin.eef1db4d6679.mp3
└── SGTTU
└── skepticast2024-04-06.mp3
2 directories, 2 files
從 PyPI 安裝:
pip install podcast_downloader
該腳本需要配置檔案才能運作。安裝後,該腳本可以作為任何 Python 模組運行:
python -m podcast_downloader
也可以使用給定的設定檔運行腳本:
python -m podcast_downloader --config my_config.json
設定檔範例
{
"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% "
}
]
}
預設情況下,設定檔放置在主目錄中。它的檔名是: .podcast_downloader_config.json
。
設定檔的格式為 JSON。預期編碼為 utf-8。
設定檔的路徑可以透過腳本參數指定。
該腳本用從設定檔中讀取的值替換預設值。這些將因命令列給出的值而過載。
command line parameters > configuration file > default values
財產 | 類型 | 必需的? | 預設 | 筆記 |
---|---|---|---|---|
downloads_limit | 數位 | 不 | 無窮大 | |
if_directory_empty | 細繩 | 不 | 最後下載 | 請參閱如果目錄為空 |
podcast_extensions | 鍵值對 | 不 | {".mp3": "audio/mpeg"} | 請參閱文件類型過濾器 |
podcasts | 小節 | 是的 | [] | 請參閱播客子類別 |
http_headers | 鍵值對 | 不 | {"User-Agent": "podcast-downloader"} | 請參閱 HTTP 請求標頭 |
fill_up_gaps | 布林值 | 不 | 錯誤的 | 請參閱從間隙下載文件 |
download_delay | 數位 | 不 | 0 | 請參閱下載延遲 |
podcasts
段是設定檔的一部分,您可以在其中提供具有以下內容的物件陣列:
財產 | 類型 | 必需的 | 預設 | 筆記 |
---|---|---|---|---|
name | 細繩 | 是的 | - | 通道名稱(在記錄器中使用) |
rss_link | 細繩 | 是的 | - | RSS 來源的 URL |
path | 細繩 | 是的 | - | 將下載儲存播客的目錄路徑 |
file_name_template | 細繩 | 不 | %file_name%.%file_extension% | 下載檔案的模板,請參考檔案名稱模板 |
disable | 布林值 | 不 | false | 該播客將被忽略 |
podcast_extensions | 鍵值對 | 不 | {".mp3": "audio/mpeg"} | 文件過濾器 |
if_directory_empty | 細繩 | 不 | download_last | 請參閱如果目錄為空 |
require_date | 布林值 | 不 | false | 已棄用播客的日期應加到檔案名稱 - 使用file_name_template : [%publish_date%] %file_name%.%file_extension%" |
http_headers | 鍵值對 | 不 | {"User-Agent": "podcast-downloader"} | 請參閱 HTTP 請求標頭 |
fill_up_gaps | 布林值 | 不 | 錯誤的 | 請參閱從間隙下載文件 |
有些伺服器可能不喜歡 urllib 呈現給它們的方式(HTTP User-Agent 標頭)。這可能會導致以下問題: urllib.error.HTTPError: HTTP Error 403: Forbidden
。這就是為什麼腳本有可能偽裝成其他東西:透過在下載檔案期間指定 HTTP 標頭。
使用設定檔中的http_headers
選項。該值應該是一個字典對象,其中每個標頭都以鍵值對的形式呈現。鍵是標題標題,值是標題值。
預設情況下,該值為: {"User-Agent": "podcast-downloader"}
。為http_headers
提供任何其他內容將覆蓋所有預設值(它們不會合併)。
另一方面,在播客子配置中, http_headers
將與全域http_headers
合併。如果發生衝突(相同的鍵名),播客子配置中的值將覆寫全域值。
例子:
{
"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== "
}
}
]
}
在此範例中,Unua Podcast 將僅使用標題下載: User-Agent: Mozilla/5.0
,而 Dua Podcast 將僅使用標題下載: User-Agent: podcast-downloader
和Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
。
當您要從單一伺服器下載大量檔案時,最好在下載之間設定較小的延遲,以避免被伺服器識別為攻擊者。腳本中有一個名為download_delay
的選項,它表示腳本在下載之間等待的秒數。
預設值為0
。
筆記:
此腳本接受以下命令列參數:
短版 | 長名字 | 範圍 | 預設 | 筆記 |
---|---|---|---|---|
--config | 細繩 | ~/.podcast_downloader_config.json | 設定檔的放置 | |
--downloads_limit | 數位 | 無窮大 | 最大下載mp3檔案數 | |
--if_directory_empty | 細繩 | download_last | 空目錄的一般方法 | |
--download_delay | 數位 | 0 | 下載之間的等待時間(秒) |
下載後用於調整檔案名稱。
預設值( %file_name%.%file_extension%
)將簡單地儲存原始建立者上傳的檔案。檔案名稱及其副檔名是基於播客檔案的連結。
模板值:
姓名 | 筆記 |
---|---|
%file_name% | 連結中的檔名,不含副檔名 |
%file_extension% | 文件的擴展名,來自鏈接 |
%publish_date% | RSS 條目的發布日期 |
%title% | RSS 條目的標題 |
預設情況下, %publish_date%
給出的結果格式為YEARMMDD
。為了更改它,您可以在冒號( :
字元)後提供新的。腳本遵循 1989 C 標準的程式碼,但百分號 ( %
) 必須替換為美元符號 ( $
)。這是因為我不幸決定使用百分比字元作為代碼的標記。
標準代碼 | 腳本程式碼 | 筆記 |
---|---|---|
%Y%m%d | $Y$m$d | %publish_date% 的預設值 |
%A | $A | 新增工作日(本地語言設定) |
%x | $x | 當地日期代表。警告:在某些設定中,此處使用了/ ,因此可能會導致檔案名稱出現問題 |
[%publish_date%] %file_name%.%file_extension%
[%publish_date%] %title%.%file_extension%
播客大多儲存為*.mp3
檔。預設情況下,播客下載器僅會尋找它們,忽略所有其他類型。
如果您的播客支援其他類型的媒體文件,您可以指定文件過濾器。提供檔案的副檔名(如.mp3
)和 RSS 提要本身的連結類型(對於mp3
為audio/mpeg
)。
如果您不知道文件的類型,可以在 RSS 文件中找到。尋找enclosure
標籤,應該如下圖所示:
< enclosure url = " https://www.vidocast.url/podcast/episode23.m4a " length = " 14527149 " type = " audio/x-m4a " />
注意:檔案副檔名上的點是必需的。
"podcast_extensions" : {
".mp3" : " audio/mpeg " ,
".m4a" : " audio/x-m4a "
}
如果播客目錄為空,腳本需要知道要做什麼。由於缺乏資料庫,您可以:
預設行為是: download_last
該腳本將從提要中下載所有劇集。
由download_all_from_feed
設定。
該腳本將僅從提要中下載最後一集。這也是腳本的預設方法。
由download_last
設定。
該腳本將從提要中準確下載給定數量的劇集。
由download_last_n_episodes
設定。 n必須替換為您想要下載的集數。例如: download_last_5_episodes
表示將下載最近的五集。
腳本將下載最近n天出現的所有劇集。當您定期下載時可以使用它。 n數字在設定值中給出: download_from_n_days
。例如: download_from_3_days
表示下載最近 3 天的所有集數。
該腳本將下載最後一集發布之日之後出現的所有劇集。
n數字是正常發作的日期。您可以在此處以單字形式提供工作日(忽略字母大小)
全週一天 | 縮短名字 |
---|---|
週一 | 週一 |
週二 | 週二 |
週三 | 星期三 |
週四 | 週四 |
星期五 | 週五 |
週六 | 星期六 |
星期日 | 太陽 |
您可以提供數字,它表示該月的日期。該腳本僅接受 1 到 28 之間的數字。
由download_from_
設定。
範例:
範例值 | 意義 |
---|---|
download_from_monday | 新劇集將於週一播出。該腳本將下載自上週二以來的所有劇集(包括它) |
download_from_Fri | 新劇集將於週五播出。該腳本將下載自上週六以來的所有劇集(包括它) |
download_from_12 | 新劇集每月 12 日出現。該腳本將下載 13 個月前的所有劇集 |
一旦建立了圖騰文件,腳本就可以使用它來儲存上次運行的日期。然後,根據該日期,腳本將下載此後出現的所有新劇集。
由download_since_last_run
設定。需要透過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 "
}
]
}
該腳本正在讀取檔案的上次修改日期。文件的修改日期由腳本更新。
此腳本識別下載檔案的串流(基於提要資料)。預設情況下,最後下載的檔案(根據提要)標誌著下載的開始。如果出現間隙,即上次下載的檔案之前遺失檔案的情況,腳本將預設忽略它們。但是,可以變更此行為以下載已下載檔案之間的所有遺失檔案。若要啟用此功能,您需要將fill_up_gaps
值設為true 。需要注意的是,腳本不會下載第一集(根據提要)(即最早的劇集)之前的文件。
預設值: false
。
該腳本查看 RSS 檔案中的所有items
節點。 item
節點可以包含enclosure
節點。這些節點用於傳遞檔案。根據慣例,單一item
應僅包含一個enclosure
,但腳本(作為其下使用的庫)可以處理附加到播客item
多個文件。
OPML 檔案可以轉換為設定。輸出檔案需要調整(缺少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 )
使用範例(將其儲存為opml_converter.py
後):
python opml_converter.py example.opml > podcast_downloader_config.json