~edwardloveall/slack-emoji-downloader

ec4fa93babddc7d00b62c85ab4f259c8d180c195 — Edward Loveall 2 years ago
Initial version
3 files changed, 122 insertions(+), 0 deletions(-)

A .gitignore
A README.md
A fetch_emoji.rb
A  => .gitignore +1 -0
@@ 1,1 @@
downloaded

A  => README.md +26 -0
@@ 1,26 @@
# Download custom Slack emoji without admin access

You'll need the `Cookie` header, and the slack token to download the list of emoji. To get those, run the Slack team in a web browser. Open up the network panel, open the emoji panel and do a search. You'll see a `POST` request to something like: `https://edgeapi.slack.com/cache/<TEAM_ID>/emojis/search`. Inspect that request, note these values as environment variables in your shell:

* `SLACK_TEAM_ID`: The `TEAM_ID` in the `search` url
* `SLACK_TOKEN`: The `POST` body has a `token` with some dashes
* `SLACK_COOKIE`: The `POST` headers will have a `Cookie` header. You need the long header _value_ only, not the whole header.
* `SLACK_PLATFORM`: Optional. `apple` or `google`. Defaults to `apple`
  * This is because some emoji have platform-specific variants. Setting this variable sets which platform image to download.

You can set these like so:

```sh
export SLACK_TEAM_ID="TXXXXX"
export SLACK_TOKEN="xoxc-xxxxxx-xxxxxx"
export SLACK_COOKIE="x=l8f8gls55xf; foo=...; bar=..."
export SLACK_PLATFORM="apple"
```

Then run the script:

```ruby
ruby fetch_emoji.rb
```

First it downloads the list of all the emoji files. Then each emoji image. Emojis will download to a directory named `downloads`. All emoji aliases are skipped.

A  => fetch_emoji.rb +95 -0
@@ 1,95 @@
require "fileutils"
require "json"
require "net/http"
require "pathname"

class Config
  def self.download_folder
    "downloaded"
  end
end

class EmojiDownloader
  PAGE_COUNT = 100

  def initialize
    team_id = ENV.fetch("SLACK_TEAM_ID")
    @emoji_list_uri = URI("https://edgeapi.slack.com/cache/#{team_id}/emojis/list")
    FileUtils.mkdir_p(Config.download_folder)
  end

  def download
    download_list.each do |emoji_data|
      emoji = EmojiData.new(emoji_data)
      next if emoji.alias?

      image_response = Net::HTTP.get_response(URI(emoji.download_uri))
      File.open(emoji.local_path, "wb") do |file|
        file.write(image_response.body)
      end
      puts "saved: #{emoji.local_path}"
    end
  end

  private

  def download_list(marker: nil)
    puts "fetching metadata: (start)" if marker.nil?
    puts "fetching metadata at: #{marker}" if marker
    response = Net::HTTP.post(@emoji_list_uri, body(marker: marker), headers).body
    json = JSON.parse(response, symbolize_names: true)
    next_marker = json[:next_marker]

    if next_marker
      json[:results] + download_list(marker: next_marker)
    else
      json[:results]
    end
  end

  def body(marker: nil)
    { token: ENV.fetch("SLACK_TOKEN"), count: PAGE_COUNT }.tap do |body|
      body[:marker] = marker if marker
    end.to_json
  end

  def headers
    { "Cookie" => ENV.fetch("SLACK_COOKIE") }
  end
end

class EmojiData
  def initialize(data)
    @data = data
  end

  def local_path
    path = Pathname.new(download_uri)
    "#{Config.download_folder}/#{@data[:name]}#{path.extname}"
  end

  def download_uri
    if platform_variants?
      platform_download_uri
    else
      @data[:value]
    end
  end

  def platform_download_uri
    platform = ENV.fetch("SLACK_PLATFORM", :apple).to_sym
    @data[:value].fetch(platform)
  end

  def alias?
    @data.fetch(:is_alias, false)
  end

  private

  def platform_variants?
    @data[:value].is_a?(Hash) && (@data[:value][:apple] || @data[:value][:google])
  end
end

EmojiDownloader.new.download