2015-04-03 64 views
2

在iTunes搜索API doc有一个名为栗色寻找一个艺术家的例子,该网址是像这样:如何实体类型的搜索结合起来,苹果的iTunes搜索API

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人..但我只是万t搜索查询具体到足以避免任何客户端过滤某种东西)。

我该如何结合这些搜索?如果我只需添加两个搜索在一起(在这个例子中我在寻找既歌曲艺术家):

https://itunes.apple.com/search?term=Across the Great Divide&entity=song&attribute=songTerm&term=Semisonic&entity=allArtist&attribute=allArtistTerm 

那么苹果将简单地忽略第一个搜索类型(即歌曲)并返回艺术家的结果只要)。

想法?

回答

1

嗯,这更多的是一种“变通”的答案..但它是我使用的解决方案..所以还不如传播爱吧?

这是一个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]; 
} 

这里的关键方法isLooselyEqualToString ..它在一个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:@""]; 
} 

奖金 这是解决我们目前正在使用..我完全知道一些术语可能出现,打破了这种算法..所以我们有一个单元测试,我们逐步添加条款,以确保我们不断改进我们的算法wh ile不会导致回归错误..我会发布它,如果我得到足够的投票在这个答案嘿。

1

abbood,

对不起,你不能从这里到达那里! (除非别人找到了新的东西。)

我目前正在开发一个应用程序,它将结合多个查询的结果。

对于更冒险的Apple向联属合作伙伴提供“从iTunes和App Store提供的完整元数据集的数据馈送”。要使用这个,我会把一个数据库服务放在云中的某个地方,并用它来做更详细的查询,并显示Search API没有返回的细节。

如果我的应用程序完成并且实际上被超过5人使用,我可能会看完整个数据库版本。

大卫

+0

看着我[回复](http://stackoverflow.com/a/29530049/766570)David – abbood 2015-04-09 04:54:19

+0

@DavidReich嗨大卫,你有没有去过使用Apple DataFeed的艰辛之路?如果是这样,你有什么要做的联盟合作伙伴? – 2017-09-17 07:34:17

+1

@ThreadPitt我从来没有完成应用程序。我发现Apple使用的关键字在URL搜索API返回的记录中不存在,并且DataFeed中不存在。例如...我做了一个返回音频书籍记录的搜索。这些记录没有我使用的搜索字词!我认为这也不在DataFeed中。 (这是几年前,现在。)我抬头看亚马逊的有声读物。搜索词是“叙述者”的名字。在这之后我放弃了! 会员也是几年前。除常规开发者帐户之外的更多步骤。 – 2017-09-17 15:21:36