朋友推薦可以將 TTS 語音下載為 mp3 檔案,而且授權很開放的網站 FreeTTS:
雖然沒有中文的,但是用來下載英文的語音也不錯。進入網站後,在輸入區輸入想讓它合成語音的文字,並選取想用的聲音,最後再按 [Convert to Mp3] 的按鈕,即可播放聲音,或是下載 MP3 檔案。
研究了 FreeTTS 下載的流程,大概可以分為三個部份:
- 填表單取得文字與設定內容。
- 由語音合成主機合成語音,並回傳一個帶有 MP3 檔案相關資料的 JSON 格式設定檔。
- 由 JSON 檔中解析出 MP3 檔案的 id ,並組合成聲音檔的網址,供播放或是下載。
FreeTTS 合成完語音檔以後,會回傳的 JSON 檔內容大概長這樣:
{"msg":"True","id":"7ef38234-5965-4b5a-9c98-45e7a39b87c5.mp3","counts":5055}
關鍵在 "id" ,它就是存放在主機上的 MP3 檔檔名。
所以想下載 FreeTTS 的 MP3 檔案必須下載兩次檔案,還要能解析第一次下載回來 JSON 檔中的 id,供第二次下載真正的 MP3 檔案。
查了一下,我常用來下載檔案的 wget 或是 curl 可以解析網頁中的連結,似乎沒有解析 JSON 檔案,並重組網址的功能。通常「卡關」了,總能得看新的東西;找方法的過程中,看到了一個叫「jq」的小工具:
它不但小巧,而且也跨平臺;和 wget / curl 搭配,各司其職,還滿好用的。
jq 的功能不少,不過我只要能由 JSON 中找出 id 的值(MP3的檔名),並在前面加上主機的網址即可。如果由 stdin 讀入資料,就是底下的語法:
jq -r "\"https://freetts.com/audio/\"+.id"
找 JSON 中的 id 用了「.id」;使用了 -r 的參數,將字串頭尾的引號去掉,並利用加號來合成檔案的下載網址。要注意的是,在引號中使用引號,得加上反斜線。
wget 中則使用了以下的參數:
- -nv : 不顯示訊息,主要是用在第一次抓到的 JSON 檔內容要直接輸出到 stdout,所以不容許有其它文字。
- -c : 遇到錯誤仍繼續
- -O : 指定輸出到哪裡,第一次用「-O - 」讓它輸出到 stdout,輸出結果(JSON檔)給 jq;第二次輸出到指定檔名的檔案。
- -i : 指定由哪裡取得網址,應用在第二次,用「-i - 」,由 stdin 取得 jq 重組後的 mp3 下載網址。
例如我想下載「just a test」的 TTS MP3 檔案,如果 wget 和 jq 都放在路徑中了,就用這一行指令:
wget -nv -c -O - "https://freetts.com/Home/PlayAudio?Language=en-US&Voice=Joey_Male&id=Joey&type=1&TextMessage=this is a test" | jq -r "\"https://freetts.com/audio/\"+.id" | wget -i - -O "this is a test.mp3"
利用這個方法,再結合批次檔的指令,就可以進行批次下載語音檔囉!
底下是我在 Windows 7 的實驗的批次檔內容:
@ECHO OFF
SetLocal EnableExtensions EnableDelayedExpansion
REM wget 程式的路徑設定
set wgetPath=wget
REM jq 程式的路徑設定
set jqPath=jq-win64
REM FreeTTS 聲音參數
set ttsLanguage=en-US
set ttsVoice=Joey_Male
set ttsId=Joey
REM 單字的欄位分隔符號
set seperator=##
REM 檢查是否有參數, 沒有就提示並結束
if %1test==test goto error
if %2test==test goto errorREM 抓第2個參數為 mp3 輸出資料夾
set outputFolderName=%2REM 建新的資料夾以存放處理好的檔案
mkdir %outputFolderName%set wgetWait=--wait 3 --random-wait
REM 計數器,用來判斷是否要暫停久一點
set /a x=0REM 抓取第1個參數的文字檔,一行行套到網址及輸出的檔名中
FOR /F "delims=%seperator%" %%w IN (%1) DO (
if not %%wtest==test ( %wgetPath% -nv -c %wgetWait% -O - "https://freetts.com/Home/PlayAudio?Language=%ttsLanguage%&Voice=%ttsVoice%&id=%ttsId%&type=1&TextMessage=%%w" | %jqPath% -r "\"https://freetts.com/audio/\"+.id" | %wgetPath% %wgetWait% -i - -O "%outputFolderName%\%%w.mp3"
REM 暫停一下下再抓下一個檔案, 每5次就要特別再停10秒
if !x! lss 5 (
rem set /a r=%random% %%4+1
set /a r=(!random! * 4 / 32768^) + 1
set /a x=!x!+1
) else (
set /a x=0
set /a r=10
)
REM echo !x!
timeout /t !r!
)
)
@echo ON
@echo.
@echo check %outputFolderName%
@echo.
@echo OFF
goto end
:error
@echo ON
@echo.
@echo 語法:
@echo.
@echo %0 英文單字清單檔 MP3儲存資料夾名稱
@echo.
:end
使用的方法,將 wget、jq和批次檔 (假設檔名為 free_tts_mp3_dl.bat) 放在一起,或是可自動搜尋的路徑中;把要下載的英文,一行一個的格式存入純文字檔(ex. list.txt),然後執行:
free_tts_mp3_dl.bat list.txt mp3
如果成功,MP3 檔案應該會儲存到名稱為 mp3 的資料夾中。
因為 FreeTTS 有防「濫用」的機置,所以批次檔中,故意使用亂數決定程序暫停的秒數,而且每五次再多延長暫停的時間。目前的程序運作算還不錯。
在本篇筆記記錄前,其實在 Google Colab 中已經先用 Python 寫了支小工具,可以進行批次下載了,他日再寫記錄囉!
沒有留言:
張貼留言