Title: How to combine entity type searches in apple itunes search api
Tags: objective-c;itunes;itunes-sdk;itunes-search-api
Question: In the itunes search api doc there is an example of searching for an artist called maroon and the url is like so:
https://itunes.apple.com/search?term=maroon&amp;entity=allArtist&amp;attribute=allArtistTerm
This returns over 50 results that start like this:
"resultCount": 50,
"results": [
{
"wrapperType": "artist",
"artistType": "Artist",
"artistName": "Maroon 5",
"artistLinkUrl": "https://itunes.apple.com/us/artist/maroon-5/id1798556?uo=4",
"artistId": 1798556,
"amgArtistId": 529962,
"primaryGenreName": "Pop",
"primaryGenreId": 14,
"radioStationUrl": "https://itunes.apple.com/station/idra.1798556"
},
{
"wrapperType": "artist",
"artistType": "Software Artist",
"artistName": "MaroonEntertainment",
"artistLinkUrl": "https://itunes.apple.com/us/artist/maroonentertainment/id537029262?uo=4",
"artistId": 537029262,
"radioStationUrl": "https://itunes.apple.com/station/idra.537029262"
},
Which is nice.  However here is my problem: I would like to create a search query that is as specific as possible by combining the search for both an artist and a song name and an album name..
So for example I got this song:
song: Across the Great Divide
album: Great Divide
Artist: Semisonic
I can search for the artist name only:
https://itunes.apple.com/search?term=Semisonic&amp;entity=allArtist&amp;attribute=allArtistTerm
I can search for the song term only:
https://itunes.apple.com/search?term=Across the Great Divide&amp;entity=song&amp;attribute=songTerm
I can search for the album name only:
https://itunes.apple.com/search?term=Great Divide&amp;entity=album&amp;attribute=albumTerm
However none of these guys give me the result i want (i can find the result i'm looking for amongst maybe 50 others.. but i just want the search query to be specific enough to avoid any client side filtering kind of thing).
How can I combine these searches? if I simply add two searches together (in this example i'm searching for both song and artist):
https://itunes.apple.com/search?term=Across the Great Divide&amp;entity=song&amp;attribute=songTerm&amp;term=Semisonic&amp;entity=allArtist&amp;attribute=allArtistTerm
then apple will simply ignore the first search type (ie song) and return the results for artist only).
ideas?

Here is the accepted answer: Well this is more of a "workaround" answer.. but it's the solution I'm using.. so might as well spread the love eh?
This is a 100% client side solution (ie the entire database of itunes music can be downloaded into my own server.. then I can create all sots of search wrappers around it.. but that's a project in itself).
this is what i got:
// this is just a wrapper around the apple search api.. it makes your
// average joe http get request
[[AppleServer shared] searchForSongWithTitle:track.title andAlbumName:track.albumName completion:^(NSArray *results, NSError *error){
if ([results count] &gt;0) {
NSLog(@"[%d] unfiltered songs retrieved from apple search api", [results count]);
NSDictionary *filteredResult = [[self class] filterResults:results ToMatchTrack:track];
if (!filteredResult) {
NSLog(@"Filtering may be too strict, we got [%d] results from apple search api but none past our filter", [results count]);
return;
}
.. process results
+ (NSDictionary *)filterResults:(NSArray *)results ToMatchTrack:(VBSong *)track
NSPredicate *predicate = [NSPredicate predicateWithBlock:^BOOL(NSDictionary *evaluatedTrack, NSDictionary *bindings){
BOOL result =
([track.title isLooselyEqualToString:evaluatedTrack[@"trackName"]] &amp;&amp;
[track.artistName isLooselyEqualToString:evaluatedTrack[@"artistName"]] &amp;&amp;
[track.albumName isLooselyEqualToString:evaluatedTrack[@"collectionName"]]);
NSLog(@"match?[%d]", result);
return result;
}];
return [[results filteredArrayUsingPredicate:predicate] firstObject];
the key method here is isLooselyEqualToString.. it's defined in an NSString category like so:
* Tests if one string equals another substring, relaxing the following contraints
*   - one string can be a substring of another
*   - it's a case insensitive comparison
*   - all special characters are removed from both strings
*     ie this should return true for this comparison:
*     - comparing self:"Circus One (Presented By Doctor P and Flux Pavilion)"
and str:"Circus One presented by Doctor P"
* @param str string to compare self against
* @return if self is the same as str, relaxing the contraints described above
- (BOOL)isLooselyEqualToString:(NSString *)str
return [[self removeSpecialCharacters] containSubstringBothDirections:[str removeSpecialCharacters]];
* Tests if one string is a substring of another
*     ie this should return true for both these comparisons:
*     - comparing self:"Doctor P &amp; Flux Pavilion" and substring:"Flux Pavilion"
*     - comparing self:"Flux Pavilion" and substring:"Doctor P &amp; Flux Pavilion"
* @param substring to compare self against
* @return if self is a substring of substring
-(BOOL)containSubstringBothDirections:(NSString*)substring
if (substring == nil) return self.length == 0;
if ([self rangeOfString:substring options:NSCaseInsensitiveSearch].location == NSNotFound) {
if ([substring rangeOfString:self options:NSCaseInsensitiveSearch].location == NSNotFound) {
return NO;
} else {
return YES;
}
} else {
return YES;
- (NSString *)removeSpecialCharacters
NSMutableCharacterSet *specialCharsSet = [[NSCharacterSet letterCharacterSet] mutableCopy];
[specialCharsSet formUnionWithCharacterSet:[NSCharacterSet whitespaceCharacterSet]];
return [[self componentsSeparatedByCharactersInSet:[specialCharsSet invertedSet]] componentsJoinedByString:@""];
This is the solution we are currently using.. I'm fully aware that some terms may come up that break this algorithm.. so we have a unit test for this that we incrementally add terms to ensure we keep on improving our algorithm while not causing regression bugs.. i'll post it if i get enough votes on this answer heh.

Here is another answer: abbood,
Sorry, you can't get there from here!  (Unless someone else has found something new.)
I'm currently developing an app that will combine the results of multiple queries.
For the more adventurous Apple provides "a data feed of the complete set of metadata from iTunes and the App Store" to affiliate partners.  To use this I would put a database service somewhere in the cloud and use it to make more detailed queries and display details not returned by the Search API.
If I get my app finished and it's actually used by more than 5 people I might look at doing the entire database version.
Comment for this answer: @DavidReich Hi David, did you ever go the hard way using the Apple DataFeed? And if so, what do you have to to do get affiliate partner?
Comment for this answer: @ThreadPitt I never finished the app.  I discovered that Apple uses keywords that are not present in the returned records from the URL search API and that are not present in the DataFeed.  For example ... I did a search that returned audio book records.  Those records did not have the search term I was using!  I don't think that was in the DataFeed, either.  (This was several years ago, now.)  I looked up the audio book on Amazon.  The search term was the name of the "narrator".  I gave up after this!
Affiliate was also several years ago.  Just more steps beyond regular developer account.

{'source': 'StackExchangeDataset', 'subset': 'stackoverflow.com', 'metadata': {'AnswerCount': 2, 'CommentCount': 0, 'ContentLicense': 'CC BY-SA 3.0', 'CreationDate': '2015:00:04/03/15', 'FavoriteCount': 4.0, 'PostTypeId': 1, 'Tags': '<objective-c><itunes><itunes-sdk><itunes-search-api>', 'Title': 'How to combine entity type searches in apple itunes search api', 'ViewCount': 1577, 'id': 29426735, 'user_AboutMe': '<p><strong>Email me</strong> at abdullah.bakhach@gmail.com<br>\n<strong>Fork me</strong> on <a href="http://github.com/abbood" rel="nofollow noreferrer">github</a><br>\n<strong>Add me</strong> on <a href="http://lb.linkedin.com/pub/abdullah-bakhach/7/78a/b71/" rel="nofollow noreferrer">linkedin</a><br>\n<strong>Work with me at</strong> <a href="https://www.totersapp.com/careers" rel="nofollow noreferrer">Toters Delivery Careers</a></p>\n', 'user_AccountId': 400546.0, 'user_DisplayName': 'abbood', 'user_Reputation': 22497.0, 'user_Views': 4027.0, 'user_id': 766570.0}}