在itunes搜索api文档中,有一个搜索艺术家的例子,名为maroon,url如下所示:
https://itunes.apple.com/search?term=maroon&entity=allArtist&attribute=allArtistTerm
这会返回50多个结果,它们的开头是这样的:
{
"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"
},
这很好。然而,我的问题是:我想创建一个尽可能具体的搜索查询,通过组合对艺术家、歌曲名称和专辑名称的搜索。。
例如,我得到了这首歌:
- 歌曲:跨越大分水岭
- 相册:大分水岭
- 艺术家:Semisonic
我只能搜索艺术家的名字:
https://itunes.apple.com/search?term=Semisonic&entity=allArtist&attribute=allArtistTerm
我只能搜索歌曲术语:
https://itunes.apple.com/search?term=Across the Great Divide&entity=song&attribute=songTerm
我只能搜索专辑名称:
https://itunes.apple.com/search?term=Great Divide&entity=album&attribute=albumTerm
然而,这些人都没有给我想要的结果(我可以在大约50个其他人中找到我要找的结果……但我只希望搜索查询足够具体,以避免任何客户端过滤之类的事情)。
如何组合这些搜索?如果我只是把两个搜索加在一起(在这个例子中,我同时搜索歌曲和艺术家):
https://itunes.apple.com/search?term=Across the Great Divide&entity=song&attribute=songTerm&term=Semisonic&entity=allArtist&attribute=allArtistTerm
然后苹果将简单地忽略第一个搜索类型(即歌曲),并只返回艺术家的搜索结果)。
想法?
这更多的是一个"变通方法"的答案。。但这是我正在使用的解决方案。。不如把爱传播出去吧?
这是一个100%的客户端解决方案(即itunes音乐的整个数据库可以下载到我自己的服务器中……然后我可以围绕它创建所有的搜索包装……但这本身就是一个项目)。
这就是我得到的:
// 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] >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"]] &&
[track.artistName isLooselyEqualToString:evaluatedTrack[@"artistName"]] &&
[track.albumName isLooselyEqualToString:evaluatedTrack[@"collectionName"]]);
NSLog(@"match?[%d]", result);
return result;
}];
return [[results filteredArrayUsingPredicate:predicate] firstObject];
}
这里的关键方法是CCD_ 1。。它被定义在NSString类别中,如下所示:
/**
* 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 & Flux Pavilion" and substring:"Flux Pavilion"
* - comparing self:"Flux Pavilion" and substring:"Doctor P & 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:@""];
}
奖金这是我们目前正在使用的解决方案。。我完全知道可能会出现一些术语来破坏这个算法。。因此,我们对此进行了一个单元测试,我们逐步添加项,以确保我们不断改进算法,同时不会导致回归错误。。如果我在这个答案上得到足够的票数,我会把它贴出来的。
abbood,
对不起,你不能从这里到那里!(除非其他人发现了新东西。)
我目前正在开发一个应用程序,它将组合多个查询的结果。
对于更具冒险精神的公司,苹果向附属合作伙伴提供"iTunes和应用商店的完整元数据数据源"。为了使用它,我将在云中放置一个数据库服务,并使用它进行更详细的查询和显示搜索API未返回的详细信息。
如果我完成了我的应用程序,并且它实际上被5个人以上使用,我可能会考虑做整个数据库版本。
David