自從帕妃在THE FIRST TAKE的 愛のしるし出現在youtube的推播上
我又開始聽帕妃的歌了….
想當年是從錄音帶買到CD
在搜尋日文歌詞翻譯的時候
看到一個日語教學網站marumaru
除了提供歌詞翻譯之外,還結合youtube呈現中文/日語動態歌詞
稍微研究了一下背後使用的技術跟方式
自己土炮的結論是
1.透過Youtube Iframe API 建立播放器與取得影片資訊
2.結合 Jquery函示庫 $.doTimeout 設定每100毫秒觸發一個擷取當前影片的播放時間秒數
3.在顯示歌詞的li標籤內自訂一個st屬性,存放歌詞顯示的時間(格式是hh:mm:ss),在Javascript利用自訂函數轉換成秒數值
4.透過判斷式,比較播放時間位於哪兩個歌詞播放區間,取最早時間的歌詞 li 序號
5.知道當前時間應該呈現的歌詞 li 序號,透過Javascript抓取並寫入要呈現的位置,同時修改css效果
重點說明
1.Youtube Iframe API
範例是用動態的方式引用 js檔,並且嵌入網頁之中
var tag = document.createElement("script"); tag.src = "https://www.youtube.com/iframe_api"; var firstScriptTag = document.getElementsByTagName("script")[0]; firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
之後是實例化、建立youtube播放器
function onYouTubeIframeAPIReady() { var player = new YT.Player("player", { height: "390", width: "640", videoId: "oIoaIlPpIcA", events: { onReady: onPlayerReady, onStateChange: onPlayerStateChange } }); }
videoId就是https://www.youtube.com/watch?v=後面的字串
在events 設定2個觸發事件
第1個 onReady,顧名思義就是播放器載入之後要觸發的函式
第2個 onStateChange,當播放狀態改變時要執行的函試
2.$.doTimeout
跟原生的setInterval()差不多,不過這個函示庫可以重複利用建立的$.doTimeout
透過這個函式每1000毫秒執行一次比對
我設定的流程是建立一個範圍在歌詞li 總數內的迴圈
透過當前 跟 當前+1的時間區間
比對從youtube API 利用getCurrentTime() 取得的影片播放時間
3.利用自訂函數轉換成秒數值
由於getCurrentTime() 取得的影片播放時間是秒數值
而參考網站在歌詞li st屬性的時間格式是 hh:mm:ss
所以我直接借用網站內的兩個函式來轉換成秒數值(其實是秒數.毫秒數)
4.透過判斷式,取得當前時間的歌詞 li 序號
因為用這種比對方式,在迴圈跑到最後一筆時,會因為沒有再下一筆而產生錯誤
所以又用一個判斷式,當跑到迴圈的最後一筆時,直接設定是li的最後一筆
之後會有3種情況
第1種:當前時間 小於 第1個區間 也就是還沒演唱
r=-1
結束迴圈
第2種:當前時間 介於 某一個時間區間
此時 r = 迴圈目前的位置
結束迴圈(因為只要取第1個符合條件的區間)
第3種:當前時間 大於所有時間區間 也就是結束演唱 沒有歌詞了
r = -2
結束迴圈
var r; for (var i = 0; i < stList; i++) { if (i != stList - 1) { var st1 = convertLST($(".LyricsYomi").eq(i).attr("st")); //取得li標籤內的st屬性值,透過convertLST()轉換成秒數.毫秒 var st2 = convertLST($(".LyricsYomi").eq(i + 1).attr("st")); }else{ var st3 = convertLST($(".LyricsYomi").eq(stList - 1).attr("st")); } //console.log("st1", st1); //console.log("st2", st2); if (mtime < st1) { r = -1; console.log(r); break; } else if (mtime >= st1 && mtime < st2) { r = i; console.log(r); break; }else if(mtime >= st3){ r = -2; console.log(r); break; } }
5.透過Javascript寫入要呈現的位置,同時修改css效果
透過前面的判斷式
會得到3種 r 值
因此就可以設計不同條件要呈現的內容
if (r > -1) { var sn1 = $(".LyricsYomi").eq(r).html(); var sn2 = $(".Translate_zh").eq(r).html(); var sn = "<li lang='ja' class='li3'>" + sn1 + "</li><li class='li4'>" + sn2 + "</li>"; $("#ly").html(sn); $(".LyricsYomi").css("color", "blue"); $(".LyricsYomi").eq(r).css("color", "red"); $(".Translate_zh").css("color", "gray"); $(".Translate_zh").eq(r).css("color", "red"); }else if (r == -1){ //$("#ly").html("<li class='li4'>雪花 - 中島美嘉</li>"); } else if(r == -2){ $("#ly").html("<li class='li4'>雪花 - 中島美嘉</li>"); }
Css與Html設定
為了讓整體頁面都能居中,因此,最外一層的div main 如下設定
display: flex; justify-content: center;
第二層div block主要是設定背景顏色與寬度跟高度
重點是設定寬度,這樣才能夠限制後面div都能夠居中,不然都會排成一行
而這個寬度則是依據 youtube播放器的寬度
background: #D4FFFF; width: 640px; height: 100%; padding:10px;
第三層有4個div,主要就是頁面上所有的內容,或者程式要寫入內容的區塊
完整的程式碼
雖然是用中島美嘉的歌…..不過之後只要改歌詞內容就可以了
See the Pen Listening to the YouTube Embed IFrame time change events–22222 by 莊幸諺 (@trico109748007) on CodePen.
參考資料
Listening to the YouTube Embed Iframe time change events without polling player.getCurrentTime()
YouTube Player API Reference for iframe Embeds
jQuery TypeError: text is not a function
[jQuery] 筆記 (五) – 選擇器 (selector)
認識 parseInt、parseFloat 與 Number 轉換成數字的三種方法