Assume packs without emoji.txt only have emoji pictures, unhardcode
[akkoma] / lib / mix / tasks / pleroma / emoji.ex
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4
5 defmodule Mix.Tasks.Pleroma.Emoji do
6 use Mix.Task
7
8 @shortdoc "Manages Pleroma instance"
9 @moduledoc """
10 """
11
12 @default_manifest "https://git.pleroma.social/vaartis/emoji-index/raw/master/index.json"
13
14 def run(["ls-packs" | args]) do
15 Application.ensure_all_started(:hackney)
16
17 {options, [], []} = parse_global_opts(args)
18
19 manifest =
20 fetch_manifest(if options[:manifest], do: options[:manifest], else: @default_manifest)
21
22 Enum.each(manifest, fn {name, info} ->
23 to_print = [
24 {"Name", name},
25 {"Homepage", info["homepage"]},
26 {"Description", info["description"]},
27 {"License", info["license"]},
28 {"Source", info["src"]}
29 ]
30
31 for {param, value} <- to_print do
32 IO.puts(IO.ANSI.format([:bright, param, :normal, ": ", value]))
33 end
34 end)
35 end
36
37 def run(["get-packs" | args]) do
38 Application.ensure_all_started(:hackney)
39
40 {options, pack_names, []} = parse_global_opts(args)
41
42 manifest_url = if options[:manifest], do: options[:manifest], else: @default_manifest
43
44 manifest = fetch_manifest(manifest_url)
45
46 for pack_name <- pack_names do
47 if Map.has_key?(manifest, pack_name) do
48 pack = manifest[pack_name]
49 src_url = pack["src"]
50
51 IO.puts(
52 IO.ANSI.format([
53 "Downloading ",
54 :bright,
55 pack_name,
56 :normal,
57 " from ",
58 :underline,
59 src_url
60 ])
61 )
62
63 binary_archive = Tesla.get!(src_url).body
64 archive_md5 = :crypto.hash(:md5, binary_archive) |> Base.encode16()
65
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"]))
69 else
70 IO.puts(IO.ANSI.format(md5_status_text ++ [:red, "BAD"]))
71
72 raise "Bad MD5 for #{pack_name}"
73 end
74
75 # The url specified in files should be in the same directory
76 files_url = Path.join(Path.dirname(manifest_url), pack["files"])
77
78 IO.puts(
79 IO.ANSI.format([
80 "Fetching the file list for ",
81 :bright,
82 pack_name,
83 :normal,
84 " from ",
85 :underline,
86 files_url
87 ])
88 )
89
90 files = Tesla.get!(files_url).body |> Poison.decode!()
91
92 IO.puts(IO.ANSI.format(["Unpacking ", :bright, pack_name]))
93
94 static_path = Path.join(:code.priv_dir(:pleroma), "static")
95
96 pack_path =
97 Path.join([
98 static_path,
99 Pleroma.Config.get!([:instance, :static_dir]),
100 "emoji",
101 pack_name
102 ])
103
104 files_to_unzip =
105 Enum.map(
106 files,
107 fn {_, f} -> to_charlist(f) end
108 )
109
110 {:ok, _} =
111 :zip.unzip(binary_archive,
112 cwd: pack_path,
113 file_list: files_to_unzip
114 )
115
116 IO.puts(IO.ANSI.format(["Writing emoji.txt for ", :bright, pack_name]))
117
118 common_pack_path = Path.join([
119 "/", Pleroma.Config.get!([:instance, :static_dir]), "emoji", pack_name
120 ])
121 emoji_txt_str =
122 Enum.map(
123 files,
124 fn {shortcode, path} ->
125 "#{shortcode}, #{Path.join(common_pack_path, path)}"
126 end
127 )
128 |> Enum.join("\n")
129
130 File.write!(Path.join(pack_path, "emoji.txt"), emoji_txt_str)
131 else
132 IO.puts(IO.ANSI.format([:bright, :red, "No pack named \"#{pack_name}\" found"]))
133 end
134 end
135 end
136
137 def run(["gen-pack", src]) do
138 Application.ensure_all_started(:hackney)
139
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
144
145 license = String.trim(IO.gets("License: "))
146 homepage = String.trim(IO.gets("Homepage: "))
147 description = String.trim(IO.gets("Description: "))
148
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
152
153 default_exts = [".png", ".gif"]
154 default_exts_str = Enum.join(default_exts, " ")
155 exts =
156 String.trim(IO.gets("Emoji file extensions (separated with spaces) [#{default_exts_str}]: "))
157 exts = if String.length(exts) > 0 do
158 String.split(exts, " ") |> Enum.filter(fn e -> (e |> String.trim() |> String.length()) > 0 end)
159 else
160 default_exts
161 end
162
163 IO.puts "Downloading the pack and generating MD5"
164
165 binary_archive = Tesla.get!(src).body
166 archive_md5 = :crypto.hash(:md5, binary_archive) |> Base.encode16()
167
168 IO.puts "MD5 is #{archive_md5}"
169
170 pack_json = %{
171 name => %{
172 license: license,
173 homepage: homepage,
174 description: description,
175 src: src,
176 src_md5: archive_md5,
177 files: files_name
178 }
179 }
180
181 tmp_pack_dir = Path.join(System.tmp_dir!(), "emoji-pack-#{name}")
182 {:ok, _} =
183 :zip.unzip(
184 binary_archive,
185 cwd: tmp_pack_dir
186 )
187
188 emoji_map = Pleroma.Emoji.make_shortcode_to_file_map(tmp_pack_dir, exts)
189
190
191 File.write!(files_name, Poison.encode!(emoji_map, pretty: true))
192
193 IO.puts """
194
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.
197 """
198
199 if File.exists?("index.json") do
200 existing_data = File.read!("index.json") |> Poison.decode!()
201
202 File.write!(
203 "index.json",
204 Poison.encode!(
205 Map.merge(
206 existing_data,
207 pack_json
208 ),
209 pretty: true
210 )
211 )
212
213 IO.puts "index.json file has been update with the #{name} pack"
214 else
215 File.write!("index.json", Poison.encode!(pack_json, pretty: true))
216
217 IO.puts "index.json has been created with the #{name} pack"
218 end
219
220 end
221
222 defp fetch_manifest(from) do
223 Tesla.get!(from).body |> Poison.decode!()
224 end
225
226 defp parse_global_opts(args) do
227 OptionParser.parse(
228 args,
229 strict: [
230 manifest: :string
231 ],
232 aliases: [
233 m: :manifest
234 ]
235 )
236 end
237 end