';
+ $output .= '
';
$output .= '';
$output .= '';
$output .= '
';
@@ -157,24 +252,29 @@ class Controller_Photo extends Controller_TemplateDefault {
return $output;
}
+ private function evaluate(Model $o,$param) {
+ $result = NULL;
+
+ if (preg_match('/\(/',$param) OR preg_match('/-\>/',$param))
+ eval("\$result = \$o->$param;");
+ else
+ $result = $o->display($param);
+
+ return $result;
+ }
+
private function table_duplicate_details(Database_MySQL_Result $dp,Model_Photo $po,$param,$title='',$content='') {
$output = '
';
- if (preg_match('/\(/',$param) OR preg_match('/-\>/',$param))
- eval("\$d = \$po->$param;");
- else
- $d = $po->display($param);
+ $v = $this->evaluate($po,$param);
$output .= sprintf('%s | ',$title);
- $output .= sprintf('%s | ',$content ? str_replace('%VALUE%',$d,$content) : $d);
+ $output .= sprintf('%s | ',$content ? str_replace('%VALUE%',$v,$content) : $v);
foreach ($dp as $dpo) {
- if (preg_match('/\(/',$param) OR preg_match('/-\>/',$param))
- eval("\$d = \$dpo->$param;");
- else
- $d = $dpo->display($param);
+ $d = $this->evaluate($dpo,$param);
- $output .= sprintf('%s | ',$content ? str_replace('%VALUE%',$d,$content) : $d);
+ $output .= sprintf('%s | ',($d==$v ? 'success' : 'warning'),$content ? str_replace('%VALUE%',$d,$content) : $d);
}
$output .= '
';
diff --git a/application/classes/File.php b/application/classes/File.php
new file mode 100644
index 0000000..1d329fb
--- /dev/null
+++ b/application/classes/File.php
@@ -0,0 +1,24 @@
+
diff --git a/application/classes/Model/Photo.php b/application/classes/Model/Photo.php
index 90b86d6..8205f28 100644
--- a/application/classes/Model/Photo.php
+++ b/application/classes/Model/Photo.php
@@ -10,7 +10,7 @@
* @license http://dev.leenooks.net/license.html
*/
class Model_Photo extends ORM {
- private $path = '/mnt/net/qnap/Multimedia/Photos';
+ private $_path = '/mnt/net/qnap/Multimedia/Photos';
private $_io = NULL;
protected $_has_many = array(
@@ -33,44 +33,27 @@ class Model_Photo extends ORM {
),
);
- public function duplicate_find() {
- $po = ORM::factory($this->_object_name);
-
- if ($this->loaded())
- $po->where('id','!=',$this->id);
-
- $po->where_open();
- $po->where('delete','!=',TRUE);
- $po->or_where('delete','is',NULL);
- $po->where_close();
-
- $po->where_open();
- $po->where('signature','=',$this->signature);
-
- if ($this->date_taken AND ($this->model OR $this->make)) {
- $po->or_where_open();
- $po->where('date_taken','=',$this->date_taken);
- $po->where('subsectime','=',$this->subsectime);
-
- if (! is_null($this->model))
- $po->and_where('model','=',$this->model);
-
- if (! is_null($this->make))
- $po->and_where('make','=',$this->make);
- $po->where_close();
+ public function date_file($type,$format=FALSE) {
+ 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;
}
- $po->where_close();
-
- return $po;
+ return $format ? Site::Datetime($t) : $t;
}
public function date_taken() {
return $this->display('date_taken').($this->subsectime ? '.'.$this->subsectime : '');
}
- public function duplicate_get() {
- return $this->duplicate_find()->find_all();
+ public function file_path($short=FALSE,$new=FALSE) {
+ $file = $new ? sprintf('%s_%03s.%s',date('Y/m/d-His',$this->date_taken),$this->subsectime,$this->type()) : $this->filename;
+
+ return (($short OR preg_match('/^\//',$file)) ? '' : $this->_path.DIRECTORY_SEPARATOR).$file;
}
public function gps(array $coordinate,$hemisphere) {
@@ -100,7 +83,9 @@ class Model_Photo extends ORM {
public function image() {
$imo = $this->io();
- $imo->removeImageProfile('exif');
+ if (array_key_exists('exif',$imo->getImageProfiles()))
+ $imo->removeImageProfile('exif');
+
$this->rotate($imo);
return $imo->getImageBlob();
@@ -114,29 +99,45 @@ class Model_Photo extends ORM {
public function io($attr=NULL) {
if (is_nulL($this->_io))
- $this->_io = new Imagick($this->path.'/'.$this->filename);
+ $this->_io = new Imagick($this->_path.DIRECTORY_SEPARATOR.$this->filename);
return is_null($attr) ? $this->_io : $this->_io->getImageProperty($attr);
}
- public function path() {
- $path = '';
- $ao = $this->album->where('primary','=',TRUE)->find();
+ public function move($path='') {
+ if (! $path)
+ $path = $this->file_path(FALSE,TRUE);
- if ($ao->loaded()) {
- $path .= $ao->path.'/';
+ $po = ORM::factory('Photo',$path);
- if ($ao->subpath_age) {
- $po = $this->people->where('primary','=',TRUE)->find();
- $path .= $po->age($this->date_taken).'/';
- }
+ // If the file already exists, we'll ignore the move.
+ if ($po->loaded() OR file_exists($path) OR ! File::ParentDirExist(dirname($path),TRUE))
+ return FALSE;
+
+ if (rename($this->file_path(FALSE,FALSE),$path)) {
+ $this->filename = preg_replace(":^{$this->_path}/:",'',$path);
+
+ // If the DB update failed, move it back.
+ if (! $this->save() AND ! rename($path,$this->file_path()))
+ throw new Kohana_Exception('Error: Unable to move file, ID: :id, OLD: :oldname, NEW: :newname',
+ array(':id'=>$this->id,':oldname'=>$this->file_path(),':newname'=>$this->file_path()));
+
+ return TRUE;
}
-
- $path .= sprintf('%s_%03s.%s',date('Ymd-His',$this->date_taken),$this->subsectime,$this->type());
-
- return $path;
}
+ public function propertydiff($id) {
+ if ($id == $this->id)
+ return;
+
+ $po = ORM::factory($this->_object_name,$id);
+ if (! $po->loaded())
+ return;
+
+ $result = array_diff_assoc($this->info(),$po->info());
+
+ return join('|',array_keys($result));
+ }
private function rotate(Imagick $imo) {
switch ($this->orientation) {
case 3: $imo->rotateImage(new ImagickPixel('none'),180);
@@ -148,15 +149,28 @@ class Model_Photo extends ORM {
}
}
- public static function Signaturetrim($signature) {
+ public function rotation() {
+ switch ($this->orientation) {
+ case 1: return 'None!';
+ case 3: return 'Upside Down';
+ case 6: return 'Rotate Right';
+ case 8: return 'Rotate Left';
+ default:
+ return 'unknown?';
+ }
+ }
+
+ public static function SignatureTrim($signature) {
return sprintf('%s...%s',substr($signature,0,6),substr($signature,-6));
}
- public function thumbnail() {
+ public function thumbnail($rotate=TRUE) {
$imo = new Imagick();
$imo->readImageBlob($this->thumbnail);
- $this->rotate($imo);
+
+ if ($rotate)
+ $this->rotate($imo);
return $imo->getImageBlob();
}
@@ -164,5 +178,41 @@ class Model_Photo extends ORM {
public function type($mime=FALSE) {
return strtolower($mime ? File::mime_by_ext(pathinfo($this->filename,PATHINFO_EXTENSION)) : pathinfo($this->filename,PATHINFO_EXTENSION));
}
+
+ public function list_duplicate() {
+ $po = ORM::factory($this->_object_name);
+
+ if ($this->loaded())
+ $po->where('id','!=',$this->id);
+
+ // Ignore photo's pending removal.
+ $po->where_open();
+ $po->where('remove','!=',TRUE);
+ $po->or_where('remove','is',NULL);
+ $po->where_close();
+
+ // Where the signature is the same
+ $po->where_open();
+ $po->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)) {
+ $po->or_where_open();
+ $po->where('date_taken','=',$this->date_taken);
+ $po->where('subsectime','=',$this->subsectime);
+
+ if (! is_null($this->model))
+ $po->and_where('model','=',$this->model);
+
+ if (! is_null($this->make))
+ $po->and_where('make','=',$this->make);
+
+ $po->where_close();
+ }
+
+ $po->where_close();
+
+ return $po;
+ }
}
?>
diff --git a/application/classes/Task/Photo/Import.php b/application/classes/Task/Photo/Import.php
index 2facb6c..2a4c2e9 100644
--- a/application/classes/Task/Photo/Import.php
+++ b/application/classes/Task/Photo/Import.php
@@ -54,7 +54,7 @@ class Task_Photo_Import extends Minion_Task {
break;
}
- if ($po->duplicate_get()->count())
+ if ($po->list_duplicate()->find_all()->count())
$po->duplicate = '1';
if (! $po->changed())
@@ -68,6 +68,7 @@ class Task_Photo_Import extends Minion_Task {
return sprintf("Image [%s] processed in DB: %s\n",$params['file'],$po->id);
}
+ // Force the return of a string or NULL
private function dbcol($val,$noval=NULL) {
return $val ? (string)$val : $noval;
}
diff --git a/application/classes/Task/Photo/Move.php b/application/classes/Task/Photo/Move.php
new file mode 100644
index 0000000..2c0cce4
--- /dev/null
+++ b/application/classes/Task/Photo/Move.php
@@ -0,0 +1,54 @@
+NULL, // Photo File to Move
+ 'batch'=>NULL, // Number of photos to move in a batch
+ );
+
+ protected function _execute(array $params) {
+ if ($params['file']) {
+ $po = ORM::factory('Photo',array('filename'=>$params['file']));
+
+ } else {
+ $p = ORM::factory('Photo')
+ ->where('date_taken','is not',NULL)
+ ->where_open()
+ ->where('remove','!=',TRUE)
+ ->or_where('remove','is',NULL)
+ ->where_close()
+ ->where_open()
+ ->where('duplicate','!=',TRUE)
+ ->or_where('duplicate','is',NULL)
+ ->where_close();
+ }
+
+ $c = 0;
+ foreach ($p->find_all() as $po) {
+ if ($po->file_path() == $po->file_path(FALSE,TRUE))
+ continue;
+
+ if ($po->move())
+ printf("Photo [%s] moved to %s.\n",$po->id,$po->file_path());
+ else
+ printf("Photo [%s] NOT moved to %s.\n",$po->id,$po->file_path(FALSE,TRUE));
+
+ $c++;
+
+ if (! is_null($params['batch']) AND $c >= $params['batch'])
+ break;
+ }
+
+ return sprintf("Images processed [%s]\n",$c);
+ }
+}
+?>
diff --git a/application/config/database.php b/application/config/database.php
index 5b249f5..c57afc1 100644
--- a/application/config/database.php
+++ b/application/config/database.php
@@ -20,7 +20,7 @@ return array
*/
'hostname' => 'mysql.leenooks.vpn',
'database' => 'weblnphoto',
- 'username' => 'ln-webphoto',
+ 'username' => 'ln-photo',
'password' => 'Ph0T0!',
'persistent' => TRUE,
),