1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
5 defmodule Mix.Tasks.Pleroma.Emoji do
8 @shortdoc "Manages emoji packs"
9 @moduledoc File.read!("docs/administration/CLI_tasks/emoji.md")
11 def run(["ls-packs" | args]) do
12 Application.ensure_all_started(:hackney)
14 {options, [], []} = parse_global_opts(args)
17 fetch_manifest(if options[:manifest], do: options[:manifest], else: default_manifest())
19 Enum.each(manifest, fn {name, info} ->
22 {"Homepage", info["homepage"]},
23 {"Description", info["description"]},
24 {"License", info["license"]},
25 {"Source", info["src"]}
28 for {param, value} <- to_print do
29 IO.puts(IO.ANSI.format([:bright, param, :normal, ": ", value]))
37 def run(["get-packs" | args]) do
38 Application.ensure_all_started(:hackney)
40 {options, pack_names, []} = parse_global_opts(args)
42 manifest_url = if options[:manifest], do: options[:manifest], else: default_manifest()
44 manifest = fetch_manifest(manifest_url)
46 for pack_name <- pack_names do
47 if Map.has_key?(manifest, pack_name) do
48 pack = manifest[pack_name]
63 binary_archive = Tesla.get!(client(), src_url).body
64 archive_sha = :crypto.hash(:sha256, binary_archive) |> Base.encode16()
66 sha_status_text = ["SHA256 of ", :bright, pack_name, :normal, " source file is ", :bright]
68 if archive_sha == String.upcase(pack["src_sha256"]) do
69 IO.puts(IO.ANSI.format(sha_status_text ++ [:green, "OK"]))
71 IO.puts(IO.ANSI.format(sha_status_text ++ [:red, "BAD"]))
73 raise "Bad SHA256 for #{pack_name}"
76 # The url specified in files should be in the same directory
77 files_url = Path.join(Path.dirname(manifest_url), pack["files"])
81 "Fetching the file list for ",
91 files = Tesla.get!(client(), files_url).body |> Jason.decode!()
93 IO.puts(IO.ANSI.format(["Unpacking ", :bright, pack_name]))
97 Pleroma.Config.get!([:instance, :static_dir]),
105 fn {_, f} -> to_charlist(f) end
109 :zip.unzip(binary_archive,
111 file_list: files_to_unzip
114 IO.puts(IO.ANSI.format(["Writing emoji.txt for ", :bright, pack_name]))
119 fn {shortcode, path} ->
120 emojo_path = Path.join("/emoji/#{pack_name}", path)
121 "#{shortcode}, #{emojo_path}"
126 File.write!(Path.join(pack_path, "emoji.txt"), emoji_txt_str)
128 IO.puts(IO.ANSI.format([:bright, :red, "No pack named \"#{pack_name}\" found"]))
133 def run(["gen-pack", src]) do
134 Application.ensure_all_started(:hackney)
136 proposed_name = Path.basename(src) |> Path.rootname()
137 name = String.trim(IO.gets("Pack name [#{proposed_name}]: "))
138 # If there's no name, use the default one
139 name = if String.length(name) > 0, do: name, else: proposed_name
141 license = String.trim(IO.gets("License: "))
142 homepage = String.trim(IO.gets("Homepage: "))
143 description = String.trim(IO.gets("Description: "))
145 proposed_files_name = "#{name}.json"
146 files_name = String.trim(IO.gets("Save file list to [#{proposed_files_name}]: "))
147 files_name = if String.length(files_name) > 0, do: files_name, else: proposed_files_name
149 default_exts = [".png", ".gif"]
150 default_exts_str = Enum.join(default_exts, " ")
154 IO.gets("Emoji file extensions (separated with spaces) [#{default_exts_str}]: ")
158 if String.length(exts) > 0 do
159 String.split(exts, " ")
160 |> Enum.filter(fn e -> e |> String.trim() |> String.length() > 0 end)
165 IO.puts("Downloading the pack and generating SHA256")
167 binary_archive = Tesla.get!(client(), src).body
168 archive_sha = :crypto.hash(:sha256, binary_archive) |> Base.encode16()
170 IO.puts("SHA256 is #{archive_sha}")
176 description: description,
178 src_sha256: archive_sha,
183 tmp_pack_dir = Path.join(System.tmp_dir!(), "emoji-pack-#{name}")
191 emoji_map = Pleroma.Emoji.Loader.make_shortcode_to_file_map(tmp_pack_dir, exts)
193 File.write!(files_name, Jason.encode!(emoji_map, pretty: true))
197 #{files_name} has been created and contains the list of all found emojis in the pack.
198 Please review the files in the remove those not needed.
201 if File.exists?("index.json") do
202 existing_data = File.read!("index.json") |> Jason.decode!()
215 IO.puts("index.json file has been update with the #{name} pack")
217 File.write!("index.json", Jason.encode!(pack_json, pretty: true))
219 IO.puts("index.json has been created with the #{name} pack")
223 defp fetch_manifest(from) do
225 if String.starts_with?(from, "http") do
226 Tesla.get!(client(), from).body
233 defp parse_global_opts(args) do
247 {Tesla.Middleware.FollowRedirects, [max_redirects: 3]}
250 Tesla.client(middleware)
253 defp default_manifest, do: Pleroma.Config.get!([:emoji, :default_manifest])