Updating 'Media Gallery' to reference local image directory

Discussion corner for Developers of Serendipity.
Marty
Regular
Posts: 13
Joined: Tue Jan 10, 2006 7:09 pm

Post by Marty »

Yes, you're right, that functionality cannot be done easily if the data is only on the file system.

Yes, we should look at synchronisation between fs and db. This would have to have the following features:

1. Directories added -> walk the directories added and add each image file therein to the image database.
2. Directories removed -> remove all entries in the image database referring to a file in that directory or it's subdirectories.
3. Files added -> add any image files to the image database.
4. Files removed -> remove references to that file from the image database.
5. Files changed -> query meta data and update database entry.

The check for changes in fs should occur after the call to serendipity_traversePath in serendipity_displayImageList, but before the call to serendipity_fetchImagesFromDatabase.

Files or directories added or removed are easily handled at this point by doing a select on the path, name and extension of every file in the image database against the array returned by _traversePath. The performance hit at this point is a single additional db query (with a possibly large result set).

For file meta data, the best solution I can see is that when a file is returned by the DB query in serendipity_fetchImagesFromDatabase', the meta data in the DB is compared to that on the FS and the database updated if necessary.

How does that sound?

Martin
garvinhicking
Core Developer
Posts: 30022
Joined: Tue Sep 16, 2003 9:45 pm
Location: Cologne, Germany
Contact:

Post by garvinhicking »

Hi Marty!
Yes, we should look at synchronisation between fs and db. This would have to have the following features:
Yup, I agree fully.
The check for changes in fs should occur after the call to serendipity_traversePath in serendipity_displayImageList, but before the call to serendipity_fetchImagesFromDatabase.
Yes, I think the call should be done within the displayImageList() function.
Files or directories added or removed are easily handled at this point by doing a select on the path, name and extension of every file in the image database against the array returned by _traversePath. The performance hit at this point is a single additional db query (with a possibly large result set).
Yes, but I think we'll need some kind of hash algorithm that we compare.

I haven't looked at the code, but how about something like this:

1. traversePath is called. Since it already recurses through all directories, it could also store a hash-value of all files per directory, also using the timestamp+filesize within the hash.

2. Now with all the hash values of the directories (which does not consume as much memory as storing each and every file) you create a combined hash. You save that hash inside the database.

3. On the next run, the returned multi-hash is compared with the one inside the database. Only if those differ, the new functionality of scanning the DB is executed and then the full result sets of the DB and the Filesystem are updated.

This saves us a lot of comparing when the FS/DB doesn't change. I'd like to omit the expensive comparing if no files are actually changed.
For file meta data, the best solution I can see is that when a file is returned by the DB query in serendipity_fetchImagesFromDatabase', the meta data in the DB is compared to that on the FS and the database updated if necessary.
I'd say to only update the metadata from FS, if the timestamp or filesize has changed. Those two meta-informations can be gathered within the directory traversal [the code needs to be changed to generate a "ls -la" like output, the current code won't do] so that you don't need additional lookups in case that hasn't changed...?

It seems to me we're finally getting close :-))

Best regards,
Garvin
# Garvin Hicking (s9y Developer)
# Did I help you? Consider making me happy: http://wishes.garv.in/
# or use my PayPal account "paypal {at} supergarv (dot) de"
# My "other" hobby: http://flickr.garv.in/
Marty
Regular
Posts: 13
Joined: Tue Jan 10, 2006 7:09 pm

Post by Marty »

How about something like this (only part of the patch):

Code: Select all

@@ -1093,6 +1261,90 @@
     $perPage = (!empty($serendipity['GET']['sortorder']['perpage']) ? $serendipity['GET']['sortorder']['perpage'] : $sort_row_interval[0]);
     $start   = ($page-1) * $perPage;

+   $aExclude = array ( "CVS" => true, ".svn" => true );
+   serendipity_plugin_api::hook_event('backend_media_path_exclude_directories', $aExclude);
+   $paths = array();
+   $aFilesOnDisk = array();
+   {
+       $aResultSet         = serendipity_traversePath($serendipity['serendipityPath'] . $serendipity['uploadPath']. $limit_path, '', false, null, 1, null, $aExclude );
+       foreach ( $aResultSet as $sKey => $sFile )
+       {
+           if ( $sFile['directory'] )
+               array_push ( $paths, $sFile );
+           else
+           {
+               $aFilesOnDisk [ substr ( $sFile['relpath'], 0, strlen ( $sFile['relpath'] ) -1 ) ] = 1;
+           }
+           unset ( $aResultSet[$sKey] );
+       }
+   }
+   foreach ( $aFilesOnDisk as $sKey => $sEmpty )
+   {
+       //echo "<p> Have filename " .$sKey . " </p>";
+   }
+
+   // MTG 21/01/06: request all images from the database, delete any which don't exist
+   // on the filesystem, and mark off files from the file list which are already
+   // in the database
+   $nCount = 0;
+   {
+       $aResultSet = serendipity_db_query("SELECT path,name,extension,thumbnail_name,id FROM {$serendipity['dbPrefix']}images", false, 'assoc');
+       if ( is_array ( $aResultSet ) )
+       {
+           foreach ( $aResultSet as $sKey => $sFile )
+           {
+               //serendipity_plugin_api::hook_event('backend_thumbnail_filename_select', $sFile );
+               $sThumbNailFile;
+               if ( isset ( $sFile['thumbnail_filename'] ) )
+                   $sThumbNailFile=$sFile['thumbnail_filename'];
+               else
+                   $sThumbNailFile=$sFile['path'].$sFile['name'].".".$sFile['thumbnail_name'].".".$sFile['extension'];
+               $sFileName = $sFile['path'].$sFile['name'].".".$sFile['extension'];
+               //echo "<p>File name is " . $sFileName . ", thumbnail is ".$sThumbNailFile."</p>";
+               unset ( $aResultSet[$sKey] );
+
+               if ( isset ( $aFilesOnDisk[$sFileName] ) )
+                   unset ( $aFilesOnDisk[$sFileName] );
+               else
+               {
+                   serendipity_db_query("DELETE FROM {$serendipity['dbPrefix']}images WHERE id = ". (int)$sFile['id']);
+                   ++$nCount;
+               }
+
+               unset ( $aFilesOnDisk[$sThumbNailFile] );
+           }
+       }
+   }
+   if ( $nCount > 0 )
+       echo "<p>Cleaned up ".$nCount." database entries</p>";
+   //error_reporting ( E_ALL );
+   $aUnmatchedOnDisk = array_keys ( $aFilesOnDisk );
+   $nCount = 0;
+   foreach ( $aUnmatchedOnDisk as $sFile )
+   {
+       // MTG: 21/01/06: put files which have just 'turned up' into the database
+       $aImageData = serendipity_getImageData ( $sFile );
+       if ( serendipity_isImage($aImageData) )
+       {
+       {
+           $nPos = strrpos ( $sFile, "/" );
+           if ( is_bool ( $nPos ) && !$nPos )
+           {
+               $sFileName = $sFile;
+               $sDirectory = "";
+           }
+           else
+           {
+               ++$nPos;
+               $sFileName = substr ($sFile, $nPos );
+               $sDirectory = substr ($sFile, 0, $nPos );
+           }
+           serendipity_insertImageInDatabase( $sFileName, $sDirectory );
+           ++$nCount;
+       }
+   }
+   if ( $nCount > 0 )
+       echo "<p>Inserted ".$nCount." images into the database</p>";
+
     $serendipity['imageList'] = serendipity_fetchImagesFromDatabase(
                                   $start,
                                   $perPage,
Time taken to process my directory tree containing about 2000 images is approximately 0.4 of a second, when no synchronisation is required. Due to network latency, this seems almost instantaneous.

Cheers!

Martin
garvinhicking
Core Developer
Posts: 30022
Joined: Tue Sep 16, 2003 9:45 pm
Location: Cologne, Germany
Contact:

Post by garvinhicking »

Baiscally the path looks nice. However, please do add a MD5 cache/hashing routine, so that the queries are not always executed. Only if the hash has changed of the traversepath call.

I know it might run fast on your host, but think about systems that have a high I/O or database load - they would execute this query again and again for each simple operation like just paginating through the results, and it would slow things down for them...

Have a nice weekend,
Garvin
# Garvin Hicking (s9y Developer)
# Did I help you? Consider making me happy: http://wishes.garv.in/
# or use my PayPal account "paypal {at} supergarv (dot) de"
# My "other" hobby: http://flickr.garv.in/
Marty
Regular
Posts: 13
Joined: Tue Jan 10, 2006 7:09 pm

Post by Marty »

Baiscally the path looks nice. However, please do add a MD5 cache/hashing routine, so that the queries are not always executed. Only if the hash has changed of the traversepath call.
OK. Where do you suggest we store the hash of the directory tree between runs?
Have a nice weekend,
You too!

Martin
garvinhicking
Core Developer
Posts: 30022
Joined: Tue Sep 16, 2003 9:45 pm
Location: Cologne, Germany
Contact:

Post by garvinhicking »

Just a quick shot at that, I have not tried it:

Code: Select all

@@ -1093,6 +1261,90 @@
     $perPage = (!empty($serendipity['GET']['sortorder']['perpage']) ? $serendipity['GET']['sortorder']['perpage'] : $sort_row_interval[0]);
     $start   = ($page-1) * $perPage;

+   $aExclude = array("CVS" => true, ".svn" => true);
+   serendipity_plugin_api::hook_event('backend_media_path_exclude_directories', $aExclude);
+   $paths = array();
+   $aFilesOnDisk = array();
+   {
+       $aResultSet = serendipity_traversePath($serendipity['serendipityPath'] . $serendipity['uploadPath']. $limit_path, '', false, null, 1, null, $aExclude );
+       foreach ($aResultSet as $sKey => $sFile) {
+           if ($sFile['directory']) {
+               array_push ( $paths, $sFile );
+           } else {
+               $aFilesOnDisk[substr($sFile['relpath'], 0, strlen($sFile['relpath']) -1)] = 1;
+           }
+           unset($aResultSet[$sKey]);
+       }
+   }
+   foreach ($aFilesOnDisk as $sKey => $sEmpty) {
+       //echo "<p> Have filename " .$sKey . " </p>";
+   }
+   $serendipity['current_image_hash'] = md5(serialize($aFilesOnDisk));
+
+   // MTG 21/01/06: request all images from the database, delete any which don't exist
+   // on the filesystem, and mark off files from the file list which are already
+   // in the database
+   $nCount = 0;
+   if ($serendipity['current_image_hash'] != $serendipity['last_image_hash'] {
+       $aResultSet = serendipity_db_query("SELECT path,name,extension,thumbnail_name,id FROM {$serendipity['dbPrefix']}images", false, 'assoc');
+       if (is_array($aResultSet)) {
+           foreach ($aResultSet as $sKey => $sFile) {
+               //serendipity_plugin_api::hook_event('backend_thumbnail_filename_select', $sFile );
+               $sThumbNailFile;
+               if (isset($sFile['thumbnail_filename'])) {
+                   $sThumbNailFile=$sFile['thumbnail_filename'];
+               } else {
+                   $sThumbNailFile=$sFile['path'].$sFile['name'].".".$sFile['thumbnail_name'].".".$sFile['extension'];
+               }
+               $sFileName = $sFile['path'].$sFile['name'].".".$sFile['extension'];
+               //echo "<p>File name is " . $sFileName . ", thumbnail is ".$sThumbNailFile."</p>";
+               unset($aResultSet[$sKey]);
+
+               if (isset($aFilesOnDisk[$sFileName])) {
+                   unset($aFilesOnDisk[$sFileName]);
+               } else {
+                   serendipity_db_query("DELETE FROM {$serendipity['dbPrefix']}images WHERE id = ". (int)$sFile['id']);
+                   ++$nCount;
+               }
+
+               unset($aFilesOnDisk[$sThumbNailFile]);
+           }
+       }
+       // TODO: See if serendipity_traverseDir() is depending on the current logged in author.
+       //       If it is, the config var below needs to be set for the specific used id instead of
+       //       ZERO (0).
+       serendipity_set_config_var('last_image_hash', $serendipity['current_image_hash'], 0);
+       if ($nCount > 0) {
+           echo "<p>Cleaned up ".$nCount." database entries</p>";
+       }
+       //error_reporting ( E_ALL );
+       $aUnmatchedOnDisk = array_keys ( $aFilesOnDisk );
+       $nCount = 0;
+       foreach ($aUnmatchedOnDisk as $sFile) {
+           // MTG: 21/01/06: put files which have just 'turned up' into the database
+           $aImageData = serendipity_getImageData ($sFile);
+           if (serendipity_isImage($aImageData)) {
+               $nPos = strrpos($sFile, "/");
+               if (is_bool($nPos) && !$nPos) {
+                   $sFileName = $sFile;
+                   $sDirectory = "";
+               } else {
+                   ++$nPos;
+                   $sFileName = substr($sFile, $nPos);
+                   $sDirectory = substr($sFile, 0, $nPos);
+               }
+               serendipity_insertImageInDatabase($sFileName, $sDirectory);
+               ++$nCount;
+           }
+       }
+       if ($nCount > 0) {
+           echo "<p>Inserted ".$nCount." images into the database</p>";
+       }
+   } else {
+       echo "The HASH is the same. No new images added on disk. All API functions that change the DB might need to create a HASH for the DB as well that is queried.
+   }
+ 
Maybe, if you prepare a final patch, you would be able to adjust to our PEAR coding style? That is, no spacing between braces, always put optional opening { and closing } braces, no linebreaks before { and }.

But that's minor, and if you can't take it, I'll adapt the patch for the final inclusion - even though that might take some time :)

Also, it would be wise to put the code above into a function/method later on. :-)

HTH,
Garvin
# Garvin Hicking (s9y Developer)
# Did I help you? Consider making me happy: http://wishes.garv.in/
# or use my PayPal account "paypal {at} supergarv (dot) de"
# My "other" hobby: http://flickr.garv.in/
Marty
Regular
Posts: 13
Joined: Tue Jan 10, 2006 7:09 pm

Post by Marty »

Hi Garvin,

Sorry, have been busy so haven't had a chance to finish this until now! Thanks for the tip about the 'serendipity_set_config_var'.

Here is the full patch:

Code: Select all

Index: include/functions_images.inc.php
===================================================================
--- include/functions_images.inc.php	(revision 847)
+++ include/functions_images.inc.php	(working copy)
@@ -17,7 +17,74 @@
     return preg_match('@\.(php[345]?|[psj]html?|aspx?|cgi|jsp|py|pl)$@i', $file);
 }
 
+function serendipity_getThumbNailPath ( $sRelativePath, $sName, $sExtension, $sThumbName) {
+	$aTempArray = array ( 'path' => $sRelativePath,
+						  'name' => $sName,
+						  'extension' => $sExtension );
+	//echo "<p> got path:".$sRelativePath.", name:". $sName. ", Extension: ". $sExtension . ", thumb:". $sThumbName."</p>";
+	serendipity_plugin_api::hook_event('backend_thumbnail_filename_select', $aTempArray );
+	if ( isset ( $aTempArray ['thumbnail_filename' ] ) )
+		$sThumbNailPath = $aTempArray['thumbnail_filename'];
+	else
+		$sThumbNailPath = $sRelativePath.$sName.".".(!empty($sThumbName) ? '.' . $sThumbName : '').".".$sExtension;
+	return $sThumbNailPath;
+}
 /**
+ * Given a relative path to an image, construct an array containing all 
+ * relavent information about that image
+
+ * @param  string   Relative Path
+ * @return array    Data about image
+ *
+ * MTG, 16/01/06
+ */
+function serendipity_getImageData ( $sRelativePath ) {
+    global $serendipity;
+	//error_reporting ( E_ALL );
+	// First, peel off the file name from the path
+	$nPos = strrpos ( $sRelativePath, "/" );
+	if ( is_bool ($nPos ) && !$nPos ) {
+		$sFileName = $sRelativePath;
+		$sDirectory = "";
+	}
+	else {
+		$nLastSlashPos = 1 + $nPos;
+		$sFileName = substr ( $sRelativePath, $nLastSlashPos );
+		$sDirectory = substr ( $sRelativePath, 0, $nLastSlashPos );
+	}
+	list($sName, $sExtension) = serendipity_parseFileName( $sFileName );
+
+	$sImagePath = $serendipity['serendipityPath'] . $serendipity['uploadPath'] . $sRelativePath;
+
+	$aSizeData = @serendipity_getimagesize( $sImagePath , '', $sExtension );
+	$nWidth = $aSizeData[0];
+	$nHeight = $aSizeData[1];
+	$sMime = $aSizeData['mime'];
+	$nFileSize = @filesize($sImagePath);
+
+	return array
+	(
+		'name'    			=> $sName,
+		'extension' 		=> $sExtension,
+		'mime' 		    	=> $sMime,
+		'size'				=> $nFileSize,
+		'dimensions_width' 	=> $nWidth,
+		'dimensions_height' => $nHeight,
+		'path'				=> $sDirectory,
+		'authorid'			=> 0,
+		'hotlink'			=> 0,
+		'id'				=> $sRelativePath
+	);
+}
+
+/**
+ * Simple function to replicate PHP 5 behaviour
+  */
+function microtime_float() {
+	list($usec, $sec) = explode(" ", microtime());
+	return ((float)$usec + (float)$sec);
+}
+/**
  * Gets a list of media items from our media database
  *
  * LONG
@@ -25,7 +92,7 @@
  * @access public
  * @param   int     The offset to start fetching media files
  * @param   int     How many items to fetch
- * @param   int     The number (referenced varaible) of fetched items
+ * @param   int     The number (referenced variable) of fetched items
  * @param   string  The "ORDER BY" sql part when fetching items
  * @param   string  Order by DESC or ASC
  * @param   string  Only fetch files from a specific directory
@@ -95,8 +162,8 @@
  */
 function serendipity_fetchImageFromDatabase($id) {
     global $serendipity;
-    $rs = serendipity_db_query("SELECT * FROM {$serendipity['dbPrefix']}images WHERE id = ". (int)$id, true, 'assoc');
-    return $rs;
+
+    return serendipity_db_query("SELECT * FROM {$serendipity['dbPrefix']}images WHERE id = ". (int)$id, true, 'assoc');
 }
 
 /**
@@ -199,7 +266,13 @@
     $basedir = $serendipity['serendipityPath'] . $serendipity['uploadPath'];
     $images = array();
     if ($dir = @opendir($basedir . $odir)) {
-        while(false !== ($f = readdir($dir))) {
+		$aTempArray = array();
+		while (($file = @readdir($dir)) !== false) {
+			array_push ( $aTempArray, $file );
+		}
+		@closedir($dir);
+		sort ( $aTempArray );
+		foreach ( $aTempArray as $f) {
             if ($f != '.' && $f != '..' && strpos($f, $serendipity['thumbSuffix']) === false) {
                 $cdir = ($odir != '' ? $odir . '/' : '');
                 if (is_dir($basedir . $odir . '/' . $f)) {
@@ -947,8 +1020,7 @@
  * @param   int         Degress to rotate
  * @return  array       New width/height of the image
  */
-function serendipity_rotate_image_gd($infilename, $outfilename, $degrees)
-{
+function serendipity_rotate_image_gd($infilename, $outfilename, $degrees) {
     $func = serendipity_functions_gd($infilename);
     if (!is_array($func)) {
         return false;
@@ -979,8 +1051,7 @@
  * @return  int         New height (can be autodetected)
  * @return  array       New image size
  */
-function serendipity_resize_image_gd($infilename, $outfilename, $newwidth, $newheight=null)
-{
+function serendipity_resize_image_gd($infilename, $outfilename, $newwidth, $newheight=null) {
     $func = serendipity_functions_gd($infilename);
     if (!is_array($func)) {
         return false;
@@ -1046,7 +1117,6 @@
 
     return array($newwidth, $newheight);
 }
-
 /**
  * Display the list of images in our database
  *
@@ -1061,7 +1131,7 @@
  */
 function serendipity_displayImageList($page = 0, $lineBreak = NULL, $manage = false, $url = NULL, $show_upload = false, $limit_path = NULL) {
     global $serendipity;
-    $sort_row_interval = array(8, 16, 50, 100);
+    $sort_row_interval = array(8, 24, 50, 100);
     $sortParams        = array('perpage', 'order', 'ordermode');
     $importParams      = array('adminModule', 'htmltarget', 'filename_only', 'textarea', 'subpage');
     $extraParems       = '';
@@ -1093,6 +1163,97 @@
     $perPage = (!empty($serendipity['GET']['sortorder']['perpage']) ? $serendipity['GET']['sortorder']['perpage'] : $sort_row_interval[0]);
     $start   = ($page-1) * $perPage;
 
+	$aExclude = array ( "CVS" => true, ".svn" => true );
+	serendipity_plugin_api::hook_event('backend_media_path_exclude_directories', $aExclude);
+	$paths = array();
+	$aFilesOnDisk = array();
+	{
+		$aResultSet         = serendipity_traversePath($serendipity['serendipityPath'] . $serendipity['uploadPath']. $limit_path, '', false, null, 1, null, $aExclude );
+		foreach ( $aResultSet as $sKey => $sFile ) {
+			if ( $sFile['directory'] ){
+				array_push ( $paths, $sFile );
+			}
+			else {
+				$aFilesOnDisk [ substr ( $sFile['relpath'], 0, strlen ( $sFile['relpath'] ) -1 ) ] = 1;
+			}
+			unset ( $aResultSet[$sKey] );
+		}
+	}
+	sort ( $paths );
+	$serendipity['current_image_hash'] = md5(serialize($aFilesOnDisk));
+
+	$nTimeStart = microtime_float ();
+	// MTG 21/01/06: request all images from the database, delete any which don't exist
+	// on the filesystem, and mark off files from the file list which are already
+	// in the database
+	
+	$nCount = 0;
+	if ($serendipity['current_image_hash'] != $serendipity['last_image_hash'] ) {
+		$aResultSet = serendipity_db_query("SELECT path,name,extension,thumbnail_name,id FROM {$serendipity['dbPrefix']}images", false, 'assoc');
+		if ( is_array ( $aResultSet ) ) {
+			foreach ( $aResultSet as $sKey => $sFile ) {	
+				serendipity_plugin_api::hook_event('backend_thumbnail_filename_select', $sFile );
+				$sThumbNailFile;
+				if ( isset ( $sFile['thumbnail_filename'] ) )
+					$sThumbNailFile=$sFile['thumbnail_filename'];
+				else
+					$sThumbNailFile=$sFile['path'].$sFile['name'].".".$sFile['thumbnail_name'].".".$sFile['extension'];
+				$sFileName = $sFile['path'].$sFile['name'].".".$sFile['extension'];
+				//echo "<p>File name is " . $sFileName . ", thumbnail is ".$sThumbNailFile."</p>";
+				unset ( $aResultSet[$sKey] );
+
+				if ( isset ( $aFilesOnDisk[$sFileName] ) ){
+					unset ( $aFilesOnDisk[$sFileName] );
+				}
+				else {
+					serendipity_db_query("DELETE FROM {$serendipity['dbPrefix']}images WHERE id = ". (int)$sFile['id']);
+					++$nCount;
+				}
+
+				unset ( $aFilesOnDisk[$sThumbNailFile] );
+			}
+		}
+		if ( $nCount > 0 ){
+			echo "<p>Cleaned up ".$nCount." database entries</p>";
+		}
+		// TODO: See if serendipity_traverseDir() is depending on the current logged in author.
+		//       If it is, the config var below needs to be set for the specific used id instead of
+		//       ZERO (0).
+		serendipity_set_config_var('last_image_hash', $serendipity['current_image_hash'], 0); 
+		//error_reporting ( E_ALL );
+		$aUnmatchedOnDisk = array_keys ( $aFilesOnDisk );	
+		$nCount = 0;
+		foreach ( $aUnmatchedOnDisk as $sFile ) {
+			// MTG: 21/01/06: put files which have just 'turned up' into the database
+			$aImageData = serendipity_getImageData ( $sFile );
+			if ( serendipity_isImage($aImageData) ) {
+				$nPos = strrpos ( $sFile, "/" );
+				if ( is_bool ( $nPos ) && !$nPos ) {
+					$sFileName = $sFile;
+					$sDirectory = "";
+				}
+				else {
+					++$nPos;
+					$sFileName = substr ($sFile, $nPos );
+					$sDirectory = substr ($sFile, 0, $nPos );
+				}
+				serendipity_insertImageInDatabase( $sFileName, $sDirectory );
+				++$nCount;
+			}
+		}
+		if ( $nCount > 0 ){
+			echo "<p>Inserted ".$nCount." images into the database</p>";
+		}
+	}
+	else {
+		echo "<p>Media Gallery database is up to date</p>";
+	}
+	/*
+	$nTimeEnd = microtime_float ( );
+	$nDifference = $nTimeEnd - $nTimeStart;
+	echo "<p> total time taken was " . $nDifference . "</p>";
+	*/
+
     $serendipity['imageList'] = serendipity_fetchImagesFromDatabase(
                                   $start,
                                   $perPage,
@@ -1102,12 +1263,10 @@
                                   (isset($serendipity['GET']['only_path']) ? $serendipity['GET']['only_path'] : ''),
                                   (isset($serendipity['GET']['only_filename']) ? $serendipity['GET']['only_filename'] : '')
     );
-
     $pages         = ceil($totalImages / $perPage);
     $linkPrevious  = '?' . $extraParems . 'serendipity[page]=' . ($page-1);
     $linkNext      = '?' . $extraParems . 'serendipity[page]=' . ($page+1);
     $sort_order    = serendipity_getImageFields();
-    $paths         = serendipity_traversePath($serendipity['serendipityPath'] . $serendipity['uploadPath']. $limit_path);
 
     if (is_null($lineBreak)) {
         $lineBreak = floor(750 / ($serendipity['thumbSize'] + 20));
@@ -1204,9 +1363,14 @@
         $x = 0;
         foreach ($serendipity['imageList'] as $k => $file) {
             ++$x; $preview = '';
-            $img = $serendipity['serendipityPath'] . $serendipity['uploadPath'] . $file['path'] . $file['name'] . (!empty($file['thumbnail_name']) ? '.' . $file['thumbnail_name'] : '') . '.' . $file['extension'];
-            $i = @getimagesize($img);
-            $file['imgsrc'] = $serendipity['uploadHTTPPath'] . $file['path'] . $file['name'] . (!empty($file['thumbnail_name']) ? '.' . $file['thumbnail_name'] : '') . '.' . $file['extension'];
+			//echo "<p> " . print_r($file) . "</p>";
+			$sThumbSource = serendipity_getThumbNailPath ($file['path'], $file['name'], $file['extension'], $file['thumbnail_name']);
+			$img = $serendipity['serendipityPath'] . $serendipity['uploadPath'] . $sThumbSource;
+			if (!isset ( $file['imgsrc'] ) ) {
+            	$file['imgsrc'] = $serendipity['uploadHTTPPath'] . $file['path'] . $file['name'] . (!empty($file['thumbnail_name']) ? '.' . $file['thumbnail_name'] : '') . '.' . $file['extension'];
+			}
+			$i = @getimagesize($img);
+				
             $is_image = serendipity_isImage($file);
 
             if (!($serendipity['authorid'] == $file['authorid'] || $file['authorid'] == '0' || serendipity_checkPermission('adminImagesViewOthers'))) {
@@ -1216,7 +1380,7 @@
 
             /* If it is an image, and the thumbnail exists */
             if ($is_image && file_exists($img)) {
-                $preview .= '<img src="' . $serendipity['serendipityHTTPPath'] . $file['imgsrc'] . '" border="0" title="' . $file['path'] . $file['name'] . '" alt="'. $file['name'] . '" />';
+               	$preview .= '<img src="' . $serendipity['serendipityHTTPPath'] . $serendipity['uploadHTTPPath'] . $sThumbSource . '" border="0" title="' . $file['path'] . $file['name'] . '" alt="'. $file['name'] . '" />';
                 if ($url) {
                     $preview = '<a href="'. $url .'&serendipity[image]='. $file['id'] .'">'. $preview .'</a>';
                 }
@@ -1416,32 +1580,34 @@
  * @param   int         The maximum level of nesting (recursive use)
  * @return  array       Array of files/directories
  */
-function serendipity_traversePath($basedir, $dir='', $onlyDirs=true, $pattern = NULL, $depth = 1, $max_depth = null) {
-
-
+function serendipity_traversePath($basedir, $dir='', $onlyDirs=true, $pattern = NULL, $depth = 1, $max_depth = NULL, $aExcludeDirs = NULL ) {
     $dh = @opendir($basedir . '/' . $dir);
     if ( !$dh ) {
         return array();
     }
-
     $files = array();
     while (($file = @readdir($dh)) !== false) {
         if ( $file != '.' && $file != '..' ) {
-            if ( $onlyDirs === false || ($onlyDirs === true && is_dir($basedir . '/' . $dir . '/' . $file)) ) {
-                if ( is_null($pattern) || preg_match($pattern, $file) ) {
+			$bPatternMatch = ( is_null($pattern) || preg_match($pattern, $file) );
+			$sFullPath = $basedir. '/' . $dir . '/' . $file; 
+			$bIsDir = is_dir ( $sFullPath );
+            if ( $onlyDirs === false || $bIsDir ) {
+				if ( $bPatternMatch &&
+				   ( !$bIsDir || $aExcludeDirs == null || !isset ( $aExcludeDirs[$file] ) ) ) {
                     $files[] = array(
                         'name'    => $file,
                         'depth'   => $depth,
-                        'relpath' => ltrim(str_replace('\\', '/', $dir) . basename($file) . '/', '/')
+                        'relpath' => ltrim(str_replace('\\', '/', $dir) . basename($file) . '/', '/'),
+						'directory' => $bIsDir
                     );
                 }
             }
-            if ( is_dir($basedir . '/' . $dir . '/' . $file) && ($max_depth === null || $depth < $max_depth)) {
-                $files = array_merge($files, serendipity_traversePath($basedir, $dir . '/' . basename($file) . '/', $onlyDirs, $pattern, ($depth+1), $max_depth));
-            }
+            if ( $bIsDir &&
+				($max_depth === null || $depth < $max_depth) &&
+				($aExcludeDirs == null || !isset($aExcludeDirs[$file] ) ) )
+				$files = array_merge($files, serendipity_traversePath($basedir, $dir . '/' . basename($file) . '/', $onlyDirs, $pattern, ($depth+2), $max_depth, $aExcludeDirs ) );
         }
     }
-
     @closedir($dh);
     return $files;
 }
@@ -1537,7 +1703,6 @@
             'noimage' => true
         );
     }
-
     return $fdim;
 }
 
Index: serendipity_admin_image_selector.php
===================================================================
--- serendipity_admin_image_selector.php	(revision 856)
+++ serendipity_admin_image_selector.php	(working copy)
@@ -111,20 +111,24 @@
         }
 
         $file           = serendipity_fetchImageFromDatabase($serendipity['GET']['image']);
-        $file['imgsrc'] = $serendipity['serendipityHTTPPath'] . $serendipity['uploadHTTPPath'] . $file['path'] . $file['name'] . (!empty($file['thumbnail_name']) ? '.' . $file['thumbnail_name'] : '') . '.' . $file['extension'];
+        $sThumbNail = serendipity_getThumbNailPath ( $file['path'], $file['name'], $file['extension'], $file['thumbnail_name']);
+        //echo "<p> sThumbNail is ".$sThumbNail."</p>";
+        $file['imgsrc'] = $serendipity['serendipityHTTPPath'] . $serendipity['uploadHTTPPath'] . $sThumbNail;
         if ($file['hotlink']) {
             $imgName    = $file['path'];
         } else {
             $imgName    = $serendipity['serendipityHTTPPath'] . $serendipity['uploadHTTPPath'] . $file['path'] . $file['name'] .'.'. $file['extension'];
         }
 
-        $thumbbasename  = $file['path'] . $file['name'] . (!empty($file['thumbnail_name']) ? '.' . $file['thumbnail_name'] : '') . '.' . $file['extension'];
+        //echo "<p> imgsrc is ".$file['imgsrc']."</p>";
+        $thumbbasename  = $sThumbNail;
 
         if ($file['hotlink']) {
             $thumbName  = $file['path'];
         } else {
             $thumbName  = $serendipity['serendipityHTTPPath'] . $serendipity['uploadHTTPPath'] . $thumbbasename;
         }
+        //echo "<p> thumbName is ".$thumbname."</p>";
         $thumbsize     = @getimagesize($serendipity['serendipityPath'] . $serendipity['uploadPath'] . $thumbbasename);
         $is_image      = serendipity_isImage($file, true);
 ?>
@@ -194,8 +198,11 @@
                 <input id="radio_islink_no"  type="radio" name="serendipity[isLink]" value="no" <?php  echo ifRemember('isLink', 'no'); ?> /><label for="radio_islink_no"> <?php echo I_WANT_IT_TO_LINK; ?></label>
                 <?php if ($file['hotlink']) { ?>
                 <input type="text"  name="serendipity[url]" size="30" value="<?php echo $file['path']; ?>" /><br />
-                <?php } else { ?>
-                <input type="text"  name="serendipity[url]" size="30" value="<?php echo $serendipity['serendipityHTTPPath'] . $serendipity['uploadHTTPPath'] . $file['path'] . $file['name'] .'.'. $file['extension']; ?>" /><br />
+                <?php } else { 
+                    $aArray = array ( 'imagelinkurl' => $sImagePath = $serendipity['serendipityHTTPPath'] . $serendipity['uploadHTTPPath'] . $file['path'] . $file['name'] .'.'. $file['extension'] );
+                serendipity_plugin_api::hook_event('frontend_image_selector_link_url', $aArray); 
+                ?>
+                <input type="text"  name="serendipity[url]" size="30" value="<?php echo $aArray['imagelinkurl']?>" /><br />
                 <?php } ?>
                 <?php serendipity_plugin_api::hook_event('frontend_image_selector_imagelink', $file); ?>
                 <br />
And this is my small plugin to handle the 'album' program:

Code: Select all

<?php # $Id: serendipity_event_imageselectorplus.php,v 1.17 2005/11/18 07:36:08 elf2000 Exp $

@define('PLUGIN_EVENT_LOCAL_IMAGE_SELECTOR', 'Local Image Selector');
@define('PLUGIN_EVENT_LOCAL_IMAGE_SELECTOR_DESC', 'Allows users to select images from a directory on the same filesystem as Serendipity');


class serendipity_event_local_image_selector extends serendipity_event
{
    var $title = PLUGIN_EVENT_LOCAL_IMAGE_SELECTOR;

    function introspect(&$propbag)
    {
        global $serendipity;

        $propbag->add('name',          PLUGIN_EVENT_LOCAL_IMAGE_SELECTOR);
        $propbag->add('description',   PLUGIN_EVENT_LOCAL_IMAGE_SELECTOR_DESC);
        $propbag->add('stackable',     false);
        $propbag->add('author',        'Martin Gallwey');
        $propbag->add('version',       '0.1');
        $propbag->add('requirements',  array(
            'serendipity' => '0.9',
            'smarty'      => '2.6.7',
            'php'         => '4.1.0'
        ));

        $propbag->add('groups', array('IMAGES'));
        $propbag->add('event_hooks',   array(
            'backend_thumbnail_filename_select' => true,
            'backend_media_path_exclude_directories' => true,
            'frontend_image_selector_link_url' => true
        ));

    }
    function generate_content(&$title) {
        $title = $this->title;
    }
    function event_hook($event, &$bag, &$eventData)
    {
        global $serendipity;

        $hooks = &$bag->get('event_hooks');

        if (isset($hooks[$event]))
        {
            switch($event)
            {
                case 'backend_media_path_exclude_directories':
                    $eventData["tn"] = true;
                    return true;
                break;
                case 'frontend_image_selector_link_url':
                    $sURL = $eventData['imagelinkurl'];
                    $nLastSlashPos = 1 + strrpos ( $sURL, "/" );
                    $sFileName = substr ( $sURL, $nLastSlashPos );
                    $sDirectory = substr ( $sURL, 0, $nLastSlashPos );
                    $sThumbHTML = $sDirectory . "tn/" . $sFileName . ".html";
                    (array)$eventData['imagelinkurl'] = $sThumbHTML;
                    return true;
                break;
                case 'backend_thumbnail_filename_select':
                    if ( isset ( $eventData['path'] ) &&
                         isset ( $eventData['name'] ) &&
                         isset ( $eventData['extension'] ) )
                        $eventData['thumbnail_filename'] = $eventData['path']."tn/".$eventData['name'].".".$eventData['extension'];
                    return true;
                break;
                default:
                    return false;
            }
        }
        return false;
    }
}

?>
How do they look? Do I need to do anything to clean them up so they can be included in s9y?

Thanks for all of your help with this, Garvin!

Martin
garvinhicking
Core Developer
Posts: 30022
Joined: Tue Sep 16, 2003 9:45 pm
Location: Cologne, Germany
Contact:

Post by garvinhicking »

Hi Marty!

A quick glance at this looks very good! I will test this more in depth, but am currently too short on time to look through it carefully.

We're about to release 1.0 final on February 15th, and I feel that we should not include this patch in the current release cycle, but implement it for SVN HEAD after the 1.0 release.

Until the release it would be a bit hard to maintain two brnaches, so I want to branch the 1.0 sourcecode on the release day, and then immediately include your patch. Does that sound okay for you?

Coudl you attach your files on our Patch tracker: http://sourceforge.net/tracker/?group_i ... tid=542824 so that it won't get lost?

Best regards,
Garvin
# Garvin Hicking (s9y Developer)
# Did I help you? Consider making me happy: http://wishes.garv.in/
# or use my PayPal account "paypal {at} supergarv (dot) de"
# My "other" hobby: http://flickr.garv.in/
Marty
Regular
Posts: 13
Joined: Tue Jan 10, 2006 7:09 pm

Post by Marty »

Hi Garvin,

That sounds good to me. Two patches added:

Code: Select all

 1416699  	  Patch to make s9y support 'album'   	   2006-01-27 10:15  	 5  	nobody  	nobody
1416690 	Automatic updating of the Media Gallery database 	  2006-01-27 10:00 	5 	nobody 	nobody
Post Reply