logo

pleroma

My custom branche(s) on git.pleroma.social/pleroma/pleroma git clone https://hacktivis.me/git/pleroma.git

emoji.ex (7158B)


  1. # Pleroma: A lightweight social networking server
  2. # Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
  3. # SPDX-License-Identifier: AGPL-3.0-only
  4. defmodule Mix.Tasks.Pleroma.Emoji do
  5. use Mix.Task
  6. import Mix.Pleroma
  7. @shortdoc "Manages emoji packs"
  8. @moduledoc File.read!("docs/administration/CLI_tasks/emoji.md")
  9. def run(["ls-packs" | args]) do
  10. start_pleroma()
  11. {options, [], []} = parse_global_opts(args)
  12. url_or_path = options[:manifest] || default_manifest()
  13. manifest = fetch_and_decode!(url_or_path)
  14. Enum.each(manifest, fn {name, info} ->
  15. to_print = [
  16. {"Name", name},
  17. {"Homepage", info["homepage"]},
  18. {"Description", info["description"]},
  19. {"License", info["license"]},
  20. {"Source", info["src"]}
  21. ]
  22. for {param, value} <- to_print do
  23. IO.puts(IO.ANSI.format([:bright, param, :normal, ": ", value]))
  24. end
  25. # A newline
  26. IO.puts("")
  27. end)
  28. end
  29. def run(["get-packs" | args]) do
  30. start_pleroma()
  31. {options, pack_names, []} = parse_global_opts(args)
  32. url_or_path = options[:manifest] || default_manifest()
  33. manifest = fetch_and_decode!(url_or_path)
  34. for pack_name <- pack_names do
  35. if Map.has_key?(manifest, pack_name) do
  36. pack = manifest[pack_name]
  37. src = pack["src"]
  38. IO.puts(
  39. IO.ANSI.format([
  40. "Downloading ",
  41. :bright,
  42. pack_name,
  43. :normal,
  44. " from ",
  45. :underline,
  46. src
  47. ])
  48. )
  49. {:ok, binary_archive} = fetch(src)
  50. archive_sha = :crypto.hash(:sha256, binary_archive) |> Base.encode16()
  51. sha_status_text = ["SHA256 of ", :bright, pack_name, :normal, " source file is ", :bright]
  52. if archive_sha == String.upcase(pack["src_sha256"]) do
  53. IO.puts(IO.ANSI.format(sha_status_text ++ [:green, "OK"]))
  54. else
  55. IO.puts(IO.ANSI.format(sha_status_text ++ [:red, "BAD"]))
  56. raise "Bad SHA256 for #{pack_name}"
  57. end
  58. # The location specified in files should be in the same directory
  59. files_loc =
  60. url_or_path
  61. |> Path.dirname()
  62. |> Path.join(pack["files"])
  63. IO.puts(
  64. IO.ANSI.format([
  65. "Fetching the file list for ",
  66. :bright,
  67. pack_name,
  68. :normal,
  69. " from ",
  70. :underline,
  71. files_loc
  72. ])
  73. )
  74. files = fetch_and_decode!(files_loc)
  75. IO.puts(IO.ANSI.format(["Unpacking ", :bright, pack_name]))
  76. pack_path =
  77. Path.join([
  78. Pleroma.Config.get!([:instance, :static_dir]),
  79. "emoji",
  80. pack_name
  81. ])
  82. files_to_unzip =
  83. Enum.map(
  84. files,
  85. fn {_, f} -> to_charlist(f) end
  86. )
  87. {:ok, _} =
  88. :zip.unzip(binary_archive,
  89. cwd: String.to_charlist(pack_path),
  90. file_list: files_to_unzip
  91. )
  92. IO.puts(IO.ANSI.format(["Writing pack.json for ", :bright, pack_name]))
  93. pack_json = %{
  94. pack: %{
  95. "license" => pack["license"],
  96. "homepage" => pack["homepage"],
  97. "description" => pack["description"],
  98. "fallback-src" => pack["src"],
  99. "fallback-src-sha256" => pack["src_sha256"],
  100. "share-files" => true
  101. },
  102. files: files
  103. }
  104. File.write!(Path.join(pack_path, "pack.json"), Jason.encode!(pack_json, pretty: true))
  105. else
  106. IO.puts(IO.ANSI.format([:bright, :red, "No pack named \"#{pack_name}\" found"]))
  107. end
  108. end
  109. end
  110. def run(["gen-pack" | args]) do
  111. start_pleroma()
  112. {opts, [src], []} =
  113. OptionParser.parse(
  114. args,
  115. strict: [
  116. name: :string,
  117. license: :string,
  118. homepage: :string,
  119. description: :string,
  120. files: :string,
  121. extensions: :string
  122. ]
  123. )
  124. proposed_name = Path.basename(src) |> Path.rootname()
  125. name = get_option(opts, :name, "Pack name:", proposed_name)
  126. license = get_option(opts, :license, "License:")
  127. homepage = get_option(opts, :homepage, "Homepage:")
  128. description = get_option(opts, :description, "Description:")
  129. proposed_files_name = "#{name}_files.json"
  130. files_name = get_option(opts, :files, "Save file list to:", proposed_files_name)
  131. default_exts = [".png", ".gif"]
  132. custom_exts =
  133. get_option(
  134. opts,
  135. :extensions,
  136. "Emoji file extensions (separated with spaces):",
  137. Enum.join(default_exts, " ")
  138. )
  139. |> String.split(" ", trim: true)
  140. exts =
  141. if MapSet.equal?(MapSet.new(default_exts), MapSet.new(custom_exts)) do
  142. default_exts
  143. else
  144. custom_exts
  145. end
  146. IO.puts("Using #{Enum.join(exts, " ")} extensions")
  147. IO.puts("Downloading the pack and generating SHA256")
  148. {:ok, %{body: binary_archive}} = Pleroma.HTTP.get(src)
  149. archive_sha = :crypto.hash(:sha256, binary_archive) |> Base.encode16()
  150. IO.puts("SHA256 is #{archive_sha}")
  151. pack_json = %{
  152. name => %{
  153. license: license,
  154. homepage: homepage,
  155. description: description,
  156. src: src,
  157. src_sha256: archive_sha,
  158. files: files_name
  159. }
  160. }
  161. tmp_pack_dir = Path.join(System.tmp_dir!(), "emoji-pack-#{name}")
  162. {:ok, _} = :zip.unzip(binary_archive, cwd: String.to_charlist(tmp_pack_dir))
  163. emoji_map = Pleroma.Emoji.Loader.make_shortcode_to_file_map(tmp_pack_dir, exts)
  164. File.write!(files_name, Jason.encode!(emoji_map, pretty: true))
  165. IO.puts("""
  166. #{files_name} has been created and contains the list of all found emojis in the pack.
  167. Please review the files in the pack and remove those not needed.
  168. """)
  169. pack_file = "#{name}.json"
  170. if File.exists?(pack_file) do
  171. existing_data = File.read!(pack_file) |> Jason.decode!()
  172. File.write!(
  173. pack_file,
  174. Jason.encode!(
  175. Map.merge(
  176. existing_data,
  177. pack_json
  178. ),
  179. pretty: true
  180. )
  181. )
  182. IO.puts("#{pack_file} has been updated with the #{name} pack")
  183. else
  184. File.write!(pack_file, Jason.encode!(pack_json, pretty: true))
  185. IO.puts("#{pack_file} has been created with the #{name} pack")
  186. end
  187. end
  188. def run(["reload"]) do
  189. start_pleroma()
  190. Pleroma.Emoji.reload()
  191. IO.puts("Emoji packs have been reloaded.")
  192. end
  193. defp fetch_and_decode!(from) do
  194. with {:ok, json} <- fetch(from) do
  195. Jason.decode!(json)
  196. else
  197. {:error, error} -> raise "#{from} cannot be fetched. Error: #{error} occur."
  198. end
  199. end
  200. defp fetch("http" <> _ = from) do
  201. with {:ok, %{body: body}} <- Pleroma.HTTP.get(from) do
  202. {:ok, body}
  203. end
  204. end
  205. defp fetch(path), do: File.read(path)
  206. defp parse_global_opts(args) do
  207. OptionParser.parse(
  208. args,
  209. strict: [
  210. manifest: :string
  211. ],
  212. aliases: [
  213. m: :manifest
  214. ]
  215. )
  216. end
  217. defp default_manifest, do: Pleroma.Config.get!([:emoji, :default_manifest])
  218. end