【GAS】複数ファイルに分散したスライドを１つのファイルに自動でまとめる

実施した環境：MacOS Big sur, Google Chrome 96.0.4664.11
実施日：2021/12/29

<h2>概略</h2>
複数のスライドを確認する際に、１つ１つファイルを開いて中身を確認するのは面倒です。
Google slideの標準機能に「インポート」は存在するが、１つのファイルしか選択ができません（執筆時点）。
そのため、確認したいスライドのファイルが20個ある場合、標準機能ではすべてのファイルを開くかインポートを手作業で20回繰り返すしかないです。
その作業を省くためのGASを作成しました。以下、概略図です。

![１つのファイルへ.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/353945/318bea4c-dc96-cc90-c985-279c27c92359.jpeg)

フォルダAには複数のスライドファイルがあります。これから紹介するGASのコードで自動変換することで、フォルダBに１つにまとめたファイルを生成します。なお、フォルダAにはスライド以外のスプレッドシート等のファイルがあっても問題ありません。スライドのファイルだけを抽出して処理を行います。また、フォルダAのスライドはコピーで１つのファイルにインポートするので、元ファイルは残ります。

各自で手入力しなければない値は、下記の３つ（概略図の青字部分）だけです。
<b>・フォルダAのURL</b>
<b>・フォルダBのURL</b> ＊フォルダAと同じURLでもOK
<b>・生成するファイルの名前</b>

<h2>使用シーン</h2>
複数ファイルのスライドを１ファイルで一気に見たい時にこのGASが有効です。
Google for educationを使用している場合は、classroomで収集した生徒のスライドを１つにまとめることもできます。そうすることで、先生が一度にすべての生徒の提出物を確認できるます。また各生徒に写真をスライドに貼って提出させ、１ファイルにまとめればクラスの写真集を作成することもできます。

<h2>コード</h2>
```Javascript
function folderToslides() {
  //手入力する設定値
  const slidesFolderURL = 'https://drive.google.com/xxxxxxxx'; //フォルダAのURL
  const destinationFolderURL = 'https://drive.google.com/yyyyyyyyyy'; //フォルダBのURL  
  const fileTitle = '〇〇集'; //生成するファイル名

  //スライドが集められているフォルダAから、スライドのファイルだけ抽出
  const slidesFolderArray = slidesFolderURL.split('/');
  const slidesFolderId = slidesFolderArray[slidesFolderArray.length-1];
  const slidesFolder = DriveApp.getFolderById(slidesFolderId);
  const subSlides = slidesFolder.getFilesByType(MimeType.GOOGLE_SLIDES);

  //雛形となるファイル(スライド)を作成し、格納先フォルダBへ移動
  const tempSlideId = SlidesApp.create(fileTitle).getId();
  const tempSlideDrive = DriveApp.getFileById(tempSlideId);
  const destinationFolderArray = destinationFolderURL.split('/');
  const destinationFolderId = destinationFolderArray[destinationFolderArray.length-1];
  const destinationFolder = DriveApp.getFolderById(destinationFolderId);
  tempSlideDrive.moveTo(destinationFolder);

  //デフォルトのスライドが残らないように１枚目を削除
  const slideFile = SlidesApp.openById(tempSlideId);
  slideFile.getSlides()[0].remove();

  //複数のスライドを雛形のファイルにインポートする
  while (subSlides.hasNext()){
    const file = subSlides.next();
    var slideUrl = file.getUrl();
    var insertPre = SlidesApp.openByUrl(slideUrl);
    var slideData = insertPre.getSlides();
      for(var i=0;i<slideData.length;i++){
        var template = insertPre.getSlides()[i];
        slideFile.appendSlide(template);
      }
  }
}
```

<h2>コードの解説</h2>
コード内のコメントで内容がわかる部分については割愛します。
<h4>スライドのファイルを抽出</h4>

```Javascript
  //スライドが集められているフォルダAから、スライドのファイルだけ抽出
  const slidesFolderArray = slidesFolderURL.split('/');
  const slidesFolderId = slidesFolderArray[slidesFolderArray.length-1];
  const slidesFolder = DriveApp.getFolderById(slidesFolderId);
  const subSlides = slidesFolder.getFilesByType(MimeType.GOOGLE_SLIDES);
```
splitを使用して、手入力で設定したフォルダAのURLからIDだけを取得します。
取得したIDをもとに、フォルダAのスライドファイルだけをGETします。

<h4>雛形スライドの作成と移動</h4>

```Javascript
  //雛形となるファイル(スライド)を作成し、格納先フォルダBへ移動
  const tempSlideId = SlidesApp.create(fileTitle).getId();
  const tempSlideDrive = DriveApp.getFileById(tempSlideId);
  const destinationFolderArray = destinationFolderURL.split('/');
  const destinationFolderId = destinationFolderArray[destinationFolderArray.length-1];
  const destinationFolder = DriveApp.getFolderById(destinationFolderId);
  tempSlideDrive.moveTo(destinationFolder);
```
複数のスライドを１つにまとめる雛形のファイルを作成します。
雛形ファイルを作成した後、手入力したフォルダBのURLをもとに、こちらでもsplitを使用してIDを取得します。
取得したIDをもとに、雛形ファイルをフォルダBのへ移動させます。

<h4>雛形ファイルにあるスライドを削除</h4>

```Javascript
  //デフォルトのスライドが残らないように１枚目を削除
  const slideFile = SlidesApp.openById(tempSlideId);
  slideFile.getSlides()[0].remove();
```
スライドを新規作成すると、１枚目にデフォルトのスライドが挿入されている。
このまま複数のスライドを雛形ファイルにインポートすると、デフォルトで作成されるスライドが混入してしまう。
デフォルト設定の変更方法がわからなかったので、ここでは事前に雛形ファイルの１枚目を削除しています。

<h4>while文とfor文の内容</h4>

```Javascript
  //複数のスライドを雛形のファイルにインポートする
  while (subSlides.hasNext()){
    const file = subSlides.next();
    var slideUrl = file.getUrl();
    var insertPre = SlidesApp.openByUrl(slideUrl);
    var slideData = insertPre.getSlides();
      for(var i=0;i<slideData.length;i++){
        var template = insertPre.getSlides()[i];
        slideFile.appendSlide(template);
      }
  }
```
while文では、フォルダAにあるスライドファイルを１つずつ確認しています。hasNextやsubSlides.next()の使い方については、「フォルダコレクションの取得」で検索すれば調べることができます。要はフォルダ内のファイルを順番に取り出すときに使用する反復処理です。
For文では、対象ファイル内にあるスライドを１つずつ取り出し、雛形ファイルへインポートしています。

<h2>実例</h2>
たとえば、生徒に好きな食べ物を提出してもらうとしましょう。スライドに料理の写真をつけて提出させます。以下のように、Googleドライブにファイルが集まっています。３ファイルがあります。このフォルダがフォルダAとなります。
ちなみに３ファイルには、それぞれタイトルが書かれたスライドと料理写真が貼られたスライドの２スライドが作成されています。
![スクリーンショット 2021-12-29 17.14.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/353945/527beaf7-c27c-30c5-42ca-59735e1c8000.png)

上記のGASを使用します。ファイル名は「1年１組の提出物」にしました。
下の画像がフォルダBに作成されたファイルです。

![スクリーンショット 2021-12-29 17.20.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/353945/f67207f5-31a8-9b1b-61ec-33e14746c9fe.png)

ファイルの中を確認してみます。「やきそば」「ピッツァ」「そうめん」の３ファイルがインポートされているのがわかります。
これで生徒の提出物を順番に確認することができます。また、複数のファイルを１つずつ開く必要もありません。

![スクリーンショット 2021-12-29 17.25.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/353945/ad3e3176-22a8-38af-2138-004565b57514.png)

<h2>備考</h2>
今回は２つのURLとファイル名を手入力でスクリプトに直接入力する想定でした。操作ミスや保守のことを考えると、スプレッドシートにバインドさせる形で実装し、設定値はスプレッドシートから取得するのがよろしいかと思います。