summaryrefslogtreecommitdiff
path: root/snac.c
diff options
context:
space:
mode:
Diffstat (limited to 'snac.c')
-rw-r--r--snac.c112
1 files changed, 99 insertions, 13 deletions
diff --git a/snac.c b/snac.c
index f4528cd..a3ba6b7 100644
--- a/snac.c
+++ b/snac.c
@@ -33,6 +33,8 @@
33#include <sys/time.h> 33#include <sys/time.h>
34#include <sys/stat.h> 34#include <sys/stat.h>
35#include <sys/wait.h> 35#include <sys/wait.h>
36#include <limits.h>
37#include <stdlib.h>
36 38
37xs_str *srv_basedir = NULL; 39xs_str *srv_basedir = NULL;
38xs_dict *srv_config = NULL; 40xs_dict *srv_config = NULL;
@@ -177,12 +179,25 @@ int strip_media(const char *fn)
177/* strips EXIF data from a file */ 179/* strips EXIF data from a file */
178{ 180{
179 int ret = 0; 181 int ret = 0;
182
180 const xs_val *v = xs_dict_get(srv_config, "strip_exif"); 183 const xs_val *v = xs_dict_get(srv_config, "strip_exif");
181 184
182 if (xs_type(v) == XSTYPE_TRUE) { 185 if (xs_type(v) == XSTYPE_TRUE) {
183 xs *l_fn = xs_tolower_i(xs_dup(fn)); 186 /* Heuristic: find 'user/' in the path to make it relative */
187 /* This works for ~/user/..., /var/snac/user/..., etc. */
188 const char *r_fn = strstr(fn, "user/");
189
190 if (r_fn == NULL) {
191 /* Fallback: try to strip ~/ if present */
192 if (strncmp(fn, "~/", 2) == 0)
193 r_fn = fn + 2;
194 else
195 r_fn = fn;
196 }
184 197
185 /* check extensions */ 198 xs *l_fn = xs_tolower_i(xs_dup(r_fn));
199
200 /* check image extensions */
186 if (xs_endswith(l_fn, ".jpg") || xs_endswith(l_fn, ".jpeg") || 201 if (xs_endswith(l_fn, ".jpg") || xs_endswith(l_fn, ".jpeg") ||
187 xs_endswith(l_fn, ".png") || xs_endswith(l_fn, ".webp") || 202 xs_endswith(l_fn, ".png") || xs_endswith(l_fn, ".webp") ||
188 xs_endswith(l_fn, ".heic") || xs_endswith(l_fn, ".heif") || 203 xs_endswith(l_fn, ".heic") || xs_endswith(l_fn, ".heif") ||
@@ -193,7 +208,7 @@ int strip_media(const char *fn)
193 if (mp == NULL) 208 if (mp == NULL)
194 mp = "mogrify"; 209 mp = "mogrify";
195 210
196 xs *cmd = xs_fmt("%s -strip \"%s\" 2>/dev/null", mp, fn); 211 xs *cmd = xs_fmt("cd \"%s\" && %s -auto-orient -strip \"%s\" 2>/dev/null", srv_basedir, mp, r_fn);
197 212
198 ret = system(cmd); 213 ret = system(cmd);
199 214
@@ -203,12 +218,64 @@ int strip_media(const char *fn)
203 code = WEXITSTATUS(ret); 218 code = WEXITSTATUS(ret);
204 219
205 if (code == 127) 220 if (code == 127)
206 srv_log(xs_fmt("strip_media: error stripping %s. '%s' not found (exit 127). Set 'mogrify_path' in server.json.", fn, mp)); 221 srv_log(xs_fmt("strip_media: error stripping %s. '%s' not found (exit 127). Set 'mogrify_path' in server.json.", r_fn, mp));
207 else 222 else
208 srv_log(xs_fmt("strip_media: error stripping %s %d", fn, ret)); 223 srv_log(xs_fmt("strip_media: error stripping %s %d", r_fn, ret));
209 } 224 }
210 else 225 else
211 srv_debug(1, xs_fmt("strip_media: stripped %s", fn)); 226 srv_debug(1, xs_fmt("strip_media: stripped %s", r_fn));
227 }
228 else
229 /* check video extensions */
230 if (xs_endswith(l_fn, ".mp4") || xs_endswith(l_fn, ".m4v") ||
231 xs_endswith(l_fn, ".mov") || xs_endswith(l_fn, ".webm") ||
232 xs_endswith(l_fn, ".mkv") || xs_endswith(l_fn, ".avi")) {
233
234 const char *fp = xs_dict_get(srv_config, "ffmpeg_path");
235 if (fp == NULL)
236 fp = "ffmpeg";
237
238 /* ffmpeg cannot modify in-place, so we need a temp file */
239 /* we must preserve valid extension for ffmpeg to guess the format */
240 const char *ext = strrchr(r_fn, '.');
241 if (ext == NULL) ext = "";
242 xs *tmp_fn = xs_fmt("%s.tmp%s", r_fn, ext);
243
244 /* -map_metadata -1 strips all global metadata */
245 /* -c copy copies input streams without re-encoding */
246 /* we don't silence stderr so we can debug issues */
247 /* we explicitly cd to srv_basedir to ensure relative paths work */
248 xs *cmd = xs_fmt("cd \"%s\" && %s -y -i \"%s\" -map_metadata -1 -c copy \"%s\"", srv_basedir, fp, r_fn, tmp_fn);
249
250 ret = system(cmd);
251
252 if (ret != 0) {
253 int code = 0;
254 if (WIFEXITED(ret))
255 code = WEXITSTATUS(ret);
256
257 if (code == 127)
258 srv_log(xs_fmt("strip_media: error stripping %s. '%s' not found (exit 127). Set 'ffmpeg_path' in server.json.", r_fn, fp));
259 else {
260 srv_log(xs_fmt("strip_media: error stripping %s %d", r_fn, ret));
261 srv_log(xs_fmt("strip_media: command was: %s", cmd));
262 }
263
264 /* try to cleanup, just in case */
265 /* unlink needs full path too if we are not in basedir */
266 xs *full_tmp_fn = xs_fmt("%s/%s", srv_basedir, tmp_fn);
267 unlink(full_tmp_fn);
268 }
269 else {
270 /* rename tmp file to original */
271 /* use full path for source because it was created relative to basedir */
272 xs *full_tmp_fn = xs_fmt("%s/%s", srv_basedir, tmp_fn);
273
274 if (rename(full_tmp_fn, fn) == 0)
275 srv_debug(1, xs_fmt("strip_media: stripped %s", fn));
276 else
277 srv_log(xs_fmt("strip_media: error renaming %s to %s", full_tmp_fn, fn));
278 }
212 } 279 }
213 } 280 }
214 281
@@ -222,14 +289,33 @@ int check_strip_tool(void)
222 int ret = 1; 289 int ret = 1;
223 290
224 if (xs_type(v) == XSTYPE_TRUE) { 291 if (xs_type(v) == XSTYPE_TRUE) {
225 const char *mp = xs_dict_get(srv_config, "mogrify_path"); 292 /* check mogrify */
226 if (mp == NULL) 293 {
227 mp = "mogrify"; 294 const char *mp = xs_dict_get(srv_config, "mogrify_path");
295 if (mp == NULL)
296 mp = "mogrify";
228 297
229 xs *cmd = xs_fmt("%s -version 2>/dev/null >/dev/null", mp); 298 xs *cmd = xs_fmt("%s -version 2>/dev/null >/dev/null", mp);
230 299
231 if (system(cmd) != 0) 300 if (system(cmd) != 0) {
232 ret = 0; 301 srv_log(xs_fmt("check_strip_tool: '%s' not working", mp));
302 ret = 0;
303 }
304 }
305
306 /* check ffmpeg */
307 if (ret) {
308 const char *fp = xs_dict_get(srv_config, "ffmpeg_path");
309 if (fp == NULL)
310 fp = "ffmpeg";
311
312 xs *cmd = xs_fmt("%s -version 2>/dev/null >/dev/null", fp);
313
314 if (system(cmd) != 0) {
315 srv_log(xs_fmt("check_strip_tool: '%s' not working", fp));
316 ret = 0;
317 }
318 }
233 } 319 }
234 320
235 return ret; 321 return ret;