]> git.p6c8.net - jirafeau.git/blob - lib/functions.js.php
1a561862e9a6852c112889f00968b476218b3e7f
[jirafeau.git] / lib / functions.js.php
1 <?php
2 /*
3 * Jirafeau, your web file repository
4 * Copyright (C) 2015 Jerome Jutteau <j.jutteau@gmail.com>
5 * Copyright (C) 2015 Nicola Spanti (RyDroid) <dev@nicola-spanti.info>
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Affero General Public License as
9 * published by the Free Software Foundation, either version 3 of the
10 * License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Affero General Public License for more details.
16 *
17 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 */
20
21 header('Content-Type: text/javascript');
22
23 define('JIRAFEAU_ROOT', dirname(__FILE__) . '/../');
24
25 require(JIRAFEAU_ROOT . 'lib/settings.php');
26 require(JIRAFEAU_ROOT . 'lib/functions.php');
27 require(JIRAFEAU_ROOT . 'lib/lang.php');
28 ?>
29
30 function translate (expr)
31 {
32 var lang_array = <?php echo json_lang_generator() ?>;
33 if (lang_array.hasOwnProperty(expr))
34 return lang_array[expr];
35 return expr;
36 }
37
38 function isEmpty(str) {
39 return (!str || 0 === str.length);
40 }
41
42 // Extend date object with format method
43 Date.prototype.format = function(format) {
44 format = format || 'YYYY-MM-DD hh:mm';
45
46 var zeropad = function(number, length) {
47 number = number.toString();
48 length = length || 2;
49 while(number.length < length)
50 number = '0' + number;
51 return number;
52 },
53 formats = {
54 YYYY: this.getFullYear(),
55 MM: zeropad(this.getMonth() + 1),
56 DD: zeropad(this.getDate()),
57 hh: zeropad(this.getHours()),
58 mm: zeropad(this.getMinutes()),
59 O: (function() {
60 localDate = new Date;
61 sign = (localDate.getTimezoneOffset() > 0) ? '-' : '+';
62 offset = Math.abs(localDate.getTimezoneOffset());
63 hours = zeropad(Math.floor(offset / 60));
64 minutes = zeropad(offset % 60);
65 return sign + hours + ":" + minutes;
66 })()
67 },
68 pattern = '(' + Object.keys(formats).join(')|(') + ')';
69
70 return format.replace(new RegExp(pattern, 'g'), function(match) {
71 return formats[match];
72 });
73 };
74
75 function dateToUtcString(datelocal) {
76 return new Date(
77 datelocal.getUTCFullYear(),
78 datelocal.getUTCMonth(),
79 datelocal.getUTCDate(),
80 datelocal.getUTCHours(),
81 datelocal.getUTCMinutes(),
82 datelocal.getUTCSeconds()
83 ).format();
84 }
85
86 function show_link (url, reference, delete_code, crypt_key, date)
87 {
88 // Upload finished
89 document.getElementById('uploading').style.display = 'none';
90 document.getElementById('upload').style.display = 'none';
91 document.getElementById('upload_finished').style.display = '';
92 document.title = 'Jirafeau - 100%';
93
94 // Download page
95 var download_link = url + 'f.php?h=' + reference;
96 var download_link_href = url + 'f.php?h=' + reference;
97 if (crypt_key.length > 0)
98 {
99 download_link += '&amp;k=' + crypt_key;
100 download_link_href += '&k=' + crypt_key;
101 }
102 if (!!document.getElementById('upload_finished_download_page'))
103 {
104 document.getElementById('upload_link').innerHTML = download_link;
105 document.getElementById('upload_link').href = download_link_href;
106 }
107
108 // Email link
109 var filename = document.getElementById('file_select').files[0].name;
110 var b = encodeURIComponent("Download file \"" + filename + "\":") + "%0D";
111 b += encodeURIComponent(download_link_href) + "%0D";
112 if (false == isEmpty(date))
113 {
114 b += "%0D" + encodeURIComponent("This file will be available until " + dateToUtcString(date)) + "%0D";
115 document.getElementById('upload_link_email').href = "mailto:?body=" + b + "&subject=" + encodeURIComponent(filename);
116 }
117
118 // Delete link
119 var delete_link = url + 'f.php?h=' + reference + '&amp;d=' + delete_code;
120 var delete_link_href = url + 'f.php?h=' + reference + '&d=' + delete_code;
121 document.getElementById('delete_link').innerHTML = delete_link;
122 document.getElementById('delete_link').href = delete_link_href;
123
124 // Validity date
125 if (isEmpty(date))
126 {
127 document.getElementById('validity').style.display = 'none';
128 }
129 else {
130 document.getElementById('date').innerHTML = '<span class="datetime">'
131 + dateToUtcString(date) + ' (GMT)'
132 + '</span>';
133 document.getElementById('validity').style.display = '';
134 }
135
136 // Preview link (if allowed)
137 if (!!document.getElementById('preview_link'))
138 {
139 document.getElementById('upload_finished_preview').style.display = 'none';
140 var preview_link = url + 'f.php?h=' + reference + '&amp;p=1';
141 var preview_link_href = url + 'f.php?h=' + reference + '&p=1';
142 if (crypt_key.length > 0)
143 {
144 preview_link += '&amp;k=' + crypt_key;
145 preview_link_href += '&k=' + crypt_key;
146 }
147
148 // Test if content can be previewed
149 type = document.getElementById('file_select').files[0].type;
150 if (type.indexOf("image") > -1 ||
151 type.indexOf("audio") > -1 ||
152 type.indexOf("text") > -1 ||
153 type.indexOf("video") > -1)
154 {
155 document.getElementById('preview_link').innerHTML = preview_link;
156 document.getElementById('preview_link').href = preview_link_href;
157 document.getElementById('upload_finished_preview').style.display = '';
158 }
159 }
160
161 // Direct download link
162 var direct_download_link = url + 'f.php?h=' + reference + '&amp;d=1';
163 var direct_download_link_href = url + 'f.php?h=' + reference + '&d=1';
164 if (crypt_key.length > 0)
165 {
166 direct_download_link += '&amp;k=' + crypt_key;
167 direct_download_link_href += '&k=' + crypt_key;
168 }
169 document.getElementById('direct_link').innerHTML = direct_download_link;
170 document.getElementById('direct_link').href = direct_download_link_href;
171
172
173 // Hide preview and direct download link if password is set
174 if (document.getElementById('input_key').value.length > 0)
175 {
176 if (!!document.getElementById('preview_link'))
177 document.getElementById('upload_finished_preview').style.display = 'none';
178 document.getElementById('upload_direct_download').style.display = 'none';
179 }
180 }
181
182 function show_upload_progression (percentage, speed, time_left)
183 {
184 document.getElementById('uploaded_percentage').innerHTML = percentage;
185 document.getElementById('uploaded_speed').innerHTML = speed;
186 document.getElementById('uploaded_time').innerHTML = time_left;
187 document.title = 'Jirafeau - ' + percentage;
188 }
189
190 function hide_upload_progression ()
191 {
192 document.getElementById('uploaded_percentage').style.display = 'none';
193 document.getElementById('uploaded_speed').style.display = 'none';
194 document.getElementById('uploaded_time').style.display = 'none';
195 document.title = 'Jirafeau';
196 }
197
198 function upload_progress (e)
199 {
200 if (e == undefined || e == null || !e.lengthComputable)
201 return;
202
203 // Init time estimation if needed
204 if (upload_time_estimation_total_size == 0)
205 upload_time_estimation_total_size = e.total;
206
207 // Compute percentage
208 var p = Math.round (e.loaded * 100 / e.total);
209 var p_str = ' ';
210 if (p != 100)
211 p_str = p.toString() + '%';
212 // Update estimation speed
213 upload_time_estimation_add(e.loaded);
214 // Get speed string
215 var speed_str = upload_time_estimation_speed_string();
216 speed_str = upload_speed_refresh_limiter(speed_str);
217 // Get time string
218 var time_str = chrono_update(upload_time_estimation_time());
219
220 show_upload_progression (p_str, speed_str, time_str);
221 }
222
223 function control_selected_file_size(max_size, error_str)
224 {
225 f_size = document.getElementById('file_select').files[0].size;
226 if (max_size > 0 && f_size > max_size * 1024 * 1024)
227 {
228 pop_failure(error_str);
229 document.getElementById('send').style.display = 'none';
230 }
231 else
232 {
233 document.getElementById('options').style.display = '';
234 document.getElementById('send').style.display = '';
235 document.getElementById('error_pop').style.display = 'none';
236 document.getElementById('file_select').style.left = 'inherit';
237 document.getElementById('file_select').style.height = 'inherit';
238 document.getElementById('file_select').style.opacity = '1';
239 }
240 }
241
242 function pop_failure (e)
243 {
244 var text = "An error occured";
245 if (typeof e !== 'undefined')
246 text = e;
247 text = "<p>" + text + "</p>";
248 document.getElementById('error_pop').innerHTML = e;
249
250 document.getElementById('uploading').style.display = 'none';
251 document.getElementById('error_pop').style.display = '';
252 document.getElementById('upload').style.display = '';
253 document.getElementById('send').style.display = '';
254 }
255
256 function add_time_string_to_date(d, time)
257 {
258 if(typeof(d) != 'object' || !(d instanceof Date))
259 {
260 return false;
261 }
262
263 if (time == 'minute')
264 {
265 d.setSeconds (d.getSeconds() + 60);
266 return true;
267 }
268 if (time == 'hour')
269 {
270 d.setSeconds (d.getSeconds() + 3600);
271 return true;
272 }
273 if (time == 'day')
274 {
275 d.setSeconds (d.getSeconds() + 86400);
276 return true;
277 }
278 if (time == 'week')
279 {
280 d.setSeconds (d.getSeconds() + 604800);
281 return true;
282 }
283 if (time == 'month')
284 {
285 d.setSeconds (d.getSeconds() + 2419200);
286 return true;
287 }
288 if (time == 'quarter')
289 {
290 d.setSeconds (d.getSeconds() + 7257600);
291 return true;
292 }
293 if (time == 'year')
294 {
295 d.setSeconds (d.getSeconds() + 29030400);
296 return true;
297 }
298 return false;
299 }
300
301 function classic_upload (url, file, time, password, one_time, upload_password)
302 {
303 // Delay time estimation init as we can't have file size
304 upload_time_estimation_init(0);
305
306 var req = new XMLHttpRequest ();
307 req.upload.addEventListener ("progress", upload_progress, false);
308 req.addEventListener ("error", pop_failure, false);
309 req.addEventListener ("abort", pop_failure, false);
310 req.onreadystatechange = function ()
311 {
312 if (req.readyState == 4 && req.status == 200)
313 {
314 var res = req.responseText;
315
316 // if response starts with "Error" then show a failure
317 if (/^Error/.test(res))
318 {
319 pop_failure (res);
320 return;
321 }
322
323 res = res.split ("\n");
324 var expiryDate = '';
325 if (time != 'none')
326 {
327 // convert time (local time + selected expiry date)
328 var localDatetime = new Date();
329 if(!add_time_string_to_date(localDatetime, time))
330 {
331 pop_failure ('Error: Date can not be parsed');
332 return;
333 }
334 expiryDate = localDatetime;
335 }
336
337 show_link (url, res[0], res[1], res[2], expiryDate);
338 }
339 }
340 req.open ("POST", url + 'script.php' , true);
341
342 var form = new FormData();
343 form.append ("file", file);
344 if (time)
345 form.append ("time", time);
346 if (password)
347 form.append ("key", password);
348 if (one_time)
349 form.append ("one_time_download", '1');
350 if (upload_password.length > 0)
351 form.append ("upload_password", upload_password);
352
353 req.send (form);
354 }
355
356 function check_html5_file_api ()
357 {
358 return window.File && window.FileReader && window.FileList && window.Blob;
359 }
360
361 var async_global_transfered = 0;
362 var async_global_url = '';
363 var async_global_file;
364 var async_global_ref = '';
365 var async_global_max_size = 0;
366 var async_global_time;
367 var async_global_transfering = 0;
368
369 function async_upload_start (url, max_size, file, time, password, one_time, upload_password)
370 {
371 async_global_transfered = 0;
372 async_global_url = url;
373 async_global_file = file;
374 async_global_max_size = max_size;
375 async_global_time = time;
376
377 var req = new XMLHttpRequest ();
378 req.addEventListener ("error", pop_failure, false);
379 req.addEventListener ("abort", pop_failure, false);
380 req.onreadystatechange = function ()
381 {
382 if (req.readyState == 4 && req.status == 200)
383 {
384 var res = req.responseText;
385
386 if (/^Error/.test(res))
387 {
388 pop_failure (res);
389 return;
390 }
391
392 res = res.split ("\n");
393 async_global_ref = res[0];
394 var code = res[1];
395 async_upload_push (code);
396 }
397 }
398 req.open ("POST", async_global_url + 'script.php?init_async' , true);
399
400 var form = new FormData();
401 form.append ("filename", async_global_file.name);
402 form.append ("type", async_global_file.type);
403 if (time)
404 form.append ("time", time);
405 if (password)
406 form.append ("key", password);
407 if (one_time)
408 form.append ("one_time_download", '1');
409 if (upload_password.length > 0)
410 form.append ("upload_password", upload_password);
411
412 // Start time estimation
413 upload_time_estimation_init(async_global_file.size);
414
415 req.send (form);
416 }
417
418 function async_upload_progress (e)
419 {
420 if (e == undefined || e == null || !e.lengthComputable && async_global_file.size != 0)
421 return;
422
423 // Compute percentage
424 var p = Math.round ((e.loaded + async_global_transfered) * 100 / (async_global_file.size));
425 var p_str = ' ';
426 if (p != 100)
427 p_str = p.toString() + '%';
428 // Update estimation speed
429 upload_time_estimation_add(e.loaded + async_global_transfered);
430 // Get speed string
431 var speed_str = upload_time_estimation_speed_string();
432 speed_str = upload_speed_refresh_limiter(speed_str);
433 // Get time string
434 var time_str = chrono_update(upload_time_estimation_time());
435
436 show_upload_progression (p_str, speed_str, time_str);
437 }
438
439 function async_upload_push (code)
440 {
441 if (async_global_transfered == async_global_file.size)
442 {
443 hide_upload_progression ();
444 async_upload_end (code);
445 return;
446 }
447 var req = new XMLHttpRequest ();
448 req.upload.addEventListener ("progress", async_upload_progress, false);
449 req.addEventListener ("error", pop_failure, false);
450 req.addEventListener ("abort", pop_failure, false);
451 req.onreadystatechange = function ()
452 {
453 if (req.readyState == 4 && req.status == 200)
454 {
455 var res = req.responseText;
456
457 if (/^Error/.test(res))
458 {
459 pop_failure (res);
460 return;
461 }
462
463 res = res.split ("\n");
464 var code = res[0]
465 async_global_transfered = async_global_transfering;
466 async_upload_push (code);
467 }
468 }
469 req.open ("POST", async_global_url + 'script.php?push_async' , true);
470
471 var chunk_size = parseInt (async_global_max_size * 0.50);
472 var start = async_global_transfered;
473 var end = start + chunk_size;
474 if (end >= async_global_file.size)
475 end = async_global_file.size;
476 var blob = async_global_file.slice (start, end);
477 async_global_transfering = end;
478
479 var form = new FormData();
480 form.append ("ref", async_global_ref);
481 form.append ("data", blob);
482 form.append ("code", code);
483 req.send (form);
484 }
485
486 function async_upload_end (code)
487 {
488 var req = new XMLHttpRequest ();
489 req.addEventListener ("error", pop_failure, false);
490 req.addEventListener ("abort", pop_failure, false);
491 req.onreadystatechange = function ()
492 {
493 if (req.readyState == 4 && req.status == 200)
494 {
495 var res = req.responseText;
496
497 if (/^Error/.test(res))
498 {
499 pop_failure (res);
500 return;
501 }
502
503 res = res.split ("\n");
504 var expiryDate = '';
505 if (async_global_time != 'none')
506 {
507 // convert time (local time + selected expiry date)
508 var localDatetime = new Date();
509 if(!add_time_string_to_date(localDatetime, async_global_time)) {
510 pop_failure ('Error: Date can not be parsed');
511 return;
512 }
513 expiryDate = localDatetime;
514 }
515
516 show_link (async_global_url, res[0], res[1], res[2], expiryDate);
517 }
518 }
519 req.open ("POST", async_global_url + 'script.php?end_async' , true);
520
521 var form = new FormData();
522 form.append ("ref", async_global_ref);
523 form.append ("code", code);
524 req.send (form);
525 }
526
527 function upload (url, max_size)
528 {
529 if (check_html5_file_api ()
530 && document.getElementById('file_select').files[0].size >= max_size)
531 {
532 async_upload_start (url,
533 max_size,
534 document.getElementById('file_select').files[0],
535 document.getElementById('select_time').value,
536 document.getElementById('input_key').value,
537 document.getElementById('one_time_download').checked,
538 document.getElementById('upload_password').value
539 );
540 }
541 else
542 {
543 classic_upload (url,
544 document.getElementById('file_select').files[0],
545 document.getElementById('select_time').value,
546 document.getElementById('input_key').value,
547 document.getElementById('one_time_download').checked,
548 document.getElementById('upload_password').value
549 );
550 }
551 }
552
553 var upload_time_estimation_total_size = 42;
554 var upload_time_estimation_transfered_size = 42;
555 var upload_time_estimation_transfered_date = 42;
556 var upload_time_estimation_moving_average_speed = 42;
557
558 function upload_time_estimation_init(total_size)
559 {
560 upload_time_estimation_total_size = total_size;
561 upload_time_estimation_transfered_size = 0;
562 upload_time_estimation_moving_average_speed = 0;
563 var d = new Date();
564 upload_time_estimation_transfered_date = d.getTime();
565 }
566
567 function upload_time_estimation_add(total_transfered_size)
568 {
569 // Let's compute the current speed
570 var d = new Date();
571 var speed = upload_time_estimation_moving_average_speed;
572 if (d.getTime() - upload_time_estimation_transfered_date != 0)
573 speed = (total_transfered_size - upload_time_estimation_transfered_size)
574 / (d.getTime() - upload_time_estimation_transfered_date);
575 // Let's compute moving average speed on 30 values
576 var m = (upload_time_estimation_moving_average_speed * 29 + speed) / 30;
577 // Update global values
578 upload_time_estimation_transfered_size = total_transfered_size;
579 upload_time_estimation_transfered_date = d.getTime();
580 upload_time_estimation_moving_average_speed = m;
581 }
582
583 function upload_time_estimation_speed_string()
584 {
585 // speed ms -> s
586 var s = upload_time_estimation_moving_average_speed * 1000;
587 var res = 0;
588 var scale = '';
589 if (s <= 1000)
590 {
591 res = s.toString();
592 scale = "o/s";
593 }
594 else if (s < 1000000)
595 {
596 res = Math.floor(s/100) / 10;
597 scale = "Ko/s";
598 }
599 else
600 {
601 res = Math.floor(s/100000) / 10;
602 scale = "Mo/s";
603 }
604 if (res == 0)
605 return '';
606 return res.toString() + ' ' + scale;
607 }
608
609 function milliseconds_to_time_string (milliseconds)
610 {
611 function numberEnding (number) {
612 return (number > 1) ? 's' : '';
613 }
614
615 var temp = Math.floor(milliseconds / 1000);
616 var years = Math.floor(temp / 31536000);
617 if (years) {
618 return years + ' ' + translate ('year') + numberEnding(years);
619 }
620 var days = Math.floor((temp %= 31536000) / 86400);
621 if (days) {
622 return days + ' ' + translate ('day') + numberEnding(days);
623 }
624 var hours = Math.floor((temp %= 86400) / 3600);
625 if (hours) {
626 return hours + ' ' + translate ('hour') + numberEnding(hours);
627 }
628 var minutes = Math.floor((temp %= 3600) / 60);
629 if (minutes) {
630 return minutes + ' ' + translate ('minute') + numberEnding(minutes);
631 }
632 var seconds = temp % 60;
633 if (seconds) {
634 return seconds + ' ' + translate ('second') + numberEnding(seconds);
635 }
636 return translate ('less than a second');
637 }
638
639 function upload_time_estimation_time()
640 {
641 // Estimate remaining time
642 if (upload_time_estimation_moving_average_speed == 0)
643 return 0;
644 return (upload_time_estimation_total_size - upload_time_estimation_transfered_size)
645 / upload_time_estimation_moving_average_speed;
646 }
647
648 var chrono_last_update = 0;
649 var chrono_time_ms = 0;
650 var chrono_time_ms_last_update = 0;
651 function chrono_update(time_ms)
652 {
653 var d = new Date();
654 var chrono = 0;
655 // Don't update too often
656 if (d.getTime() - chrono_last_update < 3000 &&
657 chrono_time_ms_last_update > 0)
658 chrono = chrono_time_ms;
659 else
660 {
661 chrono_last_update = d.getTime();
662 chrono_time_ms = time_ms;
663 chrono = time_ms;
664 chrono_time_ms_last_update = d.getTime();
665 }
666
667 // Adjust chrono for smooth estimation
668 chrono = chrono - (d.getTime() - chrono_time_ms_last_update);
669
670 // Let's update chronometer
671 var time_str = '';
672 if (chrono > 0)
673 time_str = milliseconds_to_time_string (chrono);
674 return time_str;
675 }
676
677 var upload_speed_refresh_limiter_last_update = 0;
678 var upload_speed_refresh_limiter_last_value = '';
679 function upload_speed_refresh_limiter(speed_str)
680 {
681 var d = new Date();
682 if (d.getTime() - upload_speed_refresh_limiter_last_update > 1500)
683 {
684 upload_speed_refresh_limiter_last_value = speed_str;
685 upload_speed_refresh_limiter_last_update = d.getTime();
686 }
687 return upload_speed_refresh_limiter_last_value;
688 }

patrick-canterino.de