42 Commits
1.0 ... 1.5

Author SHA1 Message Date
Chris
479798a1d2 added check for ffmpeg binary 2018-12-07 10:23:35 +01:00
Chris
75cde97ae9 fixed small warming 2018-12-07 10:23:12 +01:00
Chris
8f1a4f3af9 added ffmpeg binary location to config file so PictShare will run on a Raspberry Pi fixes #76 2018-11-30 22:41:26 +01:00
Christian Haschek
7adf83cb3a Merge pull request #73 from gabe565/master
Update docker-compose.yml for newer Docker image env vars
2018-11-21 08:58:01 +01:00
Gabe Cook
d292bbf6bd Update docker-compose.yml for newer Docker image env vars 2018-11-17 00:32:45 -06:00
Chris
15af093b27 clearing up language :D 2018-10-24 21:14:43 +02:00
Chris
e9c6795d7d added encoding for alt folder 2018-10-24 21:11:30 +02:00
Chris
977d3f6bda fixed bug in re encode script 2018-10-24 13:42:11 +02:00
Chris
e57360bcfc force re-render after upload so all mp4s can be viewed on mobile 2018-10-24 09:08:45 +02:00
Chris
8586775116 added alt folder support to re-encode script 2018-10-20 11:25:25 +02:00
Chris
fd401088bb added url input in upload form closes #69 2018-10-19 20:00:08 +02:00
Chris
abcc7ca654 preparation for encrypted storage 2018-09-19 22:38:49 +02:00
Chris
a75b2e3f62 added safeguard 2018-08-27 23:25:04 +02:00
Chris
823f7e60d8 added gradient support. closes #55 2018-08-26 15:50:10 +02:00
Chris
b63e94c566 final iteration of how the output looks, i swear 2018-08-26 10:29:51 +02:00
Chris
bfd475b37d fixed potential bug for file upload and processing 2018-08-26 09:40:45 +02:00
Chris
effeb7daea for readability 2018-08-26 09:28:48 +02:00
Chris
ee4bc7dfe0 added better reporting 2018-08-26 09:25:49 +02:00
Chris
f88268d7c6 how did it ever work without that? 2018-08-26 09:17:04 +02:00
Chris
3127158064 formatting 2018-08-26 09:15:08 +02:00
Chris
6ce37566b9 added better debugging 2018-08-26 09:13:59 +02:00
Chris
e6f5a077d3 added new config: ALT_FOLDER for on/offsite backups and mounted folders. closes #54 2018-08-25 20:54:32 +02:00
Chris
a13d5882ad removing dev things 2018-08-24 15:16:20 +02:00
Chris
dd3ea7f09b added check for caps 2018-08-23 09:20:13 +02:00
Chris
040c76dda1 Merge branch 'master' of https://github.com/chrisiaut/pictshare 2018-06-15 20:30:23 +02:00
Chris
eefaaf1643 fixes #56 and added tool to recalculate all hashes 2018-06-15 20:30:00 +02:00
Christian Haschek
3b922bb05e Merge pull request #53 from HenryYang/master
Fix docker volumes path problem
2018-06-03 17:32:02 +02:00
Henry Yang
e01a04393f Fix docker volumes path problem 2018-06-03 22:42:26 +08:00
Chris
5792bf06e2 fixed logo file permissions 2018-05-15 08:41:34 +02:00
Chris
4e680c78d5 re-encoding all upladed mp4s to mobile compatible one fixes #11 2018-03-30 14:11:24 +02:00
Chris
377d42bfcd added support for hashes via command argument 2018-03-30 14:09:36 +02:00
Chris
36089fb199 added sum of deleted file size 2018-03-29 15:40:58 +02:00
Chris
7df2ac0740 added cleanup script so you can slim down long grown pictshare instances 2018-03-29 15:32:49 +02:00
Chris
cd32706ec4 split re-encoding of mp4 and rendering of webm and ogg so you can cron the generation of webm and ogg 2018-03-29 14:38:32 +02:00
Chris
c8a6ca728f added re-encoding scripts to fix most mp4s. Also allows to render ogg and webm. closes #51 2018-03-29 12:58:39 +02:00
Chris
d2d992da6f added timefilter to upload 2018-03-26 15:48:26 +02:00
Chris
6ba5e31592 changed error reporting 2018-03-26 15:35:07 +02:00
Chris
940338159e fixed typo 2018-03-26 15:26:30 +02:00
Chris
27a65d4c59 added more configuration vars for backblaze 2018-03-26 15:12:58 +02:00
Chris
73fed1269e removed bcmath requirement 2018-03-26 15:04:55 +02:00
Chris
321d821661 changed detection of local files 2018-03-26 14:59:12 +02:00
Chris
17782dc734 added upload tool for backblaze 2018-03-26 14:54:14 +02:00
31 changed files with 830 additions and 59 deletions

View File

@@ -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) 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. - (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? ## 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. 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 - 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 - 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 - 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 - 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 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 - 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) - 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 ## Smart query system
PictShare images can be changed after upload just by modifying the URL. It works like this: 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 - You have full control over your data. PictShare doesn't need remote libaries or tracking crap
## Scaling ## 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. 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 ## nginx config
This is a simple config file that should make PictShare work on nginx This is a simple config file that should make PictShare work on nginx
- Install php fpm: ```apt-get install php5-fpm``` - Install php fpm: ```apt-get install php-fpm```
- Install php Graphics libraries: ```apt-get install php5-gd``` - Install php Graphics libraries: ```apt-get install php-gd```
``` ```
server { server {

0
bin/ffmpeg Normal file → Executable file
View File

View File

@@ -111,7 +111,10 @@ class Backblaze
curl_close ($session); // Clean up curl_close ($session); // Clean up
$data = json_decode($server_output,true); // Tell me about the rabbits, George! $data = json_decode($server_output,true); // Tell me about the rabbits, George!
$this->ulURL = $data['uploadUrl']; $this->ulURL = $data['uploadUrl'];
//var_dump("upload url at load: ".$data['uploadUrl']);
$this->ulToken = $data['authorizationToken']; $this->ulToken = $data['authorizationToken'];
//var_dump($data);
} }
function download($hash) function download($hash)
@@ -271,5 +274,7 @@ class Backblaze
if($data['nextFileName']) if($data['nextFileName'])
$this->getAllFilesInBucket($data['nextFileName']); $this->getAllFilesInBucket($data['nextFileName']);
return $this->files;
} }
} }

24
classes/crypto.php Normal file
View 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
View File

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 54 KiB

0
css/imgs/logo/horizontal2.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 57 KiB

After

Width:  |  Height:  |  Size: 57 KiB

0
css/imgs/logo/horizontal3.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 43 KiB

0
css/imgs/logo/logo.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 83 KiB

After

Width:  |  Height:  |  Size: 83 KiB

0
css/imgs/logo/logo2.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 66 KiB

0
css/imgs/logo/monochrome.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 32 KiB

0
css/imgs/logo/monochrome2.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 36 KiB

0
css/imgs/logo/picthshare.ai Normal file → Executable file
View File

0
css/imgs/logo/picthshare.pdf Normal file → Executable file
View File

0
css/imgs/logo/picthshare.svg Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 67 KiB

After

Width:  |  Height:  |  Size: 67 KiB

0
css/imgs/logo/vertical.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 54 KiB

0
css/imgs/logo/vertical2.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 99 KiB

After

Width:  |  Height:  |  Size: 99 KiB

0
css/imgs/logo/vertical3.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 203 KiB

After

Width:  |  Height:  |  Size: 203 KiB

View File

@@ -5,20 +5,25 @@ services:
restart: always restart: always
image: hascheksolutions/pictshare:latest image: hascheksolutions/pictshare:latest
volumes: volumes:
- ./volumes/upload:/opt/pictshare/upload - ./volumes/upload:/usr/share/nginx/html/upload
ports: ports:
- "80:80" - "80:80"
- "443:443" - "443:443"
environment: environment:
- TITLE=
- AUTOUPDATE=false - AUTOUPDATE=false
- MAXUPLOADSIZE= - MAX_UPLOAD_SIZE=
- MASTERDELETECODE= - TITLE=
- BLOATING= - PNG_COMPRESSION=
- UPLOADCODE= - JPEG_COMPRESSION=
- UPLOADPATH= - MASTER_DELETE_CODE=
- IMAGECHANGECODE= - MASTER_DELETE_IP=
- LOGUPLOADER= - UPLOAD_FORM_LOCATION=
- MAXRESIZEDIMAGES= - LOW_PROFILE=
- DOMAIN= - UPLOAD_CODE=
- SHOWERRORS= - IMAGE_CHANGE_CODE=
- LOG_UPLOADER=
- MAX_RESIZED_IMAGES=
- ALLOW_BLOATING=
- FORCE_DOMAIN=
- SHOW_ERRORS=
- FFMPEG_BINARY=

View File

@@ -1,6 +1,9 @@
<?php <?php
spl_autoload_register('autoload'); spl_autoload_register('autoload');
if(!defined('FFMPEG_BINARY') || !FFMPEG_BINARY )
define('FFMPEG_BINARY',ROOT.DS.'bin'.DS.'ffmpeg');
function autoload($className) function autoload($className)
{ {
if (file_exists(ROOT . DS . 'models' . DS . strtolower($className) . '.php')) if (file_exists(ROOT . DS . 'models' . DS . strtolower($className) . '.php'))
@@ -84,7 +87,26 @@ function whatToDo($url)
$data = $pm->urlToData($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)) if((UPLOAD_FORM_LOCATION && $url==UPLOAD_FORM_LOCATION) || (!UPLOAD_FORM_LOCATION))
{ {
@@ -499,4 +521,18 @@ function endswith($string, $test) {
$testlen = strlen($test); $testlen = strlen($test);
if ($testlen > $strlen) return false; if ($testlen > $strlen) return false;
return substr_compare($string, $test, $strlen - $testlen, $testlen) === 0; 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));
} }

View File

@@ -78,9 +78,32 @@ define('SHOW_ERRORS', false);
//remove comments to use //remove comments to use
/* BACKBLAZE B2 */ /* BACKBLAZE B2 */
//========
/* You can find your info here: https://secure.backblaze.com/b2_buckets.htm */ /* 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_ID','');
//define('BACKBLAZE_KEY', ''); //define('BACKBLAZE_KEY', '');
//define('BACKBLAZE_BUCKET_ID', ''); //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
//Backup Folder
//========
//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/copied there (just the originals, not resizes)
//value should be a path **without tailing slash**!
//define('ALT_FOLDER','/mnt');
//FFMPEG
//========
//If you are using PictShare on some other machine than x64 linux (eg raspberry pi or windows) the builtin ffmpeg binary won't work
//this is why you can define an alternative path to the ffmpeg binary here.
//define('FFMPEG_BINARY','/usr/bin/ffmpeg');

View File

@@ -94,7 +94,17 @@ class PictshareModel extends Model
} }
$data['hash']=$el; $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(); $b = new Backblaze();
if($b->download($el)) //if the backblaze download function says it's an image, we'll take it 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); 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 //delete from backblaze if configured
if(BACKBLAZE===true) if(BACKBLAZE===true && BACKBLAZE_AUTODELETE===true)
{ {
$b = new Backblaze(); $b = new Backblaze();
$b->deleteFile($hash); $b->deleteFile($hash);
@@ -351,7 +371,9 @@ class PictshareModel extends Model
<FORM id="form" enctype="multipart/form-data" method="post"> <FORM id="form" enctype="multipart/form-data" method="post">
<div id="formular"> <div id="formular">
'.$upload_code_form.' '.$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 class="clear"></div><br>
</div> </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()"> <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) function isTypeAllowed($type)
{ {
$type=strtolower($type);
switch($type) switch($type)
{ {
case 'image/png': return 'png'; case 'image/png': return 'png';
@@ -428,6 +451,7 @@ class PictshareModel extends Model
case 'image/jpeg': return 'jpg'; case 'image/jpeg': return 'jpg';
case 'jpeg': return 'jpg'; case 'jpeg': return 'jpg';
case 'jpg': return 'jpg';
case 'pjpeg': return 'jpg'; case 'pjpeg': return 'jpg';
case 'image/gif': return 'gif'; case 'image/gif': return 'gif';
@@ -444,7 +468,7 @@ class PictshareModel extends Model
return $this->isTypeAllowed($this->getTypeOfFile($url)); return $this->isTypeAllowed($this->getTypeOfFile($url));
} }
function uploadImageFromURL($url) function uploadImageFromURL($url,$forcehash=false)
{ {
$type = $this->getTypeOfFile($url); $type = $this->getTypeOfFile($url);
$type = $this->isTypeAllowed($type); $type = $this->isTypeAllowed($type);
@@ -452,21 +476,29 @@ class PictshareModel extends Model
if(!$type) if(!$type)
return array('status'=>'ERR','reason'=>'wrong filetype'); 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); $dup_id = $this->isDuplicate($url);
if($dup_id) if($dup_id)
{ {
$hash = $dup_id; $hash = $forcehash?$forcehash:$dup_id;
$url = ROOT.DS.'upload'.DS.$hash.DS.$hash; $url = ROOT.DS.'upload'.DS.$hash.DS.$hash;
} }
else else
{ {
$hash = $this->getNewHash($type); $hash = $forcehash?$forcehash:$this->getNewHash($type);
$this->saveSHAOfFile($url,$hash); $this->saveSHAOfFile($url,$hash);
} }
if($dup_id) if($dup_id)
return array('status'=>'OK','type'=>$type,'hash'=>$hash,'url'=>DOMAINPATH.PATH.$hash,'domain'=>DOMAINPATH); 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 = ROOT.DS.'upload'.DS.$hash.DS.$hash;
file_put_contents($file, file_get_contents($url)); file_put_contents($file, file_get_contents($url));
unlink($tempfile);
//remove all exif data from jpeg //re-render new mp4 by calling the re-encode script
if($type=='jpg') if($type=='mp4')
{ {
$res = imagecreatefromjpeg($file); system("nohup php ".ROOT.DS.'tools'.DS.'re-encode_mp4.php force '.$hash." > /dev/null 2> /dev/null &");
imagejpeg($res, $file, (defined('JPEG_COMPRESSION')?JPEG_COMPRESSION:90));
} }
if(LOG_UPLOADER) if(LOG_UPLOADER)
@@ -489,7 +521,16 @@ class PictshareModel extends Model
fclose($fh); 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 = new Backblaze();
$b->upload($hash); $b->upload($hash);
@@ -504,6 +545,8 @@ class PictshareModel extends Model
{ {
$code = getRandomString(32); $code = getRandomString(32);
$file = ROOT.DS.'upload'.DS.'deletecodes'.DS.$code; $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; if(file_exists($file)) continue;
file_put_contents($file,$hash); file_put_contents($file,$hash);
return $code; return $code;
@@ -621,7 +664,43 @@ class PictshareModel extends Model
} }
} }
if(count($hashes)>1) 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(is_array($hashes) && count($hashes)>1)
{ {
$albumlink = DOMAINPATH.PATH.implode('/',$hashes); $albumlink = DOMAINPATH.PATH.implode('/',$hashes);
$o.='<hr/><h1>Album link</h1><a href="'.$albumlink.'" >'.$albumlink.'</a>'; $o.='<hr/><h1>Album link</h1><a href="'.$albumlink.'" >'.$albumlink.'</a>';
@@ -694,6 +773,7 @@ class PictshareModel extends Model
$words[19] = $params[0].' Aufrufe aus '.$params[1]; $words[19] = $params[0].' Aufrufe aus '.$params[1];
$words[20] = 'Upload-Code'; $words[20] = 'Upload-Code';
$words[21] = 'Falscher Upload Code eingegeben. Upload abgebrochen'; $words[21] = 'Falscher Upload Code eingegeben. Upload abgebrochen';
$words[22] = 'URL für den Upload';
break; break;
@@ -720,6 +800,7 @@ class PictshareModel extends Model
$words[19] = $params[0].' views from '.$params[1]; $words[19] = $params[0].' views from '.$params[1];
$words[20] = 'Upload code'; $words[20] = 'Upload code';
$words[21] = 'Invalid upload code provided'; $words[21] = 'Invalid upload code provided';
$words[22] = 'URL to upload';
} }
return $words[$index]; return $words[$index];
@@ -814,7 +895,7 @@ class PictshareModel extends Model
{ {
$file = escapeshellarg($filename); $file = escapeshellarg($filename);
$tmp = ROOT.DS.'tmp'.DS.md5(time()+rand(1,10000)).'.'.rand(1,10000).'.log'; $tmp = ROOT.DS.'tmp'.DS.md5(time()+rand(1,10000)).'.'.rand(1,10000).'.log';
$bin = escapeshellcmd(ROOT.DS.'bin'.DS.'ffmpeg'); $bin = escapeshellcmd(FFMPEG_BINARY);
$cmd = "$bin -i $file > $tmp 2>> $tmp"; $cmd = "$bin -i $file > $tmp 2>> $tmp";
@@ -840,7 +921,7 @@ class PictshareModel extends Model
$file = ROOT.DS.'upload'.DS.$data['hash'].DS.$data['hash']; $file = ROOT.DS.'upload'.DS.$data['hash'].DS.$data['hash'];
$file = escapeshellarg($file); $file = escapeshellarg($file);
$tmp = '/dev/null'; $tmp = '/dev/null';
$bin = escapeshellcmd(ROOT.DS.'bin'.DS.'ffmpeg'); $bin = escapeshellcmd(FFMPEG_BINARY);
$size = $data['size']; $size = $data['size'];
@@ -853,7 +934,7 @@ class PictshareModel extends Model
switch($type) switch($type)
{ {
case 'mp4': case 'mp4':
$addition = '-c:v libx264'; $addition = '-c:v libx264 -profile:v baseline -level 3.0 -pix_fmt yuv420p';
break; break;
} }
@@ -868,7 +949,7 @@ class PictshareModel extends Model
function gifToMP4($gifpath,$target) function gifToMP4($gifpath,$target)
{ {
$bin = escapeshellcmd(ROOT.DS.'bin'.DS.'ffmpeg'); $bin = escapeshellcmd(FFMPEG_BINARY);
$file = escapeshellarg($gifpath); $file = escapeshellarg($gifpath);
if(!file_exists($target)) //simple caching.. have to think of something better if(!file_exists($target)) //simple caching.. have to think of something better
@@ -883,7 +964,7 @@ class PictshareModel extends Model
function saveAsMP4($source,$target) function saveAsMP4($source,$target)
{ {
$bin = escapeshellcmd(ROOT.DS.'bin'.DS.'ffmpeg'); $bin = escapeshellcmd(FFMPEG_BINARY);
$source = escapeshellarg($source); $source = escapeshellarg($source);
$target = escapeshellarg($target); $target = escapeshellarg($target);
$h265 = "$bin -y -i $source -an -c:v libx264 -qp 0 -f mp4 $target"; $h265 = "$bin -y -i $source -an -c:v libx264 -qp 0 -f mp4 $target";
@@ -892,7 +973,7 @@ class PictshareModel extends Model
function saveAsOGG($source,$target) function saveAsOGG($source,$target)
{ {
$bin = escapeshellcmd(ROOT.DS.'bin'.DS.'ffmpeg'); $bin = escapeshellcmd(FFMPEG_BINARY);
$source = escapeshellarg($source); $source = escapeshellarg($source);
$target = escapeshellarg($target); $target = escapeshellarg($target);
$h265 = "$bin -y -i $source -vcodec libtheora -acodec libvorbis -qp 0 -f ogg $target"; $h265 = "$bin -y -i $source -vcodec libtheora -acodec libvorbis -qp 0 -f ogg $target";
@@ -902,7 +983,7 @@ class PictshareModel extends Model
function saveAsWebm($source,$target) function saveAsWebm($source,$target)
{ {
return false; return false;
$bin = escapeshellcmd(ROOT.DS.'bin'.DS.'ffmpeg'); $bin = escapeshellcmd(FFMPEG_BINARY);
$source = escapeshellarg($source); $source = escapeshellarg($source);
$target = escapeshellarg($target); $target = escapeshellarg($target);
$webm = "$bin -y -i $source -vcodec libvpx -acodec libvorbis -aq 5 -ac 2 -qmax 25 -f webm $target"; $webm = "$bin -y -i $source -vcodec libvpx -acodec libvorbis -aq 5 -ac 2 -qmax 25 -f webm $target";
@@ -911,7 +992,7 @@ class PictshareModel extends Model
function saveFirstFrameOfMP4($path,$target) function saveFirstFrameOfMP4($path,$target)
{ {
$bin = escapeshellcmd(ROOT.DS.'bin'.DS.'ffmpeg'); $bin = escapeshellcmd(FFMPEG_BINARY);
$file = escapeshellarg($path); $file = escapeshellarg($path);
$cmd = "$bin -y -i $file -vframes 1 -f image2 $target"; $cmd = "$bin -y -i $file -vframes 1 -f image2 $target";
@@ -922,7 +1003,7 @@ class PictshareModel extends Model
function getSizeOfMP4($video) function getSizeOfMP4($video)
{ {
$video = escapeshellarg($video); $video = escapeshellarg($video);
$bin = escapeshellcmd(ROOT.DS.'bin'.DS.'ffmpeg'); $bin = escapeshellcmd(FFMPEG_BINARY);
$command = $bin . ' -i ' . $video . ' -vstats 2>&1'; $command = $bin . ' -i ' . $video . ' -vstats 2>&1';
$output = shell_exec($command); $output = shell_exec($command);
@@ -1001,4 +1082,63 @@ class PictshareModel extends Model
return array('width'=>$maxwidth,'height'=>$maxheight); 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);
}
} }

View File

@@ -40,8 +40,12 @@
<div id="container"> <div id="container">
<video id="video" poster="<?php echo DOMAINPATH.PATH.'preview/'.$hash; ?>" preload="auto" autoplay="autoplay" muted="muted" loop="loop" webkit-playsinline> <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/mp4/'.$hash; ?>" type="video/mp4">
<!--<source src="<?php echo DOMAINPATH.PATH.'raw/webm/'.$hash; ?>" type="video/webm"> <?php
<source src="<?php echo DOMAINPATH.PATH.'raw/ogg/'.$hash; ?>" type="video/ogg">--> 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> </video>
</div> </div>
<small><?php echo $filesize; ?></small> <small><?php echo $filesize; ?></small>

99
tools/altfolder_copy.php Normal file
View 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];
}

View 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
View 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];
}

131
tools/re-encode_mp4.php Normal file
View File

@@ -0,0 +1,131 @@
<?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:
* altfolder => Will check the altfolder (if exists) for falsly encoded files
*/
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('altfolder',$argv) && defined('ALT_FOLDER') && ALT_FOLDER && is_dir(ALT_FOLDER) )
{
echo "[i] Checking only the alt folder\n";
$dir = ALT_FOLDER.DS;
$dh = opendir($dir);
while (false !== ($filename = readdir($dh))) {
$img = $dir.$filename;
$hash = $filename;
echo "\r[$filename] ";
if(!file_exists($img)) continue;
$type = strtolower(pathinfo($img, PATHINFO_EXTENSION));
$type = $pm->isTypeAllowed($type);
if($type=='mp4')
{
echo "\n [i] $filename is ..\t";
$valid = checkFileForValidMP4($img);
$tmp = ROOT.DS.'tmp'.DS.$hash;
$cmd = FFMPEG_BINARY." -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 ($valid?'Valid'."\n":'Not valid => Converting..');
if(!$valid)
{
system($cmd);
echo " done\n";
unlink($tmp);
}
}
}
}
//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";
//TESTING
echo "[i] Checking hashes for wrongly encoded ones\n";
foreach($localfiles as $akey => $hash)
{
$mp4 = $dir.$hash.DS.$hash;
if(checkFileForValidMP4($mp4))
{
echo " [i] Skipping $hash because it's already correctly encoded\n";
unset($localfiles[$akey]);
}
}
echo "[i] Starting to convert\n";
foreach($localfiles as $hash)
{
$mp4 = $dir.$hash.DS.$hash;
$tmp = ROOT.DS.'tmp'.DS.$hash;
$cmd = FFMPEG_BINARY." -loglevel panic -y -i $mp4 -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 $mp4";
echo " [i] Converting '$hash'";
system($cmd);
if(defined('ALT_FOLDER') && ALT_FOLDER && is_dir(ALT_FOLDER))
copy($mp4,ALT_FOLDER.DS.$hash);
echo "\tdone\n";
}
function checkFileForValidMP4($file)
{
$hash = md5($file);
$cmd = FFMPEG_BINARY." -i $file -hide_banner 2> ".ROOT.DS.'tmp'.DS.$hash.'.txt';
system($cmd);
$results = file(ROOT.DS.'tmp'.DS.$hash.'.txt');
foreach($results as $l)
{
$elements = explode(':',trim($l));
$key=trim(array_shift($elements));
$value = trim(implode(':',$elements));
if($key=='encoder')
{
if(startsWith(strtolower($value),'lav'))
{
return true;
} else return false;
}
}
unlink(ROOT.DS.'tmp'.DS.$hash.'.txt');
return false;
}

View 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
View 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 = FFMPEG_BINARY." -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 = FFMPEG_BINARY." -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
View File

0
upload/.htaccess Normal file → Executable file
View File

View File

@@ -1,4 +0,0 @@
# Ignore everything in this directory
*
# Except this file
!.gitignore