myInfo::MY_LAST_FM_PUBLIC_KEY, 'secret' => myInfo::MY_LAST_FM_PRIVATE_KEY, 'username' => myInfo::MY_LAST_FM_USER_NAME ); /** * This is an authorized response from the LastFM API letting us make further requests to the API * @access private * @var lastfmApiAuth Object */ private $lastFMAuthority; //Not sure why I need this, but you do need to say your application is enabled for the LastFM API to work properly private $lastFMConfig = array( 'enabled' => true, 'path' => './lastfmapi/', 'cache_length' => 1800 ); /** * This is an instance of tha LastFM API we need it to fetch data eventually * @access private * @var lastfmApi Object */ private $lastFMAPI; /** * This is an instance of facebookLib an extension to the official facebook open graph class * @access private * @var Facebook object */ private $facebook; /** * This is an instance of the official Facebook access token, you need this to make some requests * @access private * @var Facebook object */ private $facebookAccessToken; /** * This is an instance of the official Facebook session you need this to make some requests * @access private * @var Facebook object */ private $facebookSession; /** * This is an instance a phpBrainz object it is necessary to use phpBrainz and thus MusicBrainz.org easily * @access private * @var Facebook object */ private $theBrainz; // PHP doesn't support multiple constructors so like everything they have a work around or two... public function __construct($input) { if (is_array($input)) { // Initialize albums array with input. } else if ($input instanceof SimpleXMLElement) { // Initialize albums array by parsing the XML. } else if(is_string($input)) { // Initialize albums array by reading from CSV file $this->albums = createArrayFromCSVFile($input); } else { throw new Exception('Wrong input type, to albumCollection constructor.'); } if(! $this->hasAlbums()) { //This should not be empty after the constructor is called... throw new Exception('Album array is empty and the constructor is almost finished, this is just not right. Please check when and how you create an albumCollection object'); } else { // Finish setting up the albumCollection object $this->initializeAPIs(); } } // This initializes the APIs this object/class uses to do stuff protected function initializeAPIs() { $this->amazonAPI = new AmazonProductAPI(); $this->lastFMAPI = new lastfmApi(); $this->lastFMAuthority = new lastfmApiAuth('setsession', $this->lastFMVariables); $this->facebook = new facebookLib(array( 'appId' => myInfo::MY_FACEBOOK_PUBLIC_KEY, 'secret' => myInfo::MY_FACEBOOK_SECRET_KEY, 'cookie' => true )); facebookLib::$CURL_OPTS[CURLOPT_CAINFO] = './ca-bundle.crt'; facebookLib::$CURL_OPTS[CURLOPT_FRESH_CONNECT] = 1; facebookLib::$CURL_OPTS[CURLOPT_PORT] = 443; $this->facebookAccessToken = $this->facebook->getAccessToken(); $this->facebookSession = $this->facebook->getSession(); $this->theBrainz = new phpBrainz(); // I don't want to login to Facebook, or I don't want to have to... /* if ( $this->facebookSession ) { echo 'Logout of Facebook'; } else { echo 'Login to Facebook'; } */ } // This should probably be private, but it is mainly for debugging my constructor, constructors shouldn't be this problematic... protected function dumpAlbumArrayContents() { if(!empty($this->albums)) { print_r('These are the contents of the albums array currently:'); print('
'); echo '
';
				print_r($this->albums);
				echo '
';
			}
			else
			{
				// Will this ever happen now that I got my constructor and  private variable accessing more correct
				print_r('There is nothing in the albums array right now.' . '
'); } } /** * This is a method that shouldn't be called much as it is a brute force dump of the entire album collection * fetching the images from Amazon and linking to the artist profile on Last.fm, this could be a lot of * calls to APIs, but it is what I originally thought about doing, so I implemented it as furth proof of concept * * Warning: Calling this method on a collection of more than single digits is really slow, not sure how I'll speed it up... * */ public function galleryForEntireCollection() { // This can take a long time to run the very first time on large cd collections, I don't recommend using this method if($this->hasAlbums()) { // Highly likely we find something in some database in this case print(""); } } // Added caching to this function, simple but hopefully effective means to speed up my albumCollection private function getAlbumXMLFromAmazon($albumInfoArray) { if(count($albumInfoArray) >= 2) { // Some data from cds.csv is passing in empty arrays to this method $strippedAlbumName = $albumInfoArray[0] . "-" . $albumInfoArray[1]; //This should be a unique and human readable file name $strippedAlbumName = preg_replace("/[^a-zA-Z0-9]/", "", $strippedAlbumName); if(is_array($albumInfoArray) && strlen($strippedAlbumName) > 0) { $myCache = new Caching("./AlbumCollectionCache/Amazon/", $strippedAlbumName); if ($myCache->needToRenewData()) { try { $result = $this->amazonAPI->getAlbumCoverByArtistAndTitle($albumInfoArray[0], $albumInfoArray[1]); } catch(Exception $e) { echo $e->getMessage(); } $myCache->saveXMLToFile($result); // Save new data before we return it to the caller of the method } else { // It doesn't need to be renewed so use local copy $result = $myCache->getLocalXML(); } } else { throw new Exception('Incorrect data type passed to getAlbumXMLFromAmazon()'); } } else { // What to do about this? Currently it is throwing a warning... $result = null; } return $result; } // This method is similar to the one above, it is private and is the one place so far I make artist data requests from Last.fm // The advantage of doing it in only one place, besides less code is I knew exactly where to put in the caching... private function getArtistInfoFromLastFM($artistName) { $strippedArtistName = $artistName; $strippedArtistName = preg_replace("/[^a-zA-Z0-9]/", "", $strippedArtistName); if(strlen($strippedArtistName) > 0) { $myCache = new Caching("./AlbumCollectionCache/LastFM/", $strippedArtistName); $artistClass = $this->lastFMAPI->getPackage($this->lastFMAuthority, 'artist', $this->lastFMConfig); $methodVars = array( 'artist' => $artistName ); if ($myCache->needToRenewData()) { try { // result is an array not a simpleXML Object $result = $artistClass->getInfo($methodVars); } catch(Exception $e) { echo $e->getMessage(); } $reformatedResult = serialize($result); $myCache->saveSerializedDataToFile($reformatedResult); } else { // It doesn't need to be renewed so use local copy of array $result = $myCache->getUnserializedData(); } } return $result; } // Although Matt's code is a bit unrefined and frequently Last.fm doesn't have all the information I need, it's album.getInfo // Is a good second choice to find track information or even image information. I still prefer to check Amazon.com first as // They have a lot of high res images, hopefully previewable tracks, and of course the potential of making money from referrals. private function getAlbumInfoFromLastFM($artistName, $albumTitle) { $fileName = $artistName . '-' . $albumTitle; $fileName = preg_replace("/[^a-zA-Z0-9]/", "", $fileName); // I think this removes the slash, I just put in, but maybe not RegEx is not my specialty if(strlen($fileName) > 0) { $myCache = new Caching("./AlbumCollectionCache/LastFM/", $fileName); $albumClass = $this->lastFMAPI->getPackage($this->lastFMAuthority, 'album', $this->lastFMConfig); // Setup the variables $methodVars = array( 'artist' => $artistName, 'album' => $albumTitle ); if ($myCache->needToRenewData()) { try { $result = $albumClass->getInfo($methodVars); // This method is problematic, Matt/My code needs more work... } catch (Exception $e) { // This getInfo method throws a lot more errors than artist does... echo $e->getMessage(); } $reformatedResult = serialize($result); $myCache->saveSerializedDataToFile($reformatedResult); } else { // It doesn't need to be renewed so use local copy of array $result = $myCache->getUnserializedData(); // This is where things go south... } } /* // Caching ripped out... $albumClass = $this->lastFMAPI->getPackage($this->lastFMAuthority, 'album', $this->lastFMConfig); // Setup the variables $methodVars = array( 'artist' => $artistName, 'album' => $albumTitle ); try { $result = $albumClass->getInfo($methodVars); // This method is problematic, Matt/My code needs more work... } catch (Exception $e) { // This getInfo method throws a lot more errors than artist does... echo $e->getMessage(); }*/ return $result; } // Although I don't make many calls to iTunes as I use Amazon for the primary image source and Last.fm as the primary source for // artist bios. Apple returns a lot of information when you make a search call, so I might as well cache it. Caching will be // done the same way as for Last.fm using serialize and unserialze. Apple iTunes Store returns JSON formatted strings which can be // turned into objects easily enough private function getArtistResultsFromITunes($artistName) { $iTunesInfo = null; $strippedArtistName = $artistName; $strippedArtistName = preg_replace("/[^a-zA-Z0-9]/", "", $strippedArtistName); if(is_string($artistName) && strlen($strippedArtistName) > 0) { $myCache = new Caching("./AlbumCollectionCache/iTunes/", $strippedArtistName); if ($myCache->needToRenewData()) { try { $formattedArtistString = str_replace(' ', '+', $artistName); $iTunesSearchString = 'http://ax.itunes.apple.com/WebObjects/MZStoreServices.woa/wa/wsSearch?term=' . $formattedArtistString . '&entity=musicArtist'; $searchResult = fetchThisURL($iTunesSearchString); $iTunesInfo = json_decode($searchResult); } catch(Exception $e) { echo $e->getMessage(); } $serializedObject = serialize($iTunesInfo); $myCache->saveSerializedDataToFile($serializedObject); } else { // It doesn't need to be renewed so use local copy of array $iTunesInfo = $myCache->getUnserializedData(); } } else { throw new Exception('Incorrect data type passed to getArtistResultsFromITunes()'); } return $iTunesInfo; } // Apple iTunes Music Store is one place I can get preview of tracks. // After getting this method to work like I want, including caching the information return by iTunes Music Store, I decided I might try // and use this information to supplement my cover image fetching... I still won't make any money off of iTunes but the more covers // the better my original gallery idea looks. // Apple iTunes store returns JSON formatted strings which can be turned into objects easily enough private function getAlbumAndTracksFromITunes($iTunesID, $albumName) { $iTunesInfo = null; $properFileName = $iTunesID . $albumName; $properFileName = preg_replace("/[^a-zA-Z0-9]/", "", $properFileName); if(strlen($properFileName) > 0) { $myCache = new Caching("./AlbumCollectionCache/iTunes/", $properFileName); if ($myCache->needToRenewData()) { try { // First get all the albums by an artist using a lookup request //http://ax.itunes.apple.com/WebObjects/MZStoreServices.woa/wa/wsLookup?id=909253&entity=album $iTunesLookUpString = 'http://ax.itunes.apple.com/WebObjects/MZStoreServices.woa/wa/wsLookup?id=' . $iTunesID . '&entity=album'; $lookUpResult = fetchThisURL($iTunesLookUpString); // Now we have the look up results but we need to find the $iTunesID for the correct album then get the tracks that go with it // We need collectionName to equal $albumName $lookUp = json_decode($lookUpResult); if ( ! empty($lookUp)) { $resultCount = $lookUp->resultCount; // This isn't always correct, maybe have to check more the result returned... $i = 1; // First result is the artist not an album, I already had the artist info from iTunes... $collectionID = null; while(($i < $resultCount) && ($collectionID == null)) { // Look for album in iTunes... $collectionName = (string) $lookUp->results[$i]->collectionName; if( strcasecmp($collectionName, $albumName) == 0) { // We have our match $collectionID = $lookUp->results[$i]->collectionId; } // remember to increment! $i++; } if( $collectionID != null) { // If collectionID isn't null... lookup album again in iTunes with tracks and that is what we really really want! // cache and return... //http://ax.itunes.apple.com/WebObjects/MZStoreServices.woa/wa/wsLookup?upc=075678317729&entity=song $newLookupString = 'http://ax.itunes.apple.com/WebObjects/MZStoreServices.woa/wa/wsLookup?id=' . $collectionID . '&entity=song'; $newLookUpResult = fetchThisURL($newLookupString); $iTunesInfo = json_decode($newLookUpResult); $serializedObject = serialize($iTunesInfo); $myCache->saveSerializedDataToFile($serializedObject); } } } catch(Exception $e) { echo $e->getMessage(); } } else { // It doesn't need to be renewed so use local copy $iTunesInfo = $myCache->getUnserializedData(); } } return $iTunesInfo; } // Although I don't make many calls to MusicBrainz as I use Amazon for the primary image source and Last.fm as the primary source for // artist bios. MusicBrainz has a lot of information and requires no authorization to use it. Caching will be // done the same way as for Last.fm using serialize and unserialze. MusicBrainz using phpBrainz uses it's own custom Objects. private function getReleaseFromMusicBrainz($albumASIN) { //ASIN's are unique and don't have spaces or garbage characters, hooray! $myCache = new Caching("./AlbumCollectionCache/MusicBrainz/", $albumASIN); if ($myCache->needToRenewData()) { try { $args = array( "asin"=>$albumASIN ); $releaseFilter = new phpBrainz_ReleaseFilter($args); $releaseResults = $this->theBrainz->findRelease($releaseFilter); // It says this returns an array! if( ! empty($releaseResults)) { // Not all phpBrainz_Release Objects are created equal // This is maybe why I'm not getting tracks... $trackIncludes = array( "artist", "discs", "tracks" ); // I need the musicbrainz ID for the release I just found... $mbid = $releaseResults[0]->getId(); $musicBrainzRelease = $this->theBrainz->getRelease($mbid, $trackIncludes); // This gets better results from MusicBrainz.org } else { $musicBrainzRelease = $releaseResults; // This is a new idea and may just be a waste of time without having found tracks... } } catch(Exception $e) { echo $e->getMessage(); } $serializedObject = serialize($musicBrainzRelease); $myCache->saveSerializedDataToFile($serializedObject); } else { // It doesn't need to be renewed so use local copy of array $musicBrainzRelease = $myCache->getUnserializedData(); } return $musicBrainzRelease; } // This is the worker function for a method that I wrote to get the Facebook Badge, but then retired it in preference to a like button // I never got full Facebook integration working to my satisfaction, even with facebookLib, but I can search the Graph API using curl. // This is returning a JSON Object that I decoded from Facebook's Open Graph private function getFacebookPageForArtist($artistName) { $facebookPage = null; if ($artistName != null) { $this->facebook->setDecodeJson(true); $possibleArtists = $this->facebook->search('page', $artistName); if($possibleArtists->data != null ) // This is giving me grief for various artists... { $firstID = $possibleArtists->data[0]->id; // This is a bit of fakery, an end around if you will $graphURL = Facebook::$DOMAIN_MAP['graph'] . $firstID; $resultingString = fetchThisURL($graphURL); if(is_string($resultingString)) { $facebookPage = json_decode($resultingString); } else { // We're not getting a string in JSON format WTF! // Probably should throw exception here, Facebook support is still a WIP print('
');
						print_r($resultingString);  
						print('
'); } } } return $facebookPage; } /** * Returns the current album as an array of information from Last.fm corresponding to the artist's getArtistInfo * If the artist isn't in the Last.fm system it throws an error... * * &return array */ public function currentAlbumArtistInfoFromLastFM() { $artistInfo; $artistName = $this->currentAlbumArtist(); if ( ! empty($artistName)) { $artistInfo = $this->getArtistInfoFromLastFM($artistName); } else { $artistInfo = null; } return $artistInfo; } /** * Returns a string consisting of a link and an image (icon) for the Last.fm service, the link goes to the * artist info page for the current album's artist on Last.fm. I decided to return valid HTML as I thought this * would save some time later on and some services it is much more elaborate to get the correct info and link to work. * * @return string; */ public function currentAlbumLastFMArtistBadge() { $htmlTag = null; $artistInfo = $this->currentAlbumArtistInfoFromLastFM(); if(strcmp($artistInfo["name"], "various") != 0) { $openLinkTag = ''; $closeLinkTag = ''; $iconTag = ''; $htmlTag = $openLinkTag . $iconTag . $closeLinkTag; } return $htmlTag; } /** * Returns a string consisting of a link and an image (icon) to the album on Amazon.com, I decided to return valid HTML as I thought this * would save some time later on and some services it is much more elaborate to get the correct info and link to work. The link returned has * an Amazon Associate tag as detailed here: * http://www.kavoir.com/2009/05/build-simple-amazon-affiliate-text-links-with-just-asin-10-digit-isbn-and-your-amazon-associate-tracking-id.html * * @return string; */ public function currentAlbumAmazonAssociateBadge() { $htmlTag = null; $amazonProductURL = $this->currentAlbumAmazonProductURL(); if(strcmp($amazonProductURL, "#") != 0) { $openLinkTag = ''; $closeLinkTag = ''; $iconTag = ''; $htmlTag = $openLinkTag . $iconTag . $closeLinkTag; } return $htmlTag; } /** * This method just returns the URL to the product page using the ASIN and will append on your Amazon Associate ID so you can * potentially earn a commision. If the item isn't in Amazon, well return the hash symbol which just reloads the page... * * @return string; */ public function currentAlbumAmazonProductURL() { $albumASIN = $this->currentAlbumASIN(); if($albumASIN != null) { $amazonProductURL = 'https://www.amazon.com/dp/' . $albumASIN . '?tag=' . myInfo::MY_AMAZON_ASSOCIATE_ID; } else { $amazonProductURL = "#"; // return hash instead of null or empty string so it just reloads the page } return $amazonProductURL; } /** * Returns a string consisting of a link and an image (icon) for the Apple iTunes store, the link goes to the * artist info page for the current album's artist. I decided to return valid HTML as I thought this * would save some time later on and some services it is much more elaborate to get the correct info and link to work. * Apple's iTunes Associate program isn't available in Canada but if it were, this is where you'd want to put in your associate ID * * I now cache the JSON results return from Apple as serialized objects in the method getArtistResultsFromITunes() * * @return string; */ public function currentAlbumITunesArtistBadge() { $finalHTML = null; $artistName = $this->currentAlbumArtist(); try { $iTunesInfo= $this->getArtistResultsFromITunes($artistName); } catch(Exception $e) { throw new Exception("Something went wrong while attempting to access iTunes data on: " . $artistName); } if ( count($iTunesInfo->results) > 0) { $iTunesArtistLink = $iTunesInfo->results[0]->artistLinkUrl; $openLinkTag = ''; $closeLinkTag = ''; $iconTag = ''; $finalHTML = $openLinkTag . $iconTag . $closeLinkTag; } return $finalHTML; } /** * This method uses Facebook's Open Graph format to search for a page or more likely pages corresponding to an artist in * Facebook's social graph. * The most likely URL is chosen for an artist/musician and then we creat the HTML tags necessary to display a little Facebook badge * * @return string */ public function currentAlbumFacebookArtistBadge() { // I'm not caching facebook requests after all the open graph err social graph is constantly changing... $artistName = $this->currentAlbumArtist(); $artistFacebookPage = $this->getFacebookPageForArtist($artistName); $openLinkTag = ''; $closeLinkTag = ''; $iconTag = ''; $htmlTag = $openLinkTag . $iconTag . $closeLinkTag; // Old way new way /* $this->facebook->setDecodeJson(true); $searchString = '"' . $artistName . ' Musician"'; // What do I use this for now? $possibleArtists = $this->facebook->search('page', $artistName); if( ! is_array($possibleArtists)) { $firstID = $possibleArtists->data[0]->id; // I need to make a request for client_credentials here or likely when I create the Facebook object, but what arguments to pass into // makeRequest // Time for some fakery... $graphURL = Facebook::$DOMAIN_MAP['graph'] . $firstID; $resultingString = fetchThisURL($graphURL); if(is_string($resultingString)) { $facebookPage = json_decode($resultingString); $openLinkTag = ''; $closeLinkTag = ''; $iconTag = ''; $htmlTag = $openLinkTag . $iconTag . $closeLinkTag; } else { // We're not getting a string in JSON format not an array... print('
');
					print_r($resultingString);  
					print('
'); } } else { // We're getting an array... print('
');
				print_r($possibleArtists);  
				print('
'); } */ return $htmlTag; } /** * This method goes a step further than the one above, both use Facebook's Open Graph format to search for a page or more likely pages * corresponding to an artist in Facebook's social graph. * The most likely URL is chosen for an artist/musician and then we creat the HTML tag necessary to display a fully functional like button * * @return string */ public function currentAlbumFacebookLikeButton() { // Needs to produce HTML that looks like this: /* */ // replace example.com with say $facebookPage->link from above and you're golden $htmlTag = null; $artistName = $this->currentAlbumArtist(); $this->facebook->setDecodeJson(true); $possibleArtists = $this->facebook->search('page', $artistName); if( ! empty($possibleArtists->data)) { $firstID = $possibleArtists->data[0]->id; $graphURL = Facebook::$DOMAIN_MAP['graph'] . $firstID; $resultingString = fetchThisURL($graphURL); if(is_string($resultingString)) { $facebookPage = json_decode($resultingString); $strippedURL = urlencode($facebookPage->link); $openLinkTag = ''; $htmlTag = $openLinkTag . $strippedURL . $closeLinkTag; } else { // We're not getting a string in JSON format print('
');
					print_r($resultingString);  // nor is this...
					print('
'); } } return $htmlTag; } /** * This method creates a fully functional "Tweet This" button. You don't need to register an app at Twitter to just do this. * It uses Twitter's Javascript but it passes in text and variables concerning the current album and pulls information from * myInfo.php specifically MY_TWITTER_ACCOUNT and MY_HOME_PAGE * * @return string */ public function currentAlbumTweetThisButton($tweet = myInfo::DEFAULT_TWEET) { // This method needs to produce HTML that looks like this: /* */ $tweetThisButtonCode = null; $albumInfo = $this->currentAlbumAsArray(); $twitterDataURL = myInfo::MY_HOME_PAGE; $twitterDataBy = myInfo::MY_TWITTER_ACCOUNT; $openingTag = ''; $tweetThisButtonCode = $openingTag . "Tweet" . $closingTag; return $tweetThisButtonCode; } /** * Returns the current album in array form based on currentAlbumIndex * Made this private to obscure the underlying array from users of this class. * * @return array */ private function currentAlbumAsArray() { return $this->albums[$this->currentAlbumIndex]; } /** * Returns the current album's artist, ie the first item in currentAlbumAsArray * * @return string */ public function currentAlbumArtist() { $anAlbum = $this->currentAlbumAsArray(); $artistName = $anAlbum[0]; if ($artistName == null) { $artistName = "unknown"; // This is better than returning null or nothing... } return $artistName; } /** * Returns the current album's album title, ie the second item in currentAlbumAsArray * * @return string */ public function currentAlbumTitle() { $anAlbum = $this->currentAlbumAsArray(); return $anAlbum[1]; } /** * Returns the current album's artist bio, which it can get from Last.fm or someplace else... * * @return string */ public function currentAlbumArtistBio() { $artistName = $this->currentAlbumArtist(); $artistBio = $artistName . "'s bio is proving tough to locate."; $facebookPage = null; // Now where should we look, might as well start with Last.fm, that is already cached and debugged a fair amount. try { $lastFMResults = $this->currentAlbumArtistInfoFromLastFM(); } catch (Exception $e) { // getInfo in Last.fm at least in Matt's code can go astray... // Just catch exceptions and move on... } if ( ! empty($lastFMResults) ) { // Now check that there is actually a short bio, sometimes an artist is in Last.fm but lots of data is missing. if ( ! empty($lastFMResults["bio"]["summary"])) { // Success $artistBio = $lastFMResults["bio"]["summary"]; $facebookPage = "Is unnecessary."; } } if ( $facebookPage == null ) { // We need to try a little harder and iTunes isn't the place to do it, try Facebook instead... $facebookPage = $this->getFacebookPageForArtist($artistName); if ( ! empty($facebookPage->bio)) { $artistBio = $facebookPage->bio; // This one should go first I think } elseif( ! empty($facebookPage->description)) { $artistBio = $facebookPage->description; // This was my very first attempt to get a bio from Facebook } elseif ( ! empty($facebookPage->personal_info)) { $artistBio = $facebookPage->personal_info; // This will work for Booker T and the MGs } elseif ( ! empty($facebookPage->link)) { $artistBio = 'Perhaps try this link for more information on ' . $artistName . '. Never know it could be useful after all.'; } else { // What now? print("
");
         			print_r($facebookPage);
         			print("
"); // This happens for Koerner & Murphy but I swear Amazon had data on them. try { $xmlFromAmazon = $this->amazonAPI->searchProducts($artistName, AmazonProductAPI::CATEGORY_MUSIC, AmazonProductAPI::TYPE_ARTIST, AmazonProductAPI::RESPONSE_GROUP_LARGE); if ( count($xmlFromAmazon->Items) > 0) { if( ! empty($xmlFromAmazon->Items->Item[0]->CustomerReviews)) { $artistBio = $xmlFromAmazon->Items->Item[0]->CustomerReviews->Review[0]->Content; // This is far from ideal... } } } catch (Exception $e) { // This time I want to see 'em at least for a while // throw new Exception($e->getMessage); } // If I can't find a bio in Amazon may have to try Google! // But not tonight... maybe some other API a people finding one or something... } } $betterBio = preg_replace("/[^(\x20-\x7F)]*/", "", $artistBio); // Too much garbage is in some of these results, I want <, >, and quotation marks though return $betterBio; } /** * Creats a random number and assigns that to the currentAlbumIndex then returns the new currentAlbumAsArray() * After calling this just use the various methods that return data for the current album or get another random album * This method is now private, as usually the user wants a random album that satisfies some condition. * * @return array */ private function randomAlbumAsArray() { $oldIndex = $this->currentAlbumIndex; if ($this->collectionSize() < 3) { throw new Exception("This collection is less than three albums, why are you wasting time calling randomAlbumAsArray on a collection this small?"); } else { $newIndex = rand(0, ($this->collectionSize() - 1)); while($newIndex == $oldIndex) { // I want it random, but I don't want it to ever return the same album $newIndex = rand(0, ($this->collectionSize() - 1)); } $this->currentAlbumIndex = $newIndex; } return $this->currentAlbumAsArray(); } /** * Sets current album to be a random album, for which the artist, ie cell 0 in the array isn't various. * I return the information as an array but with minimal information currently. Once it is the currentAlbum you can get piles of data * * @return array */ public function randomAlbumNotByVarious() { // This will mean I am more likely to get useful data from most APIs and then I can mash it up. $validAlbum = array(); // is this valid PHP? $randomAlbum = $this->randomAlbumAsArray(); if( ! $this->isCurrentAlbumByVarious() ) { //Hooray $validAlbum = (array) $randomAlbum; } else { // Continue Random Recursive search $validAlbum = (array) $this->randomAlbumNotByVarious(); } return $validAlbum; } /** * Since what I really care about is albums in the my collection that I can get valid album covers for * I needed a method to get only albums with both a medium and large images as they look * the best in galleries. Amazon is my primary source for album covers. * With caching working now this shouldn't be that inefficient but on a large collection with a lot of obscure old * albums that are out of print, well this method could take a while, I don't want it to time out so I only try so hard... * * @return array */ public function randomAlbumWithMediumAndLargeImagesAsArray() { // This method will obviously use randomAlbumAsArray() and various current album methods until it finds one that satisfies all the // conditions, this could concievably take forever, now that I look at the code in the morning... but the odds of that on a decent // sized collection are very small... $randomAlbum = $this->randomAlbumAsArray(); $mediumImageURL = $this->currentAlbumsMediumImageURL(); $largeImageURL = $this->currentAlbumsLargeImageURL(); while((strcmp($mediumImageURL, myInfo::MISSING_COVER_URL) == 0) || (strcmp($largeImageURL, myInfo::MISSING_COVER_URL) == 0)) { $this->goToNextAlbum(); $mediumImageURL = $this->currentAlbumsMediumImageURL(); $largeImageURL = $this->currentAlbumsLargeImageURL(); } return $this->currentAlbumAsArray(); // We've found one that satisfied conditions and it is now the currentAlbum } /** * The initial two APIs I integrated into albumCollection.php were last.fm and Amazon Product API * so I wanted a means of getting an album with all three cover images, plus some basic information on the artist * from Last.fm, I then returned this as an array with non-numerical indices for ease of use. * * &return array */ public function randomAlbumWithThreeImagesAndArtistInfo() { $hasArtistInfo = false; $hasLargeImage = false; $hasMediumImage = false; $hasSmallImage = false; $counter = 0; // I don't want any infinite loops, so I give it five tries... $randomAlbum = $this->randomAlbumWithMediumAndLargeImagesAsArray(); while (($counter < 5) && (!$hasArtistInfo || !$hasLargeImage || !$hasMediumImage || !$hasSmallImage)) { $counter++; $hasLargeImage = true; $hasMediumImage = true; $possibleSmallImage = $this->currentAlbumsSmallImageURL(); if((strcmp($possibleSmallImage, myInfo::MISSING_COVER_URL) != 0) && (! $this->isCurrentAlbumByVarious())) { // We have a useful small image $hasSmallImage = true; // Finally see if we have useful artist info try { $artistInfo = $this->currentAlbumArtistInfoFromLastFM(); // Not only do we want $artistInfo we want it to have at least some data if(!empty($artistInfo)) { $hasArtistInfo = true; } } catch(Exception $e) { // Although we have an exception we're going to deal with it here... // In this case we do nothing and let the while loop iterate again... // Lets try the album next door $this->goToNextAlbum(); $hasSmallImage = false; // WAsn't doing this before. Still not so sure on just stepping over, no guarantee it has Large Imaget etc. } } else { // We need a different random album $randomAlbum = $this->randomAlbumWithMediumAndLargeImagesAsArray(); } } // Now we should have valid information so we need to make a pretty array and return it $basicInfo = $this->currentAlbumAsArray(); $usefulInfo = array( 'artist' => $basicInfo[0], 'album' => $basicInfo[1], 'largeImageURL' => $this->currentAlbumsLargeImageURL(), 'mediumImageURL' => $this->currentAlbumsMediumImageURL(), 'smallImageURL' => $this->currentAlbumsMediumImageURL(), 'artistInfoURL' => $artistInfo['url'], 'shortArtistBio' => $artistInfo["bio"]["summary"] ); // If we don't succeed in finding a valid album, well it'll probably throw an exception before now, that's what debugging is for... return $usefulInfo; } /** * Worried about efficiency and thinking how people will actually use the class, it seems that the hardest information to find online * is supposedly high resolution album images, which is why you have to use the Amazon API which is why you jump through all the Amazon.com * hoops. To this end this method returns a random album which has a large image URL, plus that album's artist info from * Last.fm, it returns an array with the same formating and all the info as the method above and sets this random album to be the current album * * @return array; */ public function randomAlbumWithLargeImageAndArtistInfo() { $randomAlbumInfo = $this->randomAlbumAsArray(); $largeImageURL = $this->currentAlbumsLargeImageURL(); while(strcmp($largeImageURL, myInfo::MISSING_COVER_URL) == 0) { $randomAlbumInfo = $this->randomAlbumAsArray(); $largeImageURL = $this->currentAlbumsLargeImageURL(); } // When we escape the while loop we have an album with a valid large image set as the current album // It probably has artist info, but we need to check if(strcasecmp("various", $randomAlbumInfo[0]) != 0) { $artistInfo = $this->currentAlbumArtistInfoFromLastFM(); // Currently not encased in try catch structure, should probably be. } else { $artistInfo = null; } if(empty($artistInfo)) { // We need to try again $results = $this->randomAlbumWithLargeImageAndArtistInfo(); } else { $results = array( 'artist' => $randomAlbumInfo[0], 'album' => $randomAlbumInfo[1], 'largeImageURL' => $largeImageURL, 'mediumImageURL' => $this->currentAlbumsMediumImageURL(), 'smallImageURL' => $this->currentAlbumsSmallImageURL(), 'artistInfoURL' => $artistInfo['url'], 'shortArtistBio' => $artistInfo["bio"]["summary"] ); } return $results; } /** * Even with the limitations on the two random access methods above, they still are probably more computationally intensive than sequential * access. I recommend getting a single random album then calling one of the nextAlbum style methods. * This method returns data in the same format as it's random counterpart above. * * &return array */ public function nextAlbumWithThreeImagesAndArtistInfo() { $counter = 0; while($counter < $this->collectionSize()) //This still could go around more than once technically { $largeImageURL = $this->getNextValidLargeAlbumCoverImageURL(); // This method will do a fair amount of work for us. $counter++; // This is not an accurate count here, but it keeps it from going too wild if((strcmp($this->currentAlbumsMediumImageURL(), myInfo::MISSING_COVER_URL) != 0) && (strcmp($this->currentAlbumsSmallImageURL(), myInfo::MISSING_COVER_URL) != 0) && (! $this->isCurrentAlbumByVarious())) { try { $artistInfo = $this->currentAlbumArtistInfoFromLastFM(); // Not only do we want $artistInfo we want it to have at least some data if( ! empty($artistInfo)) { // This is not a sufficient test perhaps $counter = ($this->collectionSize() + 1); // This will break the while loop } } catch(Exception $e) { // Although we have an exception we're going to deal with it here... // In this case we do nothing and let the while loop iterate again... // Lets try the album next door $this->goToNextAlbum(); $counter++; } } else { $this->goToNextAlbum(); $counter++; } } // Now the current album has the data we want $basicInfo = $this->currentAlbumAsArray(); $usefulInfo = array( 'artist' => $basicInfo[0], 'album' => $basicInfo[1], 'largeImageURL' => $this->currentAlbumsLargeImageURL(), 'mediumImageURL' => $this->currentAlbumsMediumImageURL(), 'smallImageURL' => $this->currentAlbumsMediumImageURL(), 'artistInfoURL' => $artistInfo['url'], 'shortArtistBio' => $artistInfo["bio"]["summary"] ); // If we don't succeed in finding a valid album, well it'll probably throw an exception before now, that's what debugging is for... return $usefulInfo; } /** * Returns the current album in amazon XML form based on currentAlbumIndex * I currently use the Images ResponseGroup in the method in AmazonAPI that does the fetching * Don't overlook this fact. Methods like this will be minimal as they force the user of this class * to learn the AmazonXML format... * * @return XML Object from Amazon.com */ public function currentAlbumAsAmazonXML() { return $this->getAlbumXMLFromAmazon($this->currentAlbumAsArray()); } /** * Returns the current album's ASIN which is a unique identifier used for Amazon.com in their webstore. It is also used * by MusicBrainz which is why I implemented a private method to fetch just the ASIN. * * @return String */ private function currentAlbumASIN() { $albumASIN = null; $albumXML = $this->currentAlbumAsAmazonXML(); if($albumXML->Items->TotalResults > 0) { $albumASIN = $albumXML->Items->Item->ASIN; } return $albumASIN; } /** * This method searches MusicBrainz.org for information using the current album's ASIN. The returned information is in the form of * a release which in MusicBrainz lingo can be an album, a single, or a compilation. In most cases it will be an album but the other two * are valid. Once we have the release from MusicBrainz we can use that info to fetch tracks or track listings. * * @return phpBrainz_Release Object */ public function currentAlbumAsMusicBrainzRelease() { $albumASIN = $this->currentAlbumASIN(); // if $albumASIN is not found we just abort... if ( ! empty($albumASIN)) { $results = $this->getReleaseFromMusicBrainz($albumASIN); // Might have to check if string is null instead... } else { $results = null; } return $results; } // Look for this data in the iTunes Store Search API private function findCurrentAlbumTracksInITunes() { $iTunesTracks = null; $artistName = $this->currentAlbumArtist(); $albumTitle = $this->currentAlbumTitle(); try { $iTunesArtistInfo = $this->getArtistResultsFromITunes($artistName); if ( count($iTunesArtistInfo->results) > 0) // insufficient $iTunesArtistInfo != null { $iTunesAlbumInfo = $this->getAlbumAndTracksFromITunes($iTunesArtistInfo->results[0]->artistId, $albumTitle); if($iTunesAlbumInfo != null) { // Hooray! /* print("
");
						print_r($iTunesAlbumInfo);
						print("
"); */ for( $i = 1 ; $i < count($iTunesAlbumInfo->results); $i++) { // I should look at this again... Damn Tom Waits album! // The first result is the album/artist info with the tracks taking up the rest of the space in the results array $correctIndex = $i - 1; $iTunesTracks[$correctIndex]['title'] = $iTunesAlbumInfo->results[$i]->trackName; $iTunesTracks[$correctIndex]['URL'] = $iTunesAlbumInfo->results[$i]->previewUrl; // Tom Waits Orphans has more tracks than it has previews... It screws up my code... } } } } catch (Exception $e) { // Finding tracks is tough, if you can't find them, just catch the error and try another API... throw new Exception("Not going to get Tracks for: " . $albumTitle . " from iTunes."); } return $iTunesTracks; } // Look for this data in the Amazon Product API private function findCurrentAlbumTracksInAmazon() { // While debugging this method, Amazon.com throttled me, they returned a response saying that... $amazonTracks = null; try { $initialAmazonXML = $this->amazonAPI->getRelatedItemsByAsin($this->currentAlbumASIN()); if ($initialAmazonXML->Error == null) { if ( count($initialAmazonXML->Items) > 0) { print("Found Initial Item.
"); // Debugging Amazon... if (count($initialAmazonXML->Items->Item->RelatedItems) > 0) { $parentASIN = $initialAmazonXML->Items->Item->RelatedItems->RelatedItem->Item->ASIN; // this is a long chain to get the parent... if ( ! empty($parentASIN)) { print("Still got the Parent ASIN? " . $parentASIN); // I may have done something bad... or at least wrong $furtherAmazonXML = $this->amazonAPI->getRelatedItemsByAsin($parentASIN); if (count($furtherAmazonXML->Items) > 0) { if (count($furtherAmazonXML->Items->Item->RelatedItems) > 0) { print(" Now for the even harder part.
"); // Does this code ever run? // Now I need to find out which is the MP3 album so I can get the tracks of this. Gotta fetch them all till // something more clever comes around. I think iTunes will be my first destination, then Amazon, then Last.Fm then MusicBrainz $x = 0; $foundMP3Album = false; while (($x < $furtherAmazonXML->Items->Item->RelatedItems->RelatedItemCount) && ( ! $foundMP3Album)) // RelatedItemCount not items... { $tempASIN = $furtherAmazonXML->Items->Item->RelatedItems->RelatedItem[$x]->ASIN; $moreAmazonXML = $this->amazonAPI->getRelatedItemsByAsin($tempASIN); print("
");
											print_r($moreAmazonXML);
											print("
"); } } } } } } } else { // Probably been throttled, Amazon isn't so great for getting tracks or previews... print("I'm beeing throttled by Amazon, oh well...

"); } } catch(Exception $e) { // Just ignore eventually... throw new Exception($e->getMessage); } return $amazonTracks; } // Look for this data in Last.fm private function findCurrentAlbumTracksInLastFM() { $lastFMTracks = null; // Going to move code and set up some caching as Last.FM album info is useful to me... $artistName = $this->currentAlbumArtist(); $albumTitle = $this->currentAlbumTitle(); try { $album = $this->getAlbumInfoFromLastFM($artistName, $albumTitle); } catch (Exception $E) { // Just catch and move on, see if we can find info in another API } if($album && ( ! empty($album['tracks']))) { // We have found track info in last.fm not bad, but iTunes has playable previews, hopefully Last.fm will have them eventually /* print("
");
				print_r($album);
				print("
"); */ $p = 0; $numberOfTracks = count($album['tracks']); while($p < $numberOfTracks) { $lastFMTracks[$p]['title'] = $album['tracks'][$p]['name']; $lastFMTracks[$p]['URL'] = $album['tracks'][$p]['url']; $p++; } } return $lastFMTracks; } // Look for this data in MusicBrainz.org private function findCurrentAlbumTracksInMusicBrainz() { $tracks = null; try { $musicBrainzAlbumInfo = $this->currentAlbumAsMusicBrainzRelease(); } catch(Exception $e) { // This isn't the end of the world, we just have no track listings to return at all... $musicBrainzAlbumInfo = null; } if( $musicBrainzAlbumInfo != null) { $musicBrainzTracks = $musicBrainzAlbumInfo->getTracks(); // Should return an array of phpBrainz_Track Objects if (is_array($musicBrainzTracks)) { // I think there is an error condition that doesn't return an array... in the phpBrainz code $numberOfTracks = count($musicBrainzTracks); $n = 0; while ( $n < $numberOfTracks) { $tracks[$n]['title'] = (string) $musicBrainzTracks[$n]->getTitle(); // It worked before... It has to be an array I test for that! // There is no URL for tracks in MusicBrainz, yet another reason to do it last. $tracks[$n]['URL'] = $this->currentAlbumAmazonProductURL(); // Just a thought until I think of something better! // Lastly increase index $n++; } } else { print("What the hell is being returned?"); // This should never happen! print("
");
					print_r($musicBrainzTracks);
					print("
"); } } else { print('I tried to find track listings everywhere, even ' . 'MusicBrainz.org maybe you can enter that data into their system.'); // Just to see how often this happens. } return $tracks; } /** * Returns the current album's tracks if I can find them. First try to find playable previews in iTunes, then look for some sort of URL * for the track in Last.fm, lastly look in MusicBrainz... Amazon.com is still a work in progress. * * Searching for track links along with making the custom array means this method is very time consuming. * * @return array of tracks */ public function currentAlbumsTracks() { // This is the biggest most intensive method in the whole class, before I tried once again to have Amazon.com integrated, // It works fairly well and it uses caching, but sometimes it checks multiple APIs and doesn't find any track information, let alone playable previews. // I think I may eventually return two URLs one for info and one for playback eventually... $tracks = array(); // Time for some serious modularity! // First check iTunes for track info $tracks = $this->findCurrentAlbumTracksInITunes(); if ($tracks == null) { // Check Amazon $tracks = $this->findCurrentAlbumTracksInAmazon(); } if ($tracks == null) { // Check Last.fm $tracks = $this->findCurrentAlbumTracksInLastFM(); } if ($tracks == null) { // Check MusicBrainz $tracks = $this->findCurrentAlbumTracksInMusicBrainz(); } return $tracks; } /** * Returns an array of the tags associated with the album in Last.fm. I think Last.fm returns the top five tags. * * @return array of tracks */ public function currentAlbumTags() { $tags = array(); $albumInfo = $this->getAlbumInfoFromLastFM($this->currentAlbumArtist(), $this->currentAlbumTitle()); if ( ! empty($albumInfo)) { if( ! empty($albumInfo['toptags'])) { $tags = $albumInfo['toptags']; // is this sufficient? } } return $tags; } /** * Returns some sort of audio sample if I can find it. Amazon.com has previews but I never can access them so iTunes and Last.fm are the * most likely places I'll get data. Fetching all the tracks and previews for all the tracks like I try to do in currentAlbumTracks is * very intensive and I get throttled by Amazon.com when I try too hard. * * @return string */ public function currentAlbumAudioSample() { // Finding some sort of audio sample shouldn't be hard, finding all the tracks is definitely more work! $bestURL = null; // Just in case I can't find anything, actually I'd probably send them to some sort of artist or product page... // iTunes I got working previously... but if I can't find anything there where to look next? $artistName = $this->currentAlbumArtist(); $albumTitle = $this->currentAlbumTitle(); try { $iTunesArtistInfo = $this->getArtistResultsFromITunes($artistName); if ( count($iTunesArtistInfo->results) > 0) // insufficient $iTunesArtistInfo != null { $iTunesAlbumInfo = $this->getAlbumAndTracksFromITunes($iTunesArtistInfo->results[0]->artistId, $albumTitle); if($iTunesAlbumInfo != null) { $bestURL = $iTunesAlbumInfo->results[1]->previewUrl; // Track 1 is good enough, I can get them ranked by popularity perhaps... } } } catch (Exception $e) { // Finding tracks is tough, if you can't find them, just catch the error and try another API... throw new Exception("Not going to get Tracks for: " . $albumTitle . " from iTunes."); } // Last.fm is not the answer, but if I send people to track pages they can get a preview there. if ($bestURL == null) { print("Unable to fetch audio sample, just try some of the links I've already found.

"); } // Amazon is a good possibility and if they ever get their act together iLike. return $bestURL; } /** * Returns the current album's cover image in medium size as a valid URL or a place holder image * * @return string */ public function currentAlbumsMediumImageURL() { $imageURL = $this->currentAlbumsImageURLOf("Medium"); // If we can't find it in Amazon, we could try Last.fm if(strcmp($imageURL, myInfo::MISSING_COVER_URL) == 0) { $albumInfo = $this->getAlbumInfoFromLastFM($this->currentAlbumArtist() , $this->currentAlbumTitle()); if ( ! empty($albumInfo)) { $possibleImageURL = $albumInfo['image']['medium']; if ( ! empty($possibleImageURL)) { $imageURL = $possibleImageURL; // Last.fm has images, but they are not as good as Amazon or as correct. } } } return $imageURL; } /** * Returns the current album's cover image in small size as a valid URL or a place holder image * * @return string */ public function currentAlbumsSmallImageURL() { // First check Amazon.com but after that check iTunes Music Store $imageURL = $this->currentAlbumsImageURLOf("Small"); if(strcmp($imageURL, myInfo::MISSING_COVER_URL) == 0) { // Try finding this album cover in iTunes using my latest greatest caching enabled method! // This is much more work, so only do it as a last resort... $albumInfo = $this->currentAlbumAsArray(); $iTunesArtistInfo = $this->getArtistResultsFromITunes($albumInfo[0]); $iTunesAlbumInfo = $this->getAlbumAndTracksFromITunes($iTunesArtistInfo->results[0]->artistId, $albumInfo[1]); if ($iTunesAlbumInfo != null) { $imageURL = $iTunesAlbumInfo->artworkUrl100; // This is bigger than Amazon.com by 25 pixels but the browser can downsize... print("All that extra work wasn't a waste after all"); //comment this out eventually... } } return $imageURL; } /** * Returns the current album's cover image in large size as a valid URL or a place holder image * * @return string */ public function currentAlbumsLargeImageURL() { // If we can't find it in Amazon, we could try Last.fm $imageURL = $this->currentAlbumsImageURLOf("Large"); if(strcmp($imageURL, myInfo::MISSING_COVER_URL) == 0) { $albumInfo = $this->getAlbumInfoFromLastFM($this->currentAlbumArtist() , $this->currentAlbumTitle()); if ( ! empty($albumInfo)) { $possibleImageURL = $albumInfo['image']['large']; if ( ! empty($possibleImageURL)) { $imageURL = $possibleImageURL; } } } return $imageURL; } // This function is private so I don't have to worry about typos in fetching images of the wrong size // Amazon.com is the best source for large images, but images can also be sourced from other APIs, I just implemented Amazon first. private function currentAlbumsImageURLOf($size) { $amazonXML = $this->currentAlbumAsAmazonXML(); if (($amazonXML != null) && ($amazonXML->Items->TotalResults > 0)) { switch ($size) { case "Small": $imageURL = $amazonXML->Items->Item->SmallImage->URL; break; case "Medium": $imageURL = $amazonXML->Items->Item->MediumImage->URL; break; case "Large": $imageURL = $amazonXML->Items->Item->LargeImage->URL; break; } if(empty($imageURL)) { $imageURL = myInfo::MISSING_COVER_URL; } } else { // We couldn't find an image in Amazon so we need a generic image $imageURL = myInfo::MISSING_COVER_URL; } return $imageURL; } /** * Returns true if we have some albums in our collection * * @return boolean */ public function hasAlbums() { return (!empty($this->albums)); } /** * This increases the currentAlbumIndex by one and if that is one too many goes back to first item in the albums array * */ public function goToNextAlbum() { if(! $this->isCurrentAlbumTheLast()) { $this->currentAlbumIndex++; } else { //We are at the last item in the array so go to the first $this->currentAlbumIndex = 0; } } /** * This decreases the currentAlbumIndex by one and if that is one too few we go to the last item in the albums array * */ public function goToPreviousAlbum() { if($this->isCurrentAlbumTheLast()) { $this->currentAlbumIndex = ($this->collectionSize() - 1); } else { $this->currentAlbumIndex--; } } /** * Returns the currentAlbumIndex back to zero * */ public function goToFirstAlbum() { $this->currentAlbumIndex = 0; } /** * This returns the first album for which we can find a valid large image url in Amazon.com * It also advances the currentAlbumIndex so you can then call getNextValidLargeAlbumCoverImageURL() * * @return String */ public function getFirstValidLargeAlbumCoverImageURL() { return $this->getFirstValidCoverImageURLOf("Large"); } /** * This returns the first album for which we can find a valid medium image url in Amazon.com * It also advances the currentAlbumIndex so you can then call getNextValidMediumAlbumCoverImageURL() * * @return String */ public function getFirstValidMediumAlbumCoverImageURL() { return $this->getFirstValidCoverImageURLOf("Medium"); } /** * This returns the first album for which we can find a valid small image url in Amazon.com * It also advances the currentAlbumIndex so you can then call getNextValidSmallAlbumCoverImageURL() * * @return String */ public function getFirstValidSmallAlbumCoverImageURL() { return $this->getFirstValidCoverImageURLOf("Small"); } // Again I made a private function do the work after I got it to work for one size // Other functions call this one passing in the correct valid image sizes... private function getFirstValidCoverImageURLOf($size) { // First start at the beginning of the array regardless of where we are now. $this->goToFirstAlbum(); $counter = 0; $foundValidURL = false; while( ($counter < $this->collectionSize()) && ( ! $foundValidURL)) { $potentialURL = $this->currentAlbumsImageURLOf($size); if(strcmp($potentialURL, myInfo::MISSING_COVER_URL) == 0) { // We've found nothing useful $this->goToNextAlbum(); } else { $foundValidURL = true; } $counter = $counter + 1; // Always increase the counter } if(!$foundValidURL) { throw new Exception('There are no valid URLs for images of ' . $size . ' in this albumCollection'); } return $potentialURL; } /** * This returns the first album for which we can find a valid small image url * It also advances the currentAlbumIndex as many times as necessary or until the end of the array * * @return String */ public function getNextValidSmallAlbumCoverImageURL() { return $this->getNextValidAlbumCoverImageURLOf("Small"); } /** * This returns the first album for which we can find a valid medium image url in Amazon.com * It also advances the currentAlbumIndex as many times as necessary or until the end of the array * * @return String */ public function getNextValidMediumAlbumCoverImageURL() { return $this->getNextValidAlbumCoverImageURLOf("Medium"); } /** * This returns the first album for which we can find a valid large image url in Amazon.com * It also advances the currentAlbumIndex as many times as necessary or until the end of the array * * @return String */ public function getNextValidLargeAlbumCoverImageURL() { return $this->getNextValidAlbumCoverImageURLOf("Large"); } private function getNextValidAlbumCoverImageURLOf($size) { $this->goToNextAlbum(); // First advance to the next Item if ($this->isCurrentAlbumTheLast()) { // This is the last album in the index $potentialURL = $this->currentAlbumsImageURLOf($size); if(strcmp($potentialURL, myInfo::MISSING_COVER_URL) == 0) { // We've found nothing useful $potentialURL = null; } } elseif($this->isCurrentAlbumTheFirst()) { // We've looped around return null $potentialURL = null; } else { // Neither the first nor the last album in the array. $potentialURL = $this->currentAlbumsImageURLOf($size); if(strcmp($potentialURL, myInfo::MISSING_COVER_URL) == 0) { $this->goToNextAlbum(); //am I going forward two at a time? // Even if I am it is working like this to a degree... $potentialURL = $this->getNextValidAlbumCoverImageURLOf($size); } } return $potentialURL; } private function isCurrentAlbumTheLast() { $isCurrentAlbumTheLast = false; if ( $this->currentAlbumIndex == ($this->collectionSize() - 1)) { $isCurrentAlbumTheLast = true; } return $isCurrentAlbumTheLast; } private function isCurrentAlbumTheFirst() { $isCurrentAlbumTheFirst = false; if ( $this->currentAlbumIndex == 0) { $isCurrentAlbumTheFirst = true; } return $isCurrentAlbumTheFirst; } /** * Returns the number of albums in our collection * * @return int */ public function collectionSize() { return count($this->albums); } // Compilation albums screw up album getInfo fetches to Last.fm due to their being an actual band called "various" private function isCurrentAlbumByVarious() { $byVarious = false; $currentAlbum = $this->currentAlbumAsArray(); if(strcasecmp($currentAlbum[0], "various") == 0) // Changed to case insensitive not sure if that is a big deal after all { $byVarious = true; } return $byVarious; } } ?>