用關鍵字「facebook share debug」找到 FB 的「分享偵錯工具」,我找到的網址如下:
連進去以後,在「偵錯」那欄的輸入區,貼上要修正的分享網址;然後按「偵錯」的按鈕。
在「抓取時間」那欄位,按「再次抓取」的按鈕,這樣子 FB 會重新抓取,並更新它的內容。
回到 FB 自己分享的那則中,按「編輯」,應該會出現新的縮圖,將文章重新儲存,即可完成更新囉!
生活、教學、電腦、啦哩啦雜......
用關鍵字「facebook share debug」找到 FB 的「分享偵錯工具」,我找到的網址如下:
連進去以後,在「偵錯」那欄的輸入區,貼上要修正的分享網址;然後按「偵錯」的按鈕。
在「抓取時間」那欄位,按「再次抓取」的按鈕,這樣子 FB 會重新抓取,並更新它的內容。
回到 FB 自己分享的那則中,按「編輯」,應該會出現新的縮圖,將文章重新儲存,即可完成更新囉!
「量詞大考驗」是我在2010年5月左右以 Flash 寫小程式,當時曾在噗浪上和噗友分享與討論,沒幫它寫過詳細的介紹文,只在自己網站的 Flash 作品集「雄之語文高手」頁面有了底下簡單的描述:
一隻、一枝、一打......這些量詞你知道怎麼用嗎?挑戰一下你對量詞的瞭解程度。遊戲的題庫可以自行擴充的,目前的題庫的來源主要是由雄老師將之前王文裕老師設計的"喜從天降”CAI 中的題庫轉換而來。
沒文章記錄,原本已經忘了是在什麼時候將 Flash 版的量詞大考驗改為 HTML5 版了,幸好在程式的一角有留下了 2012.11.28 的戳記,應該就是那日發布的吧?
最近重新檢視了自己的 HTML5 FUN 作品中,哪些可以使用HTML5 FUN 語音外掛,才發現 HTML5 Bubble 量詞大考驗很久沒維護了,於是幫它加上了音效,也把可自訂的題庫設定,改得更有彈性一點,順便補上這篇說明。
HTML5 版的量詞大考驗可以 HTML5 FUN 的網站中玩,或是下載回來,改成使用自訂的題庫:
![]() |
HTML5 FUN 量詞大考驗 |
HTML5 量詞大考驗主要是針對量詞的練習來設計,所以題庫中主要分為「量詞」、「名詞」和「說明」,而「名詞」的部份有對的跟錯的選項,所以每一個題組中共有四個部份;出題時,再由程式在量詞前面加上數詞組合成多選題的題目。
底下稍微介紹一下它的功能特色:
HTML5 量詞大考驗可以將題庫換成自訂的題目,第一個步驟是先到 HTML5 FUN 的網站中,將打包好的 html5_bubble.zip 壓縮檔下載回來,將它解壓縮以後,應該會有一個名為「html5_bubble」的資料夾,裡面跟自訂遊戲的相關的設定檔檔案如下所示:
上面的設定檔,都可以使用純文字編輯器(例如 Windows 上可使用 Notepad++ 、記事本......) 來開啟並修改。
由 HTML5 FUN 網站下載回來的 HTML5 量詞大考驗中,預設使用的選單設定檔,檔名是「bubble_menu_set.js」。
選單設定檔主要的用途是讓程式知道要在畫面上呈現的標題及選單項目名稱;以及當選單項目被按下去以後,要載入哪一個題庫設定檔。所以它的設定項目不多。
![]() |
[圖1] HTML5 量詞大考驗選單畫面及設定的對應 |
選單設定檔中可自訂的參數如下:
以 [圖1] 中的選單設定來說,當我們按下「量詞找名詞生手級」的選項以後,程式會到資料夾「data」(datafolder 指定的)中,找到「b01-1.js」這個題庫檔案,並載入題庫。
由 HTML5 FUN 網站下載回來的 HTML5 量詞大考驗壓縮檔解壓縮後,有一個名稱為「data」的資料夾,裡面有六個範例題庫設定檔。以純文字編輯器開啟以後,即可修改為自己的題庫。
題庫設定檔中,能夠自訂的參數如下:
在題庫設定檔中,最重要的是 question_lines ,它是題目的來源,格式很簡單:
以 data 資料夾中的題庫設定檔 b01-1.js 來說,它的分隔符號、題目類型及數字列表設定值為:
question_O_X_seperator = ";";
options_seperator = ",";
question_type = 1;
question_number_string = "一,兩,三,四";
以題庫設定參數 question_lins 中的這一行為例:
頭;牛,山羊;馬,黑狗,猴子,鳥;計算牛、羊的單位。
和遊戲畫面對照的結果:
![]() |
[圖2] HTML5 量詞大考驗題庫與畫面對照圖 |
「;」分號為欄位分隔符號(question_O_X_seperator),題目中有三個「;」分號,將這個題組切為四部份:
「,」逗號為多選項的分隔符號,將正確答案切為兩個:
「,」逗號為多選項的分隔符號,將錯的選項切為五個:
因為題目的類型(question_type)是設為「1」,[圖2] 中,飛鳥所拉的紅布條上有「四頭」,數字「四」是由「question_number_string」的設定值中,以亂數隨機取出來的,它和題組中的題幹欄位(左起第一欄)的「頭」合在一起,就變成「四頭」了。
當玩家選錯選項時,就會如 [圖2] 中,跳出解說的對話框,解說的文字是在題組設定中的第四個欄位,本題組是「計算牛、羊的單位。」。
以上的資訊在製作自己的自訂題庫檔案時,可供參考。
HTML5 量詞大考驗在瀏覽器有支援語音功能下,會自動載入語音外掛(畫面左下角有 MIC 的藍色啟動按鈕)。玩的時候,按一下藍色 MIC 鈕,變成紅色的,就可以用麥克風來說答案,程式辨識成功,並發現進行中的選項有該文字,就會幫忙觸發按按鈕的動作。
另外,畫面上的「繼續挑戰」、「開始挑戰」的按鈕,可以用語音來「按」。
2006年設計的 Flash 版詞語大挑戰在2012年初改寫為「Flash : Monster 詞語大挑戰」,年底又新增了 HTML5 版,讓它可以 iOS 中使用。
不過,一直沒把 HTML5 版的參數說明整理記錄,最近將題庫的格式改得更有彈性一點,也盡量讓它和 HTML5 FUN 中的其它程式類似;都快十年過去了,順便將 HTML5 版的說明完成。
Monster 詞語大挑戰可以在 HTML5 FUN 的網站中直接玩範例題庫;如果想自訂題庫,也提供下載程式及範例。
直接玩:
![]() |
HTML5 FUN::Monster |
HTML5 FUN :: Monster 範例題庫是語詞填空的多選題,畫面下方會出現句子(題幹去掉填空的部份),上方則會顯示候選的詞語(正確跟錯誤的選項):
![]() |
HTML5 FUN Moster 的畫面 |
按下選項後,如果答對會加分,答錯則會有爆炸的音效。全部的正確答案都選完了,即可進入下一關(題)。雖然名稱是「 Monster 『詞語』大挑戰」,如果把題目換成數學式,也是可以哦!
簡單的說明一下功能特色:
HTML5 FUN 「Monster 詞語大挑戰」除了可以直接玩範例題庫,也可以將自己的題庫加入遊戲中;遊戲選單也可以自己修改項目名稱,及要載入的題庫設定檔。
如果想自訂題庫,第一個步驟是先到 HTML5 FUN 網站中,下載「Monster 詞語大挑戰」的壓縮檔,並解壓縮。接著就可以參考底下的參數說明,用文字編輯工具開啟相關的檔案來自訂選單,或是題庫。
先來看看「Monster 詞語大挑戰」的啟動程序:
下載「Monster 詞語大挑戰」,並解壓縮好的 html5_monster 資料夾中,應該可以找到一個檔名為「monster_menu_set.js」的檔案,這個檔案就是「Monster 詞語大挑戰」的選單設定檔。我們可以用純文字編輯工具(例如 Notepad++ 或是 Windows 的記事本)來開啟。
monster_menu_set.js 的範例檔中有底下的內容:
menu_title='詞語大挑戰';
menu_items = new Array(
"心緒類語詞:初級篇,monster_set_basic.js"
, "心緒類語詞:高級篇,monster_set_advance.js"
);
選單設定檔內容,對照「Monster 詞語大挑戰」的選單畫面如下圖所示:
![]() |
HTML5 Monster 選單設定與選單對照圖 |
設定檔中只使用到兩個參數:
「項目名稱」「逗號」「題庫檔檔名」
所以當使用者按下選單中的「心緒類語詞:初級篇」,程式就會試著去載入「monster_set_basic.js」這個題庫設定檔,載入成功,就可以開始玩。
前面提到,我們在 monster_menu_set.js 的選單設定中,指定按哪一個選項,讓程式去載入哪個題庫設定檔。範例中,按「心緒類語詞:初級篇」,程式就會試著去載入「monster_set_basic.js」這個題庫設定檔;我們可以利用純文字編輯工具開啟「monster_set_basic.js」,來編輯它的內容。底下來看看可以自訂哪些參數。
其中最重要的是 question_lines ,它是題目的來源,格式很簡單:
假設分隔符號及填空設定值為:
question_O_X_seperator = "##";
options_seperator = ",";
blank_pattern = "◎";
blank_replacement = "( )";
![]() |
HTML5 FUN Monster 題庫格式 |
解說一下「 question_lines 」中的這一行:
他的惡作劇,讓大家◎。##很難過,很不高興,很生氣,很討厭,受不了,發火,發狂##開心,佩服,喜歡,喜愛,感動
我們可以看到有兩個欄位分隔符號「##」,將這個題組切為三部份:
題幹的部份,「◎」會被程式用「( )」置換掉,變成:
他的惡作劇,讓大家( )。
確答案會再用選項的分隔符號「,」,切為七個:
而錯的選項也會再用選項的分隔符號「,」,切為五個:
參考上面題庫的格式,您就可以設計自己的的 HTML5 Monster 囉!
HTML5 Monster 在瀏覽器有支援語音功能下,會自動載入語音外掛(畫面左下角有 MIC 的藍色啟動按鈕)。玩的時候,按一下藍色 MIC 鈕,變成紅色的,就可以用麥克風來說答案,程式辨識成功,並發現進行中的選項有該文字,就會幫忙觸發按按鈕的動作。
另外,畫面上的「回主選單」、「重新挑戰」可以用語音來「按」。
2021年6月為了讓學生在遠距課時,仍然可以享受到自己戳「戳戳樂」的樂趣,所以寫了「雄: HTML5 : remoteClick 網路遙控器」,它算是一個 HTML5 戳戳樂的「外掛」,對戳戳樂的程式來說,不過是知道有人按了按鈕,其它的動作,仍然維持原來的程序在運作。
使用「remoteClick」有個小缺點,如果學生使用的是平板或是手機,要操作遙控器,就必須切換到「remoteClick」,這樣就看不到遠端戳戳樂的畫面。剛好最近在研究 HTML5 FUN 中,有哪些程式可以使用「雄 : HTML5 FUN : 語音輸入外掛」,就針對戳戳樂,調整了語音外掛的一些程序及優化。
![]() |
[圖1] 有語音外掛的戳戳樂 |
HTML5 FUN 的語音外掛應用在戳戳樂的流程大概是這樣子:
![]() |
[圖2] 按下藍色MIC按鈕啟動語音辨識 |
![]() |
[圖3] MIC 按鈕變紅色、左上角編號由1開始 |
![]() |
[圖4] 喊「9號」就可以戳9號那格 |
![]() |
[圖5] 9號那格被按下了 |
這樣的運作方式,如果是線上課程,主控端(老師)只要能讓電腦的麥克風,能收到學生的聲音,即可進行語音辨識,讓遠端學生也能用自己的聲音下指令「遙控」戳戳樂。
底下是使用麥克風玩戳戳樂的一小段影片:
要啟動戳戳樂的語音外掛,只要開啟有載入 HTML5 FUN 語音外掛的網頁即可,如果要直接使用 HTML5 FUN 網站中的,可以視指令的語言需求,按底下其中一個網址:
如果下載了最新的 HTML5 戳戳樂 .zip 壓縮檔,解壓縮以後,在 html5_poke 的資料夾中,找到這個網頁檔案:
html5_poke_speech.html
![]() |
[圖6] 由「html5_poke_speech.html」載入戳戳樂語音外掛 |
用 Chrome 、Edge 或是其它有支援語音辨識功能瀏覽器來開啟 html5_poke_speech.html ,即可自動載入 HTML5 FUN 的語音外掛。
使用 HTML5 戳戳樂的語音外掛時,它可以處理哪些語音辨識結果呢?
應用在等候戳格子的畫面時,可以使用中文,或是英文語音指令:
XX 為格子左上角的編號,偵測到,外掛會幫忙「按」指定的格子。
![]() |
[圖7] 內容對話框也可以使用語音關閉 |
如果是戳完格子,畫面是停在呈現內容的對話框時 [圖7],可以使用底下的語音指令:
當程式偵測到以上的語音指令,它會幫忙「按 Enter 鍵」,等同於按下對話框的「確定」鈕,可以關閉對話框,等待戳下一個格子。
戳戳樂原始的設計,格子的編號是由最左上角那格的 0 號開始,依序加一,因為英文的 zero 在這裡的應用,不太容易辨識成功,所以操作時,建議以下的程序:
![]() |
[圖8] 出現格子後再按 MIC 鈕 |
這樣的好處是:
前幾天看到朋友線上課程中,讓學生玩 HTML5 FUN 的「Monster 語詞大挑戰」,突然想到 2021年六月做了一個小實驗,幫 HTML5 Bingo 遊戲寫了一個語音輸入答案的外掛,利用語音辨識,將麥克風的收到的聲音辨識出文字以後,去比對遊戲答案選項鈕上的文字,如果找到一樣的,就觸發按按鈕的相關程序,摸擬人直接用滑鼠或是手指觸碰按鈕的動作。
利用這個外掛,如果上遠距課時,只要麥克風能收到遠端學生的聲音,學生就能直接用說的,來按老師電腦畫面中的遊戲按鈕;這跟老師聽到後,幫忙按答案來比較,能自己用語音控制,應該可以多幾分樂趣。
重新檢視了一下「Monster 語詞大挑戰」,當初設計的按鈕很簡單,觸發的特性與「HTML5 Bingo」類似,所以又把語音輸入答案的外掛拿出來改良,現在 HTML5 FUN 中的「Monster 語詞大挑戰」、「量詞大挑戰」、「Bingo」和「戳戳樂」都可以使用語音輸入答案的外掛。
![]() |
[圖1] 左下角的「MIC」按鈕為語音輸入外掛 |
這個語音外掛使用到的技術可以參考底下的文件:
不過因為不是每一種網頁瀏覽器都支援,所以加了語音輸入外掛的 HTML5 FUN 程式,如果出現 [圖1] 箭頭所標示的藍色「MIC」按鈕,就可以使用語音輸入外掛來「說」答案。
HTML5 FUN 的語音外掛是在載入原有的程式以後,再載入語音辨識的相關程式。所以只是將語音辨識結果分析是否為答案選項,符合條件的,就「按」字串相對應的按鈕,其它的,都還是 HTML5 FUN 程式原有的運作方式。所以底下僅就語音辨識的部份說明一下目前的功能特色:
HTML5 FUN 的網站網址如下:
目前支援語音外掛的程式如下:
![]() | ||
Bingo
|
![]() |
量語大考驗 |
![]() |
Monster 詞語大挑戰 |
![]() |
戳戳樂 |
進入遊戲以後,如果畫面的左下角有出現類似 [圖1] 的藍色「MIC」按鈕,表示可能可以使用麥風來「說」答案。當我們按下藍色按鈕,如果瀏覽器跳出要求使用麥克風的權限,按「允許」後,按鈕就會變成紅色的。
![]() |
[圖2] 紅色按鈕上方有語音辨識的結果 |
左下角的「MIC」按鈕變成紅色的,表示它已經開始監聽麥克風的聲音。如果有辨識出結果,就會在紅色按鈕上方出現文字。
![]() |
[圖3] 語詞的辨識結果 |
此時,可以請學生講語詞 [圖3] ;或是像 [圖4] ,說出完整的句子:
![]() |
[圖4] 長句的辨識結果 |
以 [圖4] 為例,因為答案鈕上的文字「不得了」三個字,在語音辨識結果「為了這點小事傷心得『不得了』太不像話了」有出現,所以外掛就會去觸發該按鈕「按下去」的動作。
底下的測試影片是利用 Google Meet 來進行同步視訊,老師端用桌機,並外接喇叭及麥克風,學生端使用手機接耳麥。學生透過手機收音,經由網路傳送到老師的電腦,老師的麥克風收音後,進行語音辨識,並與 Monster 詞語大挑戰程式互動。
ffplay 是 FFmpeg 套件中的一個影音播放器,沒有複雜的功能,哈!我喜歡它的精簡,不過似乎沒有支援播放清單的功能。沒關係,有人跟我有一樣的需求,找到這個討論串:
裡面看到了幾個 ffplay 的參數:
再加上 ffmpeg 也有的參數,「-hide_banner」或「-v quiet」,可以不顯示播放器的詳細資訊,畫面就更乾淨了。
所以用 ffplay 來播放 mp3 ,如果只播放一次就結束,指令可以這樣:
ffmpeg -hide_banner -autoexeit -nodisp XXX.mp3
想讓畫面更精簡就:
ffmpeg -v quiet -autoexeit -nodisp XXX.mp3
需要更多選項,可以參考官網文件:
播放清單呢?
假設要播放的 mp3 都放在一個資料夾中了,在 Windows 中,就可以先切換到該資料夾中,結 FOR /F 的指令,像這樣:
FOR /F %f IN ('dir /b') DO ffplay -autoexit -nodisp -v quiet "%f"
上面用「dir /b」來取得該目前目錄的所有檔案清單,然後一個個檔名指定給 %f。
「DO」後面就是 ffplay 的指令了,只是檔名的參數用「 %f」。
其它非 Windows 的系統的話,也是有相對應的 shell 指令可以用的。
哈!滿有意思的。
FFmpeg 中,除了 ffmpeg 以外,還有 ffprobe 和 ffplay 兩個很好用的工具,之前遇過在 Windows 中使用 ffplay 來播放影片時,看得到畫面,卻沒有聲音。因為還有 VLC Player 可以用,所以也就沒管它;這兩天想直接在程式中,下指令來呼叫 ffplay 播放 mp3,當然還是不能用。
不過,這回有認真看錯誤訊息了,大概長這樣:
SDL_OpenAudio (1 channels, 22050 Hz): WASAPI can't initialize audio client: CoInitialize
查了一下:
只要在 Windows 中設定一下環境變數「SDL_AUDIODRIVER」,讓播放器知道要用哪一個聲音的驅動程式即可解決。例如在執行 ffplay 之前,執行這一行:
set SDL_AUDIODRIVER=directsound
如果常用,就在 Windows 的系統中設定環境變數,這樣就可以一勞永逸了。
在 Windows 的批次檔中使用 FOR /F 可以讀取文字檔,然後一行行拿來處理。最近常拿它來結合 ffmpeg 處理英文的語音 mp3 檔案。不過今天遇到一個情形,「book」、「book bag」這兩行讀入後,被 FOR /F 同樣解讀為「book」了。這個狀況在別的單字也會出現,也就是,遇到空白就被截斷。
看一下 FOR 的語法說明中有這個:
FOR /F ["options"] %variable IN (file-set) DO command [command-parameters]
關於引號中的 options 有一個選項「delims」是和前述的問題相關的:
delims=xxx - 指定分隔符號集。這會取代預設的空格與定位字元的分隔符號集。
當我們使用 FOR /F 讀入一個文字檔時,讀入一行以後,預設會以空格或定位字元來當分隔符號,將這一行拆成多個欄位。所以前面提到的「book bag」,就因為空格,被拆成兩個,只取了前面的「book」。
為了解決這個問題,當然就是自己設定「delims」的選項,不要讓它使用空格來當分隔的符號。
例如:
FOR /F "delims=" %%w IN (list.txt) DO (
..........
)
上面的指令會一行行讀取 list.txt ,然後將該行,整行的資料指定給 %%w 這個變數。
最關鍵就在指令裡的這個:
"delims="
哈!等號後面沒有東西了!它的意思就是不使用分隔任何分隔符號來拆解字串,所以我們就能取得整行字串囉!
利用之前這篇「雄 : 透過 Colab 批次下載 FreeTTS mp3」下載回來的全成語音,有些聲音語速滿快的,雖然我們可以在播放時,再透過程式來調整,總覺得乾脆批次處理,一次解決比較俐落。因此,強大的 ffmpeg 又可以出場了!
我們可以使用 ffmpeg 的 atempo 來調整影音的速度:
例如:
ffmpeg -i source.mp3 -filter:a "atempo=0.75" output.mp3
上面的指令,可以將 source.mp3 的速度變成原來的 0.75 倍後,輸出成 output.mp3。
那如果想結合之前「雄 : FFmpeg : 在聲音檔前面加一小段靜音」中的 adelay filter ,在 mp3 前面加上 0.5 秒的靜音,例如:
ffmpeg -i source.mp3 -af "adelay=500|500" output.mp3
是不是直接這樣子,加分號串接?(ffmpeg 要用多種效果時用分號)
ffmpeg -i source.mp3 -filter:a "atempo=0.75; adelay=500|500" output.mp3
哈!要是像上面用,會出現類似底下的錯誤訊息啦!
Simple filtergraph 'atempo=0.75; adelay=500|500' was expected to have exactly 1 input and 1 output. However, it had >1 input(s) and >1 output(s). Please adjust, or use a complex filtergraph (-filter_complex) instead.
Error reinitializing filters!
Failed to inject frame into filter network: Invalid argument
Error while processing the decoded data for stream #0:0
Conversion failed!
錯誤訊息中有個關鍵字「-filter_complex」,就照這個方向試著改改看,變成:
ffmpeg -i source.mp3 -filter_complex "atempo=0.75 [temp]; [temp] adelay=500|500" output.mp3
有改變的部份,主要是使用 ffmpeg 的 Filtergraph
簡單的說明一下,source.mp3 先用 atempo 改變速度,處理完的結果用 [temp] 這個標籤代表;接著 [temp] 再用 adelay 在最前上加上 0.5 秒的靜音;最後輸出到 output.mp3。
這部份的技巧在「雄 : FFmpeg : 影片剪接與加馬賽克」中的影片處理中也使用過。
知道如何用 ffmpeg 來同時更改 mp3 的速度及在最前面加上一小段靜音,接下來只要再結合批次檔,就可以一次處理整個資料夾的語音檔囉!
在使用 youtube-dl 時,如果出現下面的錯誤訊息:
ERROR: Unable to download webpage: <urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:600)> (caused by URLError(SSLError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:600)'),))
表示來源網站的 SSL 憑證可能有問題,如果還是想繼續下載,可以使用 youtube-dl 的「--no-check-certificate」選項,它就會略過憑證的檢查;當然,安全就要自負囉!
在「雄 : youtbue-dl : 下載 ffmpeg 無法下載的串流影片」這篇中,利用 youtube-dl 的選項「--hls-prefer-native」,讓它避免使用 ffmpeg 來下載偽裝為圖片的串流影片,好處是可以一個網址來下載整個影片,不過因為它還是帶有圖片的識別資料,最後仍然要處理這部份,一般的影音播放工具才會識別出它是影片,才能正常播放。
後來試了一下,其實只要將帶有圖片識別資料的影片檔,去掉最前面的 3 bytes (通常是 PNG、BMP、JPG ... ),就可以利用 ffmpeg 來進行轉存為正常影片了。
假設用 youtube-dl 下載回來的串流影片檔的檔名為 NG.mp4,想要去掉前 3 bytes (也就是由第 4 bytes 讀起),就利用底下的指令來輸出為正常的影片 OK.mp4:
ffmpeg -protocol_whitelist subfile,file -start 4 -i subfile:NG.mp4 -map 0 -c copy OK.mp4
再者,因為 youtube-dl 可以利用「--exec」的選項來指定,在影片下載並儲存完後,接著要針對輸出的檔案執行的命令。讓「--hls-prefer-native」和「--exec」同時使用,前段由 youtube-dl 來下載偽裝為圖片的串流影片,後段交由 ffmpeg 來轉為正常影片。
使用前,要先確認 youtube-dl 和 ffmpeg 都放在一起了,然後執行底下的指令:
youtube-dl ---hls-prefer-native --exec "ffmpeg -protocol_whitelist subfile,file -start 4 -i subfile:{} -map 0 -c copy {}.mp4" URL
上面的指令中, URL 是要下載的串流影片網址。
如果和前面尚未合併的指令比較一下,有沒有發現到:
當使用 youtube-dl 的 --exec」的選項,後面指令的字串裡,「{}」代表最後 youtube-dl 儲存的檔名,這樣滿方便的,我們除了使用 youtube-dl 預設的檔名外,也能使用「-o」的選項來自訂檔名,利用「{}」可以自動幫我們替換掉。
不過,為了讓原始檔跟被 ffmpeg 處理過的檔案同時存在,輸出時,在原始檔名的字尾又加上了「.mp4」({}.mp4),所以如果 youtube-dl 中使用了「-o test.mp4」,ffmpget 處理完就會變成「test.mp4.mp4」。
如果 youtube-dl 下載回來的串流影片是「沒被動過手腳」的正常影片,會是什麼結果呢?
mov,mp4,m4a,3gp,3g2,mj2 @ 0000000000460440] Format mov,mp4,m4a,3gp,3g2,mj2 detected only with low score of 1, misdetection possible!
[mov,mp4,m4a,3gp,3g2,mj2 @ 0000000000460440] moov atom not found subfile:XXX.mp4: Invalid data found when processing input
ERROR: Command returned error code 1
如果已經是正常影片,在輪到 ffmpeg 進行後續處理時,會類似出現上面的錯誤訊息。
不過沒關係,youtube-dl 已經將影片儲存好了。
所以做一個小結論:
上一篇「雄 : 批次下載 FreeTTS mp3」談到以 wget、jq 和 Windows 的批次檔,將清單檔案中的英文,一行行解析後,到 FreeTTS 網站中合成 TTS 語音,並將 MP3 檔案下載回來。在那之前,其實已經先在 Google Colab 中,以 Python 寫了個「free-tts-mp3-dl.ipynb」的「筆記本」,測試過下載的程序。畢竟 Python 還是比較強大,此外, Colab 是在網頁瀏覽器中操作,環境比較單純,使用者不用再另外安裝別的工具,又可以跨平台使用,所以還是建議優先使用本篇的方法。
Google Colab 中 free-tts-mp3-dl.ipynb 的共用網址如下:
因為是用「檢視者」的方式共用的,所以如果有需要將自己的設定儲存,建議首次使用時,在雲端硬碟儲存複本,可以在開啟共用的網址後,找找上方有個「複製到雲端硬碟」的按鈕,然後按下去;或是按在主選單「檔案」中的「在雲端硬碟中儲存副本」。以後要用時,就可以開啟自己的 free-tts-mp3-dl。
![]() |
按「複製到雲端硬碟」建立副本 |
在 Colab 中使用 free-tts-mp3-dl 批次下載 FreeTTS 的 mp3 檔案,只要三個步驟:
在 Free TTS 網站中, English (US) 的的聲音選單中有12個可以選擇,為了方便使用,我將它們的相關設定都預先建立好了,只要在 free-tts-mp3-dl 中找到「ttsVoiceName」這個變數後,將等號右邊,引號內的名稱字串換成想下載的即可選定。
![]() |
設定 ttsVoiceName 決定聲音 |
可用的聲音名稱都列在註解中(井字號開頭,綠色的字),可供參考,並複製使用。
free-tts-mp3-dl 會一行行分析 textMessages 變數中的文字;一行中,只會取出英文、空白、數字,遇到第一個非英文用的的符號即終止該行的分析。所以在 textMessages 中,可以直接貼入 HTML5 FUN 中使用到的英文相關題庫設定,或是單純的英文字串。
下圖中,範例貼入的是 HTML5 FUN 單字高手/English1200 用的題庫
![]() |
在 textMessages 中填入要下載的英文清單 |
修改設定內容時,直接將上圖框框中的範例置換成想下載的英文,一行一個英文單字或句子。
在 Colab 中,每一個程式區塊(儲存格)的左上角會有一個「播放」鈕,按下去,就可以開始執行程式的功能。
![]() |
按「播放」鈕執行程式 |
如果已經完成前兩步驟,設定完 ttsVoiceName 和 textMessages ,就可以按程式區塊左上角的「播放」鈕,開始分析哪些英文要下載 MP3 檔案,並送資料給 Free TTS 網站合成語音。下載回來的 MP3 檔案會暫存在您的 Colab 空間中,全部的 .mp3 檔案都由網站抓完了以後,會打包成一個 .zip 的壓縮檔,並自動下載到您的電腦中儲存。
所以按完步驟 3 的播放鈕,就喝杯水,稍等一下囉!
朋友拿了一個罷工的鬧鐘給我幫忙看看。拆開後,觀察到兩根電線「離家出走」迷路了。一根是連接到小燈開關,小燈的另一側是接在正極,所以斷的這根是連到電池座的負極,試了一下,果然沒猜錯;另一條迷路的電線是黑色的,而電池座上的負極也是什麼都沒接。輕輕鬆鬆就把鐘不走,燈不亮的問題解決了。
仔細的觀察電線的端點,銅線都變黑了,在猜想,多半是之前電池漏液,讓電線氧化太嚴重,最後就斷頭了。
正準備將螺絲鎖回去,心血來潮,試了一下鬧鈴,哈!果然不會響。問了主人,原來它不響很久了,害我以為是自己把它修壞了。
這個鬧鐘的鬧鈴是用一個 3P兩段的滑動開關來控制鈴聲,測試了一下,兩段都不會導通。只好拆開來看看怎麼回事。
![]() |
拆開的3P兩段滑動開關 |
可以看到導通接點的銅片(接觸片)氧化得很嚴重
![]() |
滑動開關的推柄及接觸片 |
推柄下方有一個小彈簧,彈簧會將底下的接觸片往下頂,這樣子可以跟端子更緊密的接觸,又不影響它滑動,這個設計滿巧妙的。
拿細砂紙將氧化的部份都磨掉
![]() |
去除氧化物後的接觸片 |
接觸片及端子都亮晶晶的,鬧鈴又可以鈴~鈴~鈴~。
不過,這鬧鈴也太大聲了,睡夢中應該會嚇醒;如果是「葉大雄」,大概會摔下床吧!
朋友推薦可以將 TTS 語音下載為 mp3 檔案,而且授權很開放的網站 FreeTTS:
雖然沒有中文的,但是用來下載英文的語音也不錯。進入網站後,在輸入區輸入想讓它合成語音的文字,並選取想用的聲音,最後再按 [Convert to Mp3] 的按鈕,即可播放聲音,或是下載 MP3 檔案。
研究了 FreeTTS 下載的流程,大概可以分為三個部份:
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 中則使用了以下的參數:
例如我想下載「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 寫了支小工具,可以進行批次下載了,他日再寫記錄囉!
一直以來都覺得,HTML5 的聲音在 iOS 上很難處理,所以總是走一步算一步,只能說「盡量」讓它能正常播放出來。
前幾天有人反應「HTML5 單字高手」在 iPad 上,聲音會有無法播放的情形,試了一下,如果是要播放 .mp3 檔案,一切正常;如果是使用 Google TTS ,在 iOS 10.3.4 沒問題(之前都是在這台上測試的),在 iOS 15.x 中,同一個 TTS 的網址,第一次播放正常,但是按了「播放」鈕重播,只出現「播放中」的狀態,卻沒有聲音。追蹤了一下「networkState」,代碼是「2」,也就是:
MEDIA_ERR_NETWORK
似乎只有在 iOS 15.x 中這樣子。
再看了一下自己的程式碼中,這一行註解掉了:
soundQuestion.baseElement.load();
應該是原來測試時,發現可有可無,就註解掉了。
.load() 是用來重新載入影音檔的方法,把上面那行註解的符號拿掉,在 iOS 15.x 中,按「播放」鈕,果然可以正常地重播語音了。
好吧!將上面兩個觀察結合起來,只有在發生「MEDIA_ERR_NETWORK」時,才執行 .load():
if(soundQuestion.baseElement['networkState']==2) {
soundQuestion.baseElement.load();
}
Google TTS 重播的問題不只在「HTML5 單字高手」出現,在「HTML5 English 1200」也有相同的問題,趁還記得,就一起處理掉了。
個人喜歡分享,更喜歡別人將發現的問題提出來;雖然解決問題常常要花不少時間,但過程中,心情是愉悅的,問題解決了,更是開心。