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
9 @shortdoc "Manages emoji packs"
10 @moduledoc File.read!("docs/administration/CLI_tasks/emoji.md")
12 def run(["ls-packs" | args]) do
15 {options, [], []} = parse_global_opts(args)
18 fetch_manifest(if options[:manifest], do: options[:manifest], else: default_manifest())
20 Enum.each(manifest, fn {name, info} ->
23 {"Homepage", info["homepage"]},
24 {"Description", info["description"]},
25 {"License", info["license"]},
26 {"Source", info["src"]}
29 for {param, value} <- to_print do
30 IO.puts(IO.ANSI.format([:bright, param, :normal, ": ", value]))
38 def run(["get-packs" | args]) do
41 {options, pack_names, []} = parse_global_opts(args)
43 manifest_url = if options[:manifest], do: options[:manifest], else: default_manifest()
45 manifest = fetch_manifest(manifest_url)
47 for pack_name <- pack_names do
48 if Map.has_key?(manifest, pack_name) do
49 pack = manifest[pack_name]
64 binary_archive = Tesla.get!(client(), src_url).body
65 archive_sha = :crypto.hash(:sha256, binary_archive) |> Base.encode16()
67 sha_status_text = ["SHA256 of ", :bright, pack_name, :normal, " source file is ", :bright]
69 if archive_sha == String.upcase(pack["src_sha256"]) do
70 IO.puts(IO.ANSI.format(sha_status_text ++ [:green, "OK"]))
72 IO.puts(IO.ANSI.format(sha_status_text ++ [:red, "BAD"]))
74 raise "Bad SHA256 for #{pack_name}"
77 # The url specified in files should be in the same directory
78 files_url = Path.join(Path.dirname(manifest_url), pack["files"])
82 "Fetching the file list for ",
92 files = Tesla.get!(client(), files_url).body |> Jason.decode!()
94 IO.puts(IO.ANSI.format(["Unpacking ", :bright, pack_name]))
98 Pleroma.Config.get!([:instance, :static_dir]),
106 fn {_, f} -> to_charlist(f) end
110 :zip.unzip(binary_archive,
112 file_list: files_to_unzip
115 IO.puts(IO.ANSI.format(["Writing pack.json for ", :bright, pack_name]))
119 "license" => pack["license"],
120 "homepage" => pack["homepage"],
121 "description" => pack["description"],
122 "fallback-src" => pack["src"],
123 "fallback-src-sha256" => pack["src_sha256"],
124 "share-files" => true
129 File.write!(Path.join(pack_path, "pack.json"), Jason.encode!(pack_json, pretty: true))
131 IO.puts(IO.ANSI.format([:bright, :red, "No pack named \"#{pack_name}\" found"]))
136 def run(["gen-pack", src]) do
139 proposed_name = Path.basename(src) |> Path.rootname()
140 name = String.trim(IO.gets("Pack name [#{proposed_name}]: "))
141 # If there's no name, use the default one
142 name = if String.length(name) > 0, do: name, else: proposed_name
144 license = String.trim(IO.gets("License: "))
145 homepage = String.trim(IO.gets("Homepage: "))
146 description = String.trim(IO.gets("Description: "))
148 proposed_files_name = "#{name}.json"
149 files_name = String.trim(IO.gets("Save file list to [#{proposed_files_name}]: "))
150 files_name = if String.length(files_name) > 0, do: files_name, else: proposed_files_name
152 default_exts = [".png", ".gif"]
153 default_exts_str = Enum.join(default_exts, " ")
157 IO.gets("Emoji file extensions (separated with spaces) [#{default_exts_str}]: ")
161 if String.length(exts) > 0 do
162 String.split(exts, " ")
163 |> Enum.filter(fn e -> e |> String.trim() |> String.length() > 0 end)
168 IO.puts("Downloading the pack and generating SHA256")
170 binary_archive = Tesla.get!(client(), src).body
171 archive_sha = :crypto.hash(:sha256, binary_archive) |> Base.encode16()
173 IO.puts("SHA256 is #{archive_sha}")
179 description: description,
181 src_sha256: archive_sha,
186 tmp_pack_dir = Path.join(System.tmp_dir!(), "emoji-pack-#{name}")
194 emoji_map = Pleroma.Emoji.Loader.make_shortcode_to_file_map(tmp_pack_dir, exts)
196 File.write!(files_name, Jason.encode!(emoji_map, pretty: true))
200 #{files_name} has been created and contains the list of all found emojis in the pack.
201 Please review the files in the remove those not needed.
204 if File.exists?("index.json") do
205 existing_data = File.read!("index.json") |> Jason.decode!()
218 IO.puts("index.json file has been update with the #{name} pack")
220 File.write!("index.json", Jason.encode!(pack_json, pretty: true))
222 IO.puts("index.json has been created with the #{name} pack")
226 defp fetch_manifest(from) do
228 if String.starts_with?(from, "http") do
229 Tesla.get!(client(), from).body
236 defp parse_global_opts(args) do
250 {Tesla.Middleware.FollowRedirects, [max_redirects: 3]}
253 Tesla.client(middleware)
256 defp default_manifest, do: Pleroma.Config.get!([:emoji, :default_manifest])