3 * AudioscrobblerController
4 * Audioscrobbler Support Class
6 * Original Author : Kent Sutherland <kent.sutherland@ithinksw.com>
7 * Responsibility : Kent Sutherland <kent.sutherland@ithinksw.com>
9 * Copyright (c) 2005 iThink Software.
14 #import "AudioscrobblerController.h"
15 #import <openssl/evp.h>
17 static AudioscrobblerController *_sharedController = nil;
19 @implementation AudioscrobblerController
23 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
24 [[AudioscrobblerController sharedController] submitTrack:@"Stairway To Heaven" artist:@"Led Zeppelin" album:@"Led Zeppelin IV" length:483];
28 + (AudioscrobblerController *)sharedController
30 if (!_sharedController) {
31 _sharedController = [[AudioscrobblerController alloc] init];
33 return _sharedController;
38 if ( (self = [super init]) ) {
39 _handshakeCompleted = NO;
45 _md5Challenge = @"315EFDA9FDA6A24B421BE991511DEE90";
46 _postURL = [[NSURL alloc] initWithString:@"http://62.216.251.205:80/protocol_1.1"];
47 _handshakeCompleted = YES;
48 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleAudioscrobblerNotification:) name:nil object:self];
55 [_md5Challenge release];
57 [_responseData release];
61 - (void)attemptHandshake
63 NSString *version = [[[NSBundle bundleWithPath:[[NSWorkspace sharedWorkspace] fullPathForApplication:@"iTunes.app"]] infoDictionary] objectForKey:@"CFBundleVersion"], *user = @"Tristrex";
64 NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"http://post.audioscrobbler.com/?hs=true&p=1.1&c=tst&v=%@&u=%@", version, user]];
65 NSURLConnection *connection;
67 _currentStatus = AudioscrobblerRequestingHandshakeStatus;
68 _responseData = [[NSMutableData alloc] init];
69 connection = [NSURLConnection connectionWithRequest:[NSURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:30] delegate:self];
72 - (BOOL)handshakeCompleted
74 return _handshakeCompleted;
77 - (void)submitTrack:(NSString *)title artist:(NSString *)artist album:(NSString *)album length:(int)length
79 if (!_handshakeCompleted) {
80 [self attemptHandshake];
84 //What we eventually want is a submission list that sends backlogs also
85 NSMutableURLRequest *request = [[NSURLRequest requestWithURL:_postURL cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:30] mutableCopy];
86 NSString *responseHash, *requestBody;
88 char *pass = "waffles";
89 unsigned char *buffer, *buffer2, buffer3[16];
93 buffer = malloc(EVP_MD_size(EVP_md5()));
94 //buffer3 = malloc(EVP_MD_size(EVP_md5()));
96 EVP_DigestInit(&ctx, EVP_md5());
97 EVP_DigestUpdate(&ctx, pass, strlen(pass));
98 EVP_DigestUpdate(&ctx, [_md5Challenge UTF8String], strlen([_md5Challenge UTF8String]));
99 EVP_DigestFinal(&ctx, buffer, NULL);
101 for (i = 0; i < 16; i++) {
103 hex1 = toascii(48+ (buffer[i] / 16));
107 hex2 = toascii(48 + (buffer[i] % 16));
113 buffer3[i + 1] = hex2;
116 NSLog(@"%s", buffer3);
118 /*unsigned char *cat = strcat(buffer3, [[_md5Challenge lowercaseString] UTF8String]);
120 EVP_DigestInit(&ctx, EVP_md5());
121 EVP_DigestUpdate(&ctx, cat, strlen(cat));
122 EVP_DigestFinal(&ctx, buffer2, NULL);
124 for (i = 0; i < 16; i++) {
126 hex1 = toascii(48+ (buffer2[i] / 16));
130 hex2 = toascii(48 + (buffer2[i] % 16));
135 buffer3[i + 1] = hex2;
137 NSLog(@"%s", buffer3);*/
139 if ([NSString respondsToSelector:@selector(stringWithCString:encoding:)]) {
140 responseHash = [NSString stringWithCString:buffer3 encoding:NSASCIIStringEncoding];
142 responseHash = [NSString stringWithCString:buffer3 length:strlen(buffer)];
145 requestBody = [NSString stringWithFormat:@"u=%@&s=%@&a[0]=%@&t[0]=%@&b[0]=%@&m[0]=&l[0]=%i&i[0]=%@", @"Tristrex", @"rawr", responseHash, title, album, length, [[NSDate date] descriptionWithCalendarFormat:@"%Y-%m-%d %H:%M:%S" timeZone:nil locale:nil]];
146 [request setHTTPMethod:@"POST"];
147 [request setHTTPBody:[requestBody dataUsingEncoding:NSUTF8StringEncoding]];
149 _currentStatus = AudioscrobblerSubmittingTrackStatus;
150 _responseData = [[NSMutableData alloc] init];
151 [NSURLConnection connectionWithRequest:request delegate:self];
155 - (void)handleAudioscrobblerNotification:(NSNotification *)note
157 if ([[note name] isEqualToString:@"AudioscrobblerHandshakeComplete"]) {
158 [[AudioscrobblerController sharedController] submitTrack:@"Stairway To Heaven" artist:@"Led Zeppelin" album:@"Led Zeppelin IV" length:483];
164 - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
166 NSLog(@"Failed with an error: %@", error);
169 - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
171 [_responseData appendData:data];
174 - (void)connectionDidFinishLoading:(NSURLConnection *)connection
176 NSString *string = [[NSString alloc] initWithData:_responseData encoding:NSASCIIStringEncoding];
178 if (_currentStatus == AudioscrobblerRequestingHandshakeStatus) {
179 NSArray *lines = [string componentsSeparatedByString:@"\n"];
180 NSString *responseAction;
181 if ([lines count] < 2) {
184 responseAction = [lines objectAtIndex:0];
185 if ([responseAction isEqualToString:@"UPTODATE"]) {
186 if ([lines count] >= 4) {
187 _md5Challenge = [[lines objectAtIndex:1] retain];
188 _postURL = [[NSURL alloc] initWithString:[lines objectAtIndex:2]];
189 _handshakeCompleted = YES;
190 NSLog(@"%@", _md5Challenge);
191 [[NSNotificationCenter defaultCenter] postNotificationName:@"AudioscrobblerHandshakeComplete" object:self];
196 } else if (([responseAction length] > 6) && [[responseAction substringToIndex:5] isEqualToString:@"UPDATE"]) {
197 //Something plus update action
198 } else if (([responseAction length] > 6) && [[responseAction substringToIndex:5] isEqualToString:@"FAILED"]) {
200 } else if ([responseAction isEqualToString:@"BADUSER"]) {
205 } else if (_currentStatus == AudioscrobblerSubmittingTrackStatus) {