Drake's Weblog

7 minute read

某一天,一位工程師決定多“讀“點書。 於是他參加了一個訂閱制服務。 付了費,每週都有說書人導讀幾本書, 用瀏覽器上網就能“看“到這些影片。 過了一陣子,他想說,也是可以好好利用上班搭公車的時間。 於是他在想,是不是可以把那些用“看“的影片,轉成用“聽“的? 手機配合耳機,在短短不到半個小時的上班公車途中,感覺至少可以“聽“個一本書,挺不賴似的!

研究來研究去,分析東來分析西,幾天又過去了。 終於,他大概歸納了一下他的需求與目標:

  1. 找個方式把付費的那些影片,抓下來存放在自己的電腦,然後再把它們轉成音檔格式。
  2. 再找個方式把音檔放進手邊的 iPhone。如果能把音檔變成一個 podcast 節目的話,似乎更好!
  3. 希望音檔愈小愈好,這樣就可以不用顧慮網路流量或是手機的記憶體大小。但至少也要聽得清楚說書人的聲音。
  4. 希望可以盡可能的自動化。因為影片每週都會推陳出新,希望 podcast 的節目也能(半)自動跟著更新。

於是他開始了他的計畫,以工程師的方式去執行。

首先,感謝這個付費影音服務很不嚴謹。 可以是礙於預算與技術考量,或是想要試水溫,覺得不需要太在意很多細節。 它的網站雖然要經過付費並且登入才看得到,而且影片的存取,也有小小的保護一下。 但對於一位工程師來說,全球資訊網(WWW)是個非常公開與開放的架構, 只有小小的保護等於是沒有保護。 只花了一下子,他就把影片們都通通抓下來了。 第一個任務搞定!

接著,他上網研究了一下 podcast,大概看個幾個小時,就自稱他懂了。 非常的快,就真的只是幾個小時,就懂了! 但真要他介紹一下,又吱吱唔唔好一陣子。 最後,他想說,不然這樣好了,我去找個現成的軟體,先透過手工操作,弄個 podcast 出來再說如何? 於是大家就通過了,也沒有人再去在意他是不是真的懂 podcast。 事實上,沒有人在乎 podcast 的細節需要懂多少。

初試啼聲:Feeder

他試了蘋果電腦上的一套叫 Feeder 的軟體,很厲害的樣子。 很快的,他就用 Feeder 生出了一個 podcast 需要的 RSS 2.0 feed 出來。 把這個 podcast feed 連同兩三個轉好的音檔,上傳到一個網路上的個人空間。 接著他試著用 iOS 原生的 Podcast app 去開這個 podcast feed, 一切順利,直接就可以播放,還可以上一篇下一篇順利的操作著。

It just works!

一切似乎很美好,感覺也沒有必要再研究 podcast 了。 只要把抓下來的影片都轉成音檔,看是要 MP3 或是 AAC 格式都行。 然後丟給 Feeder ,再想個法子讓 feed 裏頭的每一個節目都有正確的節目名稱/講者…等資訊, 就搞定收工了。 於是他一口氣把抓下來的 59 個影片都轉成副檔名是 .m4a 的 AAC 音檔, 然後再把 59 個音檔給全數拖拉進 Feeder。 然後,Feeder 它就當了…

“Feeder 當了“這件事,有很多的解法。 解法之一,是再去找另一個更適合的軟體來處理。 只是我們這位工程師很快的就放棄了這個想法。 因為他發現,距離他真正需要的目標,Feeder 只是完成了一部分, 還有很多是他要自行手工執行的。 像是每一個節目的節目名稱、講者、簡介、…等,他都要自行手動 key。 另外就是,每一週就會有個兩三支音檔需要手動加入。 而且,這些音檔還是來自於更前頭的影片下載,轉檔。 然後這些都作完之後,他還得把產生出來的 podcast feed,連同新的音檔, 都上傳到網路上他的私人小祕密空間上去。

要做的事還是太多了。Feeder 只完成了部分, 而他不想要每個禮拜都再幾乎手工執行一系列的工,只是為了那每週新增的兩三支節目。 於是他說話了:

Feeder 已經完成了它的使命。 它展示了要建置一個個人 podcast 所需要的產出與過程是什麼,而這些我都會了。 但是它不適合我未來的需求,更無法自動化。 而且,它還要付費才能持續使用下去。 所以,我決定接著找出(或是開發出)一個更好的機制。 另外,我還會加強音檔的轉檔,讓它變得更小更可靠! 敬請期待。

音檔新格式:Opus

首先被開刀的是音檔格式。

一開始,想到音檔,就會想到 MP3。 MP3 的裝置穿透性很強,幾乎任何裝置都支援它。 加上,據說 2017 年它的板權在某些情況下過期了,更沒什麼好顧慮的了。 遺憾的是,它的壓縮率沒有後起之秀的好。 其中一個後起之秀,就是 AAC。 AAC 很優秀,可以壓得比 MP3 來得小,加上過去蘋果電腦的大力使用與推廣, iTunes, iOS, Safari 全數支援,別的平台也大多有支援。 說 AAC 幾乎取代了 MP3 也不為過。 然後它又細分為 LC-AAC, HE-AAC, HE-AAC v2, 可以因應不同的品質與需求。 使用 AAC 是個當然最好的決定。

但最後,我們這位工程師說:我們來用 Opus 吧!

他說: “因為 Opus 天生就是被設計給人聲使用的, 它可以把人聲壓得很小,但又同時可以被清楚辨識。 它更適合用在只有人聲的音檔上頭。 而且,已經有很多瀏覽器支援它了, 包括 iOS 與 OS X 也是!“

接著一路研究下去,他開始使用了更多的外部工具。 包括像是: ffmpeg, opus-tools, 甚至是 Apple 官方自帶的 afconvert! 因為偷懶加上開發方便,他直接使用 afconvert。 然後他才發現, 1) 必須升級到 iOS 11 與 OS X High Sierra 才可以支援 opus 格式。 接著他又發現到, 2) iOS Podcast 只能用 .caf 才能支援(認出) opus 來 , 但是在 podcast feed 裏頭, 3) 需要依舊使用 type=“audio/aac”

一連串的意外與技術規格調整(妥協), 最後,於是有了如下的一個流程:

.mp4 video -> .m4a audio with aac -> .caf audio with opus

他記錄下來了如何透過 ffmpeg 與 afconvert 來做轉檔:

podcast feed 全自動化產生:rfeed

接著,讓 Feeder 當掉的 “podcast feed 的生成“。 他挑上了 rfeed 這個 Python package 來解決掉。

透過使用 rfeed,可以很容易的寫一些程式,就做到類似 Feeder 的事。 而且還更加的自動化,又更了解了一丁點兒 podcast feed 的規格, 甚至是 iTunes 專有的規格也知曉了一些。 一舉數得。 但這些都不是挑選 rfeed 的主要原因。 真正的原因,如同前面這一小段程式碼, rfeed 使用起來平易近人,這點才是關鍵。 這位工程師有著「對工程師的友善設計才是好設計」的執念。

小總結

最後,前前後後使用了如下的 Python packages: pathlib 來處理檔案目錄; uuid 來產生 GUID; plumbum 來執行 shell commands; arrow 來簡化 datetime 的處理; 以及最後的 rfeed 來動態產生 podcast feed。 加上先前用的 ffmpeg, afconvert 這兩隻程式, 工程師他完成了一隻可以幫他搞定幾乎所有事的程式碼來了。

為了更進一步自動化,還準備了另一段程序來把產生出來的檔案給丟上私人伺服器。 這樣一來,就可以去訂閱 https://oo.xx.asdf/feed.xml 了。

後記

這則小故事,有耐心看到這的話,現在是重點了。

對於一位工程師,當需求不明確時,他會自行去把想像中的空缺補上。 事實上,工程師為了可以執行開發,會提出非常多需求端沒想過的細節。 需求方(stakeholder),或是代理需求方(product manager / agent), 懂得怎麼合作把需求釐清,有耐心,是至關重要的一個過程與能力。 「音檔盡可能的小,那要多小才可以」; 「似乎可以只支援 iOS 就好了」; 「只要不公開 podcast feed 的 URL,就安全了」; 這些都是“暫時而且不夠明確的規格“。

另一方面,開發是一件有趣而又複雜的過程。 永遠,事情都有另一種解法。 至於你的工程團隊選用哪個方法,做了什麼假設,妥協了些什麼,又犧牲了哪邊… 這些“無形資產“一個不小心,就會變成“無形債務“,在未來一直回過頭來煩你。 「選擇 opus 而不是 aac」; 「隨意加一些 iTunes 欄位而沒有去驗證」; 「使用 Apple 限定的 afconvert 而不是其它工具」; 這些都會在無形中製造了限制。

另外,要小心的一點是,工程師的方案二,常常不見得比方案一來得好。 他所謂的好,常常是局部來看的。甚至可以原來方案一方便的地方,在方案二就變不方便了。 拿上頭的 podcast 作法來看,原先的使用 Feeder 的作法不見得不好。 除了它提供了一個 GUI 界面讓人可以方便編輯以外, 另一個地方是,它讓人可以每週新增兩三個音檔節目,然後手動 key 一些資訊進去,有累加的過程。 如果是採用我們這位工程師的方案二的話,這些手動 key 的資訊,變成每週都要做了! 不然就是會被要求你要在使用另一個檔案來記錄,可能會有一些新的格式,新的作法, 然後就是流程變得更長,製造出更多發生人為疏失的地方!

最後,現在開發團隊的工作模式,大多是偏向 good enough: 只要做得差不多夠好了,就先交件出去吧,之後的事之後再說。 但有多少人理解到這些“夠好背後的代價“,就很重要了。

網路上有一則非常有意思的 tweet。 大致的意思是說: 你要一位工程師去猜測與了解一個需求,以及它背後真正要解決的問題與來龍去脈, 是件可能最後以不可預知的災難方式收尾的!

Ref:

comments powered by Disqus

Recent posts

Categories

About

You're looking at Drake's words or statements. All opinions are my own.