LoginSignup
71
50

More than 3 years have passed since last update.

自宅で夏の散歩ができる「夏休み君」をYoutube Player APIで作ってみた

Last updated at Posted at 2020-08-19

作業用BGM多すぎ長すぎィ!

皆さんは何か作業に没頭するときに、作業用BGMをかけたりしますか?
人によっては音楽をかけたり、人によってはYoutubeをただ流したり、ある人は耳栓をして無音で頑張ったり、色々なスタイルがあると思います。

今年はコロナの影響で、夏のイベントが何から何まで無くなってしまいました。
外出できなくても夏気分を味わいたいなあと思い、youtubeでフリー環境音BGMを探して流してみようと考えてみました。
森の音、海の音、川の音、虫の音、、、などなどいろいろあるようですが、どうせなら一つのBGMをずっと聞くより色んなBGMを聞きたいなあと思い、Youtube Player APIを使って実装してみました。

Webアプリはデプロイしてあるので、お散歩気分でお楽しみください。

コードはこちらから!
アプリはこちらから!

完成デモ

基本

「森や雨の音」と「川の音」というように基本的に2つの音源を同時に流しています
音源は5分おきにランダムで切り替わり、時々雨も降ったりもします
実は音量のバランスも毎分変わっているので、同じ組み合わせでも聞こえ方が変わったり、川の音がしたとしても天気が違うなど、何回聞いても楽しめる内容にしています。

シーンを「星空」「花火」「川」の3つ用意しており、左上の「星空を見る」「花火を歩く」「川へ歩く」をクリックして移動できます
好きなシーンに合わせて「耳をすます」をクリックするとBGMが再生されます

星空を見る

星空の背景を眺めながら、夏の音を楽しめます。
25%の確率で雨が降ります。
夏の夜独特の雰囲気を味わってみてください。

星空を見に行く

花火を見る

夏と言えば花火!
花火大会独特の雰囲気を味わってください。
花火の日なので雨は降らず、背景の虫の音声が変わるようになっています。
花火は結構激しいです。

花火を見に行く

川へ歩く

夏の川遊びも楽しいですよね。
川の音と自然の雰囲気を楽しんでください。
こちらも33%の確率で雨が降ります。

川へ遊びに行く

実装こまごま

htmlとcssの実装

全体としては
・3つのhtml:花火・川・星空、各シチュエーションにあったBGM再生
・1つのcss:ボタンのデザイン
という構成になっています。

htmlは基本的には背景にそれっぽい画像を表示する以外はしておらず、インラインのJavascriptでメインの処理を担っています。
途中のid=player1 id=player2のdivタグ部分にYoutubePlayerが挿入され音声が再生されます。
今回は縦横0pxのplayerを用意し、音は流してplayer本体は隠すようにしています。

<html>
  <head>
    <link rel="stylesheet" href="image-button.css">
  </head>
  <title>
    夏休み君
  </title>

  <style>
    body {
    background-image: url('hoshizora.jpg');
    background-size: 100% auto;
    }
  </style>
    <body>
    <a href="hanabi.html" class="btn-cross">花火を見る</a>
    <a href="kawa.html" class="btn-cross">川へ歩く</a>
    <a class="btn-cross" onclick="startSound()">耳を澄ます</a>

    <div id="player1"></div>
    <div id="player2"></div>

    <script>
    //ここに処理を記述する
    </script>
  </body>
</html>

cssはこちら。
何かおしゃれなcssは無いかなあと思い探した結果、良さそうなのがあったのでお借りいたしました。
こちらのサイトが優秀なので是非是非ご覧になってください!

.btn-cross {
    display: inline-block;
    position: relative;
    padding: 0.25em 1em;
    border-top: solid 2px rgb(206, 206, 206);
    border-bottom: solid 2px rgb(206, 206, 206);
    text-decoration: none;
    font-weight: bold;
    color: #9ee0ff;
  }
  .btn-cross:before, .btn-cross:after {
    content: '';
    position: absolute;
    top: -7px;
    width: 2px;
    height: -webkit-calc(100% + 14px);
    height: calc(100% + 14px);
    background-color: rgb(206, 206, 206);
    transition: .3s;
  }
  .btn-cross:before {
    left: 7px;
  }
  .btn-cross:after {
    right: 7px;
  }
  .btn-cross:hover:before {
    top: 0px;
    left:0;
    height: 100%;
  }
  .btn-cross:hover:after {
    top: 0px;
    right: 0;
    height: 100%;
  }


  .btn-cross2 {
    display: inline-block;
    position: relative;
    padding: 0.25em 1em;
    border-top: solid 2px rgb(182, 242, 247);
    border-bottom: solid 2px rgb(182, 242, 247);
    text-decoration: none;
    font-weight: bold;
    color: #cbf1f8;
  }
  .btn-cross2:before, .btn-cross2:after {
    content: '';
    position: absolute;
    top: -7px;
    width: 2px;
    height: -webkit-calc(100% + 14px);
    height: calc(100% + 14px);
    background-color: rgb(182, 242, 247);
    transition: .3s;
  }
  .btn-cross2:before {
    left: 7px;
  }
  .btn-cross2:after {
    right: 7px;
  }
  .btn-cross2:hover:before {
    top: 0px;
    left:0;
    height: 100%;
  }
  .btn-cross2:hover:after {
    top: 0px;
    right: 0;
    height: 100%;
  }

これで、マウスを合わせると枠が広がるボタンを実装できます。
是非是非お試しください!
button.png

Youtube Playerの埋め込み

今回はYoutube Player APIを利用しました。
ドキュメントサイトを参考に処理を実装しています。
Youtube Player APIの読み込みが始まると同時にonYoutubeIframeAPIReady()メソッドが走ります。

      //おまじない
      var tag = document.createElement('script');
      tag.src = "https://www.youtube.com/iframe_api";
      var firstScriptTag = document.getElementsByTagName('script')[0];
      firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);

      //YoutubePlayerを埋め込む処理
      var player1; //川の音,海の音
      var player2; //雨や虫、森の音など

      //読み込んだ際に最初に走る処理
      function onYouTubeIframeAPIReady() {
        //player1の定義
        player1 = new YT.Player('player1', {
          height: '0',
          width: '0',
          videoId:"",
          events: {
            'onReady': onPlayerReady1,
          }
        });

        //player2の定義
        player2 = new YT.Player('player2', {
          height: "0",
          width: '0',
          videoId:"",
          events: {
            'onReady': onPlayerReady2,
          }
        });
      }

ランダム再生

Playerの準備が完了すると、eventsのonReadyが発火し、onPlayerReady1とonPlayerReady2が走ります。
ここでPlayerに再生リストをセットし、シャッフル設定をします。
Youtubeの動画は自力で聞いて選抜したものを入れています(大変でした)。


      //Youtubeのビデオリスト
      var videolist = [
          ['p2st1-AHa5Y','_FDWgFrsSVA','xAL1rVb4EG4'], //花火
          ['N3mnyBh8y5A','2PC2Oh0vqb0','hnqk8k6a_Cw'], //虫、川と虫、虫
          ]
      //PlayerがReadyになったときに走る処理
      function onPlayerReady1(event) {
        //音量をセット
        player = event.target
        player.setVolume(p1vol);

        //Playlistをセットして、シャッフル再生
        videolength = videolist[0].length
        player.cuePlaylist(videolist[0],Math.floor(Math.random()*videolength));
        player.setShuffle(true);
        player.playVideo();
      }

      //PlayerがReadyになったときに走る処理
      function onPlayerReady2(event) {
        //音量をセット
        player = event.target
        player.setVolume(p2vol);
        player.setShuffle(true); 

        //Playlistをセットして、シャッフル再生 
        videolength = videolist[0].length
        player.cuePlaylist(videolist[1],Math.floor(Math.random()*videolength));
        player.setShuffle(true);
        player.playVideo();
      }

そして「耳をすます」ボタンをクリックすると、仕込ませたstartSound()メソッドを実行します。
player1・player2ともに15秒ずつ音量を変え、音量0になったら次の動画へ移ります。
両方が同時に音量0にならないよう、player1で音量が下がっている時はplayer2で音量が上がるように仕込んでおります。

      //音量と音量の変化量を定義
      maxvol = 20;
      p1vol = 6;
      dp1vol = -2;
      p2vol = 16;
      dp2vol = 2;
      //volumeを一段階変える時間
      var timeToChangeVolume = 15; //秒

      function startSound(){
        player1.playVideo();
        player2.playVideo();
        setInterval(gradientChange,timeToChangeVolume*1000);
      }

      function gradientChange(){
        //音量を変える
        p1vol += dp1vol;
        player1.setVolume(p1vol)

        //音量がゼロになったら次の動画へ
        if (p1vol == 0){
          dp1vol = -1 * dp1vol;
          moveNext(player1);
        }else if (p1vol == maxvol){

          //音量がmaxvolになったら音量を減らすように変更
          dp1vol = -1 * dp1vol;
        }

        //音量を変える
        p2vol += dp2vol;
        player2.setVolume(p2vol)

        //音量がゼロになったら次の動画へ
        if (p2vol == 0){
          dp2vol = -1 * dp2vol;
          moveNext(player2);
        }else if (p2vol == maxvol){
          //音量がmaxvolになったら音量を減らすように変更
          dp2vol = -1 * dp2vol;
        }
      }

      //次の動画へ映る
      function moveNext(player){
        player.setShuffle(true);
        player.nextVideo();
        player.playVideo();
      }

本当は画面遷移したら自動再生されるような実装にしたかったです。
ただ、なぜか時々再生されて時々再生されない不具合が起き、今回はbuttonでの再生としました。
読み込み完了のタイミングなどが何か関連しているんでしょうか・・・?もしご存知の方いらっしゃいましたらコメントいただけると嬉しいです。

コード全体はGist(こちらから)に載せてあるので、是非是非ご覧になってくださいね。

今後やりたいこと

Youtube Player API面白い・・・結構なんでもできますし夢があるAPIだなと思いました。
前回の記事「光センサで遊ぶ「かくれんぼ」をobnizとp5jsで作ってみた」では背景の色を時間経過とともに少しずつ変える処理を実装しました。
今回はその処理を音量に使ってみるなど、自分としても色々技術の応用ができて楽しい実装でした。

最後までご覧いただきありがとうございました!
LGTMつけていただけると励みになります、よろしくお願いいたします!

↓こちらも合わせてご覧ください!
結局Qiita記事ってどれぐらい書けばいいのさ
 Qiita APIから記事の情報を取って分析してみました!
入社一年間で学んだ「DX」「UX」を整理してみたい
 社会人2年目になったので1年間の振り返りをしました!
男「君の死神の目は、どれぐらい顔が見えればいいんだい」女「私の目cloud visionなの」
 cloud vision apiの顔認識の精度検証をしました!

71
50
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
71
50