32b92e6af737a18bb37cc8aa4c28a6db63d9fd3c
[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
8 @shortdoc "Manages emoji packs"
9
10 def run(["ls-packs" | args]) do
11 Application.ensure_all_started(:hackney)
12
13 {options, [], []} = parse_global_opts(args)
14
15 manifest =
16 fetch_manifest(if options[:manifest], do: options[:manifest], else: default_manifest())
17
18 Enum.each(manifest, fn {name, info} ->
19 to_print = [
20 {"Name", name},
21 {"Homepage", info["homepage"]},
22 {"Description", info["description"]},
23 {"License", info["license"]},
24 {"Source", info["src"]}
25 ]
26
27 for {param, value} <- to_print do
28 IO.puts(IO.ANSI.format([:bright, param, :normal, ": ", value]))
29 end
30
31 # A newline
32 IO.puts("")
33 end)
34 end
35
36 def run(["get-packs" | args]) do
37 Application.ensure_all_started(:hackney)
38
39 {options, pack_names, []} = parse_global_opts(args)
40
41 manifest_url = if options[:manifest], do: options[:manifest], else: default_manifest()
42
43 manifest = fetch_manifest(manifest_url)
44
45 for pack_name <- pack_names do
46 if Map.has_key?(manifest, pack_name) do
47 pack = manifest[pack_name]
48 src_url = pack["src"]
49
50 IO.puts(
51 IO.ANSI.format([
52 "Downloading ",
53 :bright,
54 pack_name,
55 :normal,
56 " from ",
57 :underline,
58 src_url
59 ])
60 )
61
62 binary_archive = Tesla.get!(client(), src_url).body
63 archive_sha = :crypto.hash(:sha256, binary_archive) |> Base.encode16()
64
65 sha_status_text = ["SHA256 of ", :bright, pack_name, :normal, " source file is ", :bright]
66
67 if archive_sha == String.upcase(pack["src_sha256"]) do
68 IO.puts(IO.ANSI.format(sha_status_text ++ [:green, "OK"]))
69 else
70 IO.puts(IO.ANSI.format(sha_status_text ++ [:red, "BAD"]))
71
72 raise "Bad SHA256 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!(client(), files_url).body |> Jason.decode!()
91
92 IO.puts(IO.ANSI.format(["Unpacking ", :bright, pack_name]))
93
94 pack_path =
95 Path.join([
96 Pleroma.Config.get!([:instance, :static_dir]),
97 "emoji",
98 pack_name
99 ])
100
101 files_to_unzip =
102 Enum.map(
103 files,
104 fn {_, f} -> to_charlist(f) end
105 )
106
107 {:ok, _} =
108 :zip.unzip(binary_archive,
109 cwd: pack_path,
110 file_list: files_to_unzip
111 )
112
113 IO.puts(IO.ANSI.format(["Writing emoji.txt for ", :bright, pack_name]))
114
115 emoji_txt_str =
116 Enum.map(
117 files,
118 fn {shortcode, path} ->
119 emojo_path = Path.join("/emoji/#{pack_name}", path)
120 "#{shortcode}, #{emojo_path}"
121 end
122 )
123 |> Enum.join("\n")
124
125 File.write!(Path.join(pack_path, "emoji.txt"), emoji_txt_str)
126 else
127 IO.puts(IO.ANSI.format([:bright, :red, "No pack named \"#{pack_name}\" found"]))
128 end
129 end
130 end
131
132 def run(["gen-pack", src]) do
133 Application.ensure_all_started(:hackney)
134
135 proposed_name = Path.basename(src) |> Path.rootname()
136 name = String.trim(IO.gets("Pack name [#{proposed_name}]: "))
137 # If there's no name, use the default one
138 name = if String.length(name) > 0, do: name, else: proposed_name
139
140 license = String.trim(IO.gets("License: "))
141 homepage = String.trim(IO.gets("Homepage: "))
142 description = String.trim(IO.gets("Description: "))
143
144 proposed_files_name = "#{name}.json"
145 files_name = String.trim(IO.gets("Save file list to [#{proposed_files_name}]: "))
146 files_name = if String.length(files_name) > 0, do: files_name, else: proposed_files_name
147
148 default_exts = [".png", ".gif"]
149 default_exts_str = Enum.join(default_exts, " ")
150
151 exts =
152 String.trim(
153 IO.gets("Emoji file extensions (separated with spaces) [#{default_exts_str}]: ")
154 )
155
156 exts =
157 if String.length(exts) > 0 do
158 String.split(exts, " ")
159 |> Enum.filter(fn e -> e |> String.trim() |> String.length() > 0 end)
160 else
161 default_exts
162 end
163
164 IO.puts("Downloading the pack and generating SHA256")
165
166 binary_archive = Tesla.get!(client(), src).body
167 archive_sha = :crypto.hash(:sha256, binary_archive) |> Base.encode16()
168
169 IO.puts("SHA256 is #{archive_sha}")
170
171 pack_json = %{
172 name => %{
173 license: license,
174 homepage: homepage,
175 description: description,
176 src: src,
177 src_sha256: archive_sha,
178 files: files_name
179 }
180 }
181
182 tmp_pack_dir = Path.join(System.tmp_dir!(), "emoji-pack-#{name}")
183
184 {:ok, _} =
185 :zip.unzip(
186 binary_archive,
187 cwd: tmp_pack_dir
188 )
189
190 emoji_map = Pleroma.Emoji.Loader.make_shortcode_to_file_map(tmp_pack_dir, exts)
191
192 File.write!(files_name, Jason.encode!(emoji_map, pretty: true))
193
194 IO.puts("""
195
196 #{files_name} has been created and contains the list of all found emojis in the pack.
197 Please review the files in the remove those not needed.
198 """)
199
200 if File.exists?("index.json") do
201 existing_data = File.read!("index.json") |> Jason.decode!()
202
203 File.write!(
204 "index.json",
205 Jason.encode!(
206 Map.merge(
207 existing_data,
208 pack_json
209 ),
210 pretty: true
211 )
212 )
213
214 IO.puts("index.json file has been update with the #{name} pack")
215 else
216 File.write!("index.json", Jason.encode!(pack_json, pretty: true))
217
218 IO.puts("index.json has been created with the #{name} pack")
219 end
220 end
221
222 defp fetch_manifest(from) do
223 Jason.decode!(
224 if String.starts_with?(from, "http") do
225 Tesla.get!(client(), from).body
226 else
227 File.read!(from)
228 end
229 )
230 end
231
232 defp parse_global_opts(args) do
233 OptionParser.parse(
234 args,
235 strict: [
236 manifest: :string
237 ],
238 aliases: [
239 m: :manifest
240 ]
241 )
242 end
243
244 defp client do
245 middleware = [
246 {Tesla.Middleware.FollowRedirects, [max_redirects: 3]}
247 ]
248
249 Tesla.client(middleware)
250 end
251
252 defp default_manifest, do: Pleroma.Config.get!([:emoji, :default_manifest])
253 end