added jstore path
[bookreader.git] / BookReaderIA / datanode / BookReaderMeta.inc.php
index 9601a52..89c4a69 100644 (file)
@@ -26,16 +26,31 @@ This file is part of BookReader.
 
 class BookReaderMeta {
 
+    // Fields from _meta.xml to add to response (if present)
+    var $metaFields = array(
+        'title' => 'title',
+        'author' => 'author',
+        'publisher' => 'publisher',
+        'date' => 'date',
+        'language' => 'language',
+        'contributor' => 'contributor',
+        'collection' => 'collection',
+        'page-progression' => 'pageProgression',
+        'ppi' => 'ppi',
+    );
+    
+    var $metaDefaults = array(
+        'pageProgression' => 'lr',
+    );
+    
+    // Stash spot for callback data... where are closures when we need them?
+    static $cbData = NULL;
+
     // Builds metadata object (to be encoded as JSON)
-    function buildMetadata($id, $itemPath, $bookId, $server) {
+    function buildMetadata($id, $itemPath, $subPrefix, $server) {
     
         $response = array();
         
-        if (! $bookId) {
-            $bookId = $id;
-        }
-        $subItemPath = $itemPath . '/' . $bookId;
-        
         if ("" == $id) {
             $this->BRFatal("No identifier specified!");
         }
@@ -52,8 +67,6 @@ class BookReaderMeta {
             $this->BRFatal("Bad id!");
         }
         
-        // XXX check here that subitem is okay
-        
         $filesDataFile = "$itemPath/${id}_files.xml";
         
         if (file_exists($filesDataFile)) {
@@ -62,10 +75,14 @@ class BookReaderMeta {
             $this->BRfatal("File metadata not found!");
         }
         
-        $imageStackInfo = $this->findImageStack($bookId, $filesData);
+        $imageStackInfo = $this->findImageStack($subPrefix, $filesData);
         if ($imageStackInfo['imageFormat'] == 'unknown') {
             $this->BRfatal('Couldn\'t find image stack');
         }
+        // Update subPrefix -> may have been autodetected
+        $subPrefix = $imageStackInfo['subPrefix'];
+        $subItemPath = $itemPath . '/' . $subPrefix;
+
         
         $imageFormat = $imageStackInfo['imageFormat'];
         $archiveFormat = $imageStackInfo['archiveFormat'];
@@ -145,13 +162,17 @@ class BookReaderMeta {
         }
                 
         # Load some values from meta.xml
-        $pageProgression = 'lr'; // default
-        if ('' != $metaData->{'page-progression'}) {
-          $pageProgression = $metaData->{"page-progression"};
+        foreach ($this->metaFields as $srcName => $destName) {
+            if ($metaData->{$srcName}) {
+                $response[$destName] = $metaData->{$srcName} . '';
+            } else {
+                if (array_key_exists($destName, $this->metaDefaults)) {
+                    $response[$destName] = $this->metaDefaults[$destName];
+                }
+            }
         }
         
         // General metadata
-        $response['title'] = $metaData->title . ''; // $$$ renamed
         $response['numPages'] = count($pageNums); // $$$ renamed    
         if ('' != $titleLeaf) {
             $response['titleLeaf'] = $titleLeaf; // $$$ change to titleIndex - do leaf mapping here
@@ -161,14 +182,13 @@ class BookReaderMeta {
             }
         }
         $response['url'] = "http://www.archive.org/details/$id";
-        $response['pageProgression'] = $pageProgression . '';
         $response['pageWidths'] = $pageWidths;
         $response['pageHeights'] = $pageHeights;
         $response['pageNums'] = $pageNums;
         
         // Internet Archive specific
         $response['itemId'] = $id; // $$$ renamed
-        $response['bookId'] = $bookId;  // $$$ renamed
+        $response['subPrefix'] = $subPrefix;  // $$$ renamed
         $response['itemPath'] = $itemPath;
         $response['zip'] = $imageStackFile;
         $response['server'] = $server;
@@ -244,31 +264,86 @@ class BookReaderMeta {
     
     // Returns { 'imageFormat' => , 'archiveFormat' => '} given a sub-item prefix and loaded xml data
     function findImageStack($subPrefix, $filesData) {
-    
-        // $$$ The order of the image formats determines which will be returned first
+        
+        // The order of the image formats determines which will be returned first
         $imageFormats = array('JP2' => 'jp2', 'TIFF' => 'tif', 'JPEG' => 'jpg');
+        $imageFormatOrder = array_values($imageFormats);
         $archiveFormats = array('ZIP' => 'zip', 'Tar' => 'tar');
         $imageGroup = implode('|', array_keys($imageFormats));
         $archiveGroup = implode('|', array_keys($archiveFormats));
         // $$$ Currently only return processed images
         $imageStackRegex = "/Single Page (Processed) (${imageGroup}) (${archiveGroup})/";
-            
-        foreach ($filesData->file as $file) {        
-            if (strpos($file['name'], $subPrefix) === 0) { // subprefix matches beginning
-                if (preg_match($imageStackRegex, $file->format, $matches)) {
+
+        // Strategy:
+        //   - Find potential image stacks, regardless of subPrefix
+        //   - If not given subPrefix sort based on potential subPrefix and assign based on asciibetical first
+        //   - Filter results by subPrefix
+        //   - Sort based on image format
+        //   - Take best match
+
+        $imageStacks = array();
+        foreach ($filesData->file as $file) {
+            if ( preg_match($imageStackRegex, $file->format, $matches) === 1 ) {
+                $imageFormat = $imageFormats[$matches[2]];
+                $archiveFormat = $archiveFormats[$matches[3]];
+                $imageStackFile = $file['name'] . '';
                 
-                    // Make sure we have a regular image stack
-                    $imageFormat = $imageFormats[$matches[2]];
-                    if (strpos($file['name'], $subPrefix . '_' . $imageFormat) === 0) {            
-                        return array('imageFormat' => $imageFormat,
-                                     'archiveFormat' => $archiveFormats[$matches[3]],
-                                     'imageStackFile' => $file['name']);
-                    }
+                if ( preg_match("#(.*)_${imageFormat}\.${archiveFormat}#", $imageStackFile, $matches) === 0) {
+                    // stack filename not regular
+                    continue;
+                } else {
+                    array_push($imageStacks, array(
+                                                'imageFormat' => $imageFormat,
+                                                'archiveFormat' => $archiveFormat,
+                                                'imageStackFile' => $imageStackFile,
+                                                'subPrefix' => $matches[1])
+                    );
                 }
+
+            }
+        }
+
+        // print("<pre>");
+        // print("found subPrefix $subPrefix\n");
+        // print_r($imageStacks);
+        // die(0);
+        
+        function subPrefixSort($imageStackA, $imageStackB) {
+            return strcmp($imageStackA['subPrefix'], $imageStackB['subPrefix']);
+        }
+        if (! $subPrefix) {
+            usort($imageStacks, 'subPrefixSort');
+            $subPrefix = $imageStacks[0]['subPrefix'];
+        }
+        
+        self::$cbData = $subPrefix;
+        function subPrefixFilter($imageStack) {
+            return $imageStack['subPrefix'] == BookReaderMeta::$cbData;
+        }
+        $imageStacks = array_filter($imageStacks, 'subPrefixFilter');
+                
+        function formatSort($imageStackA, $imageStackB) {
+            $formatA = $imageStackA['imageFormat'];
+            $formatB = $imageStackB['imageFormat'];
+            if ($formatA == $formatB) {
+                return 0;
             }
+            
+            $indexA = array_search($formatA, $imageFormatOrder);
+            $indexB = array_search($formatB, $imageFormatOrder);
+            // We already matched base on format, so both indices should be set
+            if ($indexA == $indexB) {
+                return 0;
+            }
+            return ($indexA < $indexB) ? 1 : -1;
         }
+        usort($imageStacks, 'formatSort'); // necessary to remap keys
         
-        return array('imageFormat' => 'unknown', 'archiveFormat' => 'unknown', 'imageStackFile' => 'unknown');    
+        if ( count($imageStacks) > 0 ) {
+            return $imageStacks[0];
+        } else {
+            return array('imageFormat' => 'unknown', 'archiveFormat' => 'unknown', 'imageStackFile' => 'unknown');
+        }
     }
     
     function isValidCallback($identifier) {
@@ -289,19 +364,19 @@ class BookReaderMeta {
         return $leafNums[$index]; // $$$ todo change to instance variables
     }
     
-    function imageURL($leafNum, $metadata, $scale, $rotate) {
+    function imageURL($leafNum, $metadata, $scale = null, $rotate = null) {
         // "Under the hood", non-public, dynamically changing (achtung!) image URLs currently look like:
         // http://{server}/BookReader/BookReaderImages.php?zip={zipPath}&file={filePath}&scale={scale}&rotate={rotate}
         // e.g. http://ia311213.us.archive.org/BookReader/BookReaderImages.php?zip=/0/items/coloritsapplicat00andriala/coloritsapplicat00andriala_jp2.zip&file=coloritsapplicat00andriala_jp2/coloritsapplicat00andriala_0009.jp2&scale=8&rotate=0
         
     
-        $filePath = $this->imageFilePath($leafNum, $metadata['bookId'], $metadata['imageFormat']);
+        $filePath = $this->imageFilePath($leafNum, $metadata['subPrefix'], $metadata['imageFormat']);
         $url = 'http://' . $metadata['server'] . '/BookReader/BookReaderImages.php?zip=' . $metadata['zip'] . '&file=' . $filePath;
         
-        if (defined($scale)) {
+        if ($scale !== null) {
             $url .= '&scale=' . $scale;
         }
-        if (defined($rotate)) {
+        if ($rotate !== null) {
             $url .= '&rotate=' . $rotate;
         }
         
@@ -312,7 +387,7 @@ class BookReaderMeta {
     function previewURL($page, $metadata) {
         $query = array(
             'id' => $metadata['itemId'],
-            'bookId' => $metadata['bookId'],
+            'subPrefix' => $metadata['subPrefix'],
             'itemPath' => $metadata['itemPath'],
             'server' => $metadata['server'],
             'page' => $page,
@@ -321,25 +396,37 @@ class BookReaderMeta {
         return 'http://' . $metadata['server'] . '/BookReader/BookReaderPreview.php?' . http_build_query($query, '', '&');
     }
     
-    function imageFilePath($leafNum, $bookId, $format) {
-        return sprintf("%s_%s/%s_%04d.%s", $bookId, $format, $bookId, intval($leafNum), $format);
+    function imageFilePath($leafNum, $subPrefix, $format) {
+        $pathParts = pathinfo($subPrefix);
+        $almostIdentifier = $pathParts['basename'];
+        return sprintf("%s_%s/%s_%04d.%s", $almostIdentifier, $format, $almostIdentifier, intval($leafNum), $format);
+    }
+    
+    // Parse date from _meta.xml to integer
+    function parseYear($dateFromMetaXML) {
+        // grab the first run of digits
+        if (preg_match('|(\d+)|', $dateFromMetaXML, $matches)) {
+            return (int)$matches[1];
+        }
+        return null;
     }
     
     function processRequest($requestEnv) {
         $id = $requestEnv['itemId']; // $$$ renamed
         $itemPath = $requestEnv['itemPath'];
-        $bookId = $requestEnv['bookId']; // $$$ renamed
+        $subPrefix = $requestEnv['subPrefix']; // $$$ renamed
         $server = $requestEnv['server'];
         
         // Check if we're on a dev vhost and point to JSIA in the user's public_html on the datanode
         // $$$ TODO consolidate this logic
-        if (strpos($_SERVER["REQUEST_URI"], "/~mang") === 0) { // Serving out of home dir
-            $server .= ':80/~mang';
-        } else if (strpos($_SERVER["REQUEST_URI"], "/~testflip") === 0) { // Serving out of home dir
-            $server .= ':80/~testflip';
+        $devHosts = array('testflip', 'rkumar', 'mang');
+        foreach ($devHosts as $host) {
+            if (strpos($_SERVER["REQUEST_URI"], '/~' . $host) === 0) { // Serving out of home dir
+                $server .= ':80/' . $host;
+            }
         }
         
-        $this->emitResponse( $this->buildMetadata($id, $itemPath, $bookId, $server) );
+        $this->emitResponse( $this->buildMetadata($id, $itemPath, $subPrefix, $server) );
     }
     
     function checkPrivs($filename) {