Optimised scanning and importing
This commit is contained in:
parent
96fadc5080
commit
cfc9bf5d9a
2
.gitignore
vendored
2
.gitignore
vendored
@ -5,3 +5,5 @@ Homestead.yaml
|
||||
Homestead.json
|
||||
.env
|
||||
.*.swp
|
||||
/storage/debugbar
|
||||
/config/debugbar.php
|
||||
|
49
app/Console/Commands/CatalogDump.php
Normal file
49
app/Console/Commands/CatalogDump.php
Normal file
@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
|
||||
class CatalogDump extends Command
|
||||
{
|
||||
// Our photo object
|
||||
private $o = NULL;
|
||||
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'catalog:dump {type : Photo | Video } {id : Photo ID}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Scan Photo for metadata';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$class = 'App\Model\\'.$this->argument('type');
|
||||
|
||||
if (! class_exists($class))
|
||||
abort(500,sprintf('No class [%s]',$this->argument('type')));
|
||||
|
||||
$o = $class::findOrFail($this->argument('id'));
|
||||
|
||||
if (! is_readable($o->file_path()))
|
||||
{
|
||||
$this->warn(sprintf('Ignoring [%s], it is not readable',$o->file_path()));
|
||||
exit;
|
||||
}
|
||||
|
||||
print_r($o->properties());
|
||||
}
|
||||
}
|
90
app/Console/Commands/CatalogScan.php
Normal file
90
app/Console/Commands/CatalogScan.php
Normal file
@ -0,0 +1,90 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
|
||||
class CatalogScan extends Command
|
||||
{
|
||||
// Our photo object
|
||||
private $o = NULL;
|
||||
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'catalog:scan {type : Photo | Video } {id : Photo ID}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Scan Photo for metadata';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$class = 'App\Model\\'.$this->argument('type');
|
||||
|
||||
if (! class_exists($class))
|
||||
abort(500,sprintf('No class [%s]',$this->argument('type')));
|
||||
|
||||
$o = $class::findOrFail($this->argument('id'));
|
||||
|
||||
if (! is_readable($o->file_path()))
|
||||
{
|
||||
$this->warn(sprintf('Ignoring [%s], it is not readable',$o->file_path()));
|
||||
exit;
|
||||
}
|
||||
|
||||
$o->setDateCreated();
|
||||
$o->setSubSecTime();
|
||||
$o->setSignature();
|
||||
$o->setMakeModel();
|
||||
$o->setLocation();
|
||||
$o->setHeightWidth();
|
||||
$o->setThumbnail();
|
||||
|
||||
// If this is a duplicate
|
||||
$x = $class::whereIN('id',$o->list_duplicate())->get();
|
||||
if (count($x)) {
|
||||
$break = FALSE;
|
||||
|
||||
foreach ($x as $oo) {
|
||||
// If this photo siganture matches another.
|
||||
if ($o->signature == $oo->signature)
|
||||
{
|
||||
// And that photo is not marked as a duplicate
|
||||
if (! $oo->duplicate)
|
||||
{
|
||||
$o->duplicate = '1';
|
||||
$this->warn(sprintf('Image [%s] marked as a duplicate',$o->file_path()));
|
||||
|
||||
// If the file signature also matches, we'll mark it for deletion
|
||||
if ($oo->file_signature AND $o->file_signature == $oo->file_signature)
|
||||
{
|
||||
$this->warn(sprintf('Image [%s] marked for deletion',$o->file_path()));
|
||||
$o->remove = '1';
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$o->scanned = '1';
|
||||
|
||||
if ($o->getDirty())
|
||||
$this->warn(sprintf('Image [%s] metadata changed',$o->file_path()));
|
||||
|
||||
$o->save();
|
||||
}
|
||||
}
|
@ -4,6 +4,7 @@ namespace App\Console\Commands;
|
||||
|
||||
use Log;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Foundation\Bus\DispatchesJobs;
|
||||
use App\Model\Person;
|
||||
use App\Model\PhotoPerson;
|
||||
use App\Model\Photo;
|
||||
@ -12,6 +13,7 @@ use App\Model\Tag;
|
||||
|
||||
class PhotoImport extends Command
|
||||
{
|
||||
use DispatchesJobs;
|
||||
use \App\Traits\Files;
|
||||
|
||||
/**
|
||||
@ -21,7 +23,7 @@ class PhotoImport extends Command
|
||||
*/
|
||||
protected $signature = 'photo:import
|
||||
{--dir= : Directory to Parse}
|
||||
{--file= : File to import}
|
||||
{--file= : File to Import}
|
||||
{--ignoredupe : Ignore duplicate files}
|
||||
{--deletedupe : Delete duplicate files}
|
||||
{--people= : People to reference in photo}
|
||||
@ -108,90 +110,39 @@ class PhotoImport extends Command
|
||||
|
||||
$c++;
|
||||
|
||||
$po = Photo::where('filename',$file)->first();
|
||||
$o = Photo::where('filename',$file)->first();
|
||||
|
||||
if (is_null($po))
|
||||
if (is_null($o))
|
||||
{
|
||||
$po = new Photo;
|
||||
$po->filename = $file;
|
||||
$o = new Photo;
|
||||
$o->filename = $file;
|
||||
}
|
||||
|
||||
if (! is_readable($po->file_path()))
|
||||
if (! is_readable($o->file_path()))
|
||||
{
|
||||
$this->warn(sprintf('Ignoring [%s], it is not readable',$po->file_path()));
|
||||
$this->warn(sprintf('Ignoring [%s], it is not readable',$o->file_path()));
|
||||
continue;
|
||||
}
|
||||
|
||||
$po->date_taken = strtotime($po->property('exif:DateTime') ? $po->property('exif:DateTime') : $po->property('exif:DateTimeOriginal'));
|
||||
$po->subsectime = $po->property('exif:SubSecTimeOriginal');
|
||||
if ($o->exists)
|
||||
$this->warn(sprintf('%s [%s] already in DB: %s',$o->objectType(),$file,$o->id));
|
||||
|
||||
$po->signature = $po->property('signature');
|
||||
$o->save();
|
||||
|
||||
$po->make = $po->property('exif:Make');
|
||||
$po->model = $po->property('exif:Model');
|
||||
|
||||
$po->height = $po->property('height');
|
||||
$po->width = $po->property('width');
|
||||
$po->orientation = $po->property('orientation');
|
||||
|
||||
$po->gps_lat = Photo::latlon(preg_split('/,\s?/',$po->property('exif:GPSLatitude')),$po->property('exif:GPSLatitudeRef'));
|
||||
$po->gps_lon = Photo::latlon(preg_split('/,\s?/',$po->property('exif:GPSLongitude')),$po->property('exif:GPSLongitudeRef'));
|
||||
|
||||
try {
|
||||
$po->thumbnail = exif_thumbnail($po->file_path());
|
||||
} catch (\Exception $e) {
|
||||
// @todo Couldnt get the thumbnail, so we should create one.
|
||||
}
|
||||
|
||||
// If this is a duplicate
|
||||
$x = Photo::whereIN('id',$po->list_duplicate())->get();
|
||||
if (count($x)) {
|
||||
$skip = FALSE;
|
||||
|
||||
foreach ($x as $o) {
|
||||
// We'll only ignore based on the same signature.
|
||||
if ($po->signature != $o->signature AND ! $po->exists)
|
||||
continue;
|
||||
|
||||
if ($this->option('ignoredupe'))
|
||||
{
|
||||
$skip = TRUE;
|
||||
$this->warn(sprintf("Ignoring file [%s], it's the same as [%s] with id %s",$po->file_path(),$o->filename,$o->id));
|
||||
break;
|
||||
|
||||
}
|
||||
elseif ($this->option('deletedupe') AND ($po->filename != $o->filename))
|
||||
{
|
||||
$skip = TRUE;
|
||||
$this->error(sprintf("Deleting file [%s], it's the same as [%s] with id %s and signature [%s]\n",$po->file_path(),$o->filename,$o->id,$po->signature));
|
||||
unlink($po->file_path());
|
||||
}
|
||||
}
|
||||
|
||||
if ($skip)
|
||||
continue;
|
||||
|
||||
$po->duplicate = '1';
|
||||
$this->warn(sprintf('Image [%s] marked as a duplicate',$file));
|
||||
}
|
||||
|
||||
if ($po->exists)
|
||||
$this->warn(sprintf('Image [%s] already in DB: %s',$file,$po->id));
|
||||
|
||||
$po->save();
|
||||
|
||||
if ($po->wasRecentlyCreated)
|
||||
$this->info(sprintf('Image [%s] stored in DB: %s',$file,$po->id));
|
||||
if ($o->wasRecentlyCreated)
|
||||
$this->info(sprintf('%s [%s] stored in DB: %s',$o->objectType(),$file,$o->id));
|
||||
|
||||
// Record our people and tags
|
||||
if ($p)
|
||||
$po->People()->sync($p);
|
||||
$o->People()->sync($p);
|
||||
if ($t)
|
||||
$po->Tags()->sync($t);
|
||||
$o->Tags()->sync($t);
|
||||
|
||||
$this->dispatch((new \App\Jobs\CatalogScan($o))->onQueue('scan'));
|
||||
}
|
||||
|
||||
$bar->finish();
|
||||
|
||||
return $this->info(sprintf('Images processed: %s',$c));
|
||||
return $this->info(sprintf('Photos processed: %s',$c));
|
||||
}
|
||||
}
|
||||
|
58
app/Console/Commands/PhotoScanAll.php
Normal file
58
app/Console/Commands/PhotoScanAll.php
Normal file
@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Foundation\Bus\DispatchesJobs;
|
||||
use Log;
|
||||
use App\Model\Photo;
|
||||
use App\Jobs\CatalogScan;
|
||||
|
||||
class PhotoScanAll extends Command
|
||||
{
|
||||
use DispatchesJobs;
|
||||
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'photo:scanall';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Command description';
|
||||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
Photo::NotScanned()->chunk(200,function ($data) {
|
||||
foreach ($data as $o)
|
||||
{
|
||||
if ($o->remove) {
|
||||
Log::warning(sprintf('Not scanning [%s], marked for removal',$o->id));
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->dispatch((new CatalogScan($o))->onQueue('scan'));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@ -4,13 +4,14 @@ namespace App\Console\Commands;
|
||||
|
||||
use Log;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Foundation\Bus\DispatchesJobs;
|
||||
use App\Model\Video;
|
||||
use App\Model\Tag;
|
||||
use App\Model\Person;
|
||||
|
||||
class VideoImport extends Command
|
||||
{
|
||||
|
||||
use DispatchesJobs;
|
||||
use \App\Traits\Files;
|
||||
|
||||
/**
|
||||
@ -108,91 +109,42 @@ class VideoImport extends Command
|
||||
|
||||
$c++;
|
||||
|
||||
$vo = Video::where('filename',$file)->first();
|
||||
$o = Video::where('filename',$file)->first();
|
||||
|
||||
if (is_null($vo))
|
||||
if (is_null($o))
|
||||
{
|
||||
$vo = new Video;
|
||||
$vo->filename = $file;
|
||||
$o = new Video;
|
||||
$o->filename = $file;
|
||||
}
|
||||
|
||||
if (! is_readable($vo->file_path()))
|
||||
if (! is_readable($o->file_path()))
|
||||
{
|
||||
$this->warn(sprintf('Ignoring [%s], it is not readable',$vo->file_path()));
|
||||
$this->warn(sprintf('Ignoring [%s], it is not readable',$o->file_path()));
|
||||
continue;
|
||||
}
|
||||
|
||||
$vo->date_created = strtotime($vo->property('creationdate'));
|
||||
$vo->signature = $vo->property('signature');
|
||||
if ($o->exists)
|
||||
$this->warn(sprintf('%s [%s] already in DB: %s',$o->objectType(),$file,$o->id));
|
||||
|
||||
$vo->make = $vo->property('make');
|
||||
$vo->model = $vo->property('model');
|
||||
$o->save();
|
||||
|
||||
$vo->height = $vo->property('height');
|
||||
$vo->width = $vo->property('width');
|
||||
$vo->type = $vo->property('type');
|
||||
$vo->length = $vo->property('length');
|
||||
$vo->codec = $vo->property('codec');
|
||||
$vo->audiochannels = $vo->property('audiochannels');
|
||||
$vo->channelmode = $vo->property('channelmode');
|
||||
$vo->samplerate = $vo->property('samplerate');
|
||||
|
||||
$vo->gps_lat = $vo->property('gps_lat');
|
||||
$vo->gps_lon = $vo->property('gps_lon');
|
||||
$vo->gps_altitude = $vo->property('gps_altitude');
|
||||
|
||||
// If this is a duplicate
|
||||
$x = Video::whereIN('id',$vo->list_duplicate())->get();
|
||||
if (count($x)) {
|
||||
$skip = FALSE;
|
||||
|
||||
foreach ($x as $o) {
|
||||
// We'll only ignore based on the same signature.
|
||||
if ($vo->signature != $o->signature AND ! $vo->exists)
|
||||
continue;
|
||||
|
||||
if ($this->option('ignoredupe'))
|
||||
{
|
||||
$skip = TRUE;
|
||||
$this->warn(sprintf("Ignoring file [%s], it's the same as [%s] with id %s",$vo->file_path(),$o->filename,$o->id));
|
||||
break;
|
||||
|
||||
}
|
||||
elseif ($this->option('deletedupe') AND ($vo->filename != $o->filename))
|
||||
{
|
||||
$skip = TRUE;
|
||||
$this->error(sprintf("Deleting file [%s], it's the same as [%s] with id %s and signature [%s]\n",$vo->file_path(),$o->filename,$o->id,$vo->signature));
|
||||
unlink($vo->file_path());
|
||||
}
|
||||
}
|
||||
|
||||
if ($skip)
|
||||
continue;
|
||||
|
||||
$vo->duplicate = '1';
|
||||
$this->warn(sprintf('Video [%s] marked as a duplicate',$file));
|
||||
}
|
||||
|
||||
if ($vo->exists)
|
||||
$this->warn(sprintf('Video [%s] already in DB: %s',$file,$vo->id));
|
||||
|
||||
$vo->save();
|
||||
|
||||
if ($vo->wasRecentlyCreated)
|
||||
$this->info(sprintf('Video [%s] stored in DB: %s',$file,$vo->id));
|
||||
if ($o->wasRecentlyCreated)
|
||||
$this->info(sprintf('%s [%s] stored in DB: %s',$o->objectType(),$file,$o->id));
|
||||
|
||||
// Record our people and tags
|
||||
if ($p)
|
||||
$vo->People()->sync($p);
|
||||
$o->People()->sync($p);
|
||||
if ($t)
|
||||
$vo->Tags()->sync($t);
|
||||
$o->Tags()->sync($t);
|
||||
|
||||
$this->dispatch((new \App\Jobs\CatalogScan($o))->onQueue('scan'));
|
||||
|
||||
if ($this->option('dumpid3'))
|
||||
dd($vo->dump());
|
||||
dd($o->dump());
|
||||
}
|
||||
|
||||
$bar->finish();
|
||||
|
||||
return $this->info(sprintf('Video processed: %s',$c));
|
||||
return $this->info(sprintf('Videos processed: %s',$c));
|
||||
}
|
||||
}
|
||||
|
58
app/Console/Commands/VideoScanAll.php
Normal file
58
app/Console/Commands/VideoScanAll.php
Normal file
@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Foundation\Bus\DispatchesJobs;
|
||||
use Log;
|
||||
use App\Model\Video;
|
||||
use App\Jobs\CatalogScan;
|
||||
|
||||
class VideoScanAll extends Command
|
||||
{
|
||||
use DispatchesJobs;
|
||||
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'video:scanall';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Command description';
|
||||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
Video::NotScanned()->chunk(200,function ($data) {
|
||||
foreach ($data as $o)
|
||||
{
|
||||
if ($o->remove) {
|
||||
Log::warning(sprintf('Not scanning [%s], marked for removal',$o->id));
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->dispatch((new CatalogScan($o))->onQueue('scan'));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@ -13,11 +13,15 @@ class Kernel extends ConsoleKernel
|
||||
* @var array
|
||||
*/
|
||||
protected $commands = [
|
||||
Commands\CatalogScan::class,
|
||||
Commands\CatalogDump::class,
|
||||
Commands\PhotoImport::class,
|
||||
Commands\PhotoMove::class,
|
||||
Commands\PhotoScanAll::class,
|
||||
Commands\PhotoUpdate::class,
|
||||
Commands\VideoImport::class,
|
||||
Commands\VideoMove::class,
|
||||
Commands\VideoScanAll::class,
|
||||
];
|
||||
|
||||
/**
|
||||
|
@ -34,19 +34,19 @@ class PhotoController extends Controller
|
||||
return redirect()->action('PhotoController@info',[$id]);
|
||||
}
|
||||
|
||||
public function deletes()
|
||||
public function deletes($id=NULL)
|
||||
{
|
||||
return view('photo.deletereview',['photos'=>Photo::where('remove',1)->paginate(2)]);
|
||||
return view('catalog.deletereview',['return'=>url('/p/deletes'),'catalog'=>is_null($id) ? Photo::where('remove',1)->paginate(50) : Photo::where('id',$id)]);
|
||||
}
|
||||
|
||||
public function deletesUpdate(Request $request)
|
||||
{
|
||||
foreach ($request->input('photo') as $id)
|
||||
foreach ($request->input('remove') as $id=>$k)
|
||||
{
|
||||
$photo = Photo::findOrFail($id);
|
||||
$o = Photo::findOrFail($id);
|
||||
|
||||
if ($photo->remove AND $request->input('remove.'.$id))
|
||||
$this->dispatch((new PhotoDelete($photo))->onQueue('delete'));
|
||||
if ($o->remove AND $request->input('remove.'.$id))
|
||||
$this->dispatch((new PhotoDelete($o))->onQueue('delete'));
|
||||
}
|
||||
|
||||
return redirect()->action('PhotoController@deletes',$request->input('pagenext') ? '?page='.$request->input('pagenext') : NULL);
|
||||
|
@ -35,19 +35,19 @@ class VideoController extends Controller
|
||||
return redirect()->action('VideoController@info',[$id]);
|
||||
}
|
||||
|
||||
public function deletes()
|
||||
public function deletes($id=NULL)
|
||||
{
|
||||
return view('video.deletereview',['videos'=>Video::where('remove',1)->paginate(2)]);
|
||||
return view('catalog.deletereview',['return'=>url('v/deletes'),'catalog'=>is_null($id) ? Video::where('remove',1)->paginate(10) : Video::where('id',$id)->paginate(1)]);
|
||||
}
|
||||
|
||||
public function deletesUpdate(Request $request)
|
||||
{
|
||||
foreach ($request->input('video') as $id)
|
||||
foreach ($request->input('remove') as $k=>$id)
|
||||
{
|
||||
$video = Video::findOrFail($id);
|
||||
$o = Video::findOrFail($k);
|
||||
|
||||
if ($video->remove AND $request->input('remove.'.$id))
|
||||
$this->dispatch((new VideoDelete($video))->onQueue('delete'));
|
||||
if ($o->remove AND $request->input('remove.'.$k))
|
||||
$this->dispatch((new VideoDelete($o))->onQueue('delete'));
|
||||
}
|
||||
|
||||
return redirect()->action('VideoController@deletes',$request->input('pagenext') ? '?page='.$request->input('pagenext') : NULL);
|
||||
|
39
app/Jobs/CatalogScan.php
Normal file
39
app/Jobs/CatalogScan.php
Normal file
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace App\Jobs;
|
||||
|
||||
use Log;
|
||||
use App\Jobs\Job;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Artisan;
|
||||
|
||||
class CatalogScan extends Job implements ShouldQueue
|
||||
{
|
||||
use InteractsWithQueue, SerializesModels;
|
||||
|
||||
// Our object
|
||||
private $o = NULL;
|
||||
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(\App\Model\Abstracted\Catalog $o)
|
||||
{
|
||||
$this->o = $o;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the job.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
Log::info(sprintf('%s: Scanning [%s|%s]',__METHOD__,$this->o->objecttype(),$this->o->id));
|
||||
Artisan::call('catalog:scan',['type'=>$this->o->objecttype(),'id'=>$this->o->id]);
|
||||
}
|
||||
}
|
353
app/Model/Abstracted/Catalog.php
Normal file
353
app/Model/Abstracted/Catalog.php
Normal file
@ -0,0 +1,353 @@
|
||||
<?php
|
||||
|
||||
namespace App\Model\Abstracted;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use DB;
|
||||
|
||||
abstract class Catalog extends Model
|
||||
{
|
||||
public function People()
|
||||
{
|
||||
return $this->belongsToMany('App\Model\Person');
|
||||
}
|
||||
|
||||
public function Tags()
|
||||
{
|
||||
return $this->belongsToMany('App\Model\Tag');
|
||||
}
|
||||
|
||||
/**
|
||||
* Multimedia NOT duplicate.
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
public function scopeNotDuplicate($query)
|
||||
{
|
||||
return $query->where(function($query)
|
||||
{
|
||||
$query->where('duplicate','!=',TRUE)
|
||||
->orWhere('duplicate','=',NULL);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Multimedia NOT pending removal.
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
public function scopeNotRemove($query)
|
||||
{
|
||||
return $query->where(function($query)
|
||||
{
|
||||
$query->where('remove','!=',TRUE)
|
||||
->orWhere('remove','=',NULL);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Multimedia NOT scanned.
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
public function scopeNotScanned($query)
|
||||
{
|
||||
return $query->where(function($query)
|
||||
{
|
||||
$query->where('scanned','!=',TRUE)
|
||||
->orWhere('scanned','=',NULL);
|
||||
});
|
||||
}
|
||||
|
||||
abstract public function setDateCreated();
|
||||
abstract public function setLocation();
|
||||
abstract public function setMakeModel();
|
||||
abstract public function setSignature();
|
||||
abstract public function setSubSecTime();
|
||||
abstract public function setThumbnail();
|
||||
abstract public function view();
|
||||
|
||||
/**
|
||||
* Date the multimedia was created
|
||||
*/
|
||||
public function date_taken()
|
||||
{
|
||||
return $this->date_created ? date('Y-m-d H:i:s',$this->date_created) : 'UNKNOWN';
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the date of the file
|
||||
*/
|
||||
public function file_date($type,$format=FALSE)
|
||||
{
|
||||
if (! is_readable($this->file_path()))
|
||||
return NULL;
|
||||
|
||||
switch ($type)
|
||||
{
|
||||
case 'a': $t = fileatime($this->file_path());
|
||||
break;
|
||||
case 'c': $t = filectime($this->file_path());
|
||||
break;
|
||||
case 'm': $t = filemtime($this->file_path());
|
||||
break;
|
||||
}
|
||||
|
||||
return $format ? date('d-m-Y H:i:s',$t) : $t;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the new name for the image
|
||||
*/
|
||||
public function file_path($short=FALSE,$new=FALSE)
|
||||
{
|
||||
$file = $this->filename;
|
||||
|
||||
if ($new)
|
||||
$file = sprintf('%s.%s',((is_null($this->date_created) OR ! $this->date_created)
|
||||
? sprintf('UNKNOWN/%07s',$this->file_path_id())
|
||||
: date('Y/m/d-His',$this->date_created)),$this->type());
|
||||
|
||||
return (($short OR preg_match('/^\//',$file)) ? '' : config('video.dir').DIRECTORY_SEPARATOR).$file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate a file path ID based on the id of the file
|
||||
*/
|
||||
public function file_path_id($sep=3,$depth=9)
|
||||
{
|
||||
return trim(chunk_split(sprintf("%0{$depth}s",$this->id),$sep,'/'),'/');
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the file signature
|
||||
*/
|
||||
public function file_signature($short=FALSE)
|
||||
{
|
||||
return $short ? static::signaturetrim($this->file_signature) : $this->file_signature;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the photo size
|
||||
*/
|
||||
public function file_size()
|
||||
{
|
||||
return (! is_readable($this->file_path())) ? NULL : filesize($this->file_path());
|
||||
}
|
||||
public function getFileSizeAttribute()
|
||||
{
|
||||
return (! is_readable($this->file_path())) ? NULL : filesize($this->file_path());
|
||||
}
|
||||
|
||||
public function getDateCreatedTextAttribute()
|
||||
{
|
||||
if ($this->date_created)
|
||||
return date('d-m-Y H:i:s',$this->date_created);
|
||||
}
|
||||
|
||||
public function getDuplicateTextAttribute()
|
||||
{
|
||||
return $this->TextTrueFalse($this->duplicate);
|
||||
}
|
||||
|
||||
public function getFlagTextAttribute()
|
||||
{
|
||||
return $this->TextTrueFalse($this->flag);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return HTML Checkbox for flagged
|
||||
*/
|
||||
public function getFlagCheckboxAttribute()
|
||||
{
|
||||
return $this->HTMLCheckbox('flag',$this->id,$this->flag);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return HTML Checkbox for remove
|
||||
*/
|
||||
public function getRemoveCheckboxAttribute()
|
||||
{
|
||||
return $this->HTMLCheckbox('remove',$this->id,$this->remove);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the GPS coordinates
|
||||
*/
|
||||
public function gps()
|
||||
{
|
||||
return ($this->gps_lat AND $this->gps_lon) ? sprintf('%s/%s',$this->gps_lat,$this->gps_lon) : 'UNKNOWN';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get ID Info link
|
||||
*/
|
||||
protected function HTMLLinkAttribute($id,$url)
|
||||
{
|
||||
return sprintf('<a href="%s" target="%s">%s</a>',url($url.$id),$id,$id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an HTML checkbox
|
||||
*/
|
||||
protected function HTMLCheckbox($name,$id,$value)
|
||||
{
|
||||
return sprintf('<input type="checkbox" name="%s[%s]" value="1"%s>',$name,$id,$value ? ' checked="checked"' : '');
|
||||
}
|
||||
|
||||
public function isParentWritable($dir)
|
||||
{
|
||||
if (file_exists($dir) AND is_writable($dir) AND is_dir($dir))
|
||||
return TRUE;
|
||||
elseif ($dir == dirname($dir) OR file_exists($dir))
|
||||
return FALSE;
|
||||
else
|
||||
return ($this->isParentWritable(dirname($dir)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a file is moveable
|
||||
*
|
||||
* useID boolean Determine if the path is based on the the ID or date
|
||||
*/
|
||||
public function moveable()
|
||||
{
|
||||
// If the source and target are the same, we dont need to move it
|
||||
if ($this->file_path() == $this->file_path(FALSE,TRUE))
|
||||
return FALSE;
|
||||
|
||||
// If there is already a file in the target.
|
||||
// @todo If the target file is to be deleted, we could move this file
|
||||
if (file_exists($this->file_path(FALSE,TRUE)))
|
||||
return 1;
|
||||
|
||||
// Test if the source is readable
|
||||
if (! is_readable($this->file_path()))
|
||||
return 2;
|
||||
|
||||
// Test if the dir is writable (so we can remove the file)
|
||||
if (! $this->isParentWritable(dirname($this->file_path())))
|
||||
return 3;
|
||||
|
||||
// Test if the target dir is writable
|
||||
// @todo The target dir may not exist yet, so we should check that a parent exists and is writable.
|
||||
if (! $this->isParentWritable($this->file_path(FALSE,TRUE)))
|
||||
return 4;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the id of the previous record
|
||||
*/
|
||||
public function next()
|
||||
{
|
||||
return DB::table($this->getTable())
|
||||
->where('id','>',$this->id)
|
||||
->orderby('id','ASC')
|
||||
->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return my class shortname
|
||||
*/
|
||||
public function objectType()
|
||||
{
|
||||
return (new \ReflectionClass($this))->getShortName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the id of the previous record
|
||||
*/
|
||||
public function previous()
|
||||
{
|
||||
return DB::table($this->getTable())
|
||||
->where('id','<',$this->id)
|
||||
->orderby('id','DEC')
|
||||
->first();
|
||||
}
|
||||
|
||||
public function setHeightWidth()
|
||||
{
|
||||
$this->height = $this->property('height');
|
||||
$this->width = $this->property('width');
|
||||
$this->orientation = $this->property('orientation');
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the media signature
|
||||
*/
|
||||
public function signature($short=FALSE)
|
||||
{
|
||||
return $short ? static::signaturetrim($this->signature) : $this->signature;
|
||||
}
|
||||
|
||||
public static function signaturetrim($signature,$chars=6)
|
||||
{
|
||||
return sprintf('%s...%s',substr($signature,0,$chars),substr($signature,-1*$chars));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the image should be moved
|
||||
*/
|
||||
public function shouldMove()
|
||||
{
|
||||
return ($this->filename != $this->file_path(TRUE,TRUE));
|
||||
}
|
||||
|
||||
protected function TextTrueFalse($value)
|
||||
{
|
||||
return $value ? 'TRUE' : 'FALSE';
|
||||
}
|
||||
|
||||
public function list_duplicate($includeme=FALSE)
|
||||
{
|
||||
return $this->list_duplicates($includeme)->pluck('id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Find duplicate images based on some attributes of the current image
|
||||
*/
|
||||
public function list_duplicates($includeme=FALSE)
|
||||
{
|
||||
$o = static::select();
|
||||
|
||||
if ($this->id AND ! $includeme)
|
||||
$o->where('id','!=',$this->id);
|
||||
|
||||
// Ignore photo's pending removal.
|
||||
if (! $includeme)
|
||||
$o->where(function($query)
|
||||
{
|
||||
$query->where('remove','!=',TRUE)
|
||||
->orWhere('remove','=',NULL);
|
||||
});
|
||||
|
||||
// Where the signature is the same
|
||||
$o->where(function($query)
|
||||
{
|
||||
$query->where('signature','=',$this->signature);
|
||||
|
||||
// Or they have the same time taken with the same camera
|
||||
if ($this->date_created AND ($this->model OR $this->make))
|
||||
{
|
||||
$query->orWhere(function($query)
|
||||
{
|
||||
$query->where('date_created','=',$this->date_created ? $this->date_created : NULL);
|
||||
if (Schema::hasColumn($this->getTable(),'subsectime'))
|
||||
$query->where('subsectime','=',$this->subsectime ? $this->subsectime : NULL);
|
||||
|
||||
if (! is_null($this->model))
|
||||
$query->where('model','=',$this->model);
|
||||
|
||||
if (! is_null($this->make))
|
||||
$query->where('make','=',$this->make);
|
||||
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return $o->get();
|
||||
}
|
||||
}
|
@ -3,14 +3,13 @@
|
||||
namespace App\Model;
|
||||
|
||||
use DB;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Photo extends Model
|
||||
class Photo extends Abstracted\Catalog
|
||||
{
|
||||
protected $table = 'photo';
|
||||
|
||||
// Imagick Object
|
||||
private $_io;
|
||||
private $_o;
|
||||
|
||||
// How should the image be rotated, based on the value of orientation
|
||||
private $_rotate = [
|
||||
@ -19,68 +18,12 @@ class Photo extends Model
|
||||
8=>-90,
|
||||
];
|
||||
|
||||
public function People()
|
||||
{
|
||||
return $this->belongsToMany('App\Model\Person');
|
||||
}
|
||||
|
||||
public function Tags()
|
||||
{
|
||||
return $this->belongsToMany('App\Model\Tag');
|
||||
}
|
||||
|
||||
/**
|
||||
* Photo's NOT pending removal.
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
* Date the photo was taken
|
||||
*/
|
||||
public function scopeNotRemove($query)
|
||||
{
|
||||
return $query->where(function($query)
|
||||
{
|
||||
$query->where('remove','!=',TRUE)
|
||||
->orWhere('remove','=',NULL);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Photo's NOT duplicate.
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
public function scopeNotDuplicate($query)
|
||||
{
|
||||
return $query->where(function($query)
|
||||
{
|
||||
$query->where('duplicate','!=',TRUE)
|
||||
->orWhere('duplicate','=',NULL);
|
||||
});
|
||||
}
|
||||
|
||||
public function date_taken()
|
||||
{
|
||||
return $this->date_taken ? (date('Y-m-d H:i:s',$this->date_taken).($this->subsectime ? '.'.$this->subsectime : '')) : 'UNKNOWN';
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the date of the file
|
||||
*/
|
||||
public function file_date($type,$format=FALSE)
|
||||
{
|
||||
if (! is_readable($this->file_path()))
|
||||
return NULL;
|
||||
|
||||
switch ($type)
|
||||
{
|
||||
case 'a': $t = fileatime($this->file_path());
|
||||
break;
|
||||
case 'c': $t = filectime($this->file_path());
|
||||
break;
|
||||
case 'm': $t = filemtime($this->file_path());
|
||||
break;
|
||||
}
|
||||
|
||||
return $format ? date('d-m-Y H:i:s',$t) : $t;
|
||||
return $this->date_created ? (date('Y-m-d H:i:s',$this->date_created).($this->subsectime ? '.'.$this->subsectime : '')) : 'UNKNOWN';
|
||||
}
|
||||
|
||||
/**
|
||||
@ -91,35 +34,17 @@ class Photo extends Model
|
||||
$file = $this->filename;
|
||||
|
||||
if ($new)
|
||||
$file = sprintf('%s.%s',((is_null($this->date_taken) OR ! $this->date_taken)
|
||||
$file = sprintf('%s.%s',((is_null($this->date_created) OR ! $this->date_created)
|
||||
? sprintf('UNKNOWN/%07s',$this->file_path_id())
|
||||
: sprintf('%s_%03s',date('Y/m/d-His',$this->date_taken),$this->subsectime).($this->subsectime ? '' : sprintf('-%05s',$this->id))),$this->type());
|
||||
: sprintf('%s_%03s',date('Y/m/d-His',$this->date_created),$this->subsectime).
|
||||
($this->subsectime ? '' : sprintf('-%05s',$this->id))),$this->type());
|
||||
|
||||
return (($short OR preg_match('/^\//',$file)) ? '' : config('photo.dir').DIRECTORY_SEPARATOR).$file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate a file path ID based on the id of the file
|
||||
*/
|
||||
public function file_path_id($sep=3,$depth=9)
|
||||
public function getIDLinkAttribute()
|
||||
{
|
||||
return trim(chunk_split(sprintf("%0{$depth}s",$this->id),$sep,'/'),'/');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the photo size
|
||||
*/
|
||||
public function file_size()
|
||||
{
|
||||
return (! is_readable($this->file_path())) ? NULL : filesize($this->file_path());
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the GPS coordinates
|
||||
*/
|
||||
public function gps()
|
||||
{
|
||||
return ($this->gps_lat AND $this->gps_lon) ? sprintf('%s/%s',$this->gps_lat,$this->gps_lon) : 'UNKNOWN';
|
||||
return $this->HTMLLinkAttribute($this->id,url('p/info').'/');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -127,7 +52,7 @@ class Photo extends Model
|
||||
*/
|
||||
public function image()
|
||||
{
|
||||
if (is_null($imo = $this->io()))
|
||||
if (is_null($imo = $this->o()))
|
||||
return NULL;
|
||||
|
||||
if (array_key_exists('exif',$imo->getImageProfiles()))
|
||||
@ -138,31 +63,6 @@ class Photo extends Model
|
||||
return $imo->getImageBlob();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an Imagick object or attribute
|
||||
*
|
||||
*/
|
||||
protected function io($attr=NULL)
|
||||
{
|
||||
if (! file_exists($this->file_path()) OR ! is_readable($this->file_path()))
|
||||
return NULL;
|
||||
|
||||
if (is_null($this->_io))
|
||||
$this->_io = new \Imagick($this->file_path());
|
||||
|
||||
return is_null($attr) ? $this->_io : $this->_io->getImageProperty($attr);
|
||||
}
|
||||
|
||||
public function isParentWritable($dir)
|
||||
{
|
||||
if (file_exists($dir) AND is_writable($dir) AND is_dir($dir))
|
||||
return TRUE;
|
||||
elseif ($dir == dirname($dir) OR file_exists($dir))
|
||||
return FALSE;
|
||||
else
|
||||
return ($this->isParentWritable(dirname($dir)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the GPS coordinates
|
||||
*/
|
||||
@ -193,46 +93,18 @@ class Photo extends Model
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a file is moveable
|
||||
* Return an Imagick object or attribute
|
||||
*
|
||||
* useID boolean Determine if the path is based on the the ID or date
|
||||
*/
|
||||
public function moveable()
|
||||
protected function o($attr=NULL)
|
||||
{
|
||||
// If the source and target are the same, we dont need to move it
|
||||
if ($this->file_path() == $this->file_path(FALSE,TRUE))
|
||||
return FALSE;
|
||||
if (! file_exists($this->file_path()) OR ! is_readable($this->file_path()))
|
||||
return NULL;
|
||||
|
||||
// If there is already a file in the target.
|
||||
// @todo If the target file is to be deleted, we could move this file
|
||||
if (file_exists($this->file_path(FALSE,TRUE)))
|
||||
return 1;
|
||||
if (is_null($this->_o))
|
||||
$this->_o = new \Imagick($this->file_path());
|
||||
|
||||
// Test if the source is readable
|
||||
if (! is_readable($this->file_path()))
|
||||
return 2;
|
||||
|
||||
// Test if the dir is writable (so we can remove the file)
|
||||
if (! $this->isParentWritable(dirname($this->file_path())))
|
||||
return 3;
|
||||
|
||||
// Test if the target dir is writable
|
||||
// @todo The target dir may not exist yet, so we should check that a parent exists and is writable.
|
||||
if (! $this->isParentWritable($this->file_path(FALSE,TRUE)))
|
||||
return 4;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the id of the previous photo
|
||||
*/
|
||||
public function next()
|
||||
{
|
||||
$po = DB::table('photo');
|
||||
$po->where('id','>',$this->id);
|
||||
$po->orderby('id','ASC');
|
||||
return $po->first();
|
||||
return is_null($attr) ? $this->_o : $this->_o->getImageProperty($attr);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -251,7 +123,6 @@ class Photo extends Model
|
||||
|
||||
/**
|
||||
* Rotate the image
|
||||
*
|
||||
*/
|
||||
private function rotate(\Imagick $imo)
|
||||
{
|
||||
@ -261,68 +132,77 @@ class Photo extends Model
|
||||
return $imo->getImageBlob();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the id of the previous photo
|
||||
*/
|
||||
public function previous()
|
||||
{
|
||||
$po = DB::table('photo');
|
||||
$po->where('id','<',$this->id);
|
||||
$po->orderby('id','DEC');
|
||||
return $po->first();
|
||||
}
|
||||
|
||||
public function property($property)
|
||||
{
|
||||
if (! $this->io())
|
||||
if (! $this->o())
|
||||
return NULL;
|
||||
|
||||
switch ($property)
|
||||
{
|
||||
case 'height': return $this->_io->getImageHeight(); break;
|
||||
case 'orientation': return $this->_io->getImageOrientation(); break;
|
||||
case 'signature': return $this->_io->getImageSignature(); break;
|
||||
case 'width': return $this->_io->getImageWidth(); break;
|
||||
case 'creationdate': return strtotime($this->property('exif:DateTimeOriginal') ? $this->property('exif:DateTimeOriginal') : $this->property('exif:DateTime')); break;
|
||||
case 'height': return $this->_o->getImageHeight(); break;
|
||||
case 'orientation': return $this->_o->getImageOrientation(); break;
|
||||
case 'signature': return $this->_o->getImageSignature(); break;
|
||||
case 'width': return $this->_o->getImageWidth(); break;
|
||||
default:
|
||||
return $this->_io->getImageProperty($property);
|
||||
return $this->_o->getImageProperty($property);
|
||||
}
|
||||
}
|
||||
|
||||
public function properties()
|
||||
{
|
||||
return $this->io() ? $this->_io->getImageProperties() : [];
|
||||
return $this->o() ? $this->_o->getImageProperties() : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the photo signature
|
||||
*/
|
||||
public function signature($short=FALSE)
|
||||
public function setDateCreated()
|
||||
{
|
||||
return $short ? static::signaturetrim($this->signature) : $this->signature;
|
||||
if ($this->property('creationdate'))
|
||||
$this->date_created = $this->property('creationdate');
|
||||
}
|
||||
|
||||
public static function signaturetrim($signature,$chars=6)
|
||||
public function setLocation()
|
||||
{
|
||||
return sprintf('%s...%s',substr($signature,0,$chars),substr($signature,-1*$chars));
|
||||
$this->gps_lat = static::latlon(preg_split('/,\s?/',$this->property('exif:GPSLatitude')),$this->property('exif:GPSLatitudeRef'));
|
||||
$this->gps_lon = static::latlon(preg_split('/,\s?/',$this->property('exif:GPSLongitude')),$this->property('exif:GPSLongitudeRef'));
|
||||
#$this->gps_altitude = $this->property('gps_altitude');
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the image should be moved
|
||||
*/
|
||||
public function shouldMove()
|
||||
public function setMakeModel()
|
||||
{
|
||||
return ($this->filename != $this->file_path(TRUE,TRUE));
|
||||
$this->make = $this->property('exif:Make') ? $this->property('exif:Make') : NULL;
|
||||
$this->model = $this->property('exif:Model') ? $this->property('exif:Model') : NULL;
|
||||
$this->software = $this->property('exif:Software') ? $this->property('exif:Software') : NULL;
|
||||
}
|
||||
|
||||
public function setSignature()
|
||||
{
|
||||
$this->signature = $this->property('signature');
|
||||
$this->file_signature = md5_file($this->file_path());
|
||||
#$this->identifier = $this->property('identifier');
|
||||
}
|
||||
|
||||
public function setSubSecTime()
|
||||
{
|
||||
$this->subsectime = $this->property('exif:SubSecTimeOriginal');
|
||||
}
|
||||
|
||||
public function setThumbnail()
|
||||
{
|
||||
try {
|
||||
$this->thumbnail = exif_thumbnail($this->file_path());
|
||||
} catch (\Exception $e) {
|
||||
// @todo Couldnt get the thumbnail, so we should create one.
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the image's thumbnail
|
||||
*
|
||||
*/
|
||||
public function thumbnail($rotate=TRUE)
|
||||
{
|
||||
if (! $this->thumbnail)
|
||||
{
|
||||
return $this->io()->thumbnailimage(200,200,true,true) ? $this->_io->getImageBlob() : NULL;
|
||||
return $this->o()->thumbnailimage(200,200,true,true) ? $this->_o->getImageBlob() : NULL;
|
||||
}
|
||||
|
||||
if (! $rotate OR ! array_key_exists($this->orientation,$this->_rotate) OR ! extension_loaded('imagick'))
|
||||
@ -336,53 +216,15 @@ class Photo extends Model
|
||||
|
||||
/**
|
||||
* Return the extension of the image
|
||||
* @todo mime-by-ext?
|
||||
*/
|
||||
public function type($mime=FALSE)
|
||||
{
|
||||
return strtolower($mime ? 'image/jpeg' : pathinfo($this->filename,PATHINFO_EXTENSION));
|
||||
}
|
||||
|
||||
/**
|
||||
* Find duplicate images based on some attributes of the current image
|
||||
*/
|
||||
public function list_duplicate($includeme=FALSE)
|
||||
public function view()
|
||||
{
|
||||
$po = DB::table('photo');
|
||||
|
||||
if ($this->id AND ! $includeme)
|
||||
$po->where('id','!=',$this->id);
|
||||
|
||||
// Ignore photo's pending removal.
|
||||
if (! $includeme)
|
||||
$po->where(function($query)
|
||||
{
|
||||
$query->where('remove','!=',TRUE)
|
||||
->orWhere('remove','=',NULL);
|
||||
});
|
||||
|
||||
// Where the signature is the same
|
||||
$po->where(function($query)
|
||||
{
|
||||
$query->where('signature','=',$this->signature);
|
||||
|
||||
// Or they have the same time taken with the same camera
|
||||
if ($this->date_taken AND ($this->model OR $this->make))
|
||||
{
|
||||
$query->orWhere(function($query)
|
||||
{
|
||||
$query->where('date_taken','=',$this->date_taken ? $this->date_taken : NULL);
|
||||
$query->where('subsectime','=',$this->subsectime ? $this->subsectime : NULL);
|
||||
|
||||
if (! is_null($this->model))
|
||||
$query->where('model','=',$this->model);
|
||||
|
||||
if (! is_null($this->make))
|
||||
$query->where('make','=',$this->make);
|
||||
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return $po->pluck('id');
|
||||
return sprintf('<img height="240" src="%s"></img>',url('/p/thumbnail/'.$this->id));
|
||||
}
|
||||
}
|
||||
|
@ -3,178 +3,19 @@
|
||||
namespace App\Model;
|
||||
|
||||
use DB;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Video extends Model
|
||||
class Video extends Abstracted\Catalog
|
||||
{
|
||||
protected $table = 'videos';
|
||||
|
||||
// ID3 Object
|
||||
private $_o = NULL;
|
||||
|
||||
public function People()
|
||||
{
|
||||
return $this->belongsToMany('App\Model\Person');
|
||||
}
|
||||
|
||||
public function Tags()
|
||||
{
|
||||
return $this->belongsToMany('App\Model\Tag');
|
||||
}
|
||||
public function getIDLinkAttribute()
|
||||
{
|
||||
return $this->HTMLLinkAttribute($this->id,url('v/info').'/');
|
||||
}
|
||||
|
||||
/**
|
||||
* Photo's NOT pending removal.
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
public function scopeNotRemove($query)
|
||||
{
|
||||
return $query->where(function($query)
|
||||
{
|
||||
$query->where('remove','!=',TRUE)
|
||||
->orWhere('remove','=',NULL);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Photo's NOT duplicate.
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
public function scopeNotDuplicate($query)
|
||||
{
|
||||
return $query->where(function($query)
|
||||
{
|
||||
$query->where('duplicate','!=',TRUE)
|
||||
->orWhere('duplicate','=',NULL);
|
||||
});
|
||||
}
|
||||
|
||||
public function date_taken()
|
||||
{
|
||||
return $this->date_created ? date('Y-m-d H:i:s',$this->date_created) : 'UNKNOWN';
|
||||
}
|
||||
|
||||
public function dump()
|
||||
{
|
||||
return $this->_o->info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the date of the file
|
||||
*/
|
||||
public function file_date($type,$format=FALSE)
|
||||
{
|
||||
if (! is_readable($this->file_path()))
|
||||
return NULL;
|
||||
|
||||
switch ($type)
|
||||
{
|
||||
case 'a': $t = fileatime($this->file_path());
|
||||
break;
|
||||
case 'c': $t = filectime($this->file_path());
|
||||
break;
|
||||
case 'm': $t = filemtime($this->file_path());
|
||||
break;
|
||||
}
|
||||
|
||||
return $format ? date('d-m-Y H:i:s',$t) : $t;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the new name for the image
|
||||
*/
|
||||
public function file_path($short=FALSE,$new=FALSE)
|
||||
{
|
||||
$file = $this->filename;
|
||||
|
||||
if ($new)
|
||||
$file = sprintf('%s.%s',((is_null($this->date_created) OR ! $this->date_created)
|
||||
? sprintf('UNKNOWN/%07s',$this->file_path_id())
|
||||
: date('Y/m/d-His',$this->date_created)),$this->type());
|
||||
|
||||
return (($short OR preg_match('/^\//',$file)) ? '' : config('video.dir').DIRECTORY_SEPARATOR).$file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate a file path ID based on the id of the file
|
||||
*/
|
||||
public function file_path_id($sep=3,$depth=9)
|
||||
{
|
||||
return trim(chunk_split(sprintf("%0{$depth}s",$this->id),$sep,'/'),'/');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the photo size
|
||||
*/
|
||||
public function file_size()
|
||||
{
|
||||
return (! is_readable($this->file_path())) ? NULL : filesize($this->file_path());
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the GPS coordinates
|
||||
*/
|
||||
public function gps()
|
||||
{
|
||||
return ($this->gps_lat AND $this->gps_lon) ? sprintf('%s/%s',$this->gps_lat,$this->gps_lon) : 'UNKNOWN';
|
||||
}
|
||||
|
||||
public function isParentWritable($dir)
|
||||
{
|
||||
if (file_exists($dir) AND is_writable($dir) AND is_dir($dir))
|
||||
return TRUE;
|
||||
elseif ($dir == dirname($dir) OR file_exists($dir))
|
||||
return FALSE;
|
||||
else
|
||||
return ($this->isParentWritable(dirname($dir)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a file is moveable
|
||||
*
|
||||
* useID boolean Determine if the path is based on the the ID or date
|
||||
*/
|
||||
public function moveable()
|
||||
{
|
||||
// If the source and target are the same, we dont need to move it
|
||||
if ($this->file_path() == $this->file_path(FALSE,TRUE))
|
||||
return FALSE;
|
||||
|
||||
// If there is already a file in the target.
|
||||
// @todo If the target file is to be deleted, we could move this file
|
||||
if (file_exists($this->file_path(FALSE,TRUE)))
|
||||
return 1;
|
||||
|
||||
// Test if the source is readable
|
||||
if (! is_readable($this->file_path()))
|
||||
return 2;
|
||||
|
||||
// Test if the dir is writable (so we can remove the file)
|
||||
if (! $this->isParentWritable(dirname($this->file_path())))
|
||||
return 3;
|
||||
|
||||
// Test if the target dir is writable
|
||||
// @todo The target dir may not exist yet, so we should check that a parent exists and is writable.
|
||||
if (! $this->isParentWritable($this->file_path(FALSE,TRUE)))
|
||||
return 4;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the id of the previous photo
|
||||
*/
|
||||
public function next()
|
||||
{
|
||||
$po = DB::table('videos');
|
||||
$po->where('id','>',$this->id);
|
||||
$po->orderby('id','ASC');
|
||||
return $po->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an Imagick object or attribute
|
||||
* Return an GetID3 object or attribute
|
||||
*
|
||||
*/
|
||||
protected function o($attr=NULL)
|
||||
@ -192,17 +33,6 @@ class Video extends Model
|
||||
return is_null($attr) ? $this->_o : (array_key_exists($attr,$this->_o->info) ? $this->_o->info[$attr] : NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the id of the previous photo
|
||||
*/
|
||||
public function previous()
|
||||
{
|
||||
$po = DB::table('videos');
|
||||
$po->where('id','<',$this->id);
|
||||
$po->orderby('id','DEC');
|
||||
return $po->first();
|
||||
}
|
||||
|
||||
public function property($property)
|
||||
{
|
||||
if (! $this->o())
|
||||
@ -222,6 +52,7 @@ class Video extends Model
|
||||
|
||||
case 'make': return array_get($this->_o->info,'quicktime.comments.make.0');
|
||||
case 'model': return array_get($this->_o->info,'quicktime.comments.model.0');
|
||||
case 'software': return array_get($this->_o->info,'quicktime.comments.software.0');
|
||||
case 'signature': return array_get($this->_o->info,'sha1_data');
|
||||
#case 'height': return $this->subatomsearch('quicktime.moov.subatoms',['trak','tkhd'],'height'); break;
|
||||
#case 'width': return $this->subatomsearch('quicktime.moov.subatoms',['trak','tkhd'],'width'); break;
|
||||
@ -236,13 +67,22 @@ class Video extends Model
|
||||
case 'gps_lat': return array_get($this->_o->info,'quicktime.comments.gps_latitude.0');
|
||||
case 'gps_lon': return array_get($this->_o->info,'quicktime.comments.gps_longitude.0');
|
||||
case 'gps_altitude': return array_get($this->_o->info,'quicktime.comments.gps_altitude.0');
|
||||
case 'identifier': if ($x=array_get($this->_o->info,'quicktime.comments')) {
|
||||
return array_get(array_flatten(array_only($x,'content.identifier')),0);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
public function properties()
|
||||
{
|
||||
return $this->o() ? $this->_o->info : [];
|
||||
}
|
||||
|
||||
/**
|
||||
Navigate through ID3 data to find the value.
|
||||
* Navigate through ID3 data to find the value.
|
||||
*/
|
||||
private function subatomsearch($atom,array $paths,$key,array $data=[]) {
|
||||
if (! $data AND is_null($data = array_get($this->_o->info,$atom)))
|
||||
@ -274,30 +114,52 @@ class Video extends Model
|
||||
return isset($data[$key]) ? $data[$key] : NULL;
|
||||
}
|
||||
|
||||
public function properties()
|
||||
public function setDateCreated()
|
||||
{
|
||||
return $this->o() ? $this->_io->info : [];
|
||||
if ($this->property('creationdate'))
|
||||
$this->date_created = $this->property('creationdate');
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the photo signature
|
||||
*/
|
||||
public function signature($short=FALSE)
|
||||
public function setDateCreatedAttribute($value)
|
||||
{
|
||||
return $short ? static::signaturetrim($this->signature) : $this->signature;
|
||||
$this->attributes['date_created'] = strtotime($value);
|
||||
}
|
||||
|
||||
public static function signaturetrim($signature,$chars=6)
|
||||
public function setLocation()
|
||||
{
|
||||
return sprintf('%s...%s',substr($signature,0,$chars),substr($signature,-1*$chars));
|
||||
$this->gps_lat = $this->property('gps_lat');
|
||||
$this->gps_lon = $this->property('gps_lon');
|
||||
$this->gps_altitude = $this->property('gps_altitude');
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the image should be moved
|
||||
*/
|
||||
public function shouldMove()
|
||||
public function setMakeModel()
|
||||
{
|
||||
return ($this->filename != $this->file_path(TRUE,TRUE));
|
||||
$this->make = $this->property('make');
|
||||
$this->model = $this->property('model');
|
||||
$this->software = $this->property('software');
|
||||
$this->type = $this->property('type');
|
||||
$this->length = $this->property('length');
|
||||
$this->codec = $this->property('codec');
|
||||
$this->audiochannels = $this->property('audiochannels');
|
||||
$this->channelmode = $this->property('channelmode');
|
||||
$this->samplerate = $this->property('samplerate');
|
||||
}
|
||||
|
||||
public function setSignature()
|
||||
{
|
||||
$this->signature = $this->property('signature');
|
||||
$this->file_signature = md5_file($this->file_path());
|
||||
$this->identifier = $this->property('identifier');
|
||||
}
|
||||
|
||||
public function setSubSecTime()
|
||||
{
|
||||
// NOOP
|
||||
}
|
||||
|
||||
public function setThumbnail()
|
||||
{
|
||||
// NOOP
|
||||
}
|
||||
|
||||
/**
|
||||
@ -312,47 +174,4 @@ class Video extends Model
|
||||
{
|
||||
return sprintf('<video width="320" height="240" src="%s" controls></video>',url('/v/view/'.$this->id));
|
||||
}
|
||||
|
||||
/**
|
||||
* Find duplicate images based on some attributes of the current image
|
||||
*/
|
||||
public function list_duplicate($includeme=FALSE)
|
||||
{
|
||||
$po = DB::table('videos');
|
||||
|
||||
if ($this->id AND ! $includeme)
|
||||
$po->where('id','!=',$this->id);
|
||||
|
||||
// Ignore photo's pending removal.
|
||||
if (! $includeme)
|
||||
$po->where(function($query)
|
||||
{
|
||||
$query->where('remove','!=',TRUE)
|
||||
->orWhere('remove','=',NULL);
|
||||
});
|
||||
|
||||
// Where the signature is the same
|
||||
$po->where(function($query)
|
||||
{
|
||||
$query->where('signature','=',$this->signature);
|
||||
|
||||
// Or they have the same time taken with the same camera
|
||||
if ($this->date_created AND ($this->model OR $this->make))
|
||||
{
|
||||
$query->orWhere(function($query)
|
||||
{
|
||||
$query->where('date_created','=',$this->date_created ? $this->date_created : NULL);
|
||||
|
||||
if (! is_null($this->model))
|
||||
$query->where('model','=',$this->model);
|
||||
|
||||
if (! is_null($this->make))
|
||||
$query->where('make','=',$this->make);
|
||||
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return $po->pluck('id');
|
||||
}
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ class AppServiceProvider extends ServiceProvider
|
||||
{
|
||||
// Any photo saved, queue it to be moved.
|
||||
Photo::saved(function($photo) {
|
||||
if (! $photo->duplicate AND ($x=$photo->moveable()) === TRUE)
|
||||
if ($photo->scanned AND ! $photo->duplicate AND ! $photo->remove AND ($x=$photo->moveable()) === TRUE)
|
||||
{
|
||||
Log::info(sprintf('%s: Need to Move [%s]',__METHOD__,$photo->id.'|'.serialize($x)));
|
||||
$this->dispatch((new PhotoMove($photo))->onQueue('move'));
|
||||
@ -32,7 +32,7 @@ class AppServiceProvider extends ServiceProvider
|
||||
|
||||
// Any video saved, queue it to be moved.
|
||||
Video::saved(function($video) {
|
||||
if (! $video->duplicate AND ($x=$video->moveable()) === TRUE)
|
||||
if ($video->scanned AND ! $video->duplicate AND ! $video->remove AND ($x=$video->moveable()) === TRUE)
|
||||
{
|
||||
Log::info(sprintf('%s: Need to Move [%s]',__METHOD__,$video->id.'|'.serialize($x)));
|
||||
$this->dispatch((new VideoMove($video))->onQueue('move'));
|
||||
|
@ -7,9 +7,11 @@
|
||||
"require": {
|
||||
"php": ">=5.5.9",
|
||||
"laravel/framework": "5.5.*",
|
||||
"james-heinrich/getid3": "^1.9"
|
||||
"james-heinrich/getid3": "^1.9",
|
||||
"doctrine/dbal": "^2.6"
|
||||
},
|
||||
"require-dev": {
|
||||
"barryvdh/laravel-debugbar": "^3.1"
|
||||
},
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
|
489
composer.lock
generated
489
composer.lock
generated
@ -4,8 +4,363 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "9032a4f9673c0b58a684f3f9dbbf559c",
|
||||
"content-hash": "a8aeeb055c8c6f1ee724994018b254a1",
|
||||
"packages": [
|
||||
{
|
||||
"name": "doctrine/annotations",
|
||||
"version": "v1.6.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/doctrine/annotations.git",
|
||||
"reference": "c7f2050c68a9ab0bdb0f98567ec08d80ea7d24d5"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/doctrine/annotations/zipball/c7f2050c68a9ab0bdb0f98567ec08d80ea7d24d5",
|
||||
"reference": "c7f2050c68a9ab0bdb0f98567ec08d80ea7d24d5",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"doctrine/lexer": "1.*",
|
||||
"php": "^7.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/cache": "1.*",
|
||||
"phpunit/phpunit": "^6.4"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.6.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Roman Borschel",
|
||||
"email": "roman@code-factory.org"
|
||||
},
|
||||
{
|
||||
"name": "Benjamin Eberlei",
|
||||
"email": "kontakt@beberlei.de"
|
||||
},
|
||||
{
|
||||
"name": "Guilherme Blanco",
|
||||
"email": "guilhermeblanco@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Jonathan Wage",
|
||||
"email": "jonwage@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Johannes Schmitt",
|
||||
"email": "schmittjoh@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "Docblock Annotations Parser",
|
||||
"homepage": "http://www.doctrine-project.org",
|
||||
"keywords": [
|
||||
"annotations",
|
||||
"docblock",
|
||||
"parser"
|
||||
],
|
||||
"time": "2017-12-06T07:11:42+00:00"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/cache",
|
||||
"version": "v1.7.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/doctrine/cache.git",
|
||||
"reference": "b3217d58609e9c8e661cd41357a54d926c4a2a1a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/doctrine/cache/zipball/b3217d58609e9c8e661cd41357a54d926c4a2a1a",
|
||||
"reference": "b3217d58609e9c8e661cd41357a54d926c4a2a1a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "~7.1"
|
||||
},
|
||||
"conflict": {
|
||||
"doctrine/common": ">2.2,<2.4"
|
||||
},
|
||||
"require-dev": {
|
||||
"alcaeus/mongo-php-adapter": "^1.1",
|
||||
"mongodb/mongodb": "^1.1",
|
||||
"phpunit/phpunit": "^5.7",
|
||||
"predis/predis": "~1.0"
|
||||
},
|
||||
"suggest": {
|
||||
"alcaeus/mongo-php-adapter": "Required to use legacy MongoDB driver"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.7.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Doctrine\\Common\\Cache\\": "lib/Doctrine/Common/Cache"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Roman Borschel",
|
||||
"email": "roman@code-factory.org"
|
||||
},
|
||||
{
|
||||
"name": "Benjamin Eberlei",
|
||||
"email": "kontakt@beberlei.de"
|
||||
},
|
||||
{
|
||||
"name": "Guilherme Blanco",
|
||||
"email": "guilhermeblanco@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Jonathan Wage",
|
||||
"email": "jonwage@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Johannes Schmitt",
|
||||
"email": "schmittjoh@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "Caching library offering an object-oriented API for many cache backends",
|
||||
"homepage": "http://www.doctrine-project.org",
|
||||
"keywords": [
|
||||
"cache",
|
||||
"caching"
|
||||
],
|
||||
"time": "2017-08-25T07:02:50+00:00"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/collections",
|
||||
"version": "v1.5.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/doctrine/collections.git",
|
||||
"reference": "a01ee38fcd999f34d9bfbcee59dbda5105449cbf"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/doctrine/collections/zipball/a01ee38fcd999f34d9bfbcee59dbda5105449cbf",
|
||||
"reference": "a01ee38fcd999f34d9bfbcee59dbda5105449cbf",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/coding-standard": "~0.1@dev",
|
||||
"phpunit/phpunit": "^5.7"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.3.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Doctrine\\Common\\Collections\\": "lib/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Roman Borschel",
|
||||
"email": "roman@code-factory.org"
|
||||
},
|
||||
{
|
||||
"name": "Benjamin Eberlei",
|
||||
"email": "kontakt@beberlei.de"
|
||||
},
|
||||
{
|
||||
"name": "Guilherme Blanco",
|
||||
"email": "guilhermeblanco@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Jonathan Wage",
|
||||
"email": "jonwage@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Johannes Schmitt",
|
||||
"email": "schmittjoh@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "Collections Abstraction library",
|
||||
"homepage": "http://www.doctrine-project.org",
|
||||
"keywords": [
|
||||
"array",
|
||||
"collections",
|
||||
"iterator"
|
||||
],
|
||||
"time": "2017-07-22T10:37:32+00:00"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/common",
|
||||
"version": "v2.8.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/doctrine/common.git",
|
||||
"reference": "f68c297ce6455e8fd794aa8ffaf9fa458f6ade66"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/doctrine/common/zipball/f68c297ce6455e8fd794aa8ffaf9fa458f6ade66",
|
||||
"reference": "f68c297ce6455e8fd794aa8ffaf9fa458f6ade66",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"doctrine/annotations": "1.*",
|
||||
"doctrine/cache": "1.*",
|
||||
"doctrine/collections": "1.*",
|
||||
"doctrine/inflector": "1.*",
|
||||
"doctrine/lexer": "1.*",
|
||||
"php": "~7.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^5.7"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.8.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Doctrine\\Common\\": "lib/Doctrine/Common"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Roman Borschel",
|
||||
"email": "roman@code-factory.org"
|
||||
},
|
||||
{
|
||||
"name": "Benjamin Eberlei",
|
||||
"email": "kontakt@beberlei.de"
|
||||
},
|
||||
{
|
||||
"name": "Guilherme Blanco",
|
||||
"email": "guilhermeblanco@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Jonathan Wage",
|
||||
"email": "jonwage@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Johannes Schmitt",
|
||||
"email": "schmittjoh@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "Common Library for Doctrine projects",
|
||||
"homepage": "http://www.doctrine-project.org",
|
||||
"keywords": [
|
||||
"annotations",
|
||||
"collections",
|
||||
"eventmanager",
|
||||
"persistence",
|
||||
"spl"
|
||||
],
|
||||
"time": "2017-08-31T08:43:38+00:00"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/dbal",
|
||||
"version": "v2.6.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/doctrine/dbal.git",
|
||||
"reference": "e3eed9b1facbb0ced3a0995244843a189e7d1b13"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/doctrine/dbal/zipball/e3eed9b1facbb0ced3a0995244843a189e7d1b13",
|
||||
"reference": "e3eed9b1facbb0ced3a0995244843a189e7d1b13",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"doctrine/common": "^2.7.1",
|
||||
"ext-pdo": "*",
|
||||
"php": "^7.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^5.4.6",
|
||||
"phpunit/phpunit-mock-objects": "!=3.2.4,!=3.2.5",
|
||||
"symfony/console": "2.*||^3.0"
|
||||
},
|
||||
"suggest": {
|
||||
"symfony/console": "For helpful console commands such as SQL execution and import of files."
|
||||
},
|
||||
"bin": [
|
||||
"bin/doctrine-dbal"
|
||||
],
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.6.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Doctrine\\DBAL\\": "lib/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Roman Borschel",
|
||||
"email": "roman@code-factory.org"
|
||||
},
|
||||
{
|
||||
"name": "Benjamin Eberlei",
|
||||
"email": "kontakt@beberlei.de"
|
||||
},
|
||||
{
|
||||
"name": "Guilherme Blanco",
|
||||
"email": "guilhermeblanco@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Jonathan Wage",
|
||||
"email": "jonwage@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "Database Abstraction Layer",
|
||||
"homepage": "http://www.doctrine-project.org",
|
||||
"keywords": [
|
||||
"database",
|
||||
"dbal",
|
||||
"persistence",
|
||||
"queryobject"
|
||||
],
|
||||
"time": "2017-11-19T13:38:54+00:00"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/inflector",
|
||||
"version": "v1.2.0",
|
||||
@ -1898,7 +2253,137 @@
|
||||
"time": "2016-09-01T10:05:43+00:00"
|
||||
}
|
||||
],
|
||||
"packages-dev": [],
|
||||
"packages-dev": [
|
||||
{
|
||||
"name": "barryvdh/laravel-debugbar",
|
||||
"version": "v3.1.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/barryvdh/laravel-debugbar.git",
|
||||
"reference": "01a859752094e00aa8548832312366753272f8af"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/barryvdh/laravel-debugbar/zipball/01a859752094e00aa8548832312366753272f8af",
|
||||
"reference": "01a859752094e00aa8548832312366753272f8af",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"illuminate/routing": "5.5.x",
|
||||
"illuminate/session": "5.5.x",
|
||||
"illuminate/support": "5.5.x",
|
||||
"maximebf/debugbar": "~1.14.0",
|
||||
"php": ">=7.0",
|
||||
"symfony/debug": "^3",
|
||||
"symfony/finder": "^3"
|
||||
},
|
||||
"require-dev": {
|
||||
"illuminate/framework": "5.5.x"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "3.0-dev"
|
||||
},
|
||||
"laravel": {
|
||||
"providers": [
|
||||
"Barryvdh\\Debugbar\\ServiceProvider"
|
||||
],
|
||||
"aliases": {
|
||||
"Debugbar": "Barryvdh\\Debugbar\\Facade"
|
||||
}
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Barryvdh\\Debugbar\\": "src/"
|
||||
},
|
||||
"files": [
|
||||
"src/helpers.php"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Barry vd. Heuvel",
|
||||
"email": "barryvdh@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "PHP Debugbar integration for Laravel",
|
||||
"keywords": [
|
||||
"debug",
|
||||
"debugbar",
|
||||
"laravel",
|
||||
"profiler",
|
||||
"webprofiler"
|
||||
],
|
||||
"time": "2017-09-18T13:32:46+00:00"
|
||||
},
|
||||
{
|
||||
"name": "maximebf/debugbar",
|
||||
"version": "v1.14.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/maximebf/php-debugbar.git",
|
||||
"reference": "64251a392344e3d22f3d21c3b7c531ba96eb01d2"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/maximebf/php-debugbar/zipball/64251a392344e3d22f3d21c3b7c531ba96eb01d2",
|
||||
"reference": "64251a392344e3d22f3d21c3b7c531ba96eb01d2",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.0",
|
||||
"psr/log": "^1.0",
|
||||
"symfony/var-dumper": "^2.6|^3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^4.0|^5.0"
|
||||
},
|
||||
"suggest": {
|
||||
"kriswallsmith/assetic": "The best way to manage assets",
|
||||
"monolog/monolog": "Log using Monolog",
|
||||
"predis/predis": "Redis storage"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.14-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"DebugBar\\": "src/DebugBar/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Maxime Bouroumeau-Fuseau",
|
||||
"email": "maxime.bouroumeau@gmail.com",
|
||||
"homepage": "http://maximebf.com"
|
||||
},
|
||||
{
|
||||
"name": "Barry vd. Heuvel",
|
||||
"email": "barryvdh@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "Debug bar in the browser for php application",
|
||||
"homepage": "https://github.com/maximebf/php-debugbar",
|
||||
"keywords": [
|
||||
"debug",
|
||||
"debugbar"
|
||||
],
|
||||
"time": "2017-09-13T12:19:36+00:00"
|
||||
}
|
||||
],
|
||||
"aliases": [],
|
||||
"minimum-stability": "stable",
|
||||
"stability-flags": [],
|
||||
|
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
|
||||
class PhotosRenameFields extends Migration {
|
||||
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('photo', function(Blueprint $table)
|
||||
{
|
||||
$table->renameColumn('date_taken', 'date_created');
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('photo', function(Blueprint $table)
|
||||
{
|
||||
$table->renameColumn('date_created', 'date_taken');
|
||||
});
|
||||
}
|
||||
}
|
51
database/migrations/2018_01_11_090453_VideoAddScanned.php
Normal file
51
database/migrations/2018_01_11_090453_VideoAddScanned.php
Normal file
@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class VideoAddScanned extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('photo', function (Blueprint $table) {
|
||||
$table->boolean('scanned')->nullable();
|
||||
$table->string('file_signature')->nullable();
|
||||
$table->string('identifier')->nullable();
|
||||
$table->string('software')->nullable();
|
||||
});
|
||||
|
||||
Schema::table('videos', function (Blueprint $table) {
|
||||
$table->boolean('scanned')->nullable();
|
||||
$table->string('file_signature')->nullable();
|
||||
$table->string('identifier')->nullable();
|
||||
$table->string('software')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('photo', function (Blueprint $table) {
|
||||
$table->dropColumn('scanned');
|
||||
$table->dropColumn('file_signature');
|
||||
$table->dropColumn('identifier');
|
||||
$table->dropColumn('software');
|
||||
});
|
||||
Schema::table('videos', function (Blueprint $table) {
|
||||
$table->dropColumn('scanned');
|
||||
$table->dropColumn('file_signature');
|
||||
$table->dropColumn('identifier');
|
||||
$table->dropColumn('software');
|
||||
});
|
||||
}
|
||||
}
|
54
database/migrations/2018_01_13_120330_PhotoAddIndex.php
Normal file
54
database/migrations/2018_01_13_120330_PhotoAddIndex.php
Normal file
@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class PhotoAddIndex extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('photo', function (Blueprint $table) {
|
||||
$table->index(['signature']);
|
||||
$table->index(['filename']);
|
||||
$table->index(['remove']);
|
||||
$table->index(['duplicate']);
|
||||
$table->index(['date_created','subsectime','model','make']);
|
||||
});
|
||||
Schema::table('videos', function (Blueprint $table) {
|
||||
$table->index(['signature']);
|
||||
$table->index(['filename']);
|
||||
$table->index(['remove']);
|
||||
$table->index(['duplicate']);
|
||||
$table->index(['date_created','model','make']);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('photo', function (Blueprint $table) {
|
||||
$table->dropIndex(['signature']);
|
||||
$table->dropIndex(['filename']);
|
||||
$table->dropIndex(['remove']);
|
||||
$table->dropIndex(['duplicate']);
|
||||
$table->dropIndex(['date_created','subsectime','model','make']);
|
||||
});
|
||||
Schema::table('videos', function (Blueprint $table) {
|
||||
$table->dropIndex(['signature']);
|
||||
$table->dropIndex(['filename']);
|
||||
$table->dropIndex(['remove']);
|
||||
$table->dropIndex(['duplicate']);
|
||||
$table->dropIndex(['date_created','model','make']);
|
||||
});
|
||||
}
|
||||
}
|
80
resources/views/catalog/deletereview.blade.php
Normal file
80
resources/views/catalog/deletereview.blade.php
Normal file
@ -0,0 +1,80 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
<?php $data = [
|
||||
'ID'=>['id','idlink'],
|
||||
'Signature'=>['signature','signature'],
|
||||
'File Signature'=>['file_signature','file_signature'],
|
||||
'Date Created'=>['date_created','datecreatedtext'],
|
||||
'Filename'=>['filename','filename'],
|
||||
'Filesize'=>['filesize','filesize'],
|
||||
'Is Duplicate'=>['duplicate','duplicatetext'],
|
||||
'Flagged'=>['flag','flagtext'],
|
||||
'Delete'=>['remove','removecheckbox'],
|
||||
];?>
|
||||
|
||||
@section('content')
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-11 col-md-offset-1">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
Permanently Delete Items
|
||||
</div>
|
||||
|
||||
<div class="text-center">{{ $catalog->links() }}</div>
|
||||
|
||||
<div class="panel-body">
|
||||
@if ($catalog->count())
|
||||
<form action="{{ $return }}" method="POST">
|
||||
<table class="table table-striped table-condensed table-hover">
|
||||
<tr>
|
||||
<th>Source</th>
|
||||
<th>Remove</th>
|
||||
</tr>
|
||||
|
||||
@foreach ($catalog as $o)
|
||||
<tr>
|
||||
@php
|
||||
$d=$o->list_duplicates(TRUE); $src=[];
|
||||
@endphp
|
||||
<td>
|
||||
@if($d->where('duplicate',null)->count() > 1)
|
||||
More than 1 source?
|
||||
@elseif($d->count())
|
||||
@php($src = $d->first())
|
||||
{!! $src->view() !!}
|
||||
<table class="table table-striped table-condensed table-hover small">
|
||||
@foreach($data as $k=>$v)
|
||||
<tr><th>{{$k}}</th><td>{!! $src->{$v[1]} !!}</td></tr>
|
||||
@endforeach
|
||||
</table>
|
||||
@endif
|
||||
</td>
|
||||
@foreach($d as $item)
|
||||
@if($src AND $item->id == $src->id) @continue @endif
|
||||
@php($diff=collect($src)->diffAssoc($item))
|
||||
<td>
|
||||
{!! $item->view() !!}
|
||||
<table class="table table-striped table-condensed table-hover small">
|
||||
@foreach($data as $k=>$v)
|
||||
<tr class="@if($diff->has($v[0])) danger @endif"><th>{{$k}}</th><td>{!! $item->{$v[1]} !!}</td></tr>
|
||||
@endforeach
|
||||
</table>
|
||||
</td>
|
||||
@endforeach
|
||||
</tr>
|
||||
@endforeach
|
||||
</table>
|
||||
<input type="hidden" name="pagenext" value="{{ $catalog->hasMorePages() ? $catalog->currentPage()+1 : NULL }}">
|
||||
<button class="btn btn-default">Confirm Delete</button>
|
||||
{{ csrf_field() }}
|
||||
</form>
|
||||
@else
|
||||
NONE!
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
@ -1,78 +0,0 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
<?php $data = [
|
||||
'ID'=>'id',
|
||||
'Thumbnail'=>'thumbnail',
|
||||
'Signature'=>'signature',
|
||||
'Date Taken'=>'datetaken',
|
||||
'File Created'=>'created',
|
||||
'File Modified'=>'modified',
|
||||
'Filename'=>'filepath',
|
||||
'Filesize'=>'filesize',
|
||||
'Width'=>'width',
|
||||
'Height'=>'height',
|
||||
'Orientation'=>'orientation',
|
||||
'Make'=>'make',
|
||||
'Model'=>'model',
|
||||
'Duplicates'=>'duplicates',
|
||||
'Is Duplicate'=>'duplicate',
|
||||
'Flagged'=>'flag',
|
||||
'Delete'=>'remove',
|
||||
];?>
|
||||
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-11 col-md-offset-1">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
Permanently Delete Photos
|
||||
</div>
|
||||
|
||||
<div class="text-center">{{ $photos->links() }}</div>
|
||||
<div class="panel-body">
|
||||
@if ($photos->count())
|
||||
<form action="{{ url('/p/deletes') }}" method="POST">
|
||||
<table class="table table-striped table-condensed table-hover">
|
||||
@foreach ($data as $k=>$v)
|
||||
<tr>
|
||||
<th>{{ $k }}</th>
|
||||
@foreach ($photos as $o)
|
||||
<?php
|
||||
switch ($v) :
|
||||
case 'id': $x=$o->id; $y=sprintf('<input type="hidden" name="photo[]" value="%s"><a href="%s">%s</a>',$o->id,url('/p/info/'.$o->id),$o->id); break;
|
||||
case 'thumbnail': $x=md5($o->thumbnail); $y=sprintf('<a href="%s"><img src="%s" width="200px"></a>',url('/p/view/'.$o->id),url('/p/thumbnail/'.$o->id)); break;
|
||||
case 'signature': $x=$y=$o->signature(TRUE); break;
|
||||
case 'datetaken': $x=$y=$o->date_taken(); break;
|
||||
case 'created': $x=$y=$o->file_date('c',TRUE); break;
|
||||
case 'modified': $x=$y=$o->file_date('m',TRUE); break;
|
||||
case 'filepath': $x=$y=$o->file_path(TRUE); break;
|
||||
case 'filesize': $x=$y=$o->file_size(); break;
|
||||
case 'width':
|
||||
case 'height':
|
||||
case 'orientation':
|
||||
case 'make':
|
||||
case 'model': $y=$o->{$v}; break;
|
||||
case 'duplicates': $x=$y='';foreach($o->list_duplicate() as $id) $y.=($y ? '|' : '').sprintf('<a href="%s">%s</a>',url('/p/info/'.$id),$id); break;
|
||||
case 'flag':
|
||||
case 'remove':
|
||||
case 'duplicate': $y=sprintf('<input type="checkbox" name="%s[%s]" value="1"%s>',$v,$o->id,$o->{$v} ? ' checked="checked"' : ''); break;
|
||||
endswitch ?>
|
||||
<td><?php echo $y; ?></td>
|
||||
@endforeach {{-- photo --}}
|
||||
</tr>
|
||||
@endforeach {{-- data --}}
|
||||
</table>
|
||||
<input type="hidden" name="pagenext" value="{{ $photos->hasMorePages() ? $photos->currentPage()+1 : NULL }}">
|
||||
<button class="btn btn-default">Confirm Delete</button>
|
||||
{{ csrf_field() }}
|
||||
</form>
|
||||
@else
|
||||
NONE!
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
@ -33,6 +33,7 @@
|
||||
<dt>Date Taken</dt><dd>{{ $photo->date_taken() }}<dd>
|
||||
<dt>Camera</dt><dd>{{ $photo->make }}<dd>
|
||||
<dt>Model</dt><dd>{{ $photo->model }}<dd>
|
||||
<dt>Software</dt><dd>{{ $photo->software }}<dd>
|
||||
<br/>
|
||||
<dt>Location</dt><dd>
|
||||
<?php if ($photo->gps() == 'UNKNOWN') : ?>
|
||||
|
@ -1,75 +0,0 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
<?php $data = [
|
||||
'ID'=>'id',
|
||||
'Signature'=>'signature',
|
||||
'Date Created'=>'datecreated',
|
||||
'File Created'=>'created',
|
||||
'File Modified'=>'modified',
|
||||
'Filename'=>'filepath',
|
||||
'Filesize'=>'filesize',
|
||||
'Width'=>'width',
|
||||
'Height'=>'height',
|
||||
'Make'=>'make',
|
||||
'Model'=>'model',
|
||||
'Duplicates'=>'duplicates',
|
||||
'Is Duplicate'=>'duplicate',
|
||||
'Flagged'=>'flag',
|
||||
'Delete'=>'remove',
|
||||
];?>
|
||||
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-11 col-md-offset-1">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
Permanently Delete Photos
|
||||
</div>
|
||||
|
||||
<div class="text-center">{{ $videos->links() }}</div>
|
||||
<div class="panel-body">
|
||||
@if ($videos->count())
|
||||
<form action="{{ url('/v/deletes') }}" method="POST">
|
||||
<table class="table table-striped table-condensed table-hover">
|
||||
@foreach ($data as $k=>$v)
|
||||
<tr>
|
||||
<th>{{ $k }}</th>
|
||||
@foreach ($videos as $o)
|
||||
<?php
|
||||
switch ($v) :
|
||||
case 'id': $x=$o->id; $y=sprintf('<input type="hidden" name="video[]" value="%s"><a href="%s">%s</a>',$o->id,url('/v/info/'.$o->id),$o->id); break;
|
||||
case 'signature': $x=$y=$o->signature(TRUE); break;
|
||||
case 'datecreated': $x=$y=$o->date_taken(); break;
|
||||
case 'created': $x=$y=$o->file_date('c',TRUE); break;
|
||||
case 'modified': $x=$y=$o->file_date('m',TRUE); break;
|
||||
case 'filepath': $x=$y=$o->file_path(TRUE); break;
|
||||
case 'filesize': $x=$y=$o->file_size(); break;
|
||||
case 'width':
|
||||
case 'height':
|
||||
case 'orientation':
|
||||
case 'make':
|
||||
case 'model': $y=$o->{$v}; break;
|
||||
case 'duplicates': $x=$y='';foreach($o->list_duplicate() as $id) $y.=($y ? '|' : '').sprintf('<a href="%s">%s</a>',url('/v/info/'.$id),$id); break;
|
||||
case 'flag':
|
||||
case 'remove':
|
||||
case 'duplicate': $y=sprintf('<input type="checkbox" name="%s[%s]" value="1"%s>',$v,$o->id,$o->{$v} ? ' checked="checked"' : ''); break;
|
||||
endswitch ?>
|
||||
<td><?php echo $y; ?></td>
|
||||
@endforeach {{-- video --}}
|
||||
</tr>
|
||||
@endforeach {{-- data --}}
|
||||
</table>
|
||||
<input type="hidden" name="pagenext" value="{{ $videos->hasMorePages() ? $videos->currentPage()+1 : NULL }}">
|
||||
<button class="btn btn-default">Confirm Delete</button>
|
||||
{{ csrf_field() }}
|
||||
</form>
|
||||
@else
|
||||
NONE!
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
@ -5,6 +5,7 @@
|
||||
'ID'=>'id',
|
||||
'Video'=>'video',
|
||||
'Signature'=>'signature',
|
||||
'File Signature'=>'file_signature',
|
||||
'Length'=>'length',
|
||||
'Date Created'=>'datecreated',
|
||||
'File Created'=>'created',
|
||||
@ -58,6 +59,7 @@ case 'id': $x=$id; $y=sprintf('<a href="%s">%s</a>',url('/v/info/'.$o->id),$o->i
|
||||
case 'video': $x=$o->signature(TRUE);$y=$o->view();; break;
|
||||
case 'length': $x=$y=$o->length; break;
|
||||
case 'signature': $x=$y=$o->signature(TRUE); break;
|
||||
case 'file_signature': $x=$y=$o->file_signature(TRUE); break;
|
||||
case 'datecreated': $x=$y=$o->date_taken(); break;
|
||||
case 'created': $x=$y=$o->file_date('c',TRUE); break;
|
||||
case 'modified': $x=$y=$o->file_date('m',TRUE); break;
|
||||
|
@ -6,7 +6,7 @@
|
||||
<div class="col-md-10 col-md-offset-1">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
Video {{ $video->id }}<?php if ($video->remove) : ?> - <strong>PENDING DELETE</strong><?php endif?>
|
||||
Video {{ $video->id }}<?php if ($video->remove) : ?> - <strong>PENDING DELETE</strong><?php endif?><?php if ($video->duplicate) : ?> - <strong>DUPLICATE</strong><?php endif?>
|
||||
</div>
|
||||
|
||||
<div class="panel-body">
|
||||
@ -39,6 +39,8 @@
|
||||
<dt>Date Taken</dt><dd>{{ $video->date_taken() }}<dd>
|
||||
<dt>Camera</dt><dd>{{ $video->make }}<dd>
|
||||
<dt>Model</dt><dd>{{ $video->model }}<dd>
|
||||
<dt>Software</dt><dd>{{ $video->software }}<dd>
|
||||
<dt>Identifier</dt><dd>{{ $video->identifier }}<dd>
|
||||
<br/>
|
||||
<dt>Location</dt><dd>
|
||||
<?php if ($video->gps() == 'UNKNOWN') : ?>
|
||||
@ -60,6 +62,14 @@
|
||||
</script>
|
||||
<?php endif ?>
|
||||
</dd>
|
||||
@if($x = $video->list_duplicate())
|
||||
<dt>Duplicates</dt><dd>
|
||||
@php
|
||||
$y=''; foreach($video->list_duplicate() as $id) $y.=($y ? '|' : '').sprintf('<a href="%s">%s</a>',url('/v/info/'.$id),$id);
|
||||
echo($y);
|
||||
@endphp
|
||||
</dd>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user