. */ header('Content-Type: application/javascript'); $id = $_REQUEST['id']; $itemPath = $_REQUEST['itemPath']; $subPrefix = $_REQUEST['subPrefix']; $server = $_REQUEST['server']; // $$$mang this code has been refactored into BookReaderMeta.inc.php for use e.g. by // BookReaderPreview.php and BookReaderImages.php. The code below should be // taken out and replaced by calls into BookReaderMeta // 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"], "/~rkumar") === 0) { // Serving out of home dir $server .= ':80/~rkumar'; } else if (strpos($_SERVER["REQUEST_URI"], "/~testflip") === 0) { // Serving out of home dir $server .= ':80/~testflip'; } if (! $subPrefix) { $subPrefix = $id; } $subItemPath = $itemPath . '/' . $subPrefix; if ("" == $id) { BRFatal("No identifier specified!"); } if ("" == $itemPath) { BRFatal("No itemPath specified!"); } if ("" == $server) { BRFatal("No server specified!"); } if (!preg_match("|^/\d+/items/{$id}$|", $itemPath)) { BRFatal("Bad id!"); } // XXX check here that subitem is okay $filesDataFile = "$itemPath/${id}_files.xml"; if (file_exists($filesDataFile)) { $filesData = simplexml_load_file("$itemPath/${id}_files.xml"); } else { BRfatal("File metadata not found!"); } $imageStackInfo = findImageStack($subPrefix, $filesData); if ($imageStackInfo['imageFormat'] == 'unknown') { BRfatal('Couldn\'t find image stack'); } $imageFormat = $imageStackInfo['imageFormat']; $archiveFormat = $imageStackInfo['archiveFormat']; $imageStackFile = $itemPath . "/" . $imageStackInfo['imageStackFile']; if ("unknown" == $imageFormat) { BRfatal("Unknown image format"); } if ("unknown" == $archiveFormat) { BRfatal("Unknown archive format"); } $scanDataFile = "${subItemPath}_scandata.xml"; $scanDataZip = "$itemPath/scandata.zip"; if (file_exists($scanDataFile)) { $scanData = simplexml_load_file($scanDataFile); } else if (file_exists($scanDataZip)) { $cmd = 'unzip -p ' . escapeshellarg($scanDataZip) . ' scandata.xml'; exec($cmd, $output, $retval); if ($retval != 0) BRFatal("Could not unzip ScanData!"); $dump = join("\n", $output); $scanData = simplexml_load_string($dump); } else if (file_exists("$itemPath/scandata.xml")) { // For e.g. Scribe v.0 books! $scanData = simplexml_load_file("$itemPath/scandata.xml"); } else { BRFatal("ScanData file not found!"); } $metaDataFile = "$itemPath/{$id}_meta.xml"; if (!file_exists($metaDataFile)) { BRFatal("MetaData file not found!"); } $metaData = simplexml_load_file($metaDataFile); //$firstLeaf = $scanData->pageData->page[0]['leafNum']; ?> // Error reporting - this helps us fix errors quickly function logError(description,page,line) { if (typeof(archive_analytics) != 'undefined') { var values = { 'bookreader': 'error', 'description': description, 'page': page, 'line': line, 'itemid': '', 'subPrefix': '', 'server': '', 'bookPath': '' }; // if no referrer set '-' as referrer if (document.referrer == '') { values['referrer'] = '-'; } else { values['referrer'] = document.referrer; } if (typeof(br) != 'undefined') { values['itemid'] = br.bookId; values['subPrefix'] = br.subPrefix; values['server'] = br.server; values['bookPath'] = br.bookPath; } var qs = archive_analytics.format_bug(values); var error_img = new Image(100,25); error_img.src = archive_analytics.img_src + "?" + qs; } return false; // allow browser error handling so user sees there was a problem } window.onerror=logError; br = new BookReader(); pageData->page as $page) { if (("Title Page" == $page->pageType) || ("Title" == $page->pageType)) { $titleLeaf = "{$page['leafNum']}"; break; } } if ('' != $titleLeaf) { printf("br.titleLeaf = %d;\n", $titleLeaf); } ?> br.getPageWidth = function(index) { return this.pageW[index]; } br.getPageHeight = function(index) { return this.pageH[index]; } // Returns true if page image is available rotated br.canRotatePage = function(index) { return 'jp2' == this.imageFormat; // Assume single format for now } // reduce defaults to 1 (no reduction) // rotate defaults to 0 (no rotation) br.getPageURI = function(index, reduce, rotate) { var _reduce; var _rotate; if ('undefined' == typeof(reduce)) { _reduce = 1; } else { _reduce = reduce; } if ('undefined' == typeof(rotate)) { _rotate = 0; } else { _rotate = rotate; } var file = this._getPageFile(index); // $$$ add more image stack formats here return 'http://'+this.server+'/BookReader/BookReaderImages.php?zip='+this.zip+'&file='+file+'&scale='+_reduce+'&rotate='+_rotate; } br._getPageFile = function(index) { var leafStr = '0000'; var imgStr = this.leafMap[index].toString(); var re = new RegExp("0{"+imgStr.length+"}$"); var insideZipPrefix = this.subPrefix.match('[^/]+$'); var file = insideZipPrefix + '_' + this.imageFormat + '/' + insideZipPrefix + '_' + leafStr.replace(re, imgStr) + '.' + this.imageFormat; return file; } br.getPageSide = function(index) { //assume the book starts with a cover (right-hand leaf) //we should really get handside from scandata.xml // assume page side based on title pagex var titleIndex = br.leafNumToIndex(br.titleLeaf); // assume title page is RHS var delta = titleIndex - index; if (0 == (delta & 0x1)) { // even delta return 'R'; } else { return 'L'; } // $$$ we should get this from scandata instead of assuming the accessible // leafs are contiguous if ('rl' != this.pageProgression) { // If pageProgression is not set RTL we assume it is LTR if (0 == (index & 0x1)) { // Even-numbered page return 'R'; } else { // Odd-numbered page return 'L'; } } else { // RTL if (0 == (index & 0x1)) { return 'L'; } else { return 'R'; } } } br.getPageNum = function(index) { var pageNum = this.pageNums[index]; if (pageNum) { return pageNum; } else { return 'n' + index; } } // Single images in the Internet Archive scandata.xml metadata are (somewhat incorrectly) // given a "leaf" number. Some of these images from the scanning process should not // be displayed in the BookReader (for example colour calibration cards). Since some // of the scanned images will not be displayed in the BookReader (those marked with // addToAccessFormats false in the scandata.xml) leaf numbers and BookReader page // indexes are generally not the same. This function returns the BookReader page // index given a scanned leaf number. // // This function is used, for example, to map between search results (that use the // leaf numbers) and the displayed pages in the BookReader. br.leafNumToIndex = function(leafNum) { for (var index = 0; index < this.leafMap.length; index++) { if (this.leafMap[index] == leafNum) { return index; } } return null; } // This function returns the left and right indices for the user-visible // spread that contains the given index. The return values may be // null if there is no facing page or the index is invalid. br.getSpreadIndices = function(pindex) { // $$$ we could make a separate function for the RTL case and // only bind it if necessary instead of always checking // $$$ we currently assume there are no gaps var spreadIndices = [null, null]; if ('rl' == this.pageProgression) { // Right to Left if (this.getPageSide(pindex) == 'R') { spreadIndices[1] = pindex; spreadIndices[0] = pindex + 1; } else { // Given index was LHS spreadIndices[0] = pindex; spreadIndices[1] = pindex - 1; } } else { // Left to right if (this.getPageSide(pindex) == 'L') { spreadIndices[0] = pindex; spreadIndices[1] = pindex + 1; } else { // Given index was RHS spreadIndices[1] = pindex; spreadIndices[0] = pindex - 1; } } //console.log(" index %d mapped to spread %d,%d", pindex, spreadIndices[0], spreadIndices[1]); return spreadIndices; } // Remove the page number assertions for all but the highest index page with // a given assertion. Ensures there is only a single page "{pagenum}" // e.g. the last page asserted as page 5 retains that assertion. br.uniquifyPageNums = function() { var seen = {}; for (var i = br.pageNums.length - 1; i--; i >= 0) { var pageNum = br.pageNums[i]; if ( !seen[pageNum] ) { seen[pageNum] = true; } else { br.pageNums[i] = null; } } } br.cleanupMetadata = function() { br.uniquifyPageNums(); } // getEmbedURL //________ // Returns a URL for an embedded version of the current book br.getEmbedURL = function(viewParams) { // We could generate a URL hash fragment here but for now we just leave at defaults var url = 'http://' + window.location.host + '/stream/'+this.bookId; if (this.subPrefix != this.bookId) { // Only include if needed url += '/' + this.subPrefix; } url += '?ui=embed'; if (typeof(viewParams) != 'undefined') { url += '#' + this.fragmentFromParams(viewParams); } return url; } // getEmbedCode //________ // Returns the embed code HTML fragment suitable for copy and paste br.getEmbedCode = function(frameWidth, frameHeight, viewParams) { return ""; } // getOpenLibraryRecord br.getOpenLibraryRecord = function(callback) { // Try looking up by ocaid first, then by source_record var jsonURL = this.olHost + '/query.json?type=/type/edition&*=&ocaid=' + br.bookId; $.ajax({ url: jsonURL, success: function(data) { if (data && data.length > 0) { callback(br, data[0]); } else { // try sourceid jsonURL = this.olHost + '/query.json?type=/type/edition&*=&source_records=ia:' + br.bookId; $.ajax({ url: jsonURL, success: function(data) { if (data && data.length > 0) { callback(br, data[0]); } }, dataType: 'jsonp' }); } }, dataType: 'jsonp' }); } br.buildInfoDiv = function(jInfoDiv) { // $$$ it might make more sense to have a URL on openlibrary.org that returns this info var escapedTitle = BookReader.util.escapeHTML(this.bookTitle); var domainRe = /(\w+\.(com|org))/; var domainMatch = domainRe.exec(this.bookUrl); var domain = this.bookUrl; if (domainMatch) { domain = domainMatch[1]; } // $$$ cover looks weird before it loads jInfoDiv.find('.BRfloatCover').append([ '
' + escapedTitle + '
'].join('') ); jInfoDiv.find('.BRfloatMeta').append([ // $$$ description //'

Published ', this.bookPublished, //, Publisher name', //'

', //'

Written in Language

', '

Other Formats

', '', '

More information on ' + domain + '

'].join('\n')); jInfoDiv.find('.BRfloatFoot').append([ '|', 'Report a problem', ].join('\n')); if (domain == 'archive.org') { jInfoDiv.find('.BRfloatMeta p.moreInfo span').css( {'background': 'url(http://www.archive.org/favicon.ico) no-repeat', 'width': 22, 'height': 18 } ); } jInfoDiv.find('.BRfloatTitle a').attr({'href': this.bookUrl, 'alt': this.bookTitle}).text(this.bookTitle); var bookPath = (window.location + '').replace('#','%23'); jInfoDiv.find('a.problem').attr('href','http://openlibrary.org/contact?path=' + bookPath); } br.pageW = [ pageData->page as $page) { if (shouldAddPage($page)) { if(0 != $i) echo ","; //stupid IE echo "{$page->cropBox->w}"; $i++; } } ?> ]; br.pageH = [ pageData->page as $page) { if (shouldAddPage($page)) { if(0 != $i) echo ","; //stupid IE echo "{$page->cropBox->h}"; $totalHeight += intval($page->cropBox->h/4) + 10; $i++; } } ?> ]; br.leafMap = [ pageData->page as $page) { if (shouldAddPage($page)) { if(0 != $i) echo ","; //stupid IE echo "{$page['leafNum']}"; $i++; } } ?> ]; br.pageNums = [ pageData->page as $page) { if (shouldAddPage($page)) { if(0 != $i) echo ","; //stupid IE if (array_key_exists('pageNumber', $page) && ('' != $page->pageNumber)) { echo "'{$page->pageNumber}'"; } else { echo "null"; } $i++; } } ?> ]; br.numLeafs = br.pageW.length; br.bookId = ''; br.zip = ''; br.subPrefix = ''; br.server = ''; br.bookTitle= 'title);?>'; br.bookPath = ''; br.bookUrl = ''; br.imageFormat = ''; br.archiveFormat = ''; {'page-progression'}) { echo "br.pageProgression = '" . $metaData->{"page-progression"} . "';\n"; } else { // Assume page progression is Left To Right echo "br.pageProgression = 'lr';\n"; } $useOLAuth = false; foreach ($metaData->xpath('//collection') as $collection) { if('browserlending' == $collection) { $useOLAuth = true; } } echo "br.olHost = 'http://openlibrary.org'\n"; #echo "br.olHost = 'http://ol-mang:8080'\n"; if ($useOLAuth) { echo "br.olAuth = true;\n"; } else { echo "br.olAuth = false;\n"; } # Special cases if ('bandersnatchhsye00scarrich' == $id) { echo "br.mode = 2;\n"; echo "br.auto = true;\n"; } ?> // Check for config object // $$$ change this to use the newer params object if (typeof(brConfig) != 'undefined') { if (typeof(brConfig["ui"]) != 'undefined') { br.ui = brConfig["ui"]; } if (brConfig['mode'] == 1) { br.mode = 1; if (typeof(brConfig['reduce'] != 'undefined')) { br.reduce = brConfig['reduce']; } } else if (brConfig['mode'] == 2) { br.mode = 2; } } // brConfig function OLAuth() { this.authUrl = br.olHost + '/ia_auth/' + br.bookId; this.olConnect = false; this.loanUUID = false; this.loanToken = false; var cookieRe = /;\s*/; var cookies = document.cookie.split(cookieRe); var length = cookies.length; var i; for (i=0; i', msg, '

', resolution, '

'].join('\n'); } OLAuth.prototype.initCallback = function(obj) { if (false == obj.success) { $(this.popup).css({ backgroundColor: "#ff", color: "#000" }); this.setPopupMsg(obj.msg, obj.resolution); return; } //user is authenticated this.setCookie(obj.token); this.olConnect = true; this.startPolling(); br.init(); } OLAuth.prototype.callback = function(obj) { if (false == obj.success) { this.showPopup("#fff", "#000", obj.msg, obj.resolution); clearInterval(this.poller); this.ttsPoller = null; } else { this.olConnect = true; this.setCookie(obj.token); } } OLAuth.prototype.setCookie = function(value) { var date = new Date(); date.setTime(date.getTime()+(10*60*1000)); //10 min expiry var expiry = date.toGMTString(); var cookie = 'loan-'+br.bookId+'='+value; cookie += '; expires='+expiry; cookie += '; path=/; domain=.archive.org;'; document.cookie = cookie; //refresh the br-loan uuid cookie with current expiry, if needed if (false !== this.loanUUID) { cookie = 'br-loan-'+br.bookId+'='+this.loanUUID; cookie += '; expires='+expiry; cookie += '; path=/; domain=.archive.org;'; document.cookie = cookie; } } OLAuth.prototype.startPolling = function () { var self = this; this.poller=setInterval(function(){ if (!self.olConnect) { self.showPopup("#f00", "#fff", 'Connection error', 'The BookReader cannot reach Open Library. This might mean that you are offline or that Open Library is down. Please check your Internet connection or try again later.'); clearInterval(self.poller); self.ttsPoller = null; } else { self.olConnect = false; //be sure to add random param to authUrl to avoid stale cache var authUrl = self.authUrl+'?rand='+Math.random(); if (false !== self.loanUUID) { authUrl += '&loan='+self.loanUUID } $.ajax({url:authUrl, dataType:'jsonp', jsonpCallback:'olAuth.callback'}); } },300000); //five minute interval } br.cleanupMetadata(); if (br.olAuth) { var olAuth = new OLAuth(); olAuth.init(); } else { br.init(); } if (typeof(archive_analytics) != 'undefined') { var values = { 'bookreader': 'fatal', 'description': "", 'itemid': "", 'server': "", 'request_uri': "" } if (document.referrer == '') { values['referrer'] = '-'; } else { values['referrer'] = document.referrer; } var qs = archive_analytics.format_bug(values); var error_img = new Image(100,25); error_img.src = archive_analytics.img_src + "?" + qs; } alert(""); addToAccessFormats)) { if ("false" == strtolower(trim($page->addToAccessFormats))) { return false; } } return true; } // 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 $imageFormats = array('JP2' => 'jp2', 'TIFF' => 'tif', 'JPEG' => 'jpg'); $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)) { // 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']); } } } } return array('imageFormat' => 'unknown', 'archiveFormat' => 'unknown', 'imageStackFile' => 'unknown'); } ?>