Internal optimisations and additional flags for Photo/Video

This commit is contained in:
Deon George 2020-01-05 00:28:00 +11:00
parent 93364ab53a
commit 1ffc2d994e
19 changed files with 402 additions and 279 deletions

View File

@ -0,0 +1,77 @@
<?php
namespace App\Console\Commands;
use App\Jobs\PhotoMove;
use App\Jobs\VideoMove;
use Illuminate\Console\Command;
use Illuminate\Foundation\Bus\DispatchesJobs;
use App\Jobs\PhotoDelete;
use App\Models\Photo;
use App\Traits\Type;
class CatalogAutoDelete extends Command
{
use DispatchesJobs,Type;
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'catalog:autodelete {type : Photo | Video }';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Auto Delete Catalog Items';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
$class = $this->getModelType($this->argument('type'));
$class::where('remove',1)->each(function($o) {
foreach ($o->myduplicates() as $oo) {
if (! $oo->signature OR ! $oo->file_signature)
continue;
if ($oo->signature == $o->signature AND $oo->file_signature == $o->file_signature) {
$this->info(sprintf('Removing: %s (%s)',$o->id,$o->filename));
continue;
// Dispatch Job to move file.
switch (strtolower($this->argument('type'))) {
case 'photo':
$this->dispatch((new PhotoDelete($o))->onQueue('delete'));
break;
case 'video':
$this->dispatch((new VideoDelete($o))->onQueue('delete'));
break;
default:
$this->error('Dont know how to handle: ',$this->argument('type'));
}
}
}
});
}
}

View File

@ -15,7 +15,10 @@ class CatalogScan extends Command
*
* @var string
*/
protected $signature = 'catalog:scan {type : Photo | Video } {id : Photo ID}';
protected $signature = 'catalog:scan'.
' {type : Photo | Video }'.
' {id : Photo ID}'.
' {--dirty : Show Dirty}';
/**
* The console command description.
@ -49,17 +52,17 @@ class CatalogScan extends Command
$o->setThumbnail();
// If this is a duplicate
$x = $o->duplicates()->get();
$x = $o->myduplicates()->get();
if (count($x)) {
foreach ($x as $oo) {
// 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()));
$this->warn(sprintf('Image [%s] marked as a duplicate',$o->filename));
// 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()));
$this->warn(sprintf('Image [%s] marked for deletion',$o->filename));
$o->remove = '1';
}
@ -72,9 +75,15 @@ class CatalogScan extends Command
if ($o->getDirty()) {
$this->warn(sprintf('Image [%s] metadata changed',$o->filename));
dump(['id'=>$o->id,'data'=>$o->getDirty()]);
if ($this->option('dirty'))
dump(['id'=>$o->id,'data'=>$o->getDirty()]);
}
// If the file signature changed, abort the update.
if ($o->getOriginal('file_signature') AND $o->getDirty('file_signature'))
abort(500,'File Signature Changed?');
$o->save();
}
}

View File

@ -61,6 +61,7 @@ class CatalogScanAll extends Command
}
$this->dispatch((new CatalogScan($item))->onQueue('scan'));
$c++;
});
Log::info(sprintf('Processed [%s]',$c));

View File

@ -1,63 +0,0 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Foundation\Bus\DispatchesJobs;
use App\Jobs\PhotoDelete;
use App\Models\Photo;
class PhotoAutoDelete extends Command
{
use DispatchesJobs;
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'photo:autodelete';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Auto Delete Photos';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
Photo::where('remove',1)->chunk(10,function($chunk) {
foreach ($chunk as $o) {
foreach ($o->list_duplicates(TRUE) as $oo) {
if (! $oo->signature OR ! $oo->file_signature)
continue;
if ($oo->signature == $o->signature AND $oo->file_signature == $o->file_signature) {
if ($oo->remove) {
$this->info(sprintf('Removing: %s (%s)',$oo->id,$oo->filename));
$this->dispatch((new PhotoDelete($o))->onQueue('delete'));
}
}
}
}
});
}
}

View File

@ -2,13 +2,13 @@
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\Photo;
use App\Jobs\PhotoDelete;
use App\Traits\Multimedia;
class PhotoController extends Controller
{
use Multimedia;
protected $list_duplicates = 20;
protected $list_deletes = 50;
@ -22,77 +22,41 @@ class PhotoController extends Controller
$this->middleware('guest');
}
public function delete($id)
public function delete(Photo $o)
{
$o = Photo::notRemove()->findOrFail($id);
$o->remove = TRUE;
$o->save();
if ($o)
{
$o->remove = TRUE;
$o->save();
}
return redirect()->action('PhotoController@info',[$id]);
return redirect()->action('PhotoController@info',[$o->id]);
}
public function deletes($id=NULL)
{
return view('catalog.deletereview',[
'catalog'=>is_null($id) ? Photo::where('remove',1)->with(['software.model.make'])->paginate($this->list_deletes) : Photo::where('id',$id)->paginate(1),
'return'=>url('p/deletes'),
'catalog'=>is_null($id) ? Photo::where('remove',1)->with(['software.model.make'])->paginate($this->list_deletes) : Photo::where('id',$id)->paginate(1)
'type'=>'photo',
]);
}
public function deletesUpdate(Request $request)
{
foreach ($request->input('remove') as $id=>$k)
{
$o = Photo::findOrFail($id);
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);
}
public function duplicates($id=NULL)
{
return view('catalog.duplicatereview',[
'catalog'=>is_null($id) ? Photo::duplicates()->with(['software.model.make'])->paginate($this->list_duplicates) : Photo::where('id',$id)->paginate(1),
'return'=>url('p/duplicates'),
'catalog'=>is_null($id) ? Photo::notRemove()->where('duplicate',1)->with(['software.model.make'])->paginate($this->list_duplicates) : Photo::where('id',$id)->paginate(1)
'type'=>'photo',
]);
}
public function duplicatesUpdate(Request $request)
{
foreach ($request->input('items') as $id)
{
$o = Photo::findOrFail($id);
// Set if duplicate
$o->duplicate = $request->input('duplicate.'.$id) ? 1 : NULL;
// Set if flag
$o->flag = $request->input('flag.'.$id) ? 1 : NULL;
// Set if delete
$o->remove = $request->input('remove.'.$id) ? 1 : NULL;
$o->save();
}
return redirect()->action('PhotoController@duplicates','?page='.$request->input('page'));
}
public function info(Photo $o)
{
return view('photo.view',['o'=>$o]);
}
public function thumbnail($id)
public function thumbnail(Photo $o)
{
return response(Photo::findOrFail($id)->thumbnail(TRUE))->header('Content-Type','image/jpeg');
return response($o->thumbnail(TRUE))
->header('Content-Type','image/jpeg');
}
public function undelete(Photo $o)
@ -103,8 +67,9 @@ class PhotoController extends Controller
return redirect()->action('PhotoController@info',[$o->id]);
}
public function view($id)
public function view(Photo $o)
{
return response(Photo::findOrFail($id)->image())->header('Content-Type','image/jpeg');
return response($o->image())
->header('Content-Type','image/jpeg');
}
}

View File

@ -2,14 +2,17 @@
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\Video;
use App\Jobs\VideoDelete;
use App\Helpers\VideoStream;
use App\Traits\Multimedia;
class VideoController extends Controller
{
use Multimedia;
protected $list_duplicates = 20;
protected $list_deletes = 50;
/**
* Create a new controller instance.
*
@ -20,71 +23,30 @@ class VideoController extends Controller
$this->middleware('guest');
}
public function delete($id)
public function delete(Video $o)
{
$o = Video::notRemove()->findOrFail($id);
$o->remove = TRUE;
$o->save();
if ($o)
{
$o->remove = TRUE;
$o->save();
}
return redirect()->action('VideoController@info',[$id]);
return redirect()->action('VideoController@info',[$o->id]);
}
public function deletes($id=NULL)
{
return view('catalog.deletereview',[
'catalog'=>is_null($id) ? Video::where('remove',1)->with(['software.model.make'])->paginate($this->list_deletes) : Video::where('id',$id)->paginate(1),
'return'=>url('v/deletes'),
'catalog'=>is_null($id) ? Video::where('remove',1)->with(['software.model.make'])->paginate(50) : Video::where('id',$id)->paginate(1)
'type'=>'photo',
]);
}
public function deletesUpdate(Request $request)
{
foreach ($request->input('remove') as $id=>$k)
{
$o = Video::findOrFail($id);
if ($o->remove AND $request->input('remove.'.$id))
$this->dispatch((new VideoDelete($o))->onQueue('delete'));
elseif (! $o->remove) {
$o->remove = TRUE;
$o->save();
}
}
return redirect()->action('VideoController@deletes',$request->input('pagenext') ? '?page='.$request->input('pagenext') : NULL);
}
public function duplicates($id=NULL)
{
return view('catalog.duplicatereview',[
'catalog'=>is_null($id) ? Video::duplicates()->with(['software.model.make'])->paginate($this->list_duplicates) : Video::where('id',$id)->paginate(1),
'return'=>url('v/duplicates'),
'catalog'=>is_null($id) ? Video::notRemove()->where('duplicate',1)->with(['software.model.make'])->paginate(50) : Video::where('id',$id)->paginate(1)]);
}
public function duplicatesUpdate(Request $request)
{
foreach ($request->input('items') as $id)
{
$o = Video::findOrFail($id);
// Set if duplicate
$o->duplicate = $request->input('duplicate.'.$id) ? 1 : NULL;
// Set if flag
$o->flag = $request->input('flag.'.$id) ? 1 : NULL;
// Set if delete
$o->remove = $request->input('remove.'.$id) ? 1 : NULL;
$o->save();
}
return redirect()->action('VideoController@duplicates','?page='.$request->input('page'));
'type'=>'photo',
]);
}
public function info(Video $o)
@ -100,8 +62,9 @@ class VideoController extends Controller
return redirect()->action('VideoController@info',[$o->id]);
}
public function view($id)
public function view(Video $o)
{
(new VideoStream(Video::findOrFail($id)->file_path()))->start();
if ($o->isReadable())
(new VideoStream($o->filename))->start();
}
}

View File

@ -4,6 +4,7 @@ namespace App\Models\Abstracted;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\DB;
@ -12,6 +13,7 @@ use App\Models\{Person,Software,Tag};
abstract class Catalog extends Model
{
protected static $includeSubSecTime = FALSE;
protected $dates = ['created'];
/**
* People in Multimedia Object
@ -44,18 +46,39 @@ abstract class Catalog extends Model
}
/**
* Search Database for duplicates of this object
* Find records marked as duplicate
*
* @param $query
* @return mixed
*/
public function scopeDuplicates($query) {
$query->notRemove()
->where('duplicate',TRUE)
->where(function($q) {
$q->Where('ignore_duplicate','<>',TRUE)
->orWhereNull('ignore_duplicate');
});
}
/**
* Search Database for duplicates of this object
*
* @param $query
* @return mixed
*/
public function scopeMyDuplicates($query) {
if (! $this->exists)
return $query;
// Exclude this record
$query->where('id','<>',$this->attributes['id']);
// Skip ignore dups
$query->where(function($q) {
$q->whereNull('ignore_duplicate')
->orWhere('ignore_duplicate','=',0);
});
// Exclude those marked as remove
$query->where(function ($q) {
$q->where('remove','<>',TRUE)
@ -69,11 +92,11 @@ abstract class Catalog extends Model
// Where the signature is the same
->orWhere(function($q) {
// Or they have the same time taken with the same camera
if ($this->attributes['date_created'] AND $this->software_id) {
$q->where('date_created','=',$this->attributes['date_created'] ?: NULL);
if ($this->attributes['created'] AND $this->software_id) {
$q->where('created','=',$this->attributes['created'] ?: NULL);
if (static::$includeSubSecTime)
$q->where('subsectime','=',$this->attributes['subsectime'] ?: NULL);
$q->where('subsectime','=',Arr::get($this->attributes,'subsectime'));
$q->where('software_id','=',$this->attributes['software_id']);
}
@ -124,9 +147,7 @@ abstract class Catalog extends Model
}
// Children objects must inherit this methods
abstract public function setDateCreated();
abstract public function setLocation();
abstract public function setSignature();
abstract public function setSubSecTime();
abstract public function setThumbnail();
abstract public function getHtmlImageURL();
@ -136,9 +157,16 @@ abstract class Catalog extends Model
*/
public function date_taken(): string
{
return $this->date_created ? $this->date_created->format('Y-m-d H:i:s') : 'UNKNOWN';
return $this->created
? $this->created->format('Y-m-d H:i:s').(static::$includeSubSecTime ? sprintf('.%03d',$this->subsectime) : '')
: 'UNKNOWN';
}
/**
* What device was the multimedia created on
*
* @return string
*/
public function device(): string
{
$result = '';
@ -169,11 +197,13 @@ abstract class Catalog extends Model
switch ($type)
{
case 'a': $t = fileatime($this->file_path());
case 'a': $t = fileatime($this->filename);
break;
case 'c': $t = filectime($this->file_path());
case 'c': $t = filectime($this->filename);
break;
case 'm': $t = filemtime($this->file_path());
case 'm': $t = filemtime($this->filename);
break;
}
@ -188,12 +218,15 @@ abstract class Catalog extends Model
public function file_name(bool $short=TRUE): string
{
// If the date created is not set, the file name will be based on the ID of the file.
$file = sprintf('%s.%s',((is_null($this->date_created) OR ! $this->date_created)
$file = sprintf('%s.%s',(is_null($this->created)
? sprintf('UNKNOWN/%07s',$this->file_path_id())
: sprintf('%s_%03s',$this->date_created->format('Y/m/d-His'),$this->subsectime).
((! static::$includeSubSecTime OR $this->subsectime) ? '' : sprintf('-%05s',$this->id))),$this->type());
: $this->created->format('Y/m/d-His').((! is_null($this->subsectime)) ? sprintf('.%03d',$this->subsectime) : '' ).
((! static::$includeSubSecTime OR ! is_null($this->subsectime)) ? '' : sprintf('-%05s',$this->id)).
($this->ignore_duplicate ? sprintf('-%06d',$this->id) : '')
),$this->type()
);
return (($short OR preg_match('/^\//',$file)) ? '' : config('photo.dir').DIRECTORY_SEPARATOR).$file;
return (($short OR preg_match('/^\//',$file)) ? '' : config($this->type.'.dir').DIRECTORY_SEPARATOR).$file;
}
/**
@ -205,11 +238,9 @@ abstract class Catalog extends Model
$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())
: $this->date_created->format('Y/m/d-His')),$this->type());
$file = $this->file_name(FALSE);
return (($short OR preg_match('/^\//',$file)) ? '' : config('video.dir').DIRECTORY_SEPARATOR).$file;
return (($short OR preg_match('/^\//',$file)) ? '' : config($this->type.'.dir').DIRECTORY_SEPARATOR).$file;
}
/**
@ -271,6 +302,14 @@ abstract class Catalog extends Model
return $this->HTMLCheckbox('flag',$this->id,$this->flag);
}
/**
* Return HTML Checkbox for ignore
*/
public function getIgnoreCheckboxAttribute()
{
return $this->HTMLCheckbox('ignore_duplicate',$this->id,$this->ignore_duplicate);
}
public function getDateCreatedAttribute() {
return $this->attributes['date_created'] ? Carbon::createFromTimestamp($this->attributes['date_created']) : NULL;
}
@ -328,7 +367,7 @@ abstract class Catalog extends Model
*/
public function isReadable(): bool
{
return is_readable($this->file_path());
return is_readable($this->filename);
}
/**
@ -344,7 +383,7 @@ abstract class Catalog extends Model
*/
protected function HTMLLinkAttribute($id,$url)
{
return sprintf('<a href="%s" target="%s">%s</a>',url($url.$id),$id,$id);
return sprintf('<a href="%s" target="%s">%s</a>',url($url,$id),$id,$id);
}
/**
@ -398,17 +437,6 @@ abstract class Catalog extends Model
return TRUE;
}
/**
* Flag to indicate if a file should be moved.
*
* @return bool
*/
public function mustMove(): bool
{
dump(['f'=>$this->filename,'fn'=>$this->file_name(),'test'=>($this->filename == $this->file_name())]);
return $this->filename !== $this->file_name();
}
/**
* Get the id of the previous record
*/
@ -441,6 +469,11 @@ abstract class Catalog extends Model
->first();
}
public function setDateCreated()
{
$this->created = $this->property('creationdate');
}
public function setHeightWidth()
{
$this->height = $this->property('height');
@ -448,6 +481,13 @@ abstract class Catalog extends Model
$this->orientation = $this->property('orientation');
}
public function setSignature()
{
$this->signature = $this->property('signature');
$this->file_signature = md5_file($this->filename);
}
/**
* Display the media signature
*/
@ -484,7 +524,7 @@ abstract class Catalog extends Model
*/
public function shouldMove(): bool
{
return ($this->filename != $this->file_path(TRUE,TRUE));
return $this->filename !== $this->file_name();
}
protected function TextTrueFalse($value): string
@ -498,7 +538,7 @@ abstract class Catalog extends Model
* @param bool $includeme
* @return mixed
*/
public function list_duplicate($includeme=FALSE)
private function list_duplicate($includeme=FALSE)
{
return $this->list_duplicates($includeme)->pluck('id');
}
@ -507,7 +547,7 @@ abstract class Catalog extends Model
* Find duplicate images based on some attributes of the current image
* @deprecate Use static::duplicates()
*/
public function list_duplicates($includeme=FALSE)
private function list_duplicates($includeme=FALSE)
{
$o = static::select();

View File

@ -22,33 +22,7 @@ class Photo extends Abstracted\Catalog
public function getIDLinkAttribute()
{
return $this->HTMLLinkAttribute($this->id,url('p/info').'/');
}
/**
* Date the photo was taken
*/
public function date_taken(): string
{
return $this->date_created
? ($this->date_created->format('Y-m-d H:i:s').($this->subsectime ? '.'.$this->subsectime : ''))
: 'UNKNOWN';
}
/**
* 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())
: sprintf('%s_%03s',$this->date_created->format('Y/m/d-His'),$this->subsectime).
($this->subsectime ? '' : sprintf('-%05s',$this->id))),$this->type());
return (($short OR preg_match('/^\//',$file)) ? '' : config('photo.dir').DIRECTORY_SEPARATOR).$file;
return $this->HTMLLinkAttribute($this->id,'p/info');
}
public function getHtmlImageURL(): string
@ -169,10 +143,6 @@ class Photo extends Abstracted\Catalog
return $this->o() ? $this->_o->getImageProperties() : [];
}
public function setDateCreated()
{
$this->date_created = $this->property('creationdate');
}
public function setLocation()
{
@ -202,15 +172,9 @@ class Photo extends Abstracted\Catalog
$this->software_id = $so->id;
}
public function setSignature()
public function setSubSecTime(): int
{
$this->signature = $this->property('signature');
$this->file_signature = md5_file($this->file_path());
}
public function setSubSecTime()
{
$this->subsectime = $this->property('exif:SubSecTimeOriginal');
$this->subsectime = (int)$this->property('exif:SubSecTimeOriginal');
// In case of an error.
if ($this->subsectime > 32767)
@ -240,7 +204,7 @@ class Photo extends Abstracted\Catalog
public function thumbnail($rotate=TRUE)
{
if (! $this->thumbnail) {
if ($this->o()->thumbnailimage(200,200,true,false)) {
if ($this->isReadable() AND $this->o()->thumbnailimage(200,200,true,false)) {
$this->_o->setImageFormat('jpg');
return $this->_o->getImageBlob();

View File

@ -11,7 +11,7 @@ class Video extends Abstracted\Catalog
public function getIDLinkAttribute()
{
return $this->HTMLLinkAttribute($this->id,url('v/info').'/');
return $this->HTMLLinkAttribute($this->id,'v/info');
}
public function getHtmlImageURL()
@ -124,16 +124,6 @@ class Video extends Abstracted\Catalog
return isset($data[$key]) ? $data[$key] : NULL;
}
public function setDateCreated()
{
$this->date_created = $this->property('creationdate');
}
public function setDateCreatedAttribute($value)
{
$this->attributes['date_created'] = strtotime($value);
}
public function setLocation()
{
$this->gps_lat = $this->property('gps_lat');
@ -172,8 +162,8 @@ class Video extends Abstracted\Catalog
public function setSignature()
{
$this->signature = $this->property('signature');
$this->file_signature = md5_file($this->file_path());
parent::setSignature();
$this->identifier = $this->property('identifier');
}

75
app/Traits/Multimedia.php Normal file
View File

@ -0,0 +1,75 @@
<?php
namespace App\Traits;
use App\Jobs\PhotoDelete;
use App\Models\Photo;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
/**
* Multimedia Controller Functions
*
* @package App\Traits
*/
trait Multimedia
{
use Type;
private function controller(string $type): string
{
switch (strtolower($type)) {
case 'photo': return 'PhotoController';
case 'video': return 'Videoontroller';
default: abort(500,'Type not handled?');
}
}
public function deletesUpdate(Request $request)
{
$class = $this->getModelType($request->input('type'));
$this->updatePostItems($request,$class,TRUE);
return redirect()->action(
sprintf('%s@deletes',$this->controller($request->input('type'))),
sprintf('?page=%s',$request->input('page'))
);
}
public function duplicatesUpdate(Request $request)
{
$class = $this->getModelType($request->input('type'));
$this->updatePostItems($request,$class);
return redirect()->action(
sprintf('%s@duplicates',$this->controller($request->input('type'))),
sprintf('?page=%s',$request->input('page'))
);
}
private function updatePostItems(Request $request,string $class,bool $delete=FALSE)
{
foreach ($request->input('items') as $id) {
$o = $class::findOrFail($id);
// Set if duplicate
$o->duplicate = $request->input('duplicate.'.$id) ? 1 : NULL;
// Set if ignore duplicate
$o->ignore_duplicate = $request->input('ignore_duplicate.'.$id) ? 1 : NULL;
// Set if flag
$o->flag = $request->input('flag.'.$id) ? 1 : NULL;
// Set if delete
if ($delete AND $o->remove AND ($request->input('remove.'.$id) ? 1 : NULL)) {
Log::info(sprintf('Dispatching delete for [%s]',$o->id));
} else {
$o->remove = $request->input('remove.'.$id) ? 1 : NULL;
}
$o->save();
}
}
}

View File

@ -0,0 +1,84 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddOverrideKeepAttributes extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('photo', function (Blueprint $table) {
$table->dateTime('created')->nullable();
$table->dateTime('created_manual')->nullable();
$table->boolean('ignore_duplicate')->nullable();
});
Schema::table('videos', function (Blueprint $table) {
$table->dateTime('created')->nullable();
$table->dateTime('created_manual')->nullable();
$table->boolean('ignore_duplicate')->nullable();
});
\App\Models\Photo::each(function($o) {
$o->created = $o->date_created;
$o->date_created = NULL;
$o->save();
});
\App\Models\Video::each(function($o) {
$o->created = $o->date_created;
$o->date_created = NULL;
$o->save();
});
Schema::table('photo', function (Blueprint $table) {
$table->dropColumn('date_created');
});
Schema::table('videos', function (Blueprint $table) {
$table->dropColumn('date_created');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('photos', function (Blueprint $table) {
$table->integer('date_created')->nullable();
});
Schema::table('videos', function (Blueprint $table) {
$table->integer('date_created')->nullable();
});
\App\Models\Photo::each(function($o) {
$o->date_created = $o->created;
$o->created = NULL;
$o->save();
});
\App\Models\Video::each(function($o) {
$o->date_created = $o->created;
$o->created = NULL;
$o->save();
});
Schema::table('videos', function (Blueprint $table) {
$table->dropColumn(['created','created_manual','ignore_duplicate']);
});
Schema::table('photo', function (Blueprint $table) {
$table->dropColumn(['created','created_manual','ignore_duplicate']);
});
}
}

View File

@ -21,12 +21,13 @@
<form action="{{ $return }}" method="POST">
{{ csrf_field() }}
<input type="hidden" name="type" value="{{ $type }}">
@include('catalog.widgets.duplicates')
<div class="pb-2"><button class="btn btn-sm btn-danger">Confirm Delete</button></div>
<input type="hidden" name="pagenext" value="{{ $catalog->hasMorePages() ? $catalog->currentPage()+1 : NULL }}">
<input type="hidden" name="page" value="{{ $catalog->hasMorePages() ? $catalog->currentPage()+1 : NULL }}">
</form>
@else
NONE!

View File

@ -21,10 +21,13 @@
<form action="{{ $return }}" method="POST">
{{ csrf_field() }}
<input type="hidden" name="type" value="{{ $type }}">
@include('catalog.widgets.duplicates')
<div class="pb-2"><button class="btn btn-sm btn-primary">Update</button></div>
<input type="hidden" name="page" value="{{ $catalog->currentPage() }}">
</form>
@else
NONE!

View File

@ -6,7 +6,15 @@
</tr>
</thead>
@php
// Remember what we have rendered
$rendered = collect();
@endphp
@foreach ($catalog as $o)
@if($rendered->search($o->id)) @continue @endif
@php($rendered->push($o->id))
<tbody>
<tr>
<td>
@ -14,7 +22,7 @@
@include($o->type.'.widgets.thumbnail',['o'=>$o])
</td>
@if (! ($d=$o->duplicates()->get())->count())
@if (! ($d=$o->myduplicates()->get())->count())
<td>
No other duplicates found?
</td>
@ -22,6 +30,8 @@
@else
@foreach($d as $item)
@if($rendered->search($item->id)) @continue @endif
@php($rendered->push($item->id))
<td>
<input type="hidden" name="items[]" value="{{ $item->id }}">
@include($item->type.'.widgets.thumbnail',['o'=>$item])

View File

@ -10,6 +10,7 @@
@section('contentheader_description')
@if(! $o->scanned)<button class="btn btn-sm btn-info">TO SCAN</button>@endif
@if($o->duplicate)<button class="btn btn-sm btn-warning">DUPLICATE</button>@endif
@if($o->ignore_duplicate)<button class="btn btn-sm btn-secondary">DUPLICATE IGNORE</button>@endif
@if($o->remove)<button class="btn btn-sm btn-danger">PENDING DELETE</button>@endif
@endsection
@section('page_title')
@ -41,10 +42,10 @@
<div class="col-9">
<div class="dl-horizontal">
<dt>Signature</dt><dd>{{ $o->signature(TRUE) }}</dd>
<dt>Filename</dt><dd>{{ $o->file_path(TRUE) }}<dd>
<dt>Filename</dt><dd>{{ $o->filename }}<dd>
@if ($o->shouldMove())
<dt>NEW Filename</dt><dd>{{ $o->file_path(TRUE,TRUE) }}<dd>
<dt>NEW Filename</dt><dd>{{ $o->file_name() }}<dd>
@endif
<dt>Size</dt><dd>{{ $o->file_size() }}<dd>
@ -70,7 +71,7 @@
</table>
</dd>
<hr>
@if($x = $o->duplicates()->get())
@if(($x=$o->myduplicates()->get())->count())
<dt>Duplicates</dt>
<dd>
@foreach($x as $oo)

View File

@ -2,20 +2,21 @@
'ID'=>['id','idlink'],
'Signature'=>['signature','signature'],
'File Signature'=>['file_signature','file_signature'],
'Date Created'=>['date_created','date_created'],
'Date Created'=>['created','created'],
'Filename'=>['filename','filename'],
'Filesize'=>['filesize','filesize'],
'Dimensions'=>['height','dimensions'],
'Duplicate'=>['duplicate','duplicatecheckbox'],
'Flagged'=>['flag','flagcheckbox'],
'Ignore Duplicate'=>['ignore','ignorecheckbox'],
'Delete'=>['remove','removecheckbox'],
];?>
<div class="card card-widget">
<div class="card-header">
<div class="user-block">
<i class="float-left fa fa-2x fa-camera"></i><span class="username"><a href="#">#{{ $o->id }} - {{ \Illuminate\Support\Str::limit($o->filename,12).\Illuminate\Support\Str::substr($o->filename,-16) }}</a></span>
<span class="description">{{ $o->date_created ? $o->date_created->toDateTimeString() : '-' }} [{{ $o->device() }}]</span>
<i class="float-left fa fa-2x fa-camera"></i><span class="username"><a href="{{ url('p/info',$o->id) }}">#{{ $o->id }} - {{ \Illuminate\Support\Str::limit($o->filename,12).\Illuminate\Support\Str::substr($o->filename,-16) }}</a></span>
<span class="description">{{ $o->created ? $o->created->toDateTimeString() : '-' }} [{{ $o->device() }}]</span>
</div>
<!-- /.user-block -->
<div class="card-tools">

View File

@ -15,7 +15,7 @@
<li class="nav-item">
<a href="{{ url('p/duplicates') }}" class="nav-link @if(preg_match('#^p/duplicates$#',request()->path())) active @endif">
<i class="fa fa-link nav-icon"></i> <p>Duplicate</p>
<span class="badge badge-warning right">{{ \App\Models\Photo::where('duplicate',TRUE)->count() }}</span>
<span class="badge badge-warning right">{{ \App\Models\Photo::duplicates()->count() }}</span>
</a>
</li>
@ -37,7 +37,7 @@
<li class="nav-item">
<a href="{{ url('v/duplicates') }}" class="nav-link @if(preg_match('#^v/duplicates$#',request()->path())) active @endif">
<i class="fa fa-link nav-icon"></i> <p>Duplicate</p>
<span class="badge badge-warning right">{{ \App\Models\Video::where('duplicate',TRUE)->count() }}</span>
<span class="badge badge-warning right">{{ \App\Models\Video::duplicates()->count() }}</span>
</a>
</li>

View File

@ -10,6 +10,7 @@
@section('contentheader_description')
@if(! $o->scanned)<button class="btn btn-sm btn-info">TO SCAN</button>@endif
@if($o->duplicate)<button class="btn btn-sm btn-warning">DUPLICATE</button>@endif
@if($o->ignore_duplicate)<button class="btn btn-sm btn-secondary">DUPLICATE IGNORE</button>@endif
@if($o->remove)<button class="btn btn-sm btn-danger">PENDING DELETE</button>@endif
@endsection
@section('page_title')
@ -41,10 +42,10 @@
<div class="col-8">
<div class="dl-horizontal">
<dt>Signature</dt><dd>{{ $o->signature(TRUE) }}</dd>
<dt>Filename</dt><dd>{{ $o->file_path(TRUE) }}<dd>
<dt>Filename</dt><dd>{{ $o->filename }}<dd>
@if ($o->shouldMove())
<dt>NEW Filename</dt><dd>{{ $o->file_path(TRUE,TRUE) }}<dd>
<dt>NEW Filename</dt><dd>{{ $o->file_name() }}<dd>
@endif
<dt>Size</dt><dd>{{ $o->file_size() }}<dd>
@ -69,7 +70,7 @@
@endif
</dd>
@if($x = $o->duplicates()->get())
@if(($x=$o->myduplicates()->get())->count())
<dt>Duplicates</dt>
<dd>
@foreach($x as $oo)

View File

@ -2,21 +2,22 @@
'ID'=>['id','idlink'],
'Signature'=>['signature','signature'],
'File Signature'=>['file_signature','file_signature'],
'Date Created'=>['date_created','date_created'],
'Date Created'=>['created','created'],
'Filename'=>['filename','filename'],
'Filesize'=>['filesize','filesize'],
'Dimensions'=>['height','dimensions'],
'Length'=>['length','length'],
'Duplicate'=>['duplicate','duplicatecheckbox'],
'Flagged'=>['flag','flagcheckbox'],
'Ignore Duplicate'=>['ignore','ignorecheckbox'],
'Delete'=>['remove','removecheckbox'],
];?>
<div class="card card-widget">
<div class="card-header">
<div class="user-block">
<i class="float-left fa fa-2x fa-camera"></i><span class="username"><a href="#">#{{ $o->id }} - {{ \Illuminate\Support\Str::limit($o->filename,12).\Illuminate\Support\Str::substr($o->filename,-16) }}</a></span>
<span class="description">{{ $o->date_created ? $o->date_created->toDateTimeString() : '-' }} [{{ $o->device() }}]</span>
<i class="float-left fa fa-2x fa-camera"></i><span class="username"><a href="{{ url('v/info',$o->id) }}">#{{ $o->id }} - {{ \Illuminate\Support\Str::limit($o->filename,12).\Illuminate\Support\Str::substr($o->filename,-16) }}</a></span>
<span class="description">{{ $o->created ? $o->created->toDateTimeString() : '-' }} [{{ $o->device() }}]</span>
</div>
<!-- /.user-block -->
<div class="card-tools">
@ -28,7 +29,7 @@
<!-- /.card-body -->
<div class="card-body">
<a href="{{ url('p/view',$o->id) }}" target="{{ $o->id }}">{!! $o->getHtmlImageURL() !!}</a>
<a href="{{ url('v/view',$o->id) }}" target="{{ $o->id }}">{!! $o->getHtmlImageURL() !!}</a>
</div>
<!-- /.card-body -->