見出し画像

【GAS】Gドライブ内のファイルをリンク指定でテンプレートに取り込めない問題を解決する(その2)

この記事は、以下の記事の続きになります。

先回の記事では、テンプレート内でImg要素やAudio要素を記載する場合、参照先のURLが機能しない場合がある事、その解決策としてBASE64エンコードという手法がある事をご説明しました。

今回は、GAS(Google Apps Script)でBASE64エンコードをどう実装するのかを、簡単なデモアプリでご説明します。

デモアプリの機能のご紹介

BASE64エンコードのデモンストレーションでお見せするWEBアプリの機能をご説明します。

まず、画像ファイル(PNG)と音声ファイル(MP3)を用意し、Googleドライブにアップします。

次に、アップしたファイルのIDを確認します。

ファイルのIDを確認するには、Gドライブ上で対象ファイルを選択して右クリックするとポップアップ表示されるメニューから、「リンクを取得」をクリックします。

すると、リンクが表示されますので、これをコピーして、メモ帳などに貼り付けます。

貼り付けた結果は以下の様になるはずです・・・

https://drive.google.com/file/d/★ここがファイルID※★/view?usp=sharing

※ file/d/ と /view に挟まれた部分

・・・上記のテキストの内、~file/d/ と /view~に挟まれた部分がファイルIDです。

フェイルIDは今後使いますので、貼り付けたURLから更にコピーして、メモ帳などに貼り付けておきます。


GAS(Google Apps Script )でファイルを文字列に置き換える(BASE64エンコード)する

Googleドライブ上のファイルをBASE64エンコードする方法をご紹介します。(以下の以下の質問板をほぼそのままなぞっています)


(1)ファイルを「Blob」オブジェクトに取り込んでバイナリデータを得る~


本記事の目標は、GASのテンプレート内で、URLを指定してもて取り込めないGoogleドライブ上のファイルを「BASE64エンコード」という手法で取り込んで利用する事です。

その第一歩は、外部のファイルを、スクリプト上で、「Blob」オブジェクトに取り込んでバイナリデータを得る事で、コードは以下の様になります。

1.Gドライブ上のファイルを getFileById()関数で取得
   ファイルオブジェクト = DriveApp.getFileById(ファイルID);


2.ファイルの中身をgetBlob() 関数でBlobオブジェクトとして取り込む
   Blobオブジェクト=ファイルオブジェクト.getBlob()



Blobオブジェクトは、Binary Large Object つまり 巨大なバイナリデータ全体をそのまま扱うオブジェクトです。画像や音声、その他のPDFなどどんなデータを何でも取り込んでしまう事ができるので、ファイルの中身をまるごと取り込む時に利用されます。

ファイルオブジェクトはデータの容器、Blobオブジェクトはその中身(01011111・・・というデジタルデータ)に関するオブジェクトと考えればよろしいかと思います。

そして、Blobオブジェクトからデータ情報だけを抜き出すには、以下の様に記述します。

3.Blobオブジェクトからバイナリデータを getBytes() 関数で取得
    バイナリデータ=Blobオブジェクト.getBytes()


(2)バイナリデータをBASE64エンコードしてテキスト情報に変える


GASのテンプレートがHTMLファイルと似て非なるのと同様、GASのスクリプトも、Javascriptコードとは似て非なる所があります。

スクリプトには、元祖Javascriptにはない、便利ツール Utilities というモジュールがあり、ここに、base64Encode( )という、エンコードのための関数が用意されています。この関数を使って、簡単にエンコードできます。

 バイナリデータを base64Encode( ) 関数でテキスト化
    テキストデータ =Utilities.base64Encode(バイナリデータ)


(3)一連の処理を関数にしておく

スクリプトで、以上の流れを関数として定義しておきます。名前はgetBae64DATA()とでもしておきましょう。引数はファイルIDです。

 getBae64DATA( 引数:ファイルID )

 function getBae64DATA(id) {

 //Gドライブから、id(ファイルID)でファイルを取得
  const file = DriveApp.getFileById(id);
  
 //バイナリデータを取得
  const data = file.getBlob().getBytes();
 
 //BASE64エンコードで文字列に変換
   return Utilities.base64Encode(data);
}

この関数の返り値は、エンコードしたテキストデータです!

エンコードした文字列をテンプレート内で利用する

次に、スクリプト内で得たテキストデータをテンプレート内に取り込んで利用します。

一般的に、GASでは、次の2つの方法でスクリプトのデータをテンプレート中で利用できます。

・インライン(埋め込み)コード方式

テンプレート内で、専用のタグ(スクリプトレット・タグ)で囲って、
 <? スクリプト内の変数や関数 ?>
の様に、スクリプト内の処理を埋め込む。


”インラインコード”という用語は「埋め込み命令文」の意味ですが、あまり使われず、ほぼ私個人の呼び方ですが個人的にはしっくりきています。”スクリプトレット(短い命令文の意味)”と呼ばれる事もあります。

・関数呼び出し方式

専用の関数 google.script.run  を使って、
  google.script.run
  ・成功時処理(返り値->(処理))
  ・失敗時処理(処理)
  ・呼び出し関数()
の様式で、スクリプト内の関数を記述する。処理はHTML文ではなく、scriptセクションを設けてその中に記述します。

今回の場合、以下のsrc=”○○○○”部分に、エンコードしたファイル情報を埋め込みたいのですが、HTML文の「”○○○”」の一部を置き換える場合、インラインコード方式は上手く機能しませんので、関数埋め込み方式を使います。

 <IMG src=”○○○○” >
 <Audio src=”○○○○” ></Audio>


これをsetAttributeを使って、HTML要素のsrc属性にエンコードしたテキストをセットする


要素のSRC属性をsetAttribute()関数でセットする

Javascriptにある setAttribute()関数を利用すると、<IMG>要素や<Audio>要素のsrc属性を編集できます。つまり、

 <IMG  src=”○○○○” >

と同じ結果を得る事が可能です。

具体的には、

 setAttribute(”SRC”、セットする値

と書いておき、”セットする値”の部分には、以下の様なコードを記載します。

 "data: データ種類/拡張子 ;+ エンコード結果 
 
データ種類/拡張子の部分は 音声ならAudio/mp3、画像ならimage/png を書きます。

関数呼び出し google.script.run コードに埋め込む

そして、上記の処理を さきほどスクリプト中で定義した getBae64DATA(ファイルID) 関数の呼び出し文の途中に以下の様に入れ込みます。


  google.script.run
  
        setAttribute(”src”、"data:audio/mp3 ;” + エンコード結果

        getBae64DATA(ファイルID)

構文は複雑なので略記しています。独特の文法ですので分かりにくいと思いますが、後述するコードをご覧頂ければと思います。

以上で、Googleドライブ上の画像ファイルや音声ファイルをテンプレート内で利用できる様になります!

音声、画像を外部からテンプレートに取り込むデモアプリを作ろう!

以下の音声ファイル、および画像ファイル(圧縮して1つのファイルにしているので解凍してください)をダウンロードし、Googleドライブ上にそれぞれアップしてください。


アップしたら、右クリックして共有リンクを参考し、ファイルIDを確認しておきます。

続いて、GASのプロジェクトを新規作成します。

作成したら、スクリプトファイルに以下のコードを入力して保存します。

//-----------------------------------------
//----外部音源ファイルの利用------------------
//---著作:Particlemethod-2021年09月23日-----
//---使用は自由ですが著作権は作成者に帰属します---
//-----------------------------------------
//以下の質問板を参考にしました。
//https://teratail.com/questions/258585
//-----------------------------------------

//=====アクセス時に実行する関数======
function doGet() {

//HTMLファイルのテンプレートをファイル名を指定して取得
 var myHTML = HtmlService.createTemplateFromFile('INDEX');

 //HTMLファイルをホスティング|メタタグを指定してスマホ表示に対応
 return myHTML.evaluate().addMetaTag("viewport", "width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=10.0");
}

//=====Base64エンコードする関数======
 function getBae64DATA(id) {

 //Gドライブから、ファイルIDでファイルを取得
  const file = DriveApp.getFileById(id);
  
 //バイナリデータを取得
  const data = file.getBlob().getBytes();
 
 //BASE64エンコードで文字列に変換
   return Utilities.base64Encode(data);
}

次に、テンプレートを「INDEX」の名前で作成し、以下を貼り付けてください。

コード中で、★音声ファイルのID★、★画像ファイルのID★ とある部分を先に確認したものに置き換えて保存します。

<!--//-----------------------------------------
//----外部音源ファイルの利用------------------
//---著作:Particlemethod-2021年09月23日-----
//---使用は自由ですが著作権は作成者に帰属します---
//-----------------------------------------
//以下の質問板を参考にしました。
//https://teratail.com/questions/258585
//------------------------------------------->

<!DOCTYPE html>
<html>
  <head>
    <base target="_top">   

    <!--折り返しスタイル設定-->
    <style>
    p {
        width: 500px;
        background-color: #dbedf0 ;
        word-break: break-all;
    }
    </style>
  </head>


<body>
  <p>GドライブからのBASE64エンコードで取得した音声</p>
  <audio controls id="sound"  preload="auto"></audio> 

  <p>GドライブからのBASE64エンコードで取得した画像</p>
  <img id="image"> 

  <p>【参考】上記画像ファイルのBASE64エンコード結果</p>
  <p id="msg"></p>

</body>


   
<!--Audio要素のソース設定-->
  <script type="text/javascript">
    //強制実行する関数
    (function() {
      //GドライブのファイルID|★音声ファイルのID★は各自手入力
      const fileId = '★音声ファイルのID★';

      //スクリプト関数の実行
      google.script.run

        //成功時の処理
        .withSuccessHandler(res => {

          //Audio要素を取得
          const sound = document.getElementById("sound");
          //ソースとして、BASE64エンコードされた文字列(res)を設定
          sound.setAttribute("src", "data:audio/mp3;base64," + res);


        })
        //失敗時の処理
        .withFailureHandler(console.error)

        //実行する関数
        .getBae64DATA(fileId);      
    })();
  </script>


<!--Img要素のソース設定-->
  <script type="text/javascript">
     //強制実行する関数
   (function() {

      //GドライブのファイルID|★画像ファイルのID★は各自手入力
      const fileId = '★画像ファイルのID★';

      //スクリプト関数の実行

      google.script.run
        //成功時の処理
        .withSuccessHandler(res => {

          //img要素を取得
          const img = document.getElementById("image");

          //ソースとして、BASE64エンコードされた文字列(res)を設定
          img.setAttribute("src", "data:image/png;base64," + res);


          //p要素を取得
          const msg = document.getElementById("msg");
     
          //メッセージのテキストの中身を変更する
          msg.textContent = res;

        })
        //失敗時の処理
        .withFailureHandler(console.error)

        //実行する関数
        .getBae64DATA(fileId);      
    })();
  </script>

<!--メモ:setAttribute  メソッドでの設定例--
 
GIF
data:image/gif;base64,[データ]
 
SVG
data:image/svg+xml;base64,[データ]
 
PDF
data:application/pdf;base64,[データ]-->

</html>

デプロイしたら、実行させてみてください。

上記の様なページが表示されたでしょうか?

うまくできなかった方は申し訳ないですが自己解決してみてください

以上、テンプレート内で、Gドライブ上の外部ファイルを利用するノウハウをシェアさせていただきました!


この記事が気に入ったらサポートをしてみませんか?