Fork of Pleroma with site-specific changes and feature branches https://git.pleroma.social/pleroma/pleroma
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

141 行
3.0KB

  1. # Pleroma: A lightweight social networking server
  2. # Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
  3. # SPDX-License-Identifier: AGPL-3.0-only
  4. defmodule Pleroma.Emoji do
  5. @moduledoc """
  6. This GenServer stores in an ETS table the list of the loaded emojis,
  7. and also allows to reload the list at runtime.
  8. """
  9. use GenServer
  10. alias Pleroma.Emoji.Loader
  11. require Logger
  12. @ets __MODULE__.Ets
  13. @ets_options [
  14. :ordered_set,
  15. :protected,
  16. :named_table,
  17. {:read_concurrency, true}
  18. ]
  19. defstruct [:code, :file, :tags, :safe_code, :safe_file]
  20. @doc "Build emoji struct"
  21. def build({code, file, tags}) do
  22. %__MODULE__{
  23. code: code,
  24. file: file,
  25. tags: tags,
  26. safe_code: Pleroma.HTML.strip_tags(code),
  27. safe_file: Pleroma.HTML.strip_tags(file)
  28. }
  29. end
  30. def build({code, file}), do: build({code, file, []})
  31. @doc false
  32. def start_link(_) do
  33. GenServer.start_link(__MODULE__, [], name: __MODULE__)
  34. end
  35. @doc "Reloads the emojis from disk."
  36. @spec reload() :: :ok
  37. def reload do
  38. GenServer.call(__MODULE__, :reload)
  39. end
  40. @doc "Returns the path of the emoji `name`."
  41. @spec get(String.t()) :: String.t() | nil
  42. def get(name) do
  43. case :ets.lookup(@ets, name) do
  44. [{_, path}] -> path
  45. _ -> nil
  46. end
  47. end
  48. @spec exist?(String.t()) :: boolean()
  49. def exist?(name), do: not is_nil(get(name))
  50. @doc "Returns all the emojos!!"
  51. @spec get_all() :: list({String.t(), String.t(), String.t()})
  52. def get_all do
  53. :ets.tab2list(@ets)
  54. end
  55. @doc "Clear out old emojis"
  56. def clear_all, do: :ets.delete_all_objects(@ets)
  57. @doc false
  58. def init(_) do
  59. @ets = :ets.new(@ets, @ets_options)
  60. GenServer.cast(self(), :reload)
  61. {:ok, nil}
  62. end
  63. @doc false
  64. def handle_cast(:reload, state) do
  65. update_emojis(Loader.load())
  66. {:noreply, state}
  67. end
  68. @doc false
  69. def handle_call(:reload, _from, state) do
  70. update_emojis(Loader.load())
  71. {:reply, :ok, state}
  72. end
  73. @doc false
  74. def terminate(_, _) do
  75. :ok
  76. end
  77. @doc false
  78. def code_change(_old_vsn, state, _extra) do
  79. update_emojis(Loader.load())
  80. {:ok, state}
  81. end
  82. defp update_emojis(emojis) do
  83. :ets.insert(@ets, emojis)
  84. end
  85. @external_resource "lib/pleroma/emoji-test.txt"
  86. regional_indicators =
  87. Enum.map(127_462..127_487, fn codepoint ->
  88. <<codepoint::utf8>>
  89. end)
  90. emojis =
  91. @external_resource
  92. |> File.read!()
  93. |> String.split("\n")
  94. |> Enum.filter(fn line ->
  95. line != "" and not String.starts_with?(line, "#") and
  96. String.contains?(line, "fully-qualified")
  97. end)
  98. |> Enum.map(fn line ->
  99. line
  100. |> String.split(";", parts: 2)
  101. |> hd()
  102. |> String.trim()
  103. |> String.split()
  104. |> Enum.map(fn codepoint ->
  105. <<String.to_integer(codepoint, 16)::utf8>>
  106. end)
  107. |> Enum.join()
  108. end)
  109. |> Enum.uniq()
  110. emojis = emojis ++ regional_indicators
  111. for emoji <- emojis do
  112. def is_unicode_emoji?(unquote(emoji)), do: true
  113. end
  114. def is_unicode_emoji?(_), do: false
  115. end