Skip to content

Instantly share code, notes, and snippets.

@indragiek
Created November 19, 2011 00:27
Show Gist options
  • Save indragiek/1378191 to your computer and use it in GitHub Desktop.
Save indragiek/1378191 to your computer and use it in GitHub Desktop.
Retrieving album artwork from Amazon's Product Services API in Cocoa (using AFNetworking)
static NSString* const kAWSAccessKey = @"__ACCESS__KEY__"; // From AWS Developer portal
static NSString* const kAWSSecretKey = @"__SECRET__KEY__"; // From AWS Developer portal
static NSString* const kAWSAssociateTag = @"examp-99"; // Can be a bogus tag in the format xxxxx-XX (x being a letter and X being a number)
/* NSString category for HMAC and URL string encoding */
@interface NSString (AWSAdditions)
- (NSString*)URLEncodedStringForCharacters:(NSString*)characters;
+ (NSData*)HMACSHA256EncodedDataWithKey:(NSString*)key data:(NSString*)data;
@end
#import <CommonCrypto/CommonHMAC.h>
@implementation NSString (AWSAdditions)
- (NSString*)URLEncodedStringForCharacters:(NSString*)characters
{
return (__bridge_transfer NSString *)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (__bridge CFStringRef)self, NULL, (__bridge CFStringRef)characters, kCFStringEncodingUTF8);
}
+ (NSData*)HMACSHA256EncodedDataWithKey:(NSString*)key data:(NSString*)data
{
const char *cKey = [key cStringUsingEncoding:NSUTF8StringEncoding];
const char *cData = [data cStringUsingEncoding:NSUTF8StringEncoding];
unsigned char cHMAC[CC_SHA256_DIGEST_LENGTH];
CCHmac(kCCHmacAlgSHA256, cKey, strlen(cKey), cData, strlen(cData), cHMAC);
return [[NSData alloc] initWithBytes:cHMAC length:CC_SHA256_DIGEST_LENGTH];
}
@end
#import "AFXMLRequestOperation.h"
/* Method that makes a request to Amazon's API and grabs the URL for the artwork
Once the URL has been retrieved, you can use whatever method you want to download the image at the URL (e.g. AFImageRequestOperation)
*/
- (void)artworkURLForAlbumWithTitle:(NSString*)title artist:(NSString*)artist completionHandler:(void (^)(NSURL *url, NSError *error))handler
{
// Amazon Product Services API requires a timestamp in a specific format
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss'Z'"];
[dateFormatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"GMT"]];
NSString *date = [dateFormatter stringFromDate:[NSDate date]];
// Order the paramters in byte order
NSString *parameters = [NSString stringWithFormat:@"AWSAccessKeyId=%@&Artist=%@&AssociateTag=%@&Operation=ItemSearch&ResponseGroup=Images&SearchIndex=Music&Service=AWSECommerceService&Timestamp=%@&Title=%@", kAWSAccessKey, artist, kAWSAssociateTag, date, title];
NSString *escaped = [parameters URLEncodedStringForCharacters:@"!*'();:@+$,/?%#[]"]; // Percent escape parameters
NSString *sign = [NSString stringWithFormat:@"GET\nwebservices.amazon.com\n/onca/xml\n%@", escaped]; // The string that will be encoded as the signature
NSData *hmac = [NSString HMACSHA256EncodedDataWithKey:kAWSSecretKey data:sign]; // HMAC encode signature with SHA256
// The -base64EncodedString is from Matt Gallagher <http://cocoawithlove.com/2009/06/base64-encoding-options-on-mac-and.html>
NSMutableString *encoded = [NSMutableString stringWithString:[hmac base64EncodedString]]; // Encode signature as base64
NSString *signature = [encoded URLEncodedStringForCharacters:@"+="]; // Percent escape encoded signature
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url];
AFXMLRequestOperation *operation = [AFXMLRequestOperation XMLDocumentRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, NSXMLDocument *document) {
// Grab the path to the large artwork image using XPath
NSArray *nodes = [document nodesForXPath:@"/ItemSearchResponse/Items/Item[1]/LargeImage/URL/text()" error:nil];
if ([nodes count]) {
NSXMLNode *node = [nodes objectAtIndex:0];
NSURL *artworkURL = [NSURL URLWithString:node.stringValue]; // Grab the text from the node and create a URL
if (handler) { handler(artworkURL, nil); }
}
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, NSXMLDocument *document) {
if (handler) { handler(nil, error); }
}];
[operationQueue addOperation:operation]; // operationQueue is the NSOperationQueue you want the request to run on
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment