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 Mix.Pleroma.start_pleroma()
13 Application.ensure_all_started(:hackney)
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
39 Mix.Pleroma.start_pleroma()
40 Application.ensure_all_started(:hackney)
42 {options, pack_names, []} = parse_global_opts(args)
44 manifest_url = if options[:manifest], do: options[:manifest], else: default_manifest()
46 manifest = fetch_manifest(manifest_url)
48 for pack_name <- pack_names do
49 if Map.has_key?(manifest, pack_name) do
50 pack = manifest[pack_name]
65 binary_archive = Tesla.get!(client(), src_url).body
66 archive_sha = :crypto.hash(:sha256, binary_archive) |> Base.encode16()
68 sha_status_text = ["SHA256 of ", :bright, pack_name, :normal, " source file is ", :bright]
70 if archive_sha == String.upcase(pack["src_sha256"]) do
71 IO.puts(IO.ANSI.format(sha_status_text ++ [:green, "OK"]))
73 IO.puts(IO.ANSI.format(sha_status_text ++ [:red, "BAD"]))
75 raise "Bad SHA256 for #{pack_name}"
78 # The url specified in files should be in the same directory
79 files_url = Path.join(Path.dirname(manifest_url), pack["files"])
83 "Fetching the file list for ",
93 files = Tesla.get!(client(), files_url).body |> Jason.decode!()
95 IO.puts(IO.ANSI.format(["Unpacking ", :bright, pack_name]))
99 Pleroma.Config.get!([:instance, :static_dir]),
107 fn {_, f} -> to_charlist(f) end
111 :zip.unzip(binary_archive,
113 file_list: files_to_unzip
116 IO.puts(IO.ANSI.format(["Writing pack.json for ", :bright, pack_name]))
120 "license" => pack["license"],
121 "homepage" => pack["homepage"],
122 "description" => pack["description"],
123 "fallback-src" => pack["src"],
124 "fallback-src-sha256" => pack["src_sha256"],
125 "share-files" => true
130 File.write!(Path.join(pack_path, "pack.json"), Jason.encode!(pack_json, pretty: true))
132 IO.puts(IO.ANSI.format([:bright, :red, "No pack named \"#{pack_name}\" found"]))
137 def run(["gen-pack", src]) do
138 Application.ensure_all_started(:hackney)
140 proposed_name = Path.basename(src) |> Path.rootname()
141 name = String.trim(IO.gets("Pack name [#{proposed_name}]: "))
142 # If there's no name, use the default one
143 name = if String.length(name) > 0, do: name, else: proposed_name
145 license = String.trim(IO.gets("License: "))
146 homepage = String.trim(IO.gets("Homepage: "))
147 description = String.trim(IO.gets("Description: "))
149 proposed_files_name = "#{name}.json"
150 files_name = String.trim(IO.gets("Save file list to [#{proposed_files_name}]: "))
151 files_name = if String.length(files_name) > 0, do: files_name, else: proposed_files_name
153 default_exts = [".png", ".gif"]
154 default_exts_str = Enum.join(default_exts, " ")
158 IO.gets("Emoji file extensions (separated with spaces) [#{default_exts_str}]: ")
162 if String.length(exts) > 0 do
163 String.split(exts, " ")
164 |> Enum.filter(fn e -> e |> String.trim() |> String.length() > 0 end)
169 IO.puts("Downloading the pack and generating SHA256")
171 binary_archive = Tesla.get!(client(), src).body
172 archive_sha = :crypto.hash(:sha256, binary_archive) |> Base.encode16()
174 IO.puts("SHA256 is #{archive_sha}")
180 description: description,
182 src_sha256: archive_sha,
187 tmp_pack_dir = Path.join(System.tmp_dir!(), "emoji-pack-#{name}")
195 emoji_map = Pleroma.Emoji.Loader.make_shortcode_to_file_map(tmp_pack_dir, exts)
197 File.write!(files_name, Jason.encode!(emoji_map, pretty: true))
201 #{files_name} has been created and contains the list of all found emojis in the pack.
202 Please review the files in the remove those not needed.
205 if File.exists?("index.json") do
206 existing_data = File.read!("index.json") |> Jason.decode!()
219 IO.puts("index.json file has been update with the #{name} pack")
221 File.write!("index.json", Jason.encode!(pack_json, pretty: true))
223 IO.puts("index.json has been created with the #{name} pack")
227 defp fetch_manifest(from) do
229 if String.starts_with?(from, "http") do
230 Tesla.get!(client(), from).body
237 defp parse_global_opts(args) do
251 {Tesla.Middleware.FollowRedirects, [max_redirects: 3]}
254 Tesla.client(middleware)
257 defp default_manifest, do: Pleroma.Config.get!([:emoji, :default_manifest])