APIトークンなしでslackの絵文字(emoji)を一括エクスポート＆インポートする

# はじめに
Slackの絵文字を一括エクスポートする方法で、SlackのAPIトークンを取得して行う方法があります。

ですが、APIトークンの取得面倒くさいよくわからないという方（私です）向けに、APIトークンなしで一括エクスポートする方法を紹介します。

Slackにログインさえしていればできます。

# 対象読者
* ブラウザでデベロッパーツールが扱える（わからない方は[こちら](https://liginc.co.jp/449322)）
* node.jsの実行ができる（参考コードはありませんが他言語でも可）

# やり方
## 1. ワークスペースの絵文字を一覧取得する
Slackの左上のワークスペース名をクリックし、ワークスペースのカスタマイズをクリックします。
![スクリーンショット 2021-08-14 0.27.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1050360/ee0c1fe3-23de-0db3-6dc3-e76b989831d0.png)

すると次のような絵文字管理画面がブラウザで開かれるので、ネットワークを開いて「emoji list」と検索してください。emoji.listへのPOSTリクエストがあり、その応答にJSON形式で全ての絵文字があります。この「emoji」の項目を右クリックしてコピーしてください。

![スクリーンショット 2021-08-14 0.37.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1050360/9eeece8c-b7b3-eb28-5d27-13f009d0e894.png)

そして`emojis.json`というJSONファイルにして保存します。

```emojis.json
{
  "emoji": {
    "hoge": "https://emoji.slack-edge.com/TAXXXXXXX/10/XXXXXXXXXXXXX.png",
    "fuga": "https://emoji.slack-edge.com/TAXXXXXXX/11/XXXXXXXXXXXXX.png",
    ...
    "piyo": "https://emoji.slack-edge.com/TAXXXXXXX/12/XXXXXXXXXXXXX.png"
  }
}
```

## 2. 全emoji画像のダウンロード
あとは先ほど保存したJSONに記載されている全画像をスクリプトでダウンロードしてあげるだけです。ここではnodeを用いますが、pythonでもシェルスクリプトでもお好きなものでOKです。

先程のJSONがおいてあるフォルダで、node環境を構築します。nodeがインストールされてない方はインストールしてください。
（新しく空のフォルダを作ってそこでやるのが良いです）

```shell
npm init
npm install request fs
```

そして、次のスクリプトを作ります。

```dl.js
const fs = require("fs");
const request = require("request");

// jsonファイルを読み込む
const json = JSON.parse(fs.readFileSync("emojis.json", "utf8"));

var download = function (uri, filename, callback) {
  request.head(uri, function (_, res) {
    if (res.statusCode === 200) {
      request(uri).pipe(fs.createWriteStream(filename)).on("close", callback);
    } else {
      console.log("failed: ", filename);
    }
  });
};

Object.keys(json.emoji).forEach((name) => {
  const url = json.emoji[name]; // 画像URL

  // Objectの場合はaliasなので無視
  if (typeof url === "string") {
    const extension = url.match(/\..{3}$/); // 拡張子
    const filename = name + extension; // ファイル名

    // ダウンロード
    download(url, filename, function () {
      console.log("success: ", filename);
    });
  }
});
```

これを実行します。

```shell
> node dl.js
success: hoge.png
success: piyo.png # 成功
failed: fuga.png # 失敗
... 
```

ソースコードと同じディレクトリに絵文字がダウンロードされていきます。
失敗したらそのファイル名と一緒にfailedと表示されます。

## 3. 一括インポート

こちらのエクステンションを用いて、slackへ絵文字の一括アップロードが可能です：
[Chromeエクステンション](https://chrome.google.com/webstore/detail/neutral-face-emoji-tools/anchoacphlfbdomdlomnbbfhcmcdmjej)
[Firefoxエクステンション](https://addons.mozilla.org/ja/firefox/addon/neutral-face-emoji-tools/)

エクステンションを有効にすると、絵文字管理画面に次のような一括アップロード画面が表示されます。この枠内に絵文字をまとめてドラッグ＆ドロップするだけで一括インポートできます。

![スクリーンショット 2021-08-14 1.20.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1050360/abf579bf-540d-19f1-6197-03c894b9020f.png)


# 例外
## emoji.listが見つからない
ステップ1のネットワークで、今回利用したemoji.listがないケースもあります。そのときは、emoji.adminListを用いてください。ただし注意点があり、emoji.adminListは一回のリクエストで100件しか返ってきません。100件以上ある場合は、一度ページ上の絵文字一覧を一番下までスクロールして全件取得してください。するとネットワークにemoji.adminListのリクエストが必要回数分（300個の絵文字があるなら3件）表示されます。それぞれの応答をコピーペーストして、1つのjsonにまとめてください。またこの場合、jsonの形式が違うのでスクリプトに変更が必要です。次のスクリプトを用いてください。

```emojis.json
{
  "emoji": [
    {
      "name": "hoge",
      "is_alias": 0,
      "alias_for": "",
      "url": "https://emoji.slack-edge.com/TBXXXXXX/XXXXXX/XXXXXXXXXXXXXXX.png",
      "created": 1563092873,
      "team_id": "XXXXXXXX",
      "user_id": "XXXXXX",
      "user_display_name": "XXXX",
      "avatar_hash": "XXXXXXX",
      "can_delete": false,
      "is_bad": false,
      "synonyms": []
    },
    ...（略）
    {
      "name": "hoge",
      "is_alias": 0,
      "alias_for": "",
      "url": "https://emoji.slack-edge.com/TBXXXXXX/XXXXXX/XXXXXXXXXXXXXXX.png",
      "created": 1563092873,
      "team_id": "XXXXXXXX",
      "user_id": "XXXXXX",
      "user_display_name": "XXXX",
      "avatar_hash": "XXXXXXX",
      "can_delete": false,
      "is_bad": false,
      "synonyms": []
    }
}
```

```dl.js
const fs = require("fs");
const request = require("request");

const json = JSON.parse(fs.readFileSync("emojis.json", "utf8"));

var download = function (uri, filename, callback) {
  request.head(uri, function (_, res) {
    if (res.statusCode === 200) {
      request(uri).pipe(fs.createWriteStream(filename)).on("close", callback);
    } else {
      console.log("failed: ", filename);
    }
  });
};

json.emoji.forEach((emoji) => {
  const url = emoji.url; // 画像URL

  // aliasじゃない場合のみ実行
  if (emoji.is_alias === 0) {
    const extension = url.match(/\..{3}$/); // 拡張子
    const filename = emoji.name + extension; // ファイル名

    // ダウンロード
    download(url, filename, function () {
      console.log("success: ", filename);
    });
  }
});
```