emoji.ex 4.21 KB
Newer Older
1
# Pleroma: A lightweight social networking server
kaniini's avatar
kaniini committed
2
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
3
4
# SPDX-License-Identifier: AGPL-3.0-only

href's avatar
href committed
5
6
7
8
9
10
11
12
13
14
15
16
defmodule Pleroma.Emoji do
  @moduledoc """
  The emojis are loaded from:

    * the built-in Finmojis (if enabled in configuration),
    * the files: `config/emoji.txt` and `config/custom_emoji.txt`
    * glob paths

  This GenServer stores in an ETS table the list of the loaded emojis, and also allows to reload the list at runtime.
  """
  use GenServer
  @ets __MODULE__.Ets
href's avatar
href committed
17
  @ets_options [:ordered_set, :protected, :named_table, {:read_concurrency, true}]
href's avatar
href committed
18
19

  @doc false
20
  def start_link do
href's avatar
href committed
21
22
23
24
25
    GenServer.start_link(__MODULE__, [], name: __MODULE__)
  end

  @doc "Reloads the emojis from disk."
  @spec reload() :: :ok
26
  def reload do
href's avatar
href committed
27
28
29
30
31
32
33
34
35
36
37
38
39
40
    GenServer.call(__MODULE__, :reload)
  end

  @doc "Returns the path of the emoji `name`."
  @spec get(String.t()) :: String.t() | nil
  def get(name) do
    case :ets.lookup(@ets, name) do
      [{_, path}] -> path
      _ -> nil
    end
  end

  @doc "Returns all the emojos!!"
  @spec get_all() :: [{String.t(), String.t()}, ...]
41
  def get_all do
href's avatar
href committed
42
43
44
45
46
47
    :ets.tab2list(@ets)
  end

  @doc false
  def init(_) do
    @ets = :ets.new(@ets, @ets_options)
href's avatar
href committed
48
49
    GenServer.cast(self(), :reload)
    {:ok, nil}
href's avatar
href committed
50
51
52
  end

  @doc false
href's avatar
href committed
53
  def handle_cast(:reload, state) do
href's avatar
href committed
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
    load()
    {:noreply, state}
  end

  @doc false
  def handle_call(:reload, _from, state) do
    load()
    {:reply, :ok, state}
  end

  @doc false
  def terminate(_, _) do
    :ok
  end

  @doc false
  def code_change(_old_vsn, state, _extra) do
    load()
    {:ok, state}
  end

75
  defp load do
href's avatar
href committed
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
    emojis =
      (load_finmoji(Keyword.get(Application.get_env(:pleroma, :instance), :finmoji_enabled)) ++
         load_from_file("config/emoji.txt") ++
         load_from_file("config/custom_emoji.txt") ++
         load_from_globs(
           Keyword.get(Application.get_env(:pleroma, :emoji, []), :shortcode_globs, [])
         ))
      |> Enum.reject(fn value -> value == nil end)

    true = :ets.insert(@ets, emojis)
    :ok
  end

  @finmoji [
    "a_trusted_friend",
    "alandislands",
    "association",
    "auroraborealis",
    "baby_in_a_box",
    "bear",
    "black_gold",
    "christmasparty",
    "crosscountryskiing",
    "cupofcoffee",
    "education",
    "fashionista_finns",
    "finnishlove",
    "flag",
    "forest",
    "four_seasons_of_bbq",
    "girlpower",
    "handshake",
    "happiness",
    "headbanger",
    "icebreaker",
    "iceman",
    "joulutorttu",
    "kaamos",
    "kalsarikannit_f",
    "kalsarikannit_m",
    "karjalanpiirakka",
    "kicksled",
    "kokko",
    "lavatanssit",
    "losthopes_f",
    "losthopes_m",
    "mattinykanen",
    "meanwhileinfinland",
    "moominmamma",
    "nordicfamily",
    "out_of_office",
    "peacemaker",
    "perkele",
    "pesapallo",
    "polarbear",
    "pusa_hispida_saimensis",
    "reindeer",
    "sami",
    "sauna_f",
    "sauna_m",
    "sauna_whisk",
    "sisu",
    "stuck",
    "suomimainittu",
    "superfood",
    "swan",
    "the_cap",
    "the_conductor",
    "the_king",
    "the_voice",
    "theoriginalsanta",
    "tomoffinland",
    "torillatavataan",
    "unbreakable",
    "waiting",
    "white_nights",
    "woollysocks"
  ]
  defp load_finmoji(true) do
    Enum.map(@finmoji, fn finmoji ->
      {finmoji, "/finmoji/128px/#{finmoji}-128.png"}
    end)
  end

160
  defp load_finmoji(_), do: []
href's avatar
href committed
161
162
163
164
165
166
167
168
169
170
171

  defp load_from_file(file) do
    if File.exists?(file) do
      load_from_file_stream(File.stream!(file))
    else
      []
    end
  end

  defp load_from_file_stream(stream) do
    stream
Maksim's avatar
Maksim committed
172
    |> Stream.map(&String.trim/1)
href's avatar
href committed
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
    |> Stream.map(fn line ->
      case String.split(line, ~r/,\s*/) do
        [name, file] -> {name, file}
        _ -> nil
      end
    end)
    |> Enum.to_list()
  end

  defp load_from_globs(globs) do
    static_path = Path.join(:code.priv_dir(:pleroma), "static")

    paths =
      Enum.map(globs, fn glob ->
        Path.join(static_path, glob)
        |> Path.wildcard()
      end)
      |> Enum.concat()

    Enum.map(paths, fn path ->
      shortcode = Path.basename(path, Path.extname(path))
      external_path = Path.join("/", Path.relative_to(path, static_path))
      {shortcode, external_path}
    end)
  end
end