【GAS】Googleドライブにあるファイルをスプレッドシートにリスト化する【GoogleAppsScript】

## はじめに
この記事にあるコードは、[パソコンスキルの教科書](https://fastclassinfo.com/)というサイトにある[「Googleドライブ上のファイル名をスプレッドシートに書き出す方法｜GASプログラム活用事例」](https://fastclassinfo.com/entry/gas_getfilenames/)の記事を参考に作られています。
仕組みや各メソッドについて非常にわかりやすく解説されているので正直私が説明するまでもないのですが、復習も兼ねて自分用の備忘録として残しておきます。
※上記サイトだとGASの導入方法が古い情報になっているので申し訳程度にその解説もします…。

## やりたいこと
Googleドライブ内の特定のフォルダにあるファイル名を取得し、スプレッドシートに一覧化する作業をGoogleAppsScriptで自動化する。

## 前提条件
私自身の趣味で、アニメの主題歌をGoogleドライブで管理しており、今回はそのフォルダ内のファイルをリスト化していくという前提のもとで説明していく。
ディレクトリ構造としては、年月ごとのフォルダがあってその中に"【アニメタイトル】曲名【アーティスト名】.拡張子"という名前のファイルがあるというようなっている。

```Googleドライブ:アニメ主題歌フォルダ
アニメ主題歌
├ 2001-01
│ └ 【きつめのやばい】残業讃歌【imgur】.wav
├ 2001-04
│ └ 【鰤市】D-technoBreak【UberEATS】.wav
├ 2001-07
├ 2001-10
│ ├ 【端金の連勤術士】リトライ【アジ缶】.wav
│ └ 【けいこく！】ちくちく時間【業務後ティータイム】.wav
├ 2002-01
│ └ 【GTR】ヒトリノ夜勤【ポルノハブ】.wav
…
[以下省略]
```
ドライブ自体は年月という指標でフォルダ分けをしたが、アニメタイトルやアーティスト名でフィルタやソートを行いたいため、以下のようなシートを作るのが今回の目的である。

#### 主題歌リスト（スプレッドシート）
|   | A | B | C | D | E | … |
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
| 1 |   |   |   | 基準フォルダURL→ | [省略]  |
| 2 |   |   |   |   |   |
| 3 | 年月 | アニメタイトル | 曲名 | アーティスト名 | URL |
| 4 | 2001-01 | きつめのやばい | 残業讃歌 | imgur | [省略]  |
| 5 | 2001-04 | 鰤市 | D-technoBreak | UberEATS | [省略] |
| 6 | 2001-10 | 多金の連勤術士 | リトライ | アジ缶 | [省略]  |
| ： |

## コード全文
GAS（GoogleAppsScript）はJavaScriptベースで作られているので、GASを使ったことがなくてもJSの知識があれば理解できるかと思います。

::: note warn
一部特有の処理や変数があるので注意してください。
:::

```javascript:getFileName.gs
function getFileName() {
  //1|対象スプレッドシートを取得する
  const targetSpreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  const targetSheet = targetSpreadsheet.getActiveSheet();

  //2|基準フォルダの取得
  //E1に対象としたいgoogleDriveのフォルダURLを貼り付けておく
  const standardFolderUrl = targetSheet.getRange("E1").getValue();
  //スラッシュ分割URLの最後がID
  const standardFolderUrlArray= standardFolderUrl.split('/');
  const standardFolderId = standardFolderUrlArray[standardFolderUrlArray.length-1];
  const standardFolder = DriveApp.getFolderById(standardFolderId);

  //3|子フォルダ（年代）リストの作成
  const folderList = [];
  const childFolders= standardFolder.getFolders();
  //フォルダ取り出せるだけループ
  while(childFolders.hasNext()) {
    let childFolder = childFolders.next();
    let childFolderName = childFolder.getName();
    let childFolderUrl = childFolder.getUrl();
    let childFolderUrlArray= childFolderUrl.split('/');
    let childFolderId = childFolderUrlArray[childFolderUrlArray.length-1];
    //フォルダ名が年代になっているので
    folderList.push({ age: childFolderName, id: childFolderId })
  }

  //4|ファイル（楽曲）リストの作成
  const fileList = [];
  //子フォルダリスト内ループ
  for (let i = 0; i < folderList.length; i++) {
    let targetFolder = DriveApp.getFolderById(folderList[i].id);
    var targetFiles= targetFolder.getFiles();
    //ファイル取り出せるだけループ
    while(targetFiles.hasNext()) {
      let file = targetFiles.next();
      let fileName = file.getName();
      let fileNameArray = fileName.split(/[【】]/);
      //元ファイルが'【アニメタイトル】曲名【アーティスト名】.拡張子'なので
      let animeTitle = fileNameArray[1];
      let songName = fileNameArray[2];
      let artistName = fileNameArray[3];
      //シート項目に合わせて配置
      fileList.push([folderList[i].age, animeTitle, songName, artistName, file.getUrl()])
    }
  }

  //5|シートに情報を貼り付ける
  //3行目が項目になっていて、A4から内容を書き出していく
  targetSheet.getRange(4, 1, fileList.length, fileList[0].length).setValues(fileList);
}
```

## 準備するもの
・Googleドライブ
・Googleスプレッドシート
・GoogleAppsScript

## 使い方
### ステップ1　スプレッドシートを用意する
①スプレッドシートのE1にリスト化したいGoogleドライブのフォルダパスをコピペする。
②3行目に項目を書く。
|   | A | B | C | D | E | … |
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
| 1 |   |   |   | 基準フォルダURL→ | [ここにURLをコピペ] |
| 2 |   |   |   |   |   |
| 3 | 年月 | アニメタイトル | 曲名 | アーティスト名 | URL |
| ： |

### ステップ2　GoogleAppsScriptの追加
①タブ（ファイルとか編集があるところ）の[拡張機能]→[Apps Script]からGASの編集画面起動
```javascript:コード.gs
function myFunction() {
  
}
```
②↑の部分を消して上述のコードをコピペ

### ステップ3　シートからGoogleAppsScriptの起動
::: note
スプレッド上にボタンを作って呼び出す方法を使います。
:::

①タブの[挿入]→[図形描画]からシート上に適当な図形を作る。
②作った図形上で右クリックをし、図形の右上に出てくる：（・3つのやつ）→[スクリプト割り当て]
③割り当て画面で関数名（今回の場合は、getFileName）を入力して[OK]

あとは図形で作ったボタンをクリックすればスクリプトが実行されます。

## コード解説
メソッドについて調べたメモ等。

### ①対象スプレッドシートの取得
```javascript:
  const targetSpreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  const targetSheet = targetSpreadsheet.getActiveSheet();
```
+ `getActiveSpreadsheet()`：スプレッドシート（エクセルで言うところの.xlsxファイル）を取得する。
+ `getActiveSheet()`：シート（エクセルで言うところの[シート1]など）を取得する。

### ②基準フォルダの取得
```javascript:
  //E1に対象としたいgoogleDriveのフォルダURLを貼り付けておく
  const standardFolderUrl = targetSheet.getRange("E1").getValue();
  //スラッシュ分割URLの最後がID
  const standardFolderUrlArray= standardFolderUrl.split('/');
  const standardFolderId = standardFolderUrlArray[standardFolderUrlArray.length-1];
  const standardFolder = DriveApp.getFolderById(standardFolderId);
```
URLの最後の部分がフォルダやファイルのIDになるので、その部分だけ取得してます（配列は0からカウントなのでlength-1）。
わざわざこんなことをしなくてもIDの部分だけコード内に貼り付ければいいのですが、できるだけスプレッドシート上だけで完結させたいのでこうしました。

### ③子フォルダ（年代）リストの作成
```javascript:
  const folderList = [];
  const childFolders= standardFolder.getFolders();
  //フォルダ取り出せるだけループ
  while(childFolders.hasNext()) {
    let childFolder = childFolders.next();
    let childFolderName = childFolder.getName();
    let childFolderUrl = childFolder.getUrl();
    let childFolderUrlArray= childFolderUrl.split('/');
    let childFolderId = childFolderUrlArray[childFolderUrlArray.length-1];
    //フォルダ名が年代になっているので
    folderList.push({ age: childFolderName, id: childFolderId })
  }
```
+ `hasNext()`：次にデータがある場合trueを返す。
+ `next()`：次のデータを取得。

### ④ファイル（楽曲）リストの作成
```javascript:
  const fileList = [];
  //子フォルダリスト内ループ
  for (let i = 0; i < folderList.length; i++) {
    let targetFolder = DriveApp.getFolderById(folderList[i].id);
    var targetFiles= targetFolder.getFiles();
    //ファイル取り出せるだけループ
    while(targetFiles.hasNext()){
      let file = targetFiles.next();
      let fileName = file.getName();
      let fileNameArray = fileName.split(/[【】]/);
      //元ファイルが'【アニメタイトル】曲名【アーティスト名】.拡張子'なので
      let animeTitle = fileNameArray[1];
      let songName = fileNameArray[2];
      let artistName = fileNameArray[3];
      //シート項目に合わせて配置
      fileList.push([folderList[i].age, animeTitle, songName, artistName, file.getUrl()])
    }
  }
```
+ `split()`：複数の文字列で分割したい時は正規表現  **/[ ]/** が使える。
並べ替えしやすいように配列の要素をわざわざ変数に入れ直してますが、入れなくても問題ないです。
forとwhileは見比べるために書いただけで特にこだわりはないです。

###   ⑤シートに情報を貼り付ける
```javascript:
  //3行目が項目になっていて、A4から内容を書き出していく
  targetSheet.getRange(4, 1, fileList.length, fileList[0].length).setValues(fileList);
```
+ `getRange()`：(行番号, 列番号, 行範囲, 列範囲)が引数。普通に("A4:E9")みたいな使い方もできる。

## おわりに
初めてGASを書いてみたので、「ここはこうした方が良い」などあればコメントいただければと思います。
### 参考文献
+ [Googleドライブ上のファイル名をスプレッドシートに書き出す方法｜GASプログラム活用事例](https://fastclassinfo.com/entry/gas_getfilenames/)
+ [Google Apps Script　公式リファレンス](https://developers.google.com/apps-script/reference)