2023/01/19

JS / 使用 Youtube Iframe API製作動態歌詞

自從帕妃在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,主要就是頁面上所有的內容,或者程式要寫入內容的區塊

 

完整的程式碼

雖然是用中島美嘉的歌…..不過之後只要改歌詞內容就可以了

 

參考資料

Youtube Iframe API 常用功能

Listening to the YouTube Embed Iframe time change events without polling player.getCurrentTime()

D09_Video元件的YouTube影片操作

Youtube 互動

YouTube Player API Reference for iframe Embeds

jQuery TypeError: text is not a function

[jQuery] 筆記 (五) – 選擇器 (selector)

jQuery 设置内容和属性

JS getAttribute()方法:讀取元素的屬性值

認識 parseInt、parseFloat 與 Number 轉換成數字的三種方法

JavaScript toFixed() 方法

【學習筆記】JavaScript – Regex 正則表達式

String.prototype.substr()

js-把秒转化为 *天*小时*分钟*秒

JS將字串轉換成數字

【相關文章】

  • 網站 / 從wordpress發佈新文章同步寄信到blogger儲存成草稿google blogger可以接收電子郵件來發佈文章當然這個電子郵件不是自己的gmail,而是指定的用於貼文的電子信箱格式是google帳號名稱.自訂文字@blogger.com因此,嘗試從wordpress發佈新文章,同步寄信到blogger設定的專用信箱來發佈草稿(因為通常會跑版,而且需要手動… Read More
  • JS / 在Blogger增加”分享到臉書”功能之前在網站 / 從wordpress發佈新文章同步發文到臉書粉絲專頁提到 臉書只能夠用分享的方式將訊息貼到個人頁面 於是,開始思考如何在Blogger達成這個效果(雖然後來發現Blogger的佈景主題有這個功能...)思路如下  1.臉書分享的功能 這個可以參考臉書的官方文件-分… Read More
  • JS / 移除或修改 iframe的屬性前幾天辦公室裡其他計畫的助理抱怨網站嵌入的google表單出現 「您的瀏覽器尚未啟用javascript...」 經詢問網站維護廠商,說因為資安掃描被列為需改善的漏洞不過之前的表單都是正常所以我比較了前後網頁的html內容 原來後面的表單iframe增加了sandbox標籤 我因為無聊想試試… Read More
  • 網站 / 從wordpress發佈新文章同步發文到臉書粉絲專頁既然可以透過寄信到Blogger發文 那有沒有可能在臉書粉絲專頁貼文?答案是可以的!! 接下來可能會問:有沒有可能在個人臉書貼文 可惜答案是不可能~~,但是可以用分享的方式 臉書已經算是商業平台了,社交只是功能之一 粉絲頁的功能主要是為了跟成員互動,所以… Read More
  • 網站 / 使用Google Translate JS將網站變成多語系網站聽說網站如果能夠具備多語系內容 可以更容易被搜尋到 但是我又不會多語還好現在AI發展的關係 機器翻譯的品質越來越好wordpress可以直接用外掛達成網站多語系目前使用的外掛Translate WordPress with GTranslate是免費的 想說為… Read More

0 comments:

張貼留言