Putting stars back in to the hotkey prefs.
[MenuTunes.git] / MainController.m
index 927a278..294e52c 100755 (executable)
@@ -9,6 +9,7 @@
 #import <ITKit/ITCategory-NSMenu.h>
 #import "StatusWindow.h"
 #import "StatusWindowController.h"
+#import "AudioscrobblerController.h"
 #import "StatusItemHack.h"
 
 @interface NSMenu (MenuImpl)
@@ -88,6 +89,7 @@ static MainController *sharedController;
         sharedController = self;
         
                _statusWindowUpdateTimer = nil;
+               _audioscrobblerTimer = nil;
                
         remoteArray = [[NSMutableArray alloc] initWithCapacity:1];
         [[PreferencesController sharedPrefs] setController:self];
@@ -138,6 +140,8 @@ static MainController *sharedController;
     currentRemote = [self loadRemote];
     [[self currentRemote] begin];
     
+       [[self currentRemote] currentSongElapsed];
+       
     //Turn on network stuff if needed
     networkController = [[NetworkController alloc] init];
     if ([df boolForKey:@"enableSharing"]) {
@@ -196,6 +200,12 @@ static MainController *sharedController;
     [statusItem setImage:[NSImage imageNamed:@"MenuNormal"]];
     [statusItem setAlternateImage:[NSImage imageNamed:@"MenuInverted"]];
 
+       if ([df boolForKey:@"audioscrobblerEnabled"]) {
+               if ([PreferencesController getKeychainItemPasswordForUser:[df stringForKey:@"audioscrobblerUser"]] != nil) {
+                       [[AudioscrobblerController sharedController] attemptHandshake:NO];
+               }
+       }
+
     [networkController startRemoteServerSearch];
     [NSApp deactivate];
        [self performSelector:@selector(rawr) withObject:nil afterDelay:1.0];
@@ -402,7 +412,12 @@ static MainController *sharedController;
 
 - (void)timerUpdate
 {
-       NSString *identifier = [[self currentRemote] playerStateUniqueIdentifier];
+       NSString *identifier = nil;
+       NS_DURING
+               identifier = [[self currentRemote] playerStateUniqueIdentifier];
+       NS_HANDLER
+               [self networkError:localException];
+       NS_ENDHANDLER
        if (refreshTimer && identifier == nil) {
                if ([statusItem isEnabled]) {
                        [statusItem setToolTip:@"iTunes not responding."];
@@ -461,6 +476,19 @@ static MainController *sharedController;
                                        [statusItem setToolTip:nil];
                                }
                        }
+                       
+                       if ([df boolForKey:@"audioscrobblerEnabled"]) {
+                               int length = [[self currentRemote] currentSongDuration];
+                               if (length > 30) {
+                                       _audioscrobblerInterval = ((length / 2 < 240) ? length / 2 : 240);
+                                       [_audioscrobblerTimer invalidate];
+                                       [_audioscrobblerTimer release];
+                                       _audioscrobblerTimer = [[NSTimer alloc] initWithFireDate:[NSDate dateWithTimeIntervalSinceNow:_audioscrobblerInterval] interval:nil target:self selector:@selector(submitAudioscrobblerTrack:) userInfo:nil repeats:NO];
+                                       [[NSRunLoop currentRunLoop] addTimer:_audioscrobblerTimer forMode:NSDefaultRunLoopMode];
+                               }
+                       } else {
+                               _audioscrobblerTimer = nil;
+                       }
         NS_HANDLER
             [self networkError:localException];
         NS_ENDHANDLER
@@ -575,6 +603,19 @@ static MainController *sharedController;
                                [statusItem setToolTip:nil];
                        }
                }
+               
+               if ([df boolForKey:@"audioscrobblerEnabled"]) {
+                       int length = [[self currentRemote] currentSongDuration];
+                       if (length > 30) {
+                               _audioscrobblerInterval = ((length / 2 < 240) ? length / 2 : 240);
+                               [_audioscrobblerTimer invalidate];
+                               [_audioscrobblerTimer release];
+                               _audioscrobblerTimer = [[NSTimer alloc] initWithFireDate:[NSDate dateWithTimeIntervalSinceNow:_audioscrobblerInterval] interval:1.0 target:self selector:@selector(submitAudioscrobblerTrack:) userInfo:nil repeats:NO];
+                               [[NSRunLoop currentRunLoop] addTimer:_audioscrobblerTimer forMode:NSDefaultRunLoopMode];
+                       }
+               } else {
+                       _audioscrobblerTimer = nil;
+               }
        NS_HANDLER
                [self networkError:localException];
        NS_ENDHANDLER
@@ -586,6 +627,39 @@ static MainController *sharedController;
     }
 }
 
+- (void)submitAudioscrobblerTrack:(NSTimer *)timer
+{
+       ITDebugLog(@"Audioscrobbler: Attempting to submit current track");
+       [timer invalidate];
+       if ([df boolForKey:@"audioscrobblerEnabled"]) {
+               NS_DURING
+                       int elapsed = [[self currentRemote] currentSongPlayed], length = [[self currentRemote] currentSongDuration], requiredInterval = ((length / 2 < 240) ? length / 2 : 240);
+                       if ((abs(elapsed - requiredInterval) < 5) && ([[self currentRemote] playerPlayingState] == ITMTRemotePlayerPlaying)) {
+                               NSString *title = [[self currentRemote] currentSongTitle], *artist = [[self currentRemote] currentSongArtist];
+                               NSLog(@"Audioscrobbler: Submitting");
+                               if (title && artist) {
+                                       ITDebugLog(@"Audioscrobbler: Submitting current track");
+                                       [[AudioscrobblerController sharedController] submitTrack:title
+                                                                                                                                       artist:artist
+                                                                                                                                       album:[[self currentRemote] currentSongAlbum]
+                                                                                                                                       length:[[self currentRemote] currentSongDuration]];
+                               }
+                       } else if (requiredInterval - elapsed > 0) {
+                               _audioscrobblerInterval = requiredInterval - elapsed;
+                               [_audioscrobblerTimer release];
+                               NSLog(@"Audioscrobbler: Creating a new timer that will run in %i seconds", _audioscrobblerInterval);
+                               ITDebugLog(@"Audioscrobbler: Creating a new timer that will run in %i seconds", _audioscrobblerInterval);
+                               _audioscrobblerTimer = [[NSTimer alloc] initWithFireDate:[NSDate dateWithTimeIntervalSinceNow:_audioscrobblerInterval] interval:1.0 target:self selector:@selector(submitAudioscrobblerTrack:) userInfo:nil repeats:NO];
+                               [[NSRunLoop currentRunLoop] addTimer:_audioscrobblerTimer forMode:NSDefaultRunLoopMode];
+                       } else {
+                               NSLog(@"Audioscrobbler: Skipping submission. %i, %i", requiredInterval, elapsed);
+                       }
+               NS_HANDLER
+                       [self networkError:localException];
+               NS_ENDHANDLER
+       }
+}
+
 //
 //
 // Menu Selectors
@@ -905,10 +979,20 @@ static MainController *sharedController;
         [hotKey setName:@"TrackInfo"];
         [hotKey setKeyCombo:[ITKeyCombo keyComboWithPlistRepresentation:[df objectForKey:@"TrackInfo"]]];
         [hotKey setTarget:self];
-        [hotKey setAction:@selector(showCurrentTrackInfo)];
+        [hotKey setAction:@selector(showCurrentTrackInfoHotKey)];
         [[ITHotKeyCenter sharedCenter] registerHotKey:[hotKey autorelease]];
     }
     
+       if ([df objectForKey:@"AlbumArt"] != nil) {
+        ITDebugLog(@"Setting up album art hot key.");
+        hotKey = [[ITHotKey alloc] init];
+        [hotKey setName:@"AlbumArt"];
+        [hotKey setKeyCombo:[ITKeyCombo keyComboWithPlistRepresentation:[df objectForKey:@"AlbumArt"]]];
+        [hotKey setTarget:self];
+        [hotKey setAction:@selector(showCurrentAlbumArtHotKey)];
+        [[ITHotKeyCenter sharedCenter] registerHotKey:[hotKey autorelease]];
+    }
+       
     if ([df objectForKey:@"UpcomingSongs"] != nil) {
         ITDebugLog(@"Setting up upcoming songs hot key.");
         hotKey = [[ITHotKey alloc] init];
@@ -1015,6 +1099,69 @@ static MainController *sharedController;
     ITDebugLog(@"Finished setting up hot keys.");
 }
 
+- (void)showCurrentTrackInfoHotKey
+{
+       //If we're already visible and the setting says so, vanish instead of displaying again.
+       if ([df boolForKey:@"ToggleTrackInfoWithHotKey"] && [statusWindowController currentStatusWindowType] == StatusWindowTrackInfoType && [[StatusWindow sharedWindow] visibilityState] == ITWindowVisibleState) {
+               ITDebugLog(@"Track window is already visible, hiding track window.");
+               [self invalidateStatusWindowUpdateTimer];
+               [[StatusWindow sharedWindow] vanish:nil];
+               return;
+       }
+       [self showCurrentTrackInfo];
+}
+
+- (void)showCurrentAlbumArtHotKey
+{
+       //If we're already visible and the setting says so, vanish instead of displaying again.
+       if ([df boolForKey:@"ToggleTrackInfoWithHotKey"] && [statusWindowController currentStatusWindowType] == StatusWindowAlbumArtType && [[StatusWindow sharedWindow] visibilityState] == ITWindowVisibleState) {
+               ITDebugLog(@"Art window is already visible, hiding track window.");
+               [[StatusWindow sharedWindow] vanish:nil];
+               return;
+       }
+       [self showCurrentAlbumArt];
+}
+
+- (void)showCurrentAlbumArt
+{
+       NSImage *art = nil;
+       NS_DURING
+               art = [[self currentRemote] currentSongAlbumArt];
+       NS_HANDLER
+               [self networkError:localException];
+       NS_ENDHANDLER
+       
+       if (art) {
+               NSSize oldSize = [art size], newSize;
+               if (oldSize.width > 300 && oldSize.height > 300) {
+                       if (oldSize.width > oldSize.height) {
+                               newSize = NSMakeSize(300, oldSize.height * (300.0f / oldSize.width));
+                       } else {
+                               newSize = NSMakeSize(oldSize.width * (300.0f / oldSize.height), 300);
+                       }
+               } else {
+                       newSize = oldSize;
+               }
+               
+               art = [[[[NSImage alloc] initWithData:[art TIFFRepresentation]] autorelease] imageScaledSmoothlyToSize:newSize];
+               
+               [statusWindowController showAlbumArtWindowWithImage:art];
+       } else {
+               NSString *string = nil;
+               NS_DURING
+                       if ([[self currentRemote] currentSongTitle]) {
+                               string = NSLocalizedString(@"noAlbumArt", @"No art for current song.");
+                       } else {
+                               string = NSLocalizedString(@"noSongPlaying", @"No song is playing.");
+                       }
+               NS_HANDLER
+                       [self networkError:localException];
+               NS_ENDHANDLER
+               //Show the no song playing window if there is no album art or no track is playing
+               [statusWindowController showAlbumArtWindowWithErrorText:string];
+       }
+}
+
 - (void)showCurrentTrackInfo
 {
     ITMTRemotePlayerSource  source      = 0;
@@ -1028,14 +1175,6 @@ static MainController *sharedController;
     int                     rating      = -1;
     int                     playCount   = -1;
        
-       //If we're already visible and the setting says so, vanish instead of displaying again.
-       if ([df boolForKey:@"ToggleTrackInfoWithHotKey"] && [statusWindowController currentStatusWindowType] == StatusWindowTrackInfoType && [[StatusWindow sharedWindow] visibilityState] == ITWindowVisibleState) {
-               ITDebugLog(@"Track window is already visible, hiding track window.");
-               [self invalidateStatusWindowUpdateTimer];
-               [[StatusWindow sharedWindow] vanish:nil];
-               return;
-       }
-       
     ITDebugLog(@"Showing track info status window.");
     
     NS_DURING
@@ -1155,9 +1294,9 @@ static MainController *sharedController;
 
 - (void)updateTime:(NSTimer *)timer
 {
-       StatusWindow *sw = [StatusWindow sharedWindow];
+       StatusWindow *sw = (StatusWindow *)[StatusWindow sharedWindow];
        _timeUpdateCount++;
-       if (_timeUpdateCount < (int)[sw exitDelay] + (int)[[sw exitEffect] effectTime] + (int)[[sw entryEffect] effectTime]) {
+       if ([statusWindowController currentStatusWindowType] == StatusWindowTrackInfoType && [sw visibilityState] != ITWindowHiddenState) {
                NSString *time = nil, *length;
                NS_DURING
                        length = [[self currentRemote] currentSongLength];
@@ -1455,12 +1594,14 @@ static MainController *sharedController;
                        if (refreshTimer) {
                                [refreshTimer invalidate];
                        }
-                       refreshTimer = [[NSTimer scheduledTimerWithTimeInterval:([networkController isConnectedToServer] ? 10.0 : 0.5)
-                                                                        target:self
-                                                                        selector:@selector(timerUpdate)
-                                                                        userInfo:nil
-                                                                        repeats:YES] retain];
                }
+               
+               refreshTimer = [[NSTimer scheduledTimerWithTimeInterval:([networkController isConnectedToServer] ? 10.0 : 0.5)
+                                                                target:self
+                                                                selector:@selector(timerUpdate)
+                                                                userInfo:nil
+                                                                repeats:YES] retain];
+               
         [self timerUpdate];
         ITDebugLog(@"Connection successful.");
         return 1;
@@ -1485,10 +1626,12 @@ static MainController *sharedController;
     [networkController disconnect];
     
     if ([[self currentRemote] playerRunningState] == ITMTRemotePlayerRunning) {
+               refreshTimer = nil;
         [self applicationLaunched:nil];
     } else {
         [self applicationTerminated:nil];
     }
+       
     if (refreshTimer) {
                [self timerUpdate];
        };