From ebfdf3f7d5cd155c39d8258f048f5fbefec9e852 Mon Sep 17 00:00:00 2001 From: Deon George Date: Sat, 14 Dec 2019 22:29:54 +1100 Subject: [PATCH] Updated photo viewing --- app/Http/Controllers/Auth/LoginController.php | 7 +- app/Http/Controllers/PhotoController.php | 8 +- app/Models/Abstracted/Catalog.php | 62 ++++++- app/Models/Photo.php | 51 +++--- app/Models/Video.php | 3 +- public/css/fixes.css | 40 ++--- .../views/catalog/duplicatereview.blade.php | 60 +++---- resources/views/photo/view.blade.php | 154 ++++++++++-------- .../views/photo/widgets/thumbnail.blade.php | 31 +--- routes/web.php | 4 +- 10 files changed, 232 insertions(+), 188 deletions(-) diff --git a/app/Http/Controllers/Auth/LoginController.php b/app/Http/Controllers/Auth/LoginController.php index 5b52a62..834be17 100644 --- a/app/Http/Controllers/Auth/LoginController.php +++ b/app/Http/Controllers/Auth/LoginController.php @@ -42,6 +42,11 @@ class LoginController extends Controller */ public function showLoginForm() { - return view('adminlte::auth.login'); + $login_note = ''; + + if (file_exists('login_note.txt')) + $login_note = file_get_contents('login_note.txt'); + + return view('adminlte::auth.login')->with('login_note',$login_note); } } diff --git a/app/Http/Controllers/PhotoController.php b/app/Http/Controllers/PhotoController.php index 7ad2e94..7028742 100644 --- a/app/Http/Controllers/PhotoController.php +++ b/app/Http/Controllers/PhotoController.php @@ -54,7 +54,7 @@ class PhotoController extends Controller { return view('catalog.duplicatereview',[ 'return'=>url('/p/duplicates'), - 'catalog'=>is_null($id) ? Photo::notRemove()->where('duplicate',1)->paginate(50) : Photo::where('id',$id)->paginate(1) + 'catalog'=>is_null($id) ? Photo::notRemove()->where('duplicate',1)->with('software.model.make')->paginate(10) : Photo::where('id',$id)->paginate(1) ]); } @@ -73,15 +73,15 @@ class PhotoController extends Controller // Set if delete $po->remove = $request->input('remove.'.$id) ? 1 : NULL; - $po->isDirty() AND $po->save(); + $po->save(); } return redirect()->action('PhotoController@duplicates','?page='.$request->input('page')); } - public function info($id) + public function info(Photo $o) { - return view('photo.view', ['photo'=> Photo::findOrFail($id)]); + return view('photo.view',['o'=>$o]); } public function thumbnail($id) diff --git a/app/Models/Abstracted/Catalog.php b/app/Models/Abstracted/Catalog.php index 9ecef54..92a7f50 100644 --- a/app/Models/Abstracted/Catalog.php +++ b/app/Models/Abstracted/Catalog.php @@ -10,7 +10,7 @@ use App\Models\{Person,Tag}; abstract class Catalog extends Model { - protected $dates = ['date_created']; + protected static $includeSubSecTime = FALSE; public function people() { @@ -22,6 +22,38 @@ abstract class Catalog extends Model return $this->belongsToMany(Tag::class); } + public function scopeDuplicates($query) { + if (! $this->exists) + return $query; + + // Exclude this record + $query->where('id','<>',$this->attributes['id']); + + // Exclude those marked as remove + $query->where(function ($q) { + $q->where('remove','<>',TRUE) + ->orWhere('remove','=',NULL); + }); + + $query->where(function ($q) { + $q->where('signature','=',$this->attributes['signature']) + ->orWhere('file_signature','=',$this->attributes['file_signature']) + + // 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 (static::$includeSubSecTime) + $q->where('subsectime','=',$this->attributes['subsectime'] ?: NULL); + + $q->where('software_id','=',$this->attributes['software_id']); + } + }); + }); + } + /** * Multimedia NOT duplicate. * @@ -66,21 +98,35 @@ abstract class Catalog extends Model 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(); + abstract public function getHtmlImageURL(); /** * Date the multimedia was created - * @todo return Carbon date or NULL */ public function date_taken(): string { return $this->date_created ? date('Y-m-d H:i:s',$this->date_created) : 'UNKNOWN'; } + public function device(): string + { + $result = ''; + + if ($this->software->model->make) + $result .= $this->software->model->make->name; + + if ($this->software->model) + $result .= ($result ? ' ' : '').$this->software->model->name; + + if ($this->software) + $result .= ($result ? ' ' : '').$this->software->name; + + return $result; + } + /** * Return the date of the file * @todo return Carbon date or NULL @@ -130,9 +176,9 @@ abstract class Catalog extends Model /** * Display the file signature */ - public function file_signature($short=FALSE) + public function file_signature($short=FALSE): string { - return $short ? static::signaturetrim($this->file_signature) : $this->file_signature; + return $short ? static::stringtrim($this->file_signature) : $this->file_signature; } /** @@ -349,7 +395,7 @@ abstract class Catalog extends Model /** * Determine if the image should be moved */ - public function shouldMove(): boolean + public function shouldMove(): bool { return ($this->filename != $this->file_path(TRUE,TRUE)); } @@ -372,7 +418,7 @@ abstract class Catalog extends Model /** * Find duplicate images based on some attributes of the current image - * @todo Optimise this query + * @deprecate Use static::duplicates() */ public function list_duplicates($includeme=FALSE) { diff --git a/app/Models/Photo.php b/app/Models/Photo.php index 92aa128..9859391 100644 --- a/app/Models/Photo.php +++ b/app/Models/Photo.php @@ -2,13 +2,15 @@ namespace App\Models; -use DB; +use Carbon\Carbon; use Illuminate\Support\Facades\Log; class Photo extends Abstracted\Catalog { protected $table = 'photo'; + protected static $includeSubSecTime = TRUE; + // Imagick Object private $_o; @@ -24,12 +26,19 @@ class Photo extends Abstracted\Catalog return $this->belongsTo(Software::class); } + 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 ? (date('Y-m-d H:i:s',$this->date_created).($this->subsectime ? '.'.$this->subsectime : '')) : 'UNKNOWN'; + return $this->date_created + ? ($this->date_created->format('Y-m-d H:i:s').($this->subsectime ? '.'.$this->subsectime : '')) + : 'UNKNOWN'; } /** @@ -49,9 +58,9 @@ class Photo extends Abstracted\Catalog return (($short OR preg_match('/^\//',$file)) ? '' : config('photo.dir').DIRECTORY_SEPARATOR).$file; } - public function getIDLinkAttribute() + public function getHtmlImageURL(): string { - return $this->HTMLLinkAttribute($this->id,url('p/info').'/'); + return sprintf('',url('/p/thumbnail/'.$this->id)); } /** @@ -65,9 +74,7 @@ class Photo extends Abstracted\Catalog if (array_key_exists('exif',$imo->getImageProfiles())) $imo->removeImageProfile('exif'); - $this->rotate($imo); - - return $imo->getImageBlob(); + return $this->rotate($imo); } /** @@ -78,8 +85,7 @@ class Photo extends Abstracted\Catalog if (! $coordinate OR ! $hemisphere) return NULL; - for ($i=0; $i<3; $i++) - { + for ($i=0; $i<3; $i++) { $part = explode('/', $coordinate[$i]); if (count($part) == 1) @@ -92,16 +98,15 @@ class Photo extends Abstracted\Catalog $coordinate[$i] = 0; } - list($degrees, $minutes, $seconds) = $coordinate; + list($degrees,$minutes,$seconds) = $coordinate; $sign = ($hemisphere == 'W' || $hemisphere == 'S') ? -1 : 1; - return round($sign*($degrees+$minutes/60+$seconds/3600),$degrees > 100 ? 3 : 4); + return round($sign*($degrees+$minutes/60+$seconds/3600),($degrees>100 ? 3 : 4)); } /** * Return an Imagick object or attribute - * */ protected function o($attr=NULL) { @@ -123,8 +128,7 @@ class Photo extends Abstracted\Catalog case 3: return 'Upside Down'; case 6: return 'Rotate Right'; case 8: return 'Rotate Left'; - default: - return 'unknown?'; + default: return 'unknown?'; } } @@ -144,8 +148,7 @@ class Photo extends Abstracted\Catalog if (! $this->o()) return NULL; - switch ($property) - { + switch ($property) { case 'creationdate': if ($this->property('exif:DateTimeOriginal') == '0000:00:00 00:00:00' && $this->property('exif:DateTimeOriginal') == '0000:00:00 00:00:00') @@ -172,6 +175,10 @@ class Photo extends Abstracted\Catalog return $this->o() ? $this->_o->getImageProperties() : []; } + public function getDateCreatedAttribute() { + return Carbon::createFromTimestamp($this->attributes['date_created']); + } + public function setDateCreated() { $this->date_created = $this->property('creationdate'); @@ -181,9 +188,9 @@ class Photo extends Abstracted\Catalog { $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'); } + // @todo Now set software_id public function setMakeModel() { $this->make = $this->property('exif:Make') ? $this->property('exif:Make') : NULL; @@ -195,7 +202,6 @@ class Photo extends Abstracted\Catalog { $this->signature = $this->property('signature'); $this->file_signature = md5_file($this->file_path()); - #$this->identifier = $this->property('identifier'); } public function setSubSecTime() @@ -211,6 +217,7 @@ class Photo extends Abstracted\Catalog { try { $this->thumbnail = exif_thumbnail($this->file_path()); + } catch (\Exception $e) { // @todo Couldnt get the thumbnail, so we should create one. Log::info(sprintf('Unable to create thumbnail for %s (%s)',$this->id,$e->getMessage())); @@ -225,8 +232,7 @@ class Photo extends Abstracted\Catalog */ public function thumbnail($rotate=TRUE) { - if (! $this->thumbnail) - { + if (! $this->thumbnail) { return $this->o()->thumbnailimage(200,200,true,true) ? $this->_o->getImageBlob() : NULL; } @@ -247,9 +253,4 @@ class Photo extends Abstracted\Catalog { return strtolower($mime ? 'image/jpeg' : pathinfo($this->filename,PATHINFO_EXTENSION)); } - - public function view() - { - return sprintf('',url('/p/thumbnail/'.$this->id)); - } } \ No newline at end of file diff --git a/app/Models/Video.php b/app/Models/Video.php index d99ddd3..bc1355e 100644 --- a/app/Models/Video.php +++ b/app/Models/Video.php @@ -132,6 +132,7 @@ class Video extends Abstracted\Catalog $this->gps_altitude = $this->property('gps_altitude'); } + // @todo Now set software_id public function setMakeModel() { $this->make = $this->property('make'); @@ -170,7 +171,7 @@ class Video extends Abstracted\Catalog return strtolower($mime ? File::mime_by_ext(pathinfo($this->filename,PATHINFO_EXTENSION)) : pathinfo($this->filename,PATHINFO_EXTENSION)); } - public function view() + public function getHtmlImageURL() { return sprintf('',url('/v/view/'.$this->id)); } diff --git a/public/css/fixes.css b/public/css/fixes.css index c60adac..7ffce65 100644 --- a/public/css/fixes.css +++ b/public/css/fixes.css @@ -1,66 +1,66 @@ /* Fixes for data tables */ .dataTables_wrapper .dataTables_paginate .paginate_button { - padding: 0em 0em; - margin-left: 0px; - border: 0px solid; + padding: 0em 0em; + margin-left: 0px; + border: 0px solid; } .dataTables_wrapper .dataTables_paginate .paginate_button:hover { - border: 0px solid; - background: #fff; + border: 0px solid; + background: #fff; } .dataTables_wrapper .dataTables_paginate .paginate_button:active { - box-shadow: 0 0 0px #fff; - background-color: #fff; + box-shadow: 0 0 0px #fff; + background-color: #fff; } table.dataTable thead .sorting_asc { - background-image: none !important; + background-image: none !important; } table.dataTable thead .sorting_desc { - background-image: none !important; + background-image: none !important; } table.dataTable thead .sorting { - background-image: none !important; + background-image: none !important; } /* Remove blue border from chrome on buttons */ /* Remove outline for non-keyboard :focus */ *:focus:not(.focus-visible) { - outline: none !important; - box-shadow: none !important; + outline: none !important; + box-shadow: none !important; } /* Optional: Customize .focus-visible */ .focus-visible { - outline-color: lightgreen; + outline-color: lightgreen; } *:disabled { - cursor: not-allowed; + cursor: not-allowed; } /* Login Box, icons when inputs disabled */ div.login-box .input-group-append .fa { - width: 2.5em; + width: 2.5em; } div.login-box .input-group .input-group-append span.fa { - line-height: 0; + line-height: 0; } #favourite.selected { - color: orange; + color: orange; } #favourite:hover { - cursor: pointer; + cursor: pointer; } body { - font-size: 0.65em; + font-size: 0.65em; } /* Change brand logo on collapse */ @@ -74,4 +74,4 @@ body.sidebar-mini img.brand-image.img-circle.elevation-3 { /* margin-left: 0px; */ max-height: 27px; border-radius: 0; -} \ No newline at end of file +} diff --git a/resources/views/catalog/duplicatereview.blade.php b/resources/views/catalog/duplicatereview.blade.php index 506425d..02ff3ad 100644 --- a/resources/views/catalog/duplicatereview.blade.php +++ b/resources/views/catalog/duplicatereview.blade.php @@ -25,53 +25,47 @@ - + - @php $c=0; @endphp @foreach ($catalog as $o) - @php - $d=$o->list_duplicates(TRUE); $src=[]; - @endphp - - - - - - @if ($d->count() == 1) + + - @continue - @else - @foreach($d as $item) - @if($loop->first) @continue @endif - @php($diff=collect($src)->diffAssoc($item)) + @if (! ($d=$o->duplicates()->with('software.model.make')->get())->count()) - @endforeach - @endif - - + @continue + + @else + @foreach($d as $item) + + @endforeach + @endif + + @endforeach + + + + + +
Source RemoveSource
- @if($d->where('duplicate',null)->count() > 1) - More than 1 source? - - @elseif($d->count()) - @php($src=$d->first()) - @include('photo.widgets.thumbnail',['o'=>$src]) - @endif -
- No other duplicates found? + + @include('photo.widgets.thumbnail',['o'=>$o]) - - XX - @include('photo.widgets.thumbnail',['o'=>$src]) + No other duplicates found?
+ + @include('photo.widgets.thumbnail',['o'=>$item]) +
+ {{-- - + --}} @else NONE! diff --git a/resources/views/photo/view.blade.php b/resources/views/photo/view.blade.php index aa397fb..79feca9 100644 --- a/resources/views/photo/view.blade.php +++ b/resources/views/photo/view.blade.php @@ -5,7 +5,7 @@ @endsection @section('contentheader_title') - Photo + Photo #{{ $o->id }} @if($o->duplicate)@endif @if($o->remove)@endif @endsection @section('contentheader_description') #{{ $o->id }} @@ -16,80 +16,90 @@ @section('main-content')
-
-
-
- Photo {{ $photo->id }}remove) : ?> - PENDING DELETE -
+
+ -
-
- -
-
    -
  • previous()) : ?>class="disabled"><<
  • -
  • next()) : ?>class="disabled">>>
  • -
-
+ +
-
-
-
Signature
{{ $photo->signature(TRUE) }}
-
Filename
{{ $photo->file_path(TRUE) }}
- shouldMove()) : ?> -
NEW Filename
{{ $photo->file_path(TRUE,TRUE) }}
- -
Size
{{ $photo->file_size() }}
-
Dimensions
{{ $photo->width }} x {{ $photo->height }} @ {{ $photo->orientation }}
-
-
Date Taken
{{ $photo->date_taken() }}
-
Camera
{{ $photo->make }}
-
Model
{{ $photo->model }}
-
Software
{{ $photo->software }}
-
-
Location
- gps() == 'UNKNOWN') : ?> - UNKNOWN - -
- - - -
-
-
Exif Data
- - properties() as $k => $v) : ?> - - -
{{ $k }}<>{{ $v }}
-
-
-
+
  • {{ $o->id }}
  • - remove) : ?> -
    - - - - - - {{ csrf_field() }} -
    -
    +
  • + >> +
  • + + + +
    + +
    +
    +
    Signature
    {{ $o->signature(TRUE) }}
    +
    Filename
    {{ $o->file_path(TRUE) }}
    + + @if ($o->shouldMove()) +
    NEW Filename
    {{ $o->file_path(TRUE,TRUE) }}
    + @endif + +
    Size
    {{ $o->file_size() }}
    +
    Dimensions
    {{ $o->dimensions }} @ {{ $o->orientation }}
    +
    +
    Date Taken
    {{ $o->date_taken() }}
    +
    Camera
    {{ $o->device() }}
    +
    +
    Location
    + @if($o->gps() == 'UNKNOWN') + UNKNOWN + @else +
    + @endif + +
    +
    +
    Exif Data
    + + @foreach ($o->properties() as $k => $v) + + @endforeach +
    {{ $k }}<>{{ $v }}
    +
    + + @if ($o->remove) +
    + {{ csrf_field() }} + + + @else + + {{ csrf_field() }} + + + @endif +
    -@endsection \ No newline at end of file +@endsection + +@section('page-scripts') + @if($o->gps() !== 'UNKNOWN') + @js('//maps.google.com/maps/api/js?sensor=false') + + + @endif +@append \ No newline at end of file diff --git a/resources/views/photo/widgets/thumbnail.blade.php b/resources/views/photo/widgets/thumbnail.blade.php index 3d0327f..5d5b384 100644 --- a/resources/views/photo/widgets/thumbnail.blade.php +++ b/resources/views/photo/widgets/thumbnail.blade.php @@ -15,42 +15,29 @@
    #{{ $o->id }} - {{ \Illuminate\Support\Str::limit($o->filename,12).\Illuminate\Support\Str::substr($o->filename,-16) }} - {{ $o->date_created->toDateTimeString() }} [{{ $o->make }} {{ $o->model }} ({{ $o->software }})] + {{ $o->date_created->toDateTimeString() }} [{{ $o->device() }}]
    - - + +
    - {!! $o->view() !!} + {!! $o->getHtmlImageURL() !!}  
    - - -
    \ No newline at end of file diff --git a/routes/web.php b/routes/web.php index 934f9f0..dd75654 100644 --- a/routes/web.php +++ b/routes/web.php @@ -16,10 +16,10 @@ Route::get('/p/deletes/{id?}','PhotoController@deletes')->where('id','[0-9]+'); Route::get('/v/deletes/{id?}','VideoController@deletes')->where('id','[0-9]+'); Route::get('/p/duplicates/{id?}','PhotoController@duplicates')->where('id','[0-9]+'); Route::get('/v/duplicates/{id?}','VideoController@duplicates')->where('id','[0-9]+'); -Route::get('/p/info/{id}','PhotoController@info')->where('id','[0-9]+'); +Route::get('/p/info/{o}','PhotoController@info')->where('o','[0-9]+'); Route::get('/v/info/{id}','VideoController@info')->where('id','[0-9]+'); Route::get('/p/thumbnail/{id}','PhotoController@thumbnail')->where('id','[0-9]+'); -Route::get('/p/view/{id}','PhotoController@view')->where('id','[0-9]+'); +Route::get('/p/view/{o}','PhotoController@view')->where('o','[0-9]+'); Route::get('/v/view/{id}','VideoController@view')->where('id','[0-9]+'); Route::post('/p/delete/{id}','PhotoController@delete')->where('id','[0-9]+');