【GAS】ニコニコ動画のコメント取得方法【ニコメア】

# はじめに
ニコニコ動画でコメント返信をしようするとWeb上では特殊なリスト表示のためコピペしづらくなっています。それだと面倒なので「ニコメア」というツールを作って公開していましたが、他機種制作の要望がありましたのでGoogleスプレッドシート上で操作するスクリプトGoogle Apps Script(以降GAS)で作ってみました。

なお筆者はGAS初心者でこれが初めてのGASプログラムになります。

起動するとこうなります、シートはExcel版から持ってきました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/637460/e0ecaaa0-0b21-aab9-2d14-b604cc88abff.png)

コメントを取得する処理はシートのクリア、動画IDの取得、スレッドIDの取得、コメントの取得の4種類で構成しています。

```getComment.js
function getComment(){
  sheetInfoClear();
  sheetCommentClear();
  let id = getId();
  let threadId= HttpInfo(id);
  HttpComment(threadId);
}
```

## シートのクリア

シートごとの情報初期化処理です。sheetオブジェクトの**getLastRow();**メソッドで行数を取得しています。
getRangeの引数は 行,列,行数,列数で**clearContent**を使ってセルを空にしています。

```sheetClear.js
function sheetInfoClear(){
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('情報');
  sheet.getRange(6, 4, 9, 1).clearContent();
  sheet.getRange(6, 2, 10, 1).clearContent();
}

function sheetCommentClear(){
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('コメント');
  let y=2;
  const lastRow = sheet.getLastRow();
  sheet.getRange(y, 2, lastRow, 4).clearContent();
}
```

## Urlから動画IDを取得

urlから動画IDを取得します
先頭2文字が「sm」であれば動画IDとしています。
動画IDは末端から文字「/」を探してその手前までとなります。
```getId.js
function getId(){
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('情報');
  let url = sheet.getRange(2, 4).getValue();
  if (isId(url)){
    return url;
  }
  else{
    let i = url.lastIndexOf("/");
    let id = url.substring(i+1);
    sheet.getRange(2, 4).setValue(id);
    return id;
  }
}

function isId(id){
  if (id.substring(0,2) === "sm"){
    return true;
  }
  else{
    return false;
  }
}
```

## 動画IDから基本情報を取得

:::note alert
2023/3/31に3DSサポートが終了したことにより下記のAPIが使用不可能になりました
:::

スレッドID取得のためのAPIの解説はこちら

https://qiita.com/vram/items/0b14bc800ce8fd69b70d


動画IDを引数にして情報を取得表示してスレッドIDを返り値として渡します。
変数**url**に取得したいUrlを格納して**const docText = UrlFetchApp.fetch(url).getContentText()**でGetリクエストを実行して受信した結果を**docText**に格納します。

取得した情報は**JSON**形式のため**let json = JSON.parse(docText);**でJSONオブジェクトに変換した後**let res = json["niconico_response"]**などタグを指定して値を取得します。

セルへの書き込みは直接行わず二次元配列**oValues**に書き込んだ後、**setValues**メソッドで一度に書き込むことで高速化を実現しています。

```HttpInfo.js
// 指定したIDから各種情報を取得しスレッド番号を返す
function HttpInfo(id) {
  const url = "https://api.ce.nicovideo.jp/nicoapi/v1/video.info?v=" + id
  const docText = UrlFetchApp.fetch(url).getContentText();
  let json = JSON.parse(docText);
  let res = json["niconico_response"]
  tags = res["tags"]
  
  let s = "" 
  for(i=0;i<tags["tag_info"].length;i++){
    if(i>0){
      s = s + ","
    }
    s = s + tags["tag_info"][i]["tag"];
  }

  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('情報');
  let thread = res["thread"];
  let threadId = thread["id"];

  let video = res["video"];
  let oValues = [];
  oValues.push([video["title"]]);
  oValues.push([video["first_retrieve"]]);
  oValues.push([video["view_counter"]]);
  oValues.push([""]);
  oValues.push([video["mylist_counter"]]);
  oValues.push([video["genre"]["label"]]);
  oValues.push([""]);
  oValues.push([s]);
  sheet.getRange(6, 4, 8, 1).setValues(oValues);
  sheet.getRange(15, 2).setValue(video["description"]);
  let thumbnail = video["thumbnail_url"];
  sheet.getRange(6, 2).setValue('=IMAGE("' + thumbnail + '")');
  return threadId
}
```

## スレッドIDからコメントを取得
スレッドIDからコメントを取得します。
レコード型のようなJSON値ですがデータ数が取得できないため値が**undefined**になるまでループさせています。
二次元配列の1行文追加するため**oValues.push([chat["no"],chat["content"],vposs,vdate]);**のような記述になります。


```HttpComment.js
// 指定したスレッドIDからコメントを取得し表示 
function HttpComment(id){
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('コメント');
  url = "https://nvcomment.nicovideo.jp/legacy/api.json/thread?thread="
  url = url + id
  url = url + "&version=20090904&scores=1&fork=0&language=0&res_from=1-199"  
  const docText = UrlFetchApp.fetch(url).getContentText();
  //console.log(docText);
  let json = JSON.parse(docText);
  let oValues = [[]];
  let i = 2; 
  let cnt = 0;
  oValues.length = 0;
  while(true){
    let res = json[i];
    if (res === undefined) {
      break;
    }
    let chat = res["chat"];
    let vpos = chat["vpos"];
    let vposs = vposToStr(vpos)
    sheet.getRange(i, 4).setValue( vposs);
    let vdate = chat["date"];
    vdate = dateFromSn(vdate);
    oValues.push([chat["no"],chat["content"],vposs,vdate]);
    i++;
    cnt++;
  }
  sheet.getRange(2, 2, cnt, 4).setValues(oValues);
}
```

## 最後に
たったこれだけでコメントを取得することが出来ます。
次回は広告データを取得する方法を紹介します。

https://qiita.com/vram/items/8517cb0e8537bf4a24d2

上記方法で作成したニコメアのDLはこちら
[ニコメア](https://commons.nicovideo.jp/material/nc289171)