如何在 Apple iTunes 搜索中组合实体类型搜索 api
How to combine entity type searches in apple itunes search api
在itunes搜索api doc中有一个搜索艺人maroon的例子,url就是这样:
https://itunes.apple.com/search?term=maroon&entity=allArtist&attribute=allArtistTerm
这 return 超过 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
然而 none 这些人给了我我想要的结果(我可以在其他 50 个中找到我正在寻找的结果..但我只是希望搜索查询足够具体以避免任何客户端过滤之类的东西)。
如何组合这些搜索?如果我简单地将两个搜索加在一起(在这个例子中我正在搜索歌曲 和 艺术家):
https://itunes.apple.com/search?term=Across the Great Divide&entity=song&attribute=songTerm&term=Semisonic&entity=allArtist&attribute=allArtistTerm
然后 apple 将简单地忽略第一个搜索类型(即歌曲)和 return 仅艺术家的结果)。
想法?
住所,
抱歉,您无法从这里到达那里! (除非其他人发现了新东西。)
我目前正在开发一个应用程序,它将结合多个查询的结果。
对于更具冒险精神的人,Apple 向附属合作伙伴提供 "a data feed of the complete set of metadata from iTunes and the App Store"。要使用它,我会在云中的某个地方放置一个数据库服务,并使用它来进行更详细的查询并显示搜索未返回的详细信息API。
如果我完成了我的应用程序并且它实际上被超过 5 个人使用,我可能会考虑做整个数据库版本。
大卫
好吧,这更像是一个 "workaround" 的答案..但这是我正在使用的解决方案..所以不妨传播爱吧?
这是一个 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:@""];
}
奖金
这是我们目前正在使用的解决方案..我完全知道可能会出现一些术语来破坏这个算法..所以我们对此进行了单元测试,我们逐渐添加术语以确保我们不断改进我们的算法而不是导致回归错误.. 如果我对这个答案有足够的投票,我会 post 嘿。
在itunes搜索api doc中有一个搜索艺人maroon的例子,url就是这样:
https://itunes.apple.com/search?term=maroon&entity=allArtist&attribute=allArtistTerm
这 return 超过 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
然而 none 这些人给了我我想要的结果(我可以在其他 50 个中找到我正在寻找的结果..但我只是希望搜索查询足够具体以避免任何客户端过滤之类的东西)。
如何组合这些搜索?如果我简单地将两个搜索加在一起(在这个例子中我正在搜索歌曲 和 艺术家):
https://itunes.apple.com/search?term=Across the Great Divide&entity=song&attribute=songTerm&term=Semisonic&entity=allArtist&attribute=allArtistTerm
然后 apple 将简单地忽略第一个搜索类型(即歌曲)和 return 仅艺术家的结果)。
想法?
住所,
抱歉,您无法从这里到达那里! (除非其他人发现了新东西。)
我目前正在开发一个应用程序,它将结合多个查询的结果。
对于更具冒险精神的人,Apple 向附属合作伙伴提供 "a data feed of the complete set of metadata from iTunes and the App Store"。要使用它,我会在云中的某个地方放置一个数据库服务,并使用它来进行更详细的查询并显示搜索未返回的详细信息API。
如果我完成了我的应用程序并且它实际上被超过 5 个人使用,我可能会考虑做整个数据库版本。
大卫
好吧,这更像是一个 "workaround" 的答案..但这是我正在使用的解决方案..所以不妨传播爱吧?
这是一个 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:@""];
}
奖金 这是我们目前正在使用的解决方案..我完全知道可能会出现一些术语来破坏这个算法..所以我们对此进行了单元测试,我们逐渐添加术语以确保我们不断改进我们的算法而不是导致回归错误.. 如果我对这个答案有足够的投票,我会 post 嘿。