Use GraceNote Web API to develop a Mac music query application

Source: Internet
Author: User
Tags parse error

I haven't written a blog for a long time. I 've been busy lately, so I'm very busy. It's rare to have a free time tonight. I wrote a blog to summarize one of the most recently completed tasks: the GraceNote Web API is used to develop an application for querying music information. In fact, the function is the same as the previous GraceNote SDK blog posts, but this time no SDK is used, I simply use Web APIs and transfer the developed platform from iOS to Mac, so the first Mac App Demo came out in my life.

Official GraceNote Web API Information: Click to open the link


First, let's take a look at the basic query and response data formats:


The interaction format is XML.

In fact, any Web API message that calls GraceNote is to POST an XML message to a specified URL, parse the returned XML message, and extract the desired information from it. Below are some constants of the program:

NSString * const kWebAPIURL = @ "https://c10239232.web.cddbp.net/webapi/xml/1.0/"; // call the network interface's URLNSString * const kClientID = @ "10239232 "; // The Client IDNSString * const kClientTag of the application you applied for = @ "46B9ABAD30F0F5EB409C7BFAA13EB2EF"; // The Client Tag of the application you applied

KWebAPIURL is the fixed URL that initiates the request. Replace the number following c with the Client ID of your App.

The kClient ID and kClient Tag can be found in the App registered on the website.


Before using the GraceNote Web API for query, you must first register a User ID through the Client ID and Client Tag of the App, then, use the User ID and the previous Client ID for authentication in all subsequent queries. The format is as follows:

First, let's take a look at the registration code. After successful registration, we will save it to the local NSUserDefaults:

// Register User ID-(void) gn_registerUserID {NSString * registerString = [NSString stringWithFormat :@"\
 
  
\
  
   
\
   
    
% @-% @
   \
  \
 ", KClientID, kClientTag]; // string to be POST. CMD = REGISTER indicates the registration action; optional * request = [NSMutableURLRequest requestWithURL: [NSURL URLWithString: kWebAPIURL]; [request setHTTPMethod: @ "POST"]; NSData * data = [registerString dataUsingEncoding: NSUTF8StringEncoding]; [request setHTTPBody: data]; // create NSURLSessionDataTask NSURLSession * session = [NSURLSession sharedSession]; _ weak AppDelegate * weakSelf = self; // prevents self and block from forming retain cycle NSURLSessionDataTask * dataTask = [session dataTaskWithRequest: request completionHandler: ^ (NSData * data, NSURLResponse * response, NSError * error) {NSLog (@ "*** Register ***"); [self showResponseCode: response]; if (data) {NSError * parseError = nil; // use the third-party class library GDataXML to parse XML data. Make sure that you have installed the GDataXML class library GDataXMLDocument * doc = [[GDataXMLDocument alloc] initWithData: data encoding: NSUTF8StringEncoding error: if (parseError) {NSLog (@ "Parse Error: % @", [parseError localizedDescription]); weakSelf. app_userID = nil;} example of XML data returned by else:
                     
                          
   
    
267493051066226693-31C70A189A61B89C0D45A782DCB7C072
                       
                   
 */GDataXMLElement * rootElement = [doc rootElement]; NSArray * responses = [rootElement elementsForName: kGNResponse]; GDataXMLElement * resp = responses [0]; if (! [Self gn_requestSucceed: resp]) {return;} NSString * userID = [[resp elementsForName: kGNUser] [0] stringValue]; // Save the obtained user id to weakSelf. app_userID = userID; // store the user id in User ults NSUserDefaults * userDefaults = [NSUserDefaults standardUserDefaults]; [userDefaults setObject: userID forKey: kUserID]; [userDefaults synchronize]; NSLog (@ "User ID = % @", userID) ;}} if (error) {NSLog (@ "error: % @", [error localizedDescription]);} NSLog (@ "--- Register Finished ---");}]; // use the resume method to start the task [dataTask resume];}

All tasks can be completed through NSURLSessionDataTask.


Then, the query request (album search) is initiated based on the artist name, album name, song title, and return range of the search results ):

// Use Artist, Album Title, and Track Title as search keywords to initiate a search request-(void) gn_albumSearchWithArtist :( NSString *) anArtist albumTitle :( NSString *) anAlbumTitle trackTitle :( NSString *) aTrackTitle start :( NSUInteger) startIndex end :( NSUInteger) endIndex {// first, remove the last residual query result [_ gn_IDs removeAllObjects]; if (startIndex <= 0 | endIndex <= 0 | startIndex> endIndex) {return;} // you can specify a query string, this request belongs to the ALBUM_SEARCH operation NSString * searchString = [NSString stringWithFormat :@"\
 
  
\\
  
   
% @-% @
  \
  
   
% @
  \\
  
   
\
   
    
% @
   \
   
    
% @
   \
   
    
% @
   \
   
    
\
    
     
% Ld
    \
    
     
% Ld
    \
   \
  \
 ", KClientID, kClientTag, _ app_userID, anArtist, comment, aTrackTitle, startIndex, endIndex]; required * request = [requestWithURL: [NSURL URLWithString: Signature]; [request setHTTPMethod: @ "POST"]; NSData * data = [searchString dataUsingEncoding: NSUTF8StringEncoding]; [request setHTTPBody: data]; // create a consumer and start the task NSURLSession * session = [NSURLSession sharedSession] Using resume; _ weak AppDelegate * weakSelf = self; NSURLSessionDataTask * dataTask = [session dataTaskWithRequest: request completionHandler: ^ (NSData * data, NSURLResponse * response, NSError * error) {NSLog (@ "*** Album Search ***"); [self showResponseCode: response]; if (data) {NSError * parseError = nil; GDataXMLDocument * doc = [[GDataXMLDocument alloc] initWithData: data encoding: NSUTF8StringEncoding error: & parseError]; if (parseError) {NSLog (@ "Parse Error: % @", [parseError localizedDescription]);} else {/*** the request is successful, and an XML result example is returned:
                     
                          
                               
    
     
2
                                
    
     
1
                                
    
     
2
                            
                                                       
   
    
7552265-4E82AF73CE400EDC94DCDA49547C585F
   The Carpenters                            
   Now & Then                            
   
    
ENG
                               
   
    
1973
                               
   
    
70's Rock
                               
   
    
6
                               
   
    
15
                               
                                   
   
    
6
                                   
   
    
7552271-366ED2D1FEB61E8D720D4941009C91A9
                                   
   Yesterday Once More                                                                                                        
   
    
19546461-AA0668FE5972459884664A7C3FE9D9C2
   The Carpenters                            
   Now And Then                            
   
    
ENG
                               
   
    
70's Rock
                               
   
    
6
                               
   
    
8
                               
                                   
   
    
6
                                   
   
    
19546467-560982E049BFF85016AB89C37513F474
                                   
   Yesterday Once More                                                                        
                   
 */GDataXMLElement * rootElement = [doc rootElement]; NSArray * responses = [rootElement elementsForName: kGNResponse]; if ([responses count]) {GDataXMLElement * resp = [responses firstObject]; if (! [Self gn_requestSucceed: resp]) {return;} GDataXMLElement * range = [resp elementsForName: kGNRange] [0]; if (! Range) {// if no range element is returned, NSLog (@ "Fail to search album"); return;} NSUInteger count = (NSUInteger) fails to capture data) [[range elementsForName: kGNCount] [0] stringValue] integerValue]; NSUInteger start = (NSUInteger) [[[range elementsForName: kGNStart] [0] stringValue] integerValue]; if (count <= 0) {// if no result is found, directly return [self showSearchResultsCountText: 0]; return;} p_currentPage = start/10 + 1; p_allPages = coun T/10; NSUInteger I = (count-count/10*10 )? 1: 0; p_allPages + = I; [self updatePagingText]; [self showSearchResultsCountText: count]; NSUInteger searchCount = 0; if (endIndex> = count) {searchCount = count-startIndex;} else {searchCount = endIndex-startIndex;} NSArray * albums = [resp elementsForName: kGNAlbum]; for (NSUInteger I = 0; I <= searchCount; I ++) {GDataXMLElement * album = albums [I]; NSString * gn_id = [[album elementsForName: kGNID] [0] stringValue]; // Add the GN_ID of each search result to the array gn_IDs [weakSelf. gn_IDs addObject: gn_id];} [_ previousPage_button setEnabled: YES]; [_ nextPage_button setEnabled: YES]; // capture album details one by one [weakSelf albumFetch];} if (error) {NSLog (@ "error: % @", [error localizedDescription]);} NSLog (@ "--- Album Search Finished ---");}]; [dataTask resume];}


Save the searched gnID (ID of the album identified in the database) into an array gn_IDs, then, based on each gn_id in the array, initiate an operation to capture the complete data of the album (album fetch ):

// Capture the specific information of an album one by one-void albumFetch {// first remove the residual data from the last search [_ searchAlbums removeAllObjects]; // use each gnID in gn_IDs as the search keyword, execute the album fetch request to capture the complete information of the album for (NSString * gnID in _ gn_IDs) {[self gn_albumFetchWithGNID: gnID] ;}// use GN_ID as the search keyword, execute the album fetch request to capture the complete information of the album-(void) gn_albumFetchWithGNID :( NSString *) aID {// set the string to be queried, this operation is ALBUM_FETCH operation NSString * searchString = [NSString stringWithFormat :@"\
 
  
\\
  
   
% @-% @
  \
  
   
% @
  \\
  
   
\
   
    
SINGLE_BEST_COVER
   \
   
    
% @
   \
   \
    
     
SELECT_EXTENDED
    \
    
     
COVER, ARTIST_IMAGE
    \\
   \
    
     
COVER_SIZE
    \
    
     
THUMBNAIL
    \\
  \
 ", KClientID, kClientTag, _ app_userID, aID]; NSMutableURLRequest * request = [descrirequestwithurl: [NSURL URLWithString: kWebAPIURL]; [request setHTTPMethod: @" POST "]; NSData * data = [searchString dataUsingEncoding: NSUTF8StringEncoding]; [request setHTTPBody: data]; // create NSURLSessionDataTask and start the task NSURLSession * session = [NSURLSession sharedSession] Using resume; _ weak AppDelegate * weakSelf = self; NSURLSessionDataTask * dataTask = [session dataTaskWithRequest: request completionHandler: ^ (NSData * data, NSURLResponse * response, NSError * error) {NSLog (@ "*** Album Fetch ***"); [self showResponseCode: response]; if (data) {// output the returned xml content // [self logoutXMLData: data]; // initialize the MFAlbum object MFAlbum * album = [[MFAlbum alloc] initWithXMLData through the returned xml binary data: data]; if (album) {// Add the query result to the searchAlbums array [weakSelf. searchAlbums addObject: album];} [weakSelf showResults];} if (error) {NSLog (@ "error: % @", [error localizedDescription]);} NSLog (@ "--- Album Fetch Finished ---") ;}]; [dataTask resume];}


Finally, load the data in NSTableView:

# Pragma mark-NSTableViewDataSource-(NSInteger) values :( NSTableView *) tableView {return [_ searchAlbums count];}-(id) tableView :( NSTableView *) tableView objectValueForTableColumn :( NSTableColumn *) tableColumn row :( NSInteger) row {NSString * unknown = @ "unknown"; MFAlbum * album = _ searchAlbums [row]; NSString * identifier = tableColumn. identifier; if ([identifier isinclutostring: @ "coverArt" ]) {NSURL * coverArtURL = [NSURL URLWithString: album. coverArtURLString]; NSImage * image; if (coverArtURL) {image = [[NSImage alloc] initWithContentsOfURL: coverArtURL];} else {image = [NSImage imageNamed: @ "NotFound"];} return image;} else if ([identifier isinclutostring: @ "artistImage"]) {NSURL * artistImageURL = [NSURL URLWithString: album. artistImageURLString]; NSImage * image; if (artistImageU RL) {image = [[NSImage alloc] initWithContentsOfURL: artistImageURL];} else {image = [NSImage imageNamed: @ "NotFound"];} return image ;} else if ([identifier isinclutostring: @ "trackCount"]) {return [NSString stringWithFormat: @ "% ld", album. trackCount]? [NSString stringWithFormat: @ "% ld", album. trackCount]: unknown;} else {NSString * info = [album valueForKey: identifier]; return info? Info: unknown ;}}


In addition, I abstracted the album metadata into an MFAlbum class, which can be initialized through the returned XML response data (Here we use the GDataXML class library for XML parsing). The Code is as follows:

-(Instancetype) initWithXMLData :( NSData *) xmlData {self = [super init]; if (self) {NSError * parseError = nil; GDataXMLDocument * doc = [[GDataXMLDocument alloc] initWithData: xmlData encoding: NSUTF8StringEncoding error: & parseError]; if (parseError) {NSLog (@ "Parse Error: % @", [parseError localizedDescription]); return nil; // Conversion error, directly return nil} // parse the xml node one by one to obtain all the information required by the album object. GDataXMLElement * rootElement = [Doc rootElement]; GDataXMLElement * response = [rootElement elementsForName: kGNResponse] [0]; if (! [Self gn_requestSucceed: response]) {return nil;} GDataXMLElement * album = [response elementsForName: kGNAlbum] [0]; _ gn_id = [[album elementsForName: kGNID] [0] stringValue]; _ artistName = [[album failed: kGNArtist] [0] stringValue]; _ albumTitle = [[album elementsForName: kGNTitle] [0] stringValue]; _ language = [[album elementsForName: kGNLanguage] [0] stringValue]; _ releaseDate = [[album elements ForName: kGNDate] [0] stringValue]; _ genre = [[album elementsForName: kGNGenre] [0] stringValue]; _ trackCount = (NSUInteger) [[[album elementsForName: kGNTrackCount] [0] stringValue] integerValue]; _ allTracks = [NSMutableArray array]; NSArray * tracks = [album elementsForName: kGNTrack]; for (GDataXMLElement * trackElement in tracks) {NSString * title = [[trackElement elementsForName: kGNTitle] [0] stringValu E]; [_ allTracks addObject: title];} NSArray * urlElements = [album elementsForName: kGNURL]; if (! UrlElements) {return self;} for (GDataXMLElement * element in urlElements) {GDataXMLNode * node = [element attributeForName: kGNType]; NSString * type = [node stringValue]; if ([type isw.tostring: kGNCoverArt]) {_ coverArtURLString = [element stringValue];} else if ([type isw.tostring: kGNArtistImage]) {_ artistImageURLString = [element stringValue] ;}}return self ;}

Main Interface (MainMenu. xib ):


<喎?http: www.bkjia.com kf ware vc " target="_blank" class="keylink"> VcD4KPHA + 1 + 6688np1mvq0l3hufujuw.vcd4kpha + pgltzybzcm9 "http://www.2cto.com/uploadfile/Collfiles/20140610/201406100918356.png" alt = "">



I haven't written a blog for a long time, and my writing skills have dropped sharply. I 've become a lot lazy again. This article is so bad that it can only be used as a mark, prove that I have completed the GraceNote music information query service.





Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.