From a04f78e7d8170dd606e4d0a4a1ec9a68a1ce9f50 Mon Sep 17 00:00:00 2001 From: vspader Date: Thu, 5 Jul 2007 23:24:25 +0000 Subject: [PATCH] Updated TODO. Seeded shuffle. Updated AudioScrobbler code from Play.. --- AudioScrobbler/AudioScrobbler.m | 84 ++++++++++----------- AudioScrobbler/AudioScrobblerClient.h | 9 ++- AudioScrobbler/AudioScrobblerClient.m | 102 ++++++++++++++++++-------- Playlist/Shuffle.m | 2 + TODO | 6 +- 5 files changed, 125 insertions(+), 78 deletions(-) diff --git a/AudioScrobbler/AudioScrobbler.m b/AudioScrobbler/AudioScrobbler.m index 40fb772c8..5ca499ca6 100644 --- a/AudioScrobbler/AudioScrobbler.m +++ b/AudioScrobbler/AudioScrobbler.m @@ -23,6 +23,14 @@ #import "AudioScrobblerClient.h" #import "PlaylistEntry.h" +// ======================================== +// Symbolic Constants +// ======================================== +NSString * const AudioScrobblerRunLoopMode = @"org.sbooth.Play.AudioScrobbler.RunLoopMode"; + +// ======================================== +// Helpers +// ======================================== static NSString * escapeForLastFM(NSString *string) { @@ -61,11 +69,10 @@ escapeForLastFM(NSString *string) { if((self = [super init])) { - _pluginID = @"cog"; + _pluginID = @"pla"; - if([[NSUserDefaults standardUserDefaults] boolForKey:@"automaticallyLaunchLastFM"]) { + if([[NSUserDefaults standardUserDefaults] boolForKey:@"automaticallyLaunchLastFM"]) [[NSWorkspace sharedWorkspace] launchApplication:@"Last.fm.app"]; - } _keepProcessingAudioScrobblerCommands = YES; @@ -85,9 +92,8 @@ escapeForLastFM(NSString *string) - (void) dealloc { - if([self keepProcessingAudioScrobblerCommands] || NO == [self audioScrobblerThreadCompleted]) { + if([self keepProcessingAudioScrobblerCommands] || NO == [self audioScrobblerThreadCompleted]) [self shutdown]; - } [_queue release], _queue = nil; @@ -98,15 +104,15 @@ escapeForLastFM(NSString *string) - (void) start:(PlaylistEntry *)pe { - [self sendCommand:[NSString stringWithFormat:@"START c=%@&a=%@&t=%@&b=%@&m=%@&l=%i&p=%@\n", - [self pluginID], - escapeForLastFM([pe artist]), - escapeForLastFM([pe title]), - escapeForLastFM([pe album]), - @"", // TODO: MusicBrainz support - (int)([[pe length] doubleValue]/1000.0), - escapeForLastFM([[pe url] path]) - ]]; + [self sendCommand:[NSString stringWithFormat:@"START c=%@&a=%@&t=%@&b=%@&m=%@&l=%i&p=%@\n", + [self pluginID], + escapeForLastFM([pe artist]), + escapeForLastFM([pe title]), + escapeForLastFM([pe album]), + @"", // TODO: MusicBrainz support + (int)([[pe length] doubleValue]/1000.0), + escapeForLastFM([[pe url] path]) + ]]; } - (void) stop @@ -130,9 +136,8 @@ escapeForLastFM(NSString *string) semaphore_signal([self semaphore]); // Wait for the thread to terminate - while(NO == [self audioScrobblerThreadCompleted]) { - [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.5]]; - } + while(NO == [self audioScrobblerThreadCompleted]) + [[NSRunLoop currentRunLoop] runMode:AudioScrobblerRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.2]]; } @end @@ -141,9 +146,8 @@ escapeForLastFM(NSString *string) - (NSMutableArray *) queue { - if(nil == _queue) { + if(nil == _queue) _queue = [[NSMutableArray alloc] init]; - } return _queue; } @@ -155,7 +159,6 @@ escapeForLastFM(NSString *string) - (void) sendCommand:(NSString *)command { - NSLog(@"Command: %@", command); @synchronized([self queue]) { [[self queue] addObject:command]; } @@ -201,7 +204,6 @@ escapeForLastFM(NSString *string) // Get the first command to be sent @synchronized([myself queue]) { - enumerator = [[myself queue] objectEnumerator]; command = [[enumerator nextObject] retain]; @@ -210,17 +212,17 @@ escapeForLastFM(NSString *string) if(nil != command) { @try { - port = [client connectToHost:@"localhost" port:port]; - [client send:command]; - - [command release]; - - response = [client receive]; - if(2 > [response length] || NSOrderedSame != [response compare:@"OK" options:NSLiteralSearch range:NSMakeRange(0,2)]) { - NSLog(@"AudioScrobbler error: %@", response); + if([client connectToHost:@"localhost" port:port]) { + port = [client connectedPort]; + [client send:command]; + [command release]; + + response = [client receive]; + if(2 > [response length] || NSOrderedSame != [response compare:@"OK" options:NSLiteralSearch range:NSMakeRange(0,2)]) + NSLog(@"AudioScrobbler error: %@", response); + + [client shutdown]; } - - [client shutdown]; } @catch(NSException *exception) { @@ -235,15 +237,15 @@ escapeForLastFM(NSString *string) // Send a final stop command to cleanup @try { - port = [client connectToHost:@"localhost" port:port]; - [client send:[NSString stringWithFormat:@"STOP c=%@\n", [myself pluginID]]]; - - response = [client receive]; - if(2 > [response length] || NSOrderedSame != [response compare:@"OK" options:NSLiteralSearch range:NSMakeRange(0,2)]) { - NSLog(@"AudioScrobbler error: %@", response); + if([client connectToHost:@"localhost" port:port]) { + [client send:[NSString stringWithFormat:@"STOP c=%@\n", [myself pluginID]]]; + + response = [client receive]; + if(2 > [response length] || NSOrderedSame != [response compare:@"OK" options:NSLiteralSearch range:NSMakeRange(0,2)]) + NSLog(@"AudioScrobbler error: %@", response); + + [client shutdown]; } - - [client shutdown]; } @catch(NSException *exception) { @@ -251,9 +253,9 @@ escapeForLastFM(NSString *string) } [client release]; - [pool release]; - [myself setAudioScrobblerThreadCompleted:YES]; + + [pool release]; } @end diff --git a/AudioScrobbler/AudioScrobblerClient.h b/AudioScrobbler/AudioScrobblerClient.h index 7456d9644..be96f8893 100644 --- a/AudioScrobbler/AudioScrobblerClient.h +++ b/AudioScrobbler/AudioScrobblerClient.h @@ -1,5 +1,5 @@ /* - * $Id: AudioScrobblerClient.h 241 2007-01-26 23:02:09Z stephen_booth $ + * $Id: AudioScrobblerClient.h 666 2007-04-26 16:35:18Z stephen_booth $ * * Copyright (C) 2006 - 2007 Stephen F. Booth * @@ -26,10 +26,13 @@ { int _socket; BOOL _doPortStepping; - in_port_t _lastPort; + in_port_t _port; } -- (in_port_t) connectToHost:(NSString *)hostname port:(in_port_t)port; +- (BOOL) connectToHost:(NSString *)hostname port:(in_port_t)port; + +- (BOOL) isConnected; +- (in_port_t) connectedPort; - (void) send:(NSString *)data; - (NSString *) receive; diff --git a/AudioScrobbler/AudioScrobblerClient.m b/AudioScrobbler/AudioScrobblerClient.m index 1f1f6f95e..f945cb8a2 100644 --- a/AudioScrobbler/AudioScrobblerClient.m +++ b/AudioScrobbler/AudioScrobblerClient.m @@ -1,5 +1,5 @@ /* - * $Id: AudioScrobblerClient.m 362 2007-02-13 05:30:49Z stephen_booth $ + * $Id: AudioScrobblerClient.m 869 2007-06-18 15:51:33Z stephen_booth $ * * Copyright (C) 2006 - 2007 Stephen F. Booth * @@ -41,7 +41,7 @@ addressForHost(NSString *hostname) if(INADDR_NONE == address) { hostinfo = gethostbyname([hostname cStringUsingEncoding:NSASCIIStringEncoding]); if(NULL == hostinfo) { - NSLog(@"Unable to resolve address for \"%@\".", hostname); + NSLog(@"AudioScrobblerClient error: Unable to resolve address for \"%@\".", hostname); return INADDR_NONE; } @@ -52,7 +52,7 @@ addressForHost(NSString *hostname) } @interface AudioScrobblerClient (Private) -- (void) connectToSocket:(in_addr_t)remoteAddress port:(in_port_t)port; +- (BOOL) connectToSocket:(in_addr_t)remoteAddress port:(in_port_t)port; @end @implementation AudioScrobblerClient @@ -61,35 +61,51 @@ addressForHost(NSString *hostname) { if((self = [super init])) { _socket = -1; - _lastPort = -1; _doPortStepping = YES; } return self; } -- (in_port_t) connectToHost:(NSString *)hostname port:(in_port_t)port +- (BOOL) connectToHost:(NSString *)hostname port:(in_port_t)port { - in_addr_t remoteAddress = addressForHost(hostname); + NSParameterAssert(nil != hostname); - [self connectToSocket:remoteAddress port:port]; + in_addr_t remoteAddress = addressForHost(hostname); - return _lastPort; + if(INADDR_NONE != remoteAddress) + return [self connectToSocket:remoteAddress port:port]; + + return NO; +} + +- (BOOL) isConnected +{ + return (-1 != _socket); +} + +- (in_port_t) connectedPort +{ + return _port; } - (void) send:(NSString *)data -{ +{ const char *utf8data = [data UTF8String]; unsigned len = strlen(utf8data); unsigned bytesToSend = len; unsigned totalBytesSent = 0; ssize_t bytesSent = 0; + + if(NO == [self isConnected]) { + NSLog(@"AudioScrobblerClient error: Can't send data, client not connected"); + return; + } while(totalBytesSent < bytesToSend && -1 != bytesSent) { bytesSent = send(_socket, utf8data + totalBytesSent, bytesToSend - totalBytesSent, 0); - if(-1 == bytesSent || 0 == bytesSent) { - NSLog(@"Unable to send data through socket"); - } + if(-1 == bytesSent || 0 == bytesSent) + NSLog(@"AudioScrobblerClient error: Unable to send data through socket: %s", strerror(errno)); totalBytesSent += bytesSent; } @@ -102,10 +118,18 @@ addressForHost(NSString *hostname) ssize_t bytesRead = 0; BOOL keepGoing = YES; NSString *result = nil; + + if(NO == [self isConnected]) { + NSLog(@"AudioScrobblerClient error: Can't receive data, client not connected"); + return nil; + } do { bytesRead = recv(_socket, buffer, readSize, 0); - NSAssert1(-1 != bytesRead && 0 < bytesRead, @"Unable to receive data through socket (%s).", strerror(errno)); + if(-1 == bytesRead || 0 == bytesRead) { + NSLog(@"AudioScrobblerClient error: Unable to receive data through socket: %s", strerror(errno)); + break; + } if('\n' == buffer[bytesRead - 1]) { --bytesRead; @@ -126,64 +150,80 @@ addressForHost(NSString *hostname) char buffer [ kBufferSize ]; ssize_t bytesRead; - if(-1 == _socket) { + if(NO == [self isConnected]) { return; } result = shutdown(_socket, SHUT_WR); - NSAssert1(-1 != result, @"Socket shutdown failed (%s).", strerror(errno)); + if(-1 == result) + NSLog(@"AudioScrobblerClient error: Socket shutdown failed: %s", strerror(errno)); for(;;) { bytesRead = recv(_socket, buffer, kBufferSize, 0); - - NSAssert1(-1 != bytesRead, @"Waiting for shutdown confirmation failed (%s).", strerror(errno)); + if(-1 == bytesRead) + NSLog(@"AudioScrobblerClient error: Waiting for shutdown confirmation failed: %s", strerror(errno)); if(0 != bytesRead) { - NSLog(@"Received unexpected bytes during shutdown: %@.", [[[NSString alloc] initWithBytes:buffer length:bytesRead encoding:NSUTF8StringEncoding] autorelease]); + NSString *received = [[NSString alloc] initWithBytes:buffer length:bytesRead encoding:NSUTF8StringEncoding]; + NSLog(@"Received unexpected bytes during shutdown: %@", received); + [received release]; } - else { + else break; - } } result = close(_socket); - NSAssert1(-1 != result, @"Couldn't close socket (%s).", strerror(errno)); + if(-1 == result) + NSLog(@"Couldn't close socket (%s)", strerror(errno)); - _socket = -1; + _socket = -1; + _port = 0; } @end @implementation AudioScrobblerClient (Private) -- (void) connectToSocket:(in_addr_t)remoteAddress port:(in_port_t)port +- (BOOL) connectToSocket:(in_addr_t)remoteAddress port:(in_port_t)port { + NSParameterAssert(INADDR_NONE != remoteAddress); + struct sockaddr_in socketAddress; int result; _socket = socket(AF_INET, SOCK_STREAM, 0); - NSAssert1(-1 != _socket, @"Unable to create socket (%s).", strerror(errno)); + if(-1 == _socket) { + NSLog(@"Unable to create socket (%s)", strerror(errno)); + return NO; + } - _lastPort = port; + _port = port; socketAddress.sin_family = AF_INET; socketAddress.sin_addr.s_addr = remoteAddress; - socketAddress.sin_port = htons(_lastPort); + socketAddress.sin_port = htons(_port); result = connect(_socket, (const struct sockaddr *)&socketAddress, sizeof(struct sockaddr_in)); + // Don't check result yet if(_doPortStepping) { - while(-1 == result && _lastPort <= (port + kPortsToStep)) { - socketAddress.sin_port = htons(++_lastPort); + while(-1 == result && _port <= (port + kPortsToStep)) { + socketAddress.sin_port = htons(++_port); result = connect(_socket, (const struct sockaddr *)&socketAddress, sizeof(struct sockaddr_in)); } } + // Don't log failures, because the client may not be running if(-1 == result) { - _doPortStepping = NO; close(_socket); - _socket = -1; -// NSAssert1(-1 != result, @"Couldn't connect to server (%s).", strerror(errno)); + + _socket = -1; + _port = 0; + _doPortStepping = NO; + + return NO; } + + return YES; } @end diff --git a/Playlist/Shuffle.m b/Playlist/Shuffle.m index 10ad6f748..65d4a9a8c 100644 --- a/Playlist/Shuffle.m +++ b/Playlist/Shuffle.m @@ -28,6 +28,8 @@ int randint(int low, int high) + (NSMutableArray *)shuffleList:(NSArray *)l { + srandom(time(NULL)); + NSMutableArray *a = [l mutableCopy]; NSMutableArray *b = [[NSMutableArray alloc] init]; diff --git a/TODO b/TODO index a93a94bdb..e1f967f8e 100644 --- a/TODO +++ b/TODO @@ -5,8 +5,8 @@ Incubate. BUGS: Files still in use (File handle leak?): http://sbooth.org/forums/viewtopic.php?t=1619 - Window order not preserved (incorrect use of makeKeyAndOrderFront in nsapp dock click delegate method?): http://sbooth.org/forums/viewtopic.php?t=1615 - Slider enabled on launch: http://sbooth.org/forums/viewtopic.php?t=1471 - Drag slider to the end: http://sbooth.org/forums/viewtopic.php?t=1537 + #Window order not preserved (incorrect use of makeKeyAndOrderFront in nsapp dock click delegate method?): http://sbooth.org/forums/viewtopic.php?t=1615 + #Slider enabled on launch: http://sbooth.org/forums/viewtopic.php?t=1471 + #Drag slider to the end: http://sbooth.org/forums/viewtopic.php?t=1537 Shuffle is not random: http://sbooth.org/forums/viewtopic.php?p=5225