Merge branch 'develop' into gun
[akkoma] / lib / mix / tasks / pleroma / emoji.ex
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2019 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 import Mix.Pleroma
8
9 @shortdoc "Manages emoji packs"
10 @moduledoc File.read!("docs/administration/CLI_tasks/emoji.md")
11
12 def run(["ls-packs" | args]) do
13 start_pleroma()
14
15 {options, [], []} = parse_global_opts(args)
16
17 manifest =
18 fetch_manifest(if options[:manifest], do: options[:manifest], else: default_manifest())
19
20 Enum.each(manifest, fn {name, info} ->
21 to_print = [
22 {"Name", name},
23 {"Homepage", info["homepage"]},
24 {"Description", info["description"]},
25 {"License", info["license"]},
26 {"Source", info["src"]}
27 ]
28
29 for {param, value} <- to_print do
30 IO.puts(IO.ANSI.format([:bright, param, :normal, ": ", value]))
31 end
32
33 # A newline
34 IO.puts("")
35 end)
36 end
37
38 def run(["get-packs" | args]) do
39 start_pleroma()
40
41 {options, pack_names, []} = parse_global_opts(args)
42
43 manifest_url = if options[:manifest], do: options[:manifest], else: default_manifest()
44
45 manifest = fetch_manifest(manifest_url)
46
47 for pack_name <- pack_names do
48 if Map.has_key?(manifest, pack_name) do
49 pack = manifest[pack_name]
50 src_url = pack["src"]
51
52 IO.puts(
53 IO.ANSI.format([
54 "Downloading ",
55 :bright,
56 pack_name,
57 :normal,
58 " from ",
59 :underline,
60 src_url
61 ])
62 )
63
64 binary_archive = Tesla.get!(client(), src_url).body
65 archive_sha = :crypto.hash(:sha256, binary_archive) |> Base.encode16()
66
67 sha_status_text = ["SHA256 of ", :bright, pack_name, :normal, " source file is ", :bright]
68
69 if archive_sha == String.upcase(pack["src_sha256"]) do
70 IO.puts(IO.ANSI.format(sha_status_text ++ [:green, "OK"]))
71 else
72 IO.puts(IO.ANSI.format(sha_status_text ++ [:red, "BAD"]))
73
74 raise "Bad SHA256 for #{pack_name}"
75 end
76
77 # The url specified in files should be in the same directory
78 files_url = Path.join(Path.dirname(manifest_url), pack["files"])
79
80 IO.puts(
81 IO.ANSI.format([
82 "Fetching the file list for ",
83 :bright,
84 pack_name,
85 :normal,
86 " from ",
87 :underline,
88 files_url
89 ])
90 )
91
92 files = Tesla.get!(client(), files_url).body |> Jason.decode!()
93
94 IO.puts(IO.ANSI.format(["Unpacking ", :bright, pack_name]))
95
96 pack_path =
97 Path.join([
98 Pleroma.Config.get!([:instance, :static_dir]),
99 "emoji",
100 pack_name
101 ])
102
103 files_to_unzip =
104 Enum.map(
105 files,
106 fn {_, f} -> to_charlist(f) end
107 )
108
109 {:ok, _} =
110 :zip.unzip(binary_archive,
111 cwd: pack_path,
112 file_list: files_to_unzip
113 )
114
115 IO.puts(IO.ANSI.format(["Writing pack.json for ", :bright, pack_name]))
116
117 pack_json = %{
118 pack: %{
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
125 },
126 files: files
127 }
128
129 File.write!(Path.join(pack_path, "pack.json"), Jason.encode!(pack_json, pretty: true))
130 else
131 IO.puts(IO.ANSI.format([:bright, :red, "No pack named \"#{pack_name}\" found"]))
132 end
133 end
134 end
135
136 def run(["gen-pack", src]) do
137 start_pleroma()
138
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
143
144 license = String.trim(IO.gets("License: "))
145 homepage = String.trim(IO.gets("Homepage: "))
146 description = String.trim(IO.gets("Description: "))
147
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
151
152 default_exts = [".png", ".gif"]
153 default_exts_str = Enum.join(default_exts, " ")
154
155 exts =
156 String.trim(
157 IO.gets("Emoji file extensions (separated with spaces) [#{default_exts_str}]: ")
158 )
159
160 exts =
161 if String.length(exts) > 0 do
162 String.split(exts, " ")
163 |> Enum.filter(fn e -> e |> String.trim() |> String.length() > 0 end)
164 else
165 default_exts
166 end
167
168 IO.puts("Downloading the pack and generating SHA256")
169
170 binary_archive = Tesla.get!(client(), src).body
171 archive_sha = :crypto.hash(:sha256, binary_archive) |> Base.encode16()
172
173 IO.puts("SHA256 is #{archive_sha}")
174
175 pack_json = %{
176 name => %{
177 license: license,
178 homepage: homepage,
179 description: description,
180 src: src,
181 src_sha256: archive_sha,
182 files: files_name
183 }
184 }
185
186 tmp_pack_dir = Path.join(System.tmp_dir!(), "emoji-pack-#{name}")
187
188 {:ok, _} =
189 :zip.unzip(
190 binary_archive,
191 cwd: tmp_pack_dir
192 )
193
194 emoji_map = Pleroma.Emoji.Loader.make_shortcode_to_file_map(tmp_pack_dir, exts)
195
196 File.write!(files_name, Jason.encode!(emoji_map, pretty: true))
197
198 IO.puts("""
199
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.
202 """)
203
204 if File.exists?("index.json") do
205 existing_data = File.read!("index.json") |> Jason.decode!()
206
207 File.write!(
208 "index.json",
209 Jason.encode!(
210 Map.merge(
211 existing_data,
212 pack_json
213 ),
214 pretty: true
215 )
216 )
217
218 IO.puts("index.json file has been update with the #{name} pack")
219 else
220 File.write!("index.json", Jason.encode!(pack_json, pretty: true))
221
222 IO.puts("index.json has been created with the #{name} pack")
223 end
224 end
225
226 defp fetch_manifest(from) do
227 Jason.decode!(
228 if String.starts_with?(from, "http") do
229 Tesla.get!(client(), from).body
230 else
231 File.read!(from)
232 end
233 )
234 end
235
236 defp parse_global_opts(args) do
237 OptionParser.parse(
238 args,
239 strict: [
240 manifest: :string
241 ],
242 aliases: [
243 m: :manifest
244 ]
245 )
246 end
247
248 defp client do
249 middleware = [
250 {Tesla.Middleware.FollowRedirects, [max_redirects: 3]}
251 ]
252
253 Tesla.client(middleware)
254 end
255
256 defp default_manifest, do: Pleroma.Config.get!([:emoji, :default_manifest])
257 end