1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
5 defmodule Mix.Tasks.Pleroma.Emoji do
8 @shortdoc "Manages Pleroma instance"
12 @default_manifest "https://git.pleroma.social/vaartis/emoji-index/raw/master/index.json"
14 def run(["ls-packs" | args]) do
15 Application.ensure_all_started(:hackney)
17 {options, [], []} = parse_global_opts(args)
20 fetch_manifest(if options[:manifest], do: options[:manifest], else: @default_manifest)
22 Enum.each(manifest, fn {name, info} ->
25 {"Homepage", info["homepage"]},
26 {"Description", info["description"]},
27 {"License", info["license"]},
28 {"Source", info["src"]}
31 for {param, value} <- to_print do
32 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!(src_url).body
64 archive_md5 = :crypto.hash(:md5, binary_archive) |> Base.encode16()
66 md5_status_text = ["MD5 of ", :bright, pack_name, :normal, " source file is ", :bright]
67 if archive_md5 == String.upcase(pack["src_md5"]) do
68 IO.puts(IO.ANSI.format(md5_status_text ++ [:green, "OK"]))
70 IO.puts(IO.ANSI.format(md5_status_text ++ [:red, "BAD"]))
72 raise "Bad MD5 for #{pack_name}"
75 # The url specified in files should be in the same directory
76 files_url = Path.join(Path.dirname(manifest_url), pack["files"])
80 "Fetching the file list for ",
90 files = Tesla.get!(files_url).body |> Poison.decode!()
92 IO.puts(IO.ANSI.format(["Unpacking ", :bright, pack_name]))
94 static_path = Path.join(:code.priv_dir(:pleroma), "static")
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 emoji.txt for ", :bright, pack_name]))
121 fn {shortcode, path} ->
122 "#{shortcode}, /instance/static/emoji/#{pack_name}/#{path}"
127 File.write!(Path.join(pack_path, "emoji.txt"), emoji_txt_str)
129 IO.puts(IO.ANSI.format([:bright, :red, "No pack named \"#{pack_name}\" found"]))
134 def run(["gen-pack", src]) do
135 Application.ensure_all_started(:hackney)
137 proposed_name = Path.basename(src) |> Path.rootname()
138 name = String.trim(IO.gets("Pack name [#{proposed_name}]: "))
139 # If there's no name, use the default one
140 name = if String.length(name) > 0, do: name, else: proposed_name
142 license = String.trim(IO.gets("License: "))
143 homepage = String.trim(IO.gets("Homepage: "))
144 description = String.trim(IO.gets("Description: "))
146 proposed_files_name = "#{name}.json"
147 files_name = String.trim(IO.gets("Save file list to [#{proposed_files_name}]: "))
148 files_name = if String.length(files_name) > 0, do: files_name, else: proposed_files_name
150 default_exts = [".png", ".gif"]
151 default_exts_str = Enum.join(default_exts, " ")
153 String.trim(IO.gets("Emoji file extensions (separated with spaces) [#{default_exts_str}]: "))
154 exts = if String.length(exts) > 0 do
155 String.split(exts, " ") |> Enum.filter(fn e -> (e |> String.trim() |> String.length()) > 0 end)
160 IO.puts "Downloading the pack and generating MD5"
162 binary_archive = Tesla.get!(src).body
163 archive_md5 = :crypto.hash(:md5, binary_archive) |> Base.encode16()
165 IO.puts "MD5 is #{archive_md5}"
171 description: description,
173 src_md5: archive_md5,
178 tmp_pack_dir = Path.join(System.tmp_dir!(), "emoji-pack-#{name}")
186 find_all_emoji(tmp_pack_dir, exts) |>
187 Enum.map(&Path.relative_to(&1, tmp_pack_dir)) |>
188 Enum.map(fn f -> {f |> Path.basename() |> Path.rootname(), f} end) |>
191 File.write!(files_name, Poison.encode!(emoji_map, pretty: true))
195 #{files_name} has been created and contains the list of all found emojis in the pack.
196 Please review the files in the remove those not needed.
199 if File.exists?("index.json") do
200 existing_data = File.read!("index.json") |> Poison.decode!()
213 IO.puts "index.json file has been update with the #{name} pack"
215 File.write!("index.json", Poison.encode!(pack_json, pretty: true))
217 IO.puts "index.json has been created with the #{name} pack"
222 defp find_all_emoji(dir, exts) do
227 filepath = Path.join(dir, f)
228 if File.dir?(filepath) do
229 acc ++ find_all_emoji(filepath, exts)
234 ) |> Enum.filter(fn f -> Path.extname(f) in exts end)
237 defp fetch_manifest(from) do
238 Tesla.get!(from).body |> Poison.decode!()
241 defp parse_global_opts(args) do