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("
'); 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: /* Tweet */ $tweetThisButtonCode = null; $albumInfo = $this->currentAlbumAsArray(); $twitterDataURL = myInfo::MY_HOME_PAGE; $twitterDataBy = myInfo::MY_TWITTER_ACCOUNT; $openingTag = ''; $closingTag = ''; $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.
"); 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...
"); 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.