Compare commits
32 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fd401088bb | ||
|
|
abcc7ca654 | ||
|
|
a75b2e3f62 | ||
|
|
823f7e60d8 | ||
|
|
b63e94c566 | ||
|
|
bfd475b37d | ||
|
|
effeb7daea | ||
|
|
ee4bc7dfe0 | ||
|
|
f88268d7c6 | ||
|
|
3127158064 | ||
|
|
6ce37566b9 | ||
|
|
e6f5a077d3 | ||
|
|
a13d5882ad | ||
|
|
dd3ea7f09b | ||
|
|
040c76dda1 | ||
|
|
eefaaf1643 | ||
|
|
3b922bb05e | ||
|
|
e01a04393f | ||
|
|
5792bf06e2 | ||
|
|
4e680c78d5 | ||
|
|
377d42bfcd | ||
|
|
36089fb199 | ||
|
|
7df2ac0740 | ||
|
|
cd32706ec4 | ||
|
|
c8a6ca728f | ||
|
|
d2d992da6f | ||
|
|
6ba5e31592 | ||
|
|
940338159e | ||
|
|
27a65d4c59 | ||
|
|
73fed1269e | ||
|
|
321d821661 | ||
|
|
17782dc734 |
19
README.md
@@ -79,17 +79,6 @@ By using this compose file, you should know that:
|
||||
- (optional) You can and should put a [nginx](https://www.nginx.com/) proxy before the Apache server. That thing is just insanely fast with static content like images.
|
||||
- (optional) To secure your traffic I'd highly recommend getting an [SSL Cert](https://letsencrypt.org/) for your server if you don't already have one.
|
||||
|
||||
|
||||
UPDATES
|
||||
========
|
||||
- Nov. 23: Added support for MP4 uploads and conversion from gif to MP4
|
||||
- Nov. 12: Created new git project: [Pictshare stats](https://github.com/chrisiaut/pictshare_stats)
|
||||
- Nov. 07: Added 9 new (instagram-like) filters
|
||||
- Nov. 06: Master delete code. One code to delete them all
|
||||
- Nov. 01: [Restricted uploads and option-use](#restriction-settings)
|
||||
- Oct. 30: [Rotations and filters](#smart-query-system)
|
||||
- Oct. 10: [Album functionality](#smart-query-system) finally ready
|
||||
|
||||
## Why would I want to host my own images?
|
||||
If you own a server (even a home server) you can host your own PictShare instance so you have full control over your content and can delete images hasslefree.
|
||||
|
||||
@@ -106,10 +95,12 @@ If you're a blogger like myself, you can use it as storage for your images so th
|
||||
- MP4 resizing
|
||||
- PictShare removes all exif data so you can upload photos from your phone and all GPS tags and camera model info get wiped
|
||||
- Smart [resize, filter and rotation](#smart-query-system) features
|
||||
- Generate gradients by specifying only a size. eg: https://pictshare.net/800x200
|
||||
- Duplicates don't take up space. If the exact same images is uploaded twice, the second upload will link to the first
|
||||
- You can control who can upload images or use filters/resizes by defining an [upload-code](#restriction-settings)
|
||||
- You can set a code in your ```/inc/config.inc.php``` (MASTER_DELETE_CODE) that, if appended to any URL of an Image, will delete the image and all cached versions of it from the server
|
||||
- Detailed traffic and view statistics of your images via [Pictshare stats](https://github.com/chrisiaut/pictshare_stats)
|
||||
- For more configuration possibilities check out the ```/inc/example.config.inc.php``` file
|
||||
|
||||
## Smart query system
|
||||
PictShare images can be changed after upload just by modifying the URL. It works like this:
|
||||
@@ -225,7 +216,7 @@ If you access the image with the code like this: ```https://www.pictshare.net/ch
|
||||
- You have full control over your data. PictShare doesn't need remote libaries or tracking crap
|
||||
|
||||
## Scaling
|
||||
You can use Backblaze Buckets for storage of images so you can use multiple instances of PictShare and if the image is not found on the instance, it will look in the bucket.
|
||||
You can use **Backblaze Buckets** for storage of images so you can use multiple instances of PictShare and if the image is not found on the instance, it will look in the bucket.
|
||||
|
||||
Just add your credentials to the config.inc.php file as described in the ```example.config.inc.php``` file.
|
||||
|
||||
@@ -237,8 +228,8 @@ Just add your credentials to the config.inc.php file as described in the ```exam
|
||||
## nginx config
|
||||
This is a simple config file that should make PictShare work on nginx
|
||||
|
||||
- Install php fpm: ```apt-get install php5-fpm```
|
||||
- Install php Graphics libraries: ```apt-get install php5-gd```
|
||||
- Install php fpm: ```apt-get install php-fpm```
|
||||
- Install php Graphics libraries: ```apt-get install php-gd```
|
||||
|
||||
```
|
||||
server {
|
||||
|
||||
0
bin/ffmpeg
Normal file → Executable file
@@ -111,7 +111,10 @@ class Backblaze
|
||||
curl_close ($session); // Clean up
|
||||
$data = json_decode($server_output,true); // Tell me about the rabbits, George!
|
||||
$this->ulURL = $data['uploadUrl'];
|
||||
//var_dump("upload url at load: ".$data['uploadUrl']);
|
||||
$this->ulToken = $data['authorizationToken'];
|
||||
|
||||
//var_dump($data);
|
||||
}
|
||||
|
||||
function download($hash)
|
||||
@@ -271,5 +274,7 @@ class Backblaze
|
||||
|
||||
if($data['nextFileName'])
|
||||
$this->getAllFilesInBucket($data['nextFileName']);
|
||||
|
||||
return $this->files;
|
||||
}
|
||||
}
|
||||
24
classes/crypto.php
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
class Crypto
|
||||
{
|
||||
function encrypt($inputfile,$outputfile)
|
||||
{
|
||||
if(!file_exists($inputfile)) return;
|
||||
$data = base64_encode(file_get_contents($inputfile));
|
||||
$nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
|
||||
$ciphertext = sodium_crypto_secretbox($data, $nonce, ENCRYPTION_KEY);
|
||||
$encoded = base64_encode($nonce . $ciphertext);
|
||||
file_put_contents($outputfile,$encoded);
|
||||
}
|
||||
|
||||
function decrypt($inputfile,$outputfile)
|
||||
{
|
||||
if(!file_exists($inputfile)) return;
|
||||
$decoded = base64_decode(file_get_contents($inputfile));
|
||||
$nonce = mb_substr($decoded, 0, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, '8bit');
|
||||
$ciphertext = mb_substr($decoded, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, null, '8bit');
|
||||
$plaintext = sodium_crypto_secretbox_open($ciphertext, $nonce, ENCRYPTION_KEY);
|
||||
file_put_contents($outputfile,base64_decode($plaintext));
|
||||
}
|
||||
}
|
||||
0
css/imgs/logo/horizontal.png
Normal file → Executable file
|
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 54 KiB |
0
css/imgs/logo/horizontal2.png
Normal file → Executable file
|
Before Width: | Height: | Size: 57 KiB After Width: | Height: | Size: 57 KiB |
0
css/imgs/logo/horizontal3.png
Normal file → Executable file
|
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 43 KiB |
0
css/imgs/logo/logo.png
Normal file → Executable file
|
Before Width: | Height: | Size: 83 KiB After Width: | Height: | Size: 83 KiB |
0
css/imgs/logo/logo2.png
Normal file → Executable file
|
Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 66 KiB |
0
css/imgs/logo/monochrome.png
Normal file → Executable file
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |
0
css/imgs/logo/monochrome2.png
Normal file → Executable file
|
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 36 KiB |
0
css/imgs/logo/picthshare.ai
Normal file → Executable file
0
css/imgs/logo/picthshare.pdf
Normal file → Executable file
0
css/imgs/logo/picthshare.svg
Normal file → Executable file
|
Before Width: | Height: | Size: 67 KiB After Width: | Height: | Size: 67 KiB |
0
css/imgs/logo/vertical.png
Normal file → Executable file
|
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 54 KiB |
0
css/imgs/logo/vertical2.png
Normal file → Executable file
|
Before Width: | Height: | Size: 99 KiB After Width: | Height: | Size: 99 KiB |
0
css/imgs/logo/vertical3.png
Normal file → Executable file
|
Before Width: | Height: | Size: 203 KiB After Width: | Height: | Size: 203 KiB |
@@ -5,7 +5,7 @@ services:
|
||||
restart: always
|
||||
image: hascheksolutions/pictshare:latest
|
||||
volumes:
|
||||
- ./volumes/upload:/opt/pictshare/upload
|
||||
- ./volumes/upload:/usr/share/nginx/html/upload
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
|
||||
35
inc/core.php
@@ -84,7 +84,26 @@ function whatToDo($url)
|
||||
|
||||
$data = $pm->urlToData($url);
|
||||
|
||||
if(!is_array($data) || !$data['hash'])
|
||||
if(!$data['hash'] && $data['size']) //if there is only a size but no hash, generate a pattern
|
||||
{
|
||||
$sd = $pm->sizeStringToWidthHeight($data['size']);
|
||||
$width = ($sd['width'] <= 2000)?$sd['width']:2000;
|
||||
$height = ($sd['height'] <= 2000)?$sd['height']:2000;
|
||||
|
||||
$cachefile = ROOT.DS.'tmp'.DS.$width .'x'.$height.'.png';
|
||||
if(!file_exists($cachefile))
|
||||
{
|
||||
$image=$pm->gradient($width, $height, array('#A7FF78', '#A7FF78', '#78FFD4', '#78FFD4'));
|
||||
imagepng($image,$cachefile);
|
||||
}
|
||||
else
|
||||
$image = imagecreatefrompng($cachefile);
|
||||
header('Content-type: image/png');
|
||||
imagepng($image);
|
||||
imagedestroy($image);
|
||||
exit();
|
||||
}
|
||||
else if(!is_array($data) || !$data['hash'])
|
||||
{
|
||||
if((UPLOAD_FORM_LOCATION && $url==UPLOAD_FORM_LOCATION) || (!UPLOAD_FORM_LOCATION))
|
||||
{
|
||||
@@ -499,4 +518,18 @@ function endswith($string, $test) {
|
||||
$testlen = strlen($test);
|
||||
if ($testlen > $strlen) return false;
|
||||
return substr_compare($string, $test, $strlen - $testlen, $testlen) === 0;
|
||||
}
|
||||
|
||||
function remote_filesize($url) {
|
||||
static $regex = '/^Content-Length: *+\K\d++$/im';
|
||||
if (!$fp = @fopen($url, 'rb')) {
|
||||
return false;
|
||||
}
|
||||
if (
|
||||
isset($http_response_header) &&
|
||||
preg_match($regex, implode("\n", $http_response_header), $matches)
|
||||
) {
|
||||
return (int)$matches[0];
|
||||
}
|
||||
return strlen(stream_get_contents($fp));
|
||||
}
|
||||
@@ -79,8 +79,19 @@ define('SHOW_ERRORS', false);
|
||||
|
||||
/* BACKBLAZE B2 */
|
||||
/* You can find your info here: https://secure.backblaze.com/b2_buckets.htm */
|
||||
//define('BACKBLAZE',true); //true=>use backblaze to upload images, false=>don't
|
||||
//define('BACKBLAZE',true); //true=>use backblaze false=>don't
|
||||
//define('BACKBLAZE_ID','');
|
||||
//define('BACKBLAZE_KEY', '');
|
||||
//define('BACKBLAZE_BUCKET_ID', '');
|
||||
//define('BACKBLAZE_BUCKET_NAME', '');
|
||||
//define('BACKBLAZE_BUCKET_NAME', '');
|
||||
//define('BACKBLAZE_AUTODOWNLOAD', true); //if true, will download images from backblaze if not found local
|
||||
//define('BACKBLAZE_AUTOUPLOAD', true); //if true, will upload images to backblaze when they are uploaded to pictshare
|
||||
//define('BACKBLAZE_AUTODELETE', true); //if true, will delete images from backblaze if they are deleted from pictshare
|
||||
|
||||
//If you have a NAS or some cifs or nfs mounted drive, you can specify this here as a folder
|
||||
//if a requested hash is not found locally, its looked up on this location. This allows for mounted external spaces
|
||||
//or just backups on a second drive.
|
||||
//Also new hashes will be uploaded there (just the originals, not resizes)
|
||||
//value should be a path **without tailing slash**!
|
||||
|
||||
define('ALT_FOLDER','/mnt');
|
||||
@@ -94,7 +94,17 @@ class PictshareModel extends Model
|
||||
}
|
||||
$data['hash']=$el;
|
||||
}
|
||||
else if(BACKBLAZE === true && $this->couldThisBeAnImage($el)) //looks like it might be a hash but didn't find it here. Let's see
|
||||
else if(defined('ALT_FOLDER') && ALT_FOLDER && $this->couldThisBeAnImage($el)) //check alternative folder for the hash
|
||||
{
|
||||
$altname=ALT_FOLDER.DS.$el;
|
||||
//var_dump($altname);
|
||||
if(file_exists($altname))
|
||||
{
|
||||
$this->uploadImageFromURL($altname,$el);
|
||||
$data['hash'] = $el;
|
||||
}
|
||||
}
|
||||
else if(BACKBLAZE === true && $this->couldThisBeAnImage($el) && BACKBLAZE_AUTODOWNLOAD ===true) //looks like it might be a hash but didn't find it here. Let's see
|
||||
{
|
||||
$b = new Backblaze();
|
||||
if($b->download($el)) //if the backblaze download function says it's an image, we'll take it
|
||||
@@ -211,8 +221,18 @@ class PictshareModel extends Model
|
||||
|
||||
rmdir($base_path);
|
||||
|
||||
//delete from alt folder if configured
|
||||
if(defined('ALT_FOLDER') && ALT_FOLDER)
|
||||
{
|
||||
$altname=ALT_FOLDER.DS.$hash;
|
||||
if(file_exists($altname))
|
||||
{
|
||||
unlink($altname);
|
||||
}
|
||||
}
|
||||
|
||||
//delete from backblaze if configured
|
||||
if(BACKBLAZE===true)
|
||||
if(BACKBLAZE===true && BACKBLAZE_AUTODELETE===true)
|
||||
{
|
||||
$b = new Backblaze();
|
||||
$b->deleteFile($hash);
|
||||
@@ -351,7 +371,9 @@ class PictshareModel extends Model
|
||||
<FORM id="form" enctype="multipart/form-data" method="post">
|
||||
<div id="formular">
|
||||
'.$upload_code_form.'
|
||||
<strong>'.$this->translate(4).': </strong><input class="input" type="file" name="pic[]" multiple><div class="clear"></div>
|
||||
<strong>'.$this->translate(4).': </strong><br/><input class="input" type="file" name="pic[]" multiple><div class="clear"></div>
|
||||
<div class="clear"></div><br>
|
||||
<strong>'.$this->translate(22).': </strong><br/><input style="width:80%" type="text" name="picurl" /><div class="clear"></div>
|
||||
<div class="clear"></div><br>
|
||||
</div>
|
||||
<INPUT class="btn" style="font-size:15px;font-weight:bold;background-color:#74BDDE;padding:3px;" type="submit" id="submit" name="submit" value="'.$this->translate(3).'" onClick="setTimeout(function(){document.getElementById(\'submit\').disabled = \'disabled\';}, 1);$(\'#movingBallG\').fadeIn()">
|
||||
@@ -419,6 +441,7 @@ class PictshareModel extends Model
|
||||
|
||||
function isTypeAllowed($type)
|
||||
{
|
||||
$type=strtolower($type);
|
||||
switch($type)
|
||||
{
|
||||
case 'image/png': return 'png';
|
||||
@@ -428,6 +451,7 @@ class PictshareModel extends Model
|
||||
|
||||
case 'image/jpeg': return 'jpg';
|
||||
case 'jpeg': return 'jpg';
|
||||
case 'jpg': return 'jpg';
|
||||
case 'pjpeg': return 'jpg';
|
||||
|
||||
case 'image/gif': return 'gif';
|
||||
@@ -444,7 +468,7 @@ class PictshareModel extends Model
|
||||
return $this->isTypeAllowed($this->getTypeOfFile($url));
|
||||
}
|
||||
|
||||
function uploadImageFromURL($url)
|
||||
function uploadImageFromURL($url,$forcehash=false)
|
||||
{
|
||||
$type = $this->getTypeOfFile($url);
|
||||
$type = $this->isTypeAllowed($type);
|
||||
@@ -452,21 +476,29 @@ class PictshareModel extends Model
|
||||
if(!$type)
|
||||
return array('status'=>'ERR','reason'=>'wrong filetype');
|
||||
|
||||
$tempfile = ROOT.DS.'tmp'.DS.md5(rand(1,999)*rand(0,10000)+time());
|
||||
file_put_contents($tempfile, file_get_contents($url));
|
||||
|
||||
//remove all exif data from jpeg
|
||||
if($type=='jpg')
|
||||
{
|
||||
$res = imagecreatefromjpeg($tempfile);
|
||||
imagejpeg($res, $tempfile, (defined('JPEG_COMPRESSION')?JPEG_COMPRESSION:90));
|
||||
}
|
||||
$url = $tempfile;
|
||||
|
||||
$dup_id = $this->isDuplicate($url);
|
||||
if($dup_id)
|
||||
{
|
||||
$hash = $dup_id;
|
||||
$hash = $forcehash?$forcehash:$dup_id;
|
||||
$url = ROOT.DS.'upload'.DS.$hash.DS.$hash;
|
||||
}
|
||||
else
|
||||
{
|
||||
$hash = $this->getNewHash($type);
|
||||
$hash = $forcehash?$forcehash:$this->getNewHash($type);
|
||||
$this->saveSHAOfFile($url,$hash);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
if($dup_id)
|
||||
return array('status'=>'OK','type'=>$type,'hash'=>$hash,'url'=>DOMAINPATH.PATH.$hash,'domain'=>DOMAINPATH);
|
||||
|
||||
@@ -474,12 +506,12 @@ class PictshareModel extends Model
|
||||
$file = ROOT.DS.'upload'.DS.$hash.DS.$hash;
|
||||
|
||||
file_put_contents($file, file_get_contents($url));
|
||||
unlink($tempfile);
|
||||
|
||||
//remove all exif data from jpeg
|
||||
if($type=='jpg')
|
||||
//re-render new mp4 by calling the re-encode script
|
||||
if($type=='mp4' && strtoupper(substr(PHP_OS, 0, 3)) === 'WIN')
|
||||
{
|
||||
$res = imagecreatefromjpeg($file);
|
||||
imagejpeg($res, $file, (defined('JPEG_COMPRESSION')?JPEG_COMPRESSION:90));
|
||||
system("nohup php ".ROOT.DS.'tools'.DS.'re-encode_mp4.php force '.$hash." > /dev/null 2> /dev/null &");
|
||||
}
|
||||
|
||||
if(LOG_UPLOADER)
|
||||
@@ -489,7 +521,16 @@ class PictshareModel extends Model
|
||||
fclose($fh);
|
||||
}
|
||||
|
||||
if(BACKBLAZE===true)
|
||||
if(defined('ALT_FOLDER') && ALT_FOLDER)
|
||||
{
|
||||
$altname=ALT_FOLDER.DS.$hash;
|
||||
if(!file_exists($altname) && is_dir(ALT_FOLDER))
|
||||
{
|
||||
copy($file,$altname);
|
||||
}
|
||||
}
|
||||
|
||||
if(BACKBLAZE===true && BACKBLAZE_AUTOUPLOAD===true)
|
||||
{
|
||||
$b = new Backblaze();
|
||||
$b->upload($hash);
|
||||
@@ -504,6 +545,8 @@ class PictshareModel extends Model
|
||||
{
|
||||
$code = getRandomString(32);
|
||||
$file = ROOT.DS.'upload'.DS.'deletecodes'.DS.$code;
|
||||
if(!is_dir(ROOT.DS.'upload'.DS.'deletecodes'))
|
||||
mkdir(ROOT.DS.'upload'.DS.'deletecodes');
|
||||
if(file_exists($file)) continue;
|
||||
file_put_contents($file,$hash);
|
||||
return $code;
|
||||
@@ -621,6 +664,42 @@ class PictshareModel extends Model
|
||||
}
|
||||
}
|
||||
|
||||
if($_REQUEST['picurl'])
|
||||
{
|
||||
$url = $_REQUEST['picurl'];
|
||||
if(startsWith($url,'http://') || startsWith($url,'https://'))
|
||||
{
|
||||
$size_mb = remote_filesize($url)*0.000001;
|
||||
$maxsize = (int)(ini_get('upload_max_filesize'));
|
||||
if(endswith($maxsize,'MB'))
|
||||
{
|
||||
$maxsize = substr($maxsize,0,strpos($maxsize,'MB'));
|
||||
}
|
||||
else $maxsize = 20;
|
||||
if($size_mb <= $maxsize) //if the file is within maxsize lets download it
|
||||
{
|
||||
$name = basename($url);//md5(rand(1,9999)*rand(1,99999));
|
||||
file_put_contents(ROOT.DS.'tmp'.DS.$name, file_get_contents($url));
|
||||
$data = $this->uploadImageFromURL(ROOT.DS.'tmp'.DS.$name);
|
||||
if($data['status']=='OK')
|
||||
{
|
||||
if($data['deletecode'])
|
||||
$deletecode = '<br/><a target="_blank" href="'.DOMAINPATH.PATH.$data['hash'].'/delete_'.$data['deletecode'].'">Delete image</a>';
|
||||
else $deletecode = '';
|
||||
if($data['type']=='mp4')
|
||||
$o.= '<div><h2>'.$this->translate(4).' '.++$i.'</h2><a target="_blank" href="'.DOMAINPATH.PATH.$data['hash'].'">'.$data['hash'].'</a>'.$deletecode.'</div>';
|
||||
else
|
||||
$o.= '<div><h2>'.$this->translate(4).' '.++$i.'</h2><a target="_blank" href="'.DOMAINPATH.PATH.$data['hash'].'"><img src="'.DOMAINPATH.PATH.'300/'.$data['hash'].'" /></a>'.$deletecode.'</div>';
|
||||
|
||||
$hashes[] = $data['hash'];
|
||||
}
|
||||
unlink(ROOT.DS.'tmp'.DS.$name);
|
||||
}
|
||||
else
|
||||
$o.= '<div><h2>Error</h2>File '.$url.' is too large. Max upload size: '.$maxsize.'MB</div>';
|
||||
}
|
||||
}
|
||||
|
||||
if(count($hashes)>1)
|
||||
{
|
||||
$albumlink = DOMAINPATH.PATH.implode('/',$hashes);
|
||||
@@ -694,6 +773,7 @@ class PictshareModel extends Model
|
||||
$words[19] = $params[0].' Aufrufe aus '.$params[1];
|
||||
$words[20] = 'Upload-Code';
|
||||
$words[21] = 'Falscher Upload Code eingegeben. Upload abgebrochen';
|
||||
$words[22] = 'URL für den Upload';
|
||||
|
||||
break;
|
||||
|
||||
@@ -720,6 +800,7 @@ class PictshareModel extends Model
|
||||
$words[19] = $params[0].' views from '.$params[1];
|
||||
$words[20] = 'Upload code';
|
||||
$words[21] = 'Invalid upload code provided';
|
||||
$words[22] = 'URL to upload';
|
||||
}
|
||||
|
||||
return $words[$index];
|
||||
@@ -853,7 +934,7 @@ class PictshareModel extends Model
|
||||
switch($type)
|
||||
{
|
||||
case 'mp4':
|
||||
$addition = '-c:v libx264';
|
||||
$addition = '-c:v libx264 -profile:v baseline -level 3.0 -pix_fmt yuv420p';
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1001,4 +1082,63 @@ class PictshareModel extends Model
|
||||
return array('width'=>$maxwidth,'height'=>$maxheight);
|
||||
}
|
||||
|
||||
|
||||
function gradient($w=100, $h=100, $c=array('#FFFFFF','#FF0000','#00FF00','#0000FF'), $hex=true)
|
||||
{
|
||||
/*
|
||||
Generates a gradient image
|
||||
|
||||
Author: Christopher Kramer
|
||||
|
||||
Parameters:
|
||||
w: width in px
|
||||
h: height in px
|
||||
c: color-array with 4 elements:
|
||||
$c[0]: top left color
|
||||
$c[1]: top right color
|
||||
$c[2]: bottom left color
|
||||
$c[3]: bottom right color
|
||||
|
||||
if $hex is true (default), colors are hex-strings like '#FFFFFF' (NOT '#FFF')
|
||||
if $hex is false, a color is an array of 3 elements which are the rgb-values, e.g.:
|
||||
$c[0]=array(0,255,255);
|
||||
|
||||
*/
|
||||
|
||||
$im=imagecreatetruecolor($w,$h);
|
||||
|
||||
if($hex) { // convert hex-values to rgb
|
||||
for($i=0;$i<=3;$i++) {
|
||||
$c[$i]=$this->hex2rgb($c[$i]);
|
||||
}
|
||||
}
|
||||
|
||||
$rgb=$c[0]; // start with top left color
|
||||
for($x=0;$x<=$w;$x++) { // loop columns
|
||||
for($y=0;$y<=$h;$y++) { // loop rows
|
||||
// set pixel color
|
||||
$col=imagecolorallocate($im,$rgb[0],$rgb[1],$rgb[2]);
|
||||
imagesetpixel($im,$x-1,$y-1,$col);
|
||||
// calculate new color
|
||||
for($i=0;$i<=2;$i++) {
|
||||
$rgb[$i]=
|
||||
$c[0][$i]*(($w-$x)*($h-$y)/($w*$h)) +
|
||||
$c[1][$i]*($x *($h-$y)/($w*$h)) +
|
||||
$c[2][$i]*(($w-$x)*$y /($w*$h)) +
|
||||
$c[3][$i]*($x *$y /($w*$h));
|
||||
}
|
||||
}
|
||||
}
|
||||
return $im;
|
||||
}
|
||||
|
||||
function hex2rgb($hex)
|
||||
{
|
||||
$rgb[0]=hexdec(substr($hex,1,2));
|
||||
$rgb[1]=hexdec(substr($hex,3,2));
|
||||
$rgb[2]=hexdec(substr($hex,5,2));
|
||||
return($rgb);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -40,8 +40,12 @@
|
||||
<div id="container">
|
||||
<video id="video" poster="<?php echo DOMAINPATH.PATH.'preview/'.$hash; ?>" preload="auto" autoplay="autoplay" muted="muted" loop="loop" webkit-playsinline>
|
||||
<source src="<?php echo DOMAINPATH.PATH.'raw/mp4/'.$hash; ?>" type="video/mp4">
|
||||
<!--<source src="<?php echo DOMAINPATH.PATH.'raw/webm/'.$hash; ?>" type="video/webm">
|
||||
<source src="<?php echo DOMAINPATH.PATH.'raw/ogg/'.$hash; ?>" type="video/ogg">-->
|
||||
<?php
|
||||
if(file_exists(ROOT.DS.'upload'.DS.$hash.DS.'webm_1.'.$hash))
|
||||
echo '<source src="'.DOMAINPATH.PATH.'raw/webm/'.$hash.'" type="video/webm">'."\n";
|
||||
if(file_exists(ROOT.DS.'upload'.DS.$hash.DS.'ogg_1.'.$hash))
|
||||
echo '<source src="'.DOMAINPATH.PATH.'raw/ogg/'.$hash.'" type="video/ogg">'."\n";
|
||||
?>
|
||||
</video>
|
||||
</div>
|
||||
<small><?php echo $filesize; ?></small>
|
||||
|
||||
99
tools/altfolder_copy.php
Normal file
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Alternative folder upload
|
||||
* This tool copies all raw images/videos/gifs to the defined ALT_FOLDER location
|
||||
* This will create a copy in the location. The location can be a mounted external server like CIFS or sshfs
|
||||
* This will allow you to store a backup of your images on some other server
|
||||
*
|
||||
*/
|
||||
|
||||
if(php_sapi_name() !== 'cli') exit('This script can only be called via CLI');
|
||||
error_reporting(E_ALL & ~E_DEPRECATED & ~E_STRICT & ~E_NOTICE);
|
||||
define('DS', DIRECTORY_SEPARATOR);
|
||||
define('ROOT', dirname(__FILE__).DS.'..');
|
||||
include_once(ROOT.DS.'inc/config.inc.php');
|
||||
include_once(ROOT.DS.'inc/core.php');
|
||||
|
||||
if(!defined('ALT_FOLDER') || !ALT_FOLDER)
|
||||
die("[X] Error: You should define the ALT_FOLDER config in your inc/config.inc.php first");
|
||||
|
||||
$pm = new PictshareModel();
|
||||
|
||||
if(in_array('sim',$argv))
|
||||
{
|
||||
echo "[!!!!] SIMULATION MODE. Nothing will be uploaded [!!!!] \n\n";
|
||||
$sim = true;
|
||||
}
|
||||
else $sim = false;
|
||||
|
||||
|
||||
//gather local data
|
||||
echo "[i] Looping through local files\n";
|
||||
|
||||
$dir = ROOT.DS.'upload'.DS;
|
||||
$dh = opendir($dir);
|
||||
$localfiles = array();
|
||||
|
||||
$allhashes=0;$allsize=0;
|
||||
$skips=0;$skipsize=0;
|
||||
$copied=0;$copysize=0;
|
||||
$errors=0;$errorsize=0;
|
||||
|
||||
while (false !== ($hash = readdir($dh))) {
|
||||
if($hash=='.'||$hash=='..') continue;
|
||||
$img = $dir.$hash.DS.$hash;
|
||||
if(!file_exists($img)) continue;
|
||||
$info = strtolower(pathinfo($img, PATHINFO_EXTENSION));
|
||||
$thissize = filesize($img);
|
||||
$type = $pm->isTypeAllowed($info);
|
||||
++$allhashes;
|
||||
$allsize+=$thissize;
|
||||
if($type)
|
||||
{
|
||||
if(file_exists(ALT_FOLDER.DS.$hash))
|
||||
{
|
||||
echo " [!] Skipping existing $hash \n";
|
||||
++$skips;
|
||||
$skipsize+=$thissize;
|
||||
}
|
||||
else
|
||||
{
|
||||
++$copied;
|
||||
$copysize+=$thissize;
|
||||
echo "[i] Copying $hash to ".ALT_FOLDER.DS.$hash." \r";
|
||||
if($sim===false)
|
||||
copy($img,ALT_FOLDER.DS.$hash);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
++$errors;
|
||||
$errorsize+=$thissize;
|
||||
echo " [X] ERROR $hash not allowed format: $info \n";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
echo "\n[i] Done\n";
|
||||
echo "\n----------- STATS ----------\n\n";
|
||||
echo " All files found:\t$allhashes\t".renderSize($allsize)."\n";
|
||||
echo " Copied files:\t$copied\t".renderSize($copysize)."\n";
|
||||
echo " Skipped files:\t$skips\t".renderSize($skipsize)."\n";
|
||||
echo " Erroneous files:\t$errors\t".renderSize($errorsize)."\n";
|
||||
echo "\n";
|
||||
|
||||
|
||||
function renderSize($bytes, $precision = 2) {
|
||||
$units = array('B', 'KB', 'MB', 'GB', 'TB');
|
||||
|
||||
$bytes = max($bytes, 0);
|
||||
$pow = floor(($bytes ? log($bytes) : 0) / log(1024));
|
||||
$pow = min($pow, count($units) - 1);
|
||||
|
||||
// Uncomment one of the following alternatives
|
||||
$bytes /= pow(1024, $pow);
|
||||
// $bytes /= (1 << (10 * $pow));
|
||||
|
||||
return round($bytes, $precision) . ' ' . $units[$pow];
|
||||
}
|
||||
91
tools/backblaze_upload.php
Normal file
@@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Backblaze uploader
|
||||
* This tool uploads all local images to backblaze if they don't exist yet
|
||||
* You can use this to backup your images to backblaze or set it up as your data source for scaling
|
||||
*
|
||||
*/
|
||||
|
||||
if(php_sapi_name() !== 'cli') exit('This script can only be called via CLI');
|
||||
error_reporting(E_ALL & ~E_DEPRECATED & ~E_STRICT & ~E_NOTICE);
|
||||
define('DS', DIRECTORY_SEPARATOR);
|
||||
define('ROOT', dirname(__FILE__).DS.'..');
|
||||
include_once(ROOT.DS.'inc/config.inc.php');
|
||||
include_once(ROOT.DS.'inc/core.php');
|
||||
include_once(ROOT.DS.'classes/backblaze.php');
|
||||
|
||||
$pm = new PictshareModel();
|
||||
|
||||
if(in_array('sim',$argv))
|
||||
{
|
||||
echo "[!!!!] SIMULATION MODE. Nothing will be uploaded [!!!!] \n\n";
|
||||
$sim = true;
|
||||
}
|
||||
else $sim = false;
|
||||
|
||||
if(in_array('recentlyrendered',$argv))
|
||||
{
|
||||
echo "[O] Will only upload if the image was recently viewed. Recently meaning now minus one year \n\n";
|
||||
$recentonly = true;
|
||||
}
|
||||
else $recentonly = false;
|
||||
|
||||
|
||||
$b = new Backblaze();
|
||||
echo "[i] Loading file list from Backblaze ..";
|
||||
$remotefiles = $b->getAllFilesInBucket();
|
||||
echo " done. Got ".count($remotefiles)." files\n";
|
||||
|
||||
$uploadsize = 0;
|
||||
|
||||
|
||||
//gather local data
|
||||
$dir = ROOT.DS.'upload'.DS;
|
||||
$dh = opendir($dir);
|
||||
$localfiles = array();
|
||||
|
||||
echo "[i] Loading local files ..";
|
||||
while (false !== ($filename = readdir($dh))) {
|
||||
$img = $dir.$filename.DS.$filename;
|
||||
if(!file_exists($img)) continue;
|
||||
$type = strtolower(pathinfo($img, PATHINFO_EXTENSION));
|
||||
$type = $pm->isTypeAllowed($type);
|
||||
if($type)
|
||||
{
|
||||
if($recentonly===true)
|
||||
{
|
||||
$recent = @file_get_contents($dir.$filename.DS.'last_rendered.txt');
|
||||
if(!$recent || (time()-$recent) > 3600*24*365) continue;
|
||||
}
|
||||
$localfiles[] = $filename;
|
||||
}
|
||||
}
|
||||
|
||||
echo " done. Got ".count($localfiles)." files\n";
|
||||
|
||||
echo "[i] Checking if there are local files that are not remote\n";
|
||||
foreach($localfiles as $hash)
|
||||
{
|
||||
if(!$remotefiles[$hash])
|
||||
{
|
||||
echo " [!] $hash not found on BB. Uploading...";
|
||||
if($sim!==true)
|
||||
$b->upload($hash);
|
||||
$uploadsize+=filesize($dir.$hash.DS.$hash);
|
||||
echo " done.\tUploaded so far: ".renderSize($uploadsize)."\n";
|
||||
}
|
||||
}
|
||||
function renderSize($bytes, $precision = 2) {
|
||||
$units = array('B', 'KB', 'MB', 'GB', 'TB');
|
||||
|
||||
$bytes = max($bytes, 0);
|
||||
$pow = floor(($bytes ? log($bytes) : 0) / log(1024));
|
||||
$pow = min($pow, count($units) - 1);
|
||||
|
||||
// Uncomment one of the following alternatives
|
||||
$bytes /= pow(1024, $pow);
|
||||
// $bytes /= (1 << (10 * $pow));
|
||||
|
||||
return round($bytes, $precision) . ' ' . $units[$pow];
|
||||
}
|
||||
97
tools/cleanup.php
Normal file
@@ -0,0 +1,97 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Cleanup
|
||||
* This script cleans up all uploads and only leaves the original files
|
||||
* So if you have an image and it was converted to change sizes, these files are deleted
|
||||
* And will be re-created next time they are requested
|
||||
*
|
||||
* usage: php cleanup.php [sim]
|
||||
*
|
||||
* Params:
|
||||
* sim => Just simulate everything, don't actually delete
|
||||
*/
|
||||
|
||||
|
||||
if(php_sapi_name() !== 'cli') exit('This script can only be called via CLI');
|
||||
error_reporting(E_ALL & ~E_DEPRECATED & ~E_STRICT & ~E_NOTICE);
|
||||
define('DS', DIRECTORY_SEPARATOR);
|
||||
define('ROOT', dirname(__FILE__).DS.'..');
|
||||
include_once(ROOT.DS.'inc/config.inc.php');
|
||||
include_once(ROOT.DS.'inc/core.php');
|
||||
|
||||
$pm = new PictshareModel();
|
||||
|
||||
if(in_array('sim',$argv))
|
||||
{
|
||||
echo "[!!!!] SIMULATION MODE. Nothing will be deleted [!!!!] \n\n";
|
||||
$sim = true;
|
||||
}
|
||||
else $sim = false;
|
||||
|
||||
$dir = ROOT.DS.'upload'.DS;
|
||||
$dh = opendir($dir);
|
||||
$localfiles = array();
|
||||
|
||||
if(in_array('noskip',$argv))
|
||||
{
|
||||
echo "Won't skip existing files\n\n";
|
||||
$allowskipping = false;
|
||||
}
|
||||
else
|
||||
$allowskipping = true;
|
||||
|
||||
//making sure ffmpeg is executable
|
||||
system("chmod +x ".ROOT.DS.'bin'.DS.'ffmpeg');
|
||||
|
||||
echo "[i] Finding local mp4 files ..";
|
||||
while (false !== ($filename = readdir($dh))) {
|
||||
$img = $dir.$filename.DS.$filename;
|
||||
if(!file_exists($img)) continue;
|
||||
$type = strtolower(pathinfo($img, PATHINFO_EXTENSION));
|
||||
$type = $pm->isTypeAllowed($type);
|
||||
if($type)
|
||||
$localfiles[] = $filename;
|
||||
}
|
||||
|
||||
if(count($localfiles)==0) exit('No files found'."\n");
|
||||
|
||||
echo " done. Got ".count($localfiles)." folders\n";
|
||||
|
||||
$sumsize = 0;
|
||||
|
||||
echo "[i] Looking for files to clean up\n";
|
||||
foreach($localfiles as $hash)
|
||||
{
|
||||
$dir = ROOT.DS.'upload'.DS.$hash.DS;
|
||||
$dh = opendir($dir);
|
||||
|
||||
while (false !== ($filename = readdir($dh))) {
|
||||
if(!is_file($dir.$filename) || $filename==$hash || $filename == 'last_rendered.txt')
|
||||
continue;
|
||||
|
||||
echo "[$hash] $filename";
|
||||
$sumsize+=filesize($dir.$filename);
|
||||
if(!$sim)
|
||||
unlink($dir.$filename);
|
||||
|
||||
echo "\t".(file_exists($dir.$filename)?'NOT DELETED':'DELETED')."\n";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
echo "\n[!] Finished! Deleted ".renderSize($sumsize)."\n";
|
||||
|
||||
function renderSize($bytes, $precision = 2) {
|
||||
$units = array('B', 'KB', 'MB', 'GB', 'TB');
|
||||
|
||||
$bytes = max($bytes, 0);
|
||||
$pow = floor(($bytes ? log($bytes) : 0) / log(1024));
|
||||
$pow = min($pow, count($units) - 1);
|
||||
|
||||
// Uncomment one of the following alternatives
|
||||
$bytes /= pow(1024, $pow);
|
||||
// $bytes /= (1 << (10 * $pow));
|
||||
|
||||
return round($bytes, $precision) . ' ' . $units[$pow];
|
||||
}
|
||||
77
tools/re-encode_mp4.php
Normal file
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* MP4 re-encoder
|
||||
* Since we don't know where the mp4's come from we'll have to handle them ourselves
|
||||
* While desktop browsers are more forgiving older phones might not be
|
||||
*
|
||||
* usage: php re-encode_mp4.php [noogg] [nowebm] [noskip]
|
||||
*
|
||||
* Params:
|
||||
* noskip => Won't skip existing videos (re-renders them)
|
||||
*/
|
||||
|
||||
|
||||
if(php_sapi_name() !== 'cli') exit('This script can only be called via CLI');
|
||||
error_reporting(E_ALL & ~E_DEPRECATED & ~E_STRICT & ~E_NOTICE);
|
||||
define('DS', DIRECTORY_SEPARATOR);
|
||||
define('ROOT', dirname(__FILE__).DS.'..');
|
||||
include_once(ROOT.DS.'inc/config.inc.php');
|
||||
include_once(ROOT.DS.'inc/core.php');
|
||||
|
||||
$pm = new PictshareModel();
|
||||
|
||||
$dir = ROOT.DS.'upload'.DS;
|
||||
$dh = opendir($dir);
|
||||
$localfiles = array();
|
||||
|
||||
foreach($argv as $arg)
|
||||
{
|
||||
if($pm->isImage($arg) && $pm->isTypeAllowed(pathinfo($dir.$arg, PATHINFO_EXTENSION)) == 'mp4')
|
||||
$localfiles[] = $arg;
|
||||
}
|
||||
|
||||
if(in_array('noskip',$argv) || in_array('force',$argv))
|
||||
{
|
||||
echo "Won't skip existing files\n\n";
|
||||
$allowskipping = false;
|
||||
}
|
||||
else
|
||||
$allowskipping = true;
|
||||
|
||||
//making sure ffmpeg is executable
|
||||
system("chmod +x ".ROOT.DS.'bin'.DS.'ffmpeg');
|
||||
|
||||
if(count($localfiles)==0)
|
||||
{
|
||||
echo "[i] Finding local mp4 files\n";
|
||||
while (false !== ($filename = readdir($dh))) {
|
||||
$img = $dir.$filename.DS.$filename;
|
||||
if(!file_exists($img)) continue;
|
||||
$type = strtolower(pathinfo($img, PATHINFO_EXTENSION));
|
||||
$type = $pm->isTypeAllowed($type);
|
||||
if($type=='mp4')
|
||||
$localfiles[] = $filename;
|
||||
}
|
||||
}
|
||||
|
||||
if(count($localfiles)==0) exit('No MP4 files found'."\n");
|
||||
|
||||
echo "[i] Got ".count($localfiles)." files\n";
|
||||
|
||||
echo "[i] Starting to convert\n";
|
||||
foreach($localfiles as $hash)
|
||||
{
|
||||
$img = $dir.$hash.DS.$hash;
|
||||
$tmp = ROOT.DS.'tmp'.DS.$hash;
|
||||
if(file_exists($tmp) && $allowskipping==true)
|
||||
echo "Skipping $hash\n";
|
||||
else
|
||||
{
|
||||
$cmd = ROOT.DS.'bin'.DS."ffmpeg -loglevel panic -y -i $img -vcodec libx264 -an -profile:v baseline -level 3.0 -pix_fmt yuv420p -vf \"scale=trunc(iw/2)*2:trunc(ih/2)*2\" $tmp && cp $tmp $img";
|
||||
echo " [i] Converting $hash";
|
||||
system($cmd);
|
||||
echo "\tdone\n";
|
||||
}
|
||||
|
||||
}
|
||||
24
tools/recreate_hashlist.php
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
define('DS', DIRECTORY_SEPARATOR);
|
||||
define('ROOT', dirname(__FILE__).DS.'..');
|
||||
|
||||
echo "[i] Starting recreation of hashes.csv\n";
|
||||
|
||||
$dir = ROOT.DS.'upload'.DS;
|
||||
$dh = opendir($dir);
|
||||
|
||||
$fp = fopen($dir.'hashes.csv','w');
|
||||
if(!$fp)
|
||||
exit("[X] Can't open hashes.csv to write");
|
||||
|
||||
while (false !== ($hash = readdir($dh))) {
|
||||
$img = $dir.$hash.DS.$hash;
|
||||
if(!file_exists($img) || $hash=='.' || $hash=='..') continue;
|
||||
echo " [s] Calculating $hash\n";
|
||||
$sha1 = sha1_file($img);
|
||||
fwrite($fp,"$sha1;$hash\n");
|
||||
}
|
||||
|
||||
fclose($fp);
|
||||
|
||||
echo "[i] Finished\n";
|
||||
105
tools/render_webm_ogg.php
Normal file
@@ -0,0 +1,105 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* MP4 to webm and ogg converter
|
||||
* When MP4s are uploaded we only have MP4s. This script converts also to
|
||||
* webm and ogg for wider range of supported devices
|
||||
*
|
||||
* usage: php render_webm_ogg.php [noogg] [nowebm] [noskip]
|
||||
*
|
||||
* Params:
|
||||
* noogg => Won't render videos as OGG
|
||||
* nowebm => Won't render videos as webm
|
||||
* noskip => Won't skip existing videos (re-renders them)
|
||||
*/
|
||||
|
||||
if(php_sapi_name() !== 'cli') exit('This script can only be called via CLI');
|
||||
error_reporting(E_ALL & ~E_DEPRECATED & ~E_STRICT & ~E_NOTICE);
|
||||
define('DS', DIRECTORY_SEPARATOR);
|
||||
define('ROOT', dirname(__FILE__).DS.'..');
|
||||
include_once(ROOT.DS.'inc/config.inc.php');
|
||||
include_once(ROOT.DS.'inc/core.php');
|
||||
|
||||
$pm = new PictshareModel();
|
||||
|
||||
$dir = ROOT.DS.'upload'.DS;
|
||||
$dh = opendir($dir);
|
||||
$localfiles = array();
|
||||
|
||||
if(in_array('noskip',$argv))
|
||||
{
|
||||
echo "Won't skip existing files\n\n";
|
||||
$allowskipping = false;
|
||||
}
|
||||
else
|
||||
$allowskipping = true;
|
||||
|
||||
//making sure ffmpeg is executable
|
||||
system("chmod +x ".ROOT.DS.'bin'.DS.'ffmpeg');
|
||||
|
||||
echo "[i] Finding local mp4 files ..";
|
||||
while (false !== ($filename = readdir($dh))) {
|
||||
$img = $dir.$filename.DS.$filename;
|
||||
if(!file_exists($img)) continue;
|
||||
$type = strtolower(pathinfo($img, PATHINFO_EXTENSION));
|
||||
$type = $pm->isTypeAllowed($type);
|
||||
if($type=='mp4')
|
||||
$localfiles[] = $filename;
|
||||
}
|
||||
|
||||
if(count($localfiles)==0) exit(' No MP4 files found'."\n");
|
||||
|
||||
echo " done. Got ".count($localfiles)." files\n";
|
||||
|
||||
echo "[i] Starting to convert\n";
|
||||
foreach($localfiles as $hash)
|
||||
{
|
||||
$img = $dir.$hash.DS.$hash;
|
||||
|
||||
if(!in_array('noogg',$argv))
|
||||
{
|
||||
$tmp = ROOT.DS.'tmp'.DS.$hash.'.ogg';
|
||||
$ogg = $dir.$hash.DS.'ogg_1.'.$hash;
|
||||
if(file_exists($ogg) && $allowskipping==true)
|
||||
echo "Skipping OGG of $hash\n";
|
||||
else
|
||||
{
|
||||
echo " [OGG] User wants OGG. Will do.. ";
|
||||
$cmd = "../bin/ffmpeg -y -i $img -loglevel panic -vcodec libtheora -an $tmp && cp $tmp $ogg";
|
||||
system($cmd);
|
||||
echo "done\n";
|
||||
}
|
||||
}
|
||||
|
||||
if(!in_array('nowebm',$argv))
|
||||
{
|
||||
$tmp = ROOT.DS.'tmp'.DS.$hash.'.webm';
|
||||
$webm = $dir.$hash.DS.'webm_1.'.$hash;
|
||||
if(file_exists($webm) && $allowskipping==true)
|
||||
echo "Skipping WEBM of $hash\n";
|
||||
else
|
||||
{
|
||||
echo " [WEBM] User wants WEBM. Will do.. ";
|
||||
$cmd = "../bin/ffmpeg -y -i $img -loglevel panic -c:v libvpx -crf 10 -b:v 1M $tmp && cp $tmp $webm";
|
||||
system($cmd);
|
||||
echo "done\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
function renderSize($bytes, $precision = 2) {
|
||||
$units = array('B', 'KB', 'MB', 'GB', 'TB');
|
||||
|
||||
$bytes = max($bytes, 0);
|
||||
$pow = floor(($bytes ? log($bytes) : 0) / log(1024));
|
||||
$pow = min($pow, count($units) - 1);
|
||||
|
||||
// Uncomment one of the following alternatives
|
||||
$bytes /= pow(1024, $pow);
|
||||
// $bytes /= (1 << (10 * $pow));
|
||||
|
||||
return round($bytes, $precision) . ' ' . $units[$pow];
|
||||
}
|
||||
0
upload/.gitignore
vendored
Normal file → Executable file
0
upload/.htaccess
Normal file → Executable file
4
upload/deletecodes/.gitignore
vendored
@@ -1,4 +0,0 @@
|
||||
# Ignore everything in this directory
|
||||
*
|
||||
# Except this file
|
||||
!.gitignore
|
||||