public void InitializeSource(int minimumScrobbleSeconds, TrackStarted onTrackStartedCallback, TrackEnded onTrackEndedCallback, ScrobbleTrack onScrobbleTrack)
        {
            _minimumScrobbleSeconds = minimumScrobbleSeconds;

            _onTrackStarted  = onTrackStartedCallback;
            _onTrackEnded    = onTrackEndedCallback;
            _onScrobbleTrack = onScrobbleTrack;

            _isIntialized = true;

            try
            {
                _scrobbleTimer          = new Timer();
                _scrobbleTimer.Interval = 1000;

                _scrobbleTimer.Elapsed += async(o, e) =>
                {
                    _scrobbleTimer.Stop();

                    iTunesApp iTunesApp = null;

                    // Check for the iTunes process to ensure it's running.
                    // If we don't check for it, the plugin would end up launching it, which we don't want
                    Process[] iTunesProcesses = Process.GetProcessesByName("iTunes");

                    if (iTunesProcesses.Length > 0)
                    {
                        try
                        {
                            iTunesApp = new iTunesApp();
                            Console.WriteLine("iTunes Plugin successfully connected to iTunes COM library.");
                        }
                        catch (Exception)
                        {
                            // Ignore this, more than likely the application was in the process of closing while we tried to read from it
                        }
                    }
                    else if (iTunesProcesses.Length == 0 && _currentMediaItem != null)
                    {
                        _onTrackEnded(null);
                        _currentMediaItem = null;
                        Console.WriteLine("iTunes process not detected.  Waiting for iTunes process to start...");
                    }

                    if (iTunesApp != null)
                    {
                        Console.WriteLine("iTunes Plugin checking media state...");

                        if (_isEnabled)
                        {
                            MediaItem mediaDetail = await GetMediaDetail(iTunesApp);

                            if (mediaDetail != null && _mediaToScrobble.Count(mediaItem => mediaItem.TrackName == mediaDetail?.TrackName) == 0 && _currentMediaItem?.TrackName != mediaDetail?.TrackName && iTunesApp.PlayerState == ITPlayerState.ITPlayerStatePlaying)
                            {
                                _currentMediaPlayTime = 1;

                                if (_currentMediaItem != null)
                                {
                                    _onTrackEnded?.Invoke(_currentMediaItem);
                                }

                                _currentMediaItem = mediaDetail;
                                _lastStatePaused  = false;

                                Console.WriteLine("Raising Track Change Method.");

                                _onTrackStarted?.Invoke(mediaDetail, false);
                                mediaDetail.StartedPlaying = DateTime.Now;
                            }
                            else if (iTunesApp.PlayerState != ITPlayerState.ITPlayerStatePlaying)
                            {
                                if (_currentMediaPlayTime > 0)
                                {
                                    _onTrackEnded?.Invoke(_currentMediaItem);
                                    _currentMediaItem = null;
                                }

                                if (iTunesApp.PlayerState != ITPlayerState.ITPlayerStateStopped)
                                {
                                    _lastStatePaused      = false;
                                    _currentMediaPlayTime = 0;
                                }
                            }
                            else if (iTunesApp.PlayerState == ITPlayerState.ITPlayerStatePlaying && _currentMediaItem?.TrackName == mediaDetail?.TrackName)
                            {
                                if (_currentMediaPlayTime == 0 || _lastStatePaused)
                                {
                                    _onTrackStarted?.Invoke(_currentMediaItem, _lastStatePaused);
                                }
                                _currentMediaPlayTime++;
                            }

                            if (_currentMediaItem != null)
                            {
                                Console.WriteLine($"Current media playing time: {_currentMediaPlayTime} of {_currentMediaItem.TrackLength}.");

                                if (mediaDetail != null && _mediaToScrobble.Count(item => item.TrackName == mediaDetail?.TrackName) == 0 &&
                                    _currentMediaPlayTime >= _minimumScrobbleSeconds && _currentMediaPlayTime >= Math.Min(_currentMediaItem.TrackLength / 2, 5 * 60) &&
                                    mediaDetail?.TrackName != _lastQueuedItem?.TrackName)
                                {
                                    _lastQueuedItem = mediaDetail;

                                    lock (_mediaLock)
                                    {
                                        _mediaToScrobble.Add(mediaDetail);
                                        Console.WriteLine($"Track {mediaDetail.TrackName} queued for Scrobbling.");
                                    }

                                    _onScrobbleTrack?.Invoke(mediaDetail);
                                }
                            }
                        }

                        Console.WriteLine("iTunes Plugin checking media state complete.");
                    }
                    else if (_currentMediaItem != null)
                    {
                        _onTrackEnded?.Invoke(_currentMediaItem);
                        _currentMediaItem = null;
                    }

                    if (iTunesApp != null)
                    {
                        Marshal.ReleaseComObject(iTunesApp);
                    }

                    _scrobbleTimer.Start();
                };
            }
            catch (Exception ex)
            {
                _scrobbleTimer.Start();
            }
        }
Beispiel #2
0
        // Plugin intialization function
        public void InitializeSource(int minimumScrobbleSeconds, TrackMonitoringStarted onTrackMonitoringStarted, TrackMonitoring onTrackMonitoring, TrackMonitoringEnded onTrackMonitoringEnded, ScrobbleTrack onScrobbleTrack)
        {
            _minimumScrobbleSeconds = minimumScrobbleSeconds;

            _onTrackMonitoringStarted = onTrackMonitoringStarted;
            _onTrackMonitoring        = onTrackMonitoring;
            _onTrackMonitoringEnded   = onTrackMonitoringEnded;
            _onScrobbleTrack          = onScrobbleTrack;

            _isIntialized = true;

            try
            {
                // Create a new scrobbler timer, to fire every second
                _scrobbleTimer          = new System.Timers.Timer();
                _scrobbleTimer.Interval = 2000;

                // The ananoymous delegate event that occurs every time the timer fires (elapses)
                _scrobbleTimer.Elapsed += async(o, e) =>
                {
                    // Stop the timer to prevent multiple executions at the same time
                    _scrobbleTimer.Stop();

                    // Check for the Windows Media Player process to ensure it's running.
                    // If we don't check for it, the plugin would end up launching it, which we don't want
                    Process[] wmpProcesses = Process.GetProcessesByName("wmplayer");

                    if (wmpProcesses.Length > 0 && _mediaPlayer == null)
                    {
                        _mediaPlayer = new WindowsMediaPlayer();
                        Console.WriteLine("Windows Media Player Plugin successfully connected to the WMP COM library.");
                    }
                    else if (wmpProcesses.Length == 0 && _mediaPlayer != null)
                    {
                        Console.WriteLine("Windows Media Player process not detected.  Waiting for Windows Media Player process to start...");
                    }

                    if (_mediaPlayer != null)
                    {
                            #if DebugWMPScrobbler
                        Console.WriteLine("Windows Media Player Plugin checking media state...");
                            #endif

                        if (_isEnabled)
                        {
                            // Get the current media from Windows Media Player itself (using our helper function)
                            MediaItem mediaDetail = await GetMediaDetail().ConfigureAwait(false);

                            // Get the media player state
                            WMPPlayState playerState    = _mediaPlayer?.Player?.playState ?? WMPPlayState.wmppsStopped;
                            double       playerPosition = _mediaPlayer?.Player?.Ctlcontrols?.currentPosition ?? 0;

                            // Determine if there is any media loaded
                            bool hasMedia = mediaDetail != null;

                            // Determine if the current track is deemed to have 'ended' as it's been fully listened to
                            bool hasReachedTrackEnd = hasMedia && (int)playerPosition + 1 >= (int)mediaDetail?.TrackLength && mediaDetail?.TrackLength > 0;

                            // Determine if the current track playing isn't the last one we knew about
                            bool hasTrackChanged = _currentMediaItem?.TrackName != mediaDetail?.TrackName;

                            // Determine if the media player is in the 'Paused' state
                            bool isPaused = playerState == WMPPlayState.wmppsPaused;

                            // Determine if the media player is in the 'Playing' state
                            bool isPlaying = playerState == WMPPlayState.wmppsPlaying;

                            bool isTrackChanging = playerState == WMPPlayState.wmppsTransitioning;

                            // Determine if the current media item is scrobbleable
                            bool canScrobble = _currentMediaTrackingTime >= _minimumScrobbleSeconds &&
                                               (_currentMediaTrackingTime >= Convert.ToInt32(Math.Min(Convert.ToInt32(_currentMediaItem?.TrackLength) / 2, 4 * 60)) && !_currentMediaWasScrobbled);


#if DebugWMPScrobbler
                            Console.WriteLine($"Windows Media Player Plugin: Position {playerPosition} of { mediaDetail?.TrackLength }, Tracker time: {_currentMediaTrackingTime}...");
#endif

                            // If the media player is still playing and the track has changed, or the current media has reached it's end (and therefore the media player has stopped)
                            if ((isPlaying && hasMedia && hasTrackChanged) || hasReachedTrackEnd)
                            {
                                // Reset the last paused state
                                _lastStatePaused = false;

                                // Reset the current tracking time to the default number of timer seconds
                                _currentMediaTrackingTime = (_currentMediaTrackingTime == 2) ? 3 : 2;

                                // If we knew about a media item before we got here
                                if (_currentMediaItem != null)
                                {
                                    // Fire the 'track monitoring has ended' event for the previous item
                                    _onTrackMonitoringEnded?.BeginInvoke(_currentMediaItem, null, null);

                                    // Fire the 'scrobble the item' event for the previous item
                                    _onScrobbleTrack?.BeginInvoke(_currentMediaItem, null, null);
                                }

                                Console.WriteLine("Windows Media Player: Raising Track Change Method.");

                                // If the reason we are here is because there is a new track being monitored
                                if (hasTrackChanged)
                                {
                                    // Track when we started monitoring the new item (to pass to the Last.fm API)
                                    mediaDetail.StartedPlaying = DateTime.Now;

                                    // Set the current monitor item, to what the media player has told us is playing
                                    _currentMediaItem = mediaDetail;

                                    // Fire the 'track monitoring has started' even for the new item
                                    _onTrackMonitoringStarted?.BeginInvoke(mediaDetail, false, null, null);
                                }
                                // Otherwise if we got here because the current item has ended, and no new item is playing
                                else if (hasReachedTrackEnd)
                                {
                                    _currentMediaTrackingTime = 2;

                                    // Clear the currently tracked media item, so that if the user starts playing it again, it is treated
                                    // as an entirely new scrobble
                                    _currentMediaItem = null;
                                }

                                // Reset the flag determining if the current item has been added to the Scrobble queue
                                _currentMediaWasScrobbled = false;
                            }
                            // If the media playing is playing and has media associated, we have reached the point where the item has been
                            // tracked beyond the minimum number of tracking seconds and the item hasn't already been added to the scrobble queue
                            else if (isPlaying && hasMedia && canScrobble && !_currentMediaWasScrobbled)
                            {
                                // Safely add the media item to the scrobble queue
                                lock (_mediaLock)
                                {
                                    _mediaToScrobble.Add(_currentMediaItem);
                                }

                                // Fire the 'we are still tracking this item' event
                                _onTrackMonitoring?.BeginInvoke(_currentMediaItem, (int)playerPosition, null, null);

                                // Update the current media tracking time
                                _currentMediaTrackingTime += 2;

                                // Mark the item as having been added to the scrobble queue
                                //(potential improvement, move this property to _currentMediaItem and remove the local variable)
                                _currentMediaWasScrobbled = true;

                                Console.WriteLine($"Windows Media Player: Track {mediaDetail.TrackName} queued for Scrobbling.");
                            }
                            // The media player is playing, and is still playing the same track
                            else if (isPlaying && !hasTrackChanged)
                            {
                                // If the media player wasn't last in the paused state
                                if (_lastStatePaused)
                                {
                                    // Fire the 'we started monitoring this item' event
                                    _onTrackMonitoringStarted?.BeginInvoke(_currentMediaItem, _lastStatePaused, null, null);

                                    // Reset the pause flag
                                    _lastStatePaused = false;
                                }

                                // Fire the 'we are still monitoring this item event' (possibly should be inside an else, although won't hurt
                                // where it is)
                                _onTrackMonitoring?.BeginInvoke(_currentMediaItem, (int)playerPosition, null, null);

                                // Update the current media tracking time
                                _currentMediaTrackingTime += 2;
                            }
                            // The media player is not playing
                            else if (!isPlaying && !isTrackChanging)
                            {
                                // If we had been playing, invoke the Track Ended callback
                                if (_currentMediaTrackingTime > 1 && !_lastStatePaused)
                                {
                                    _onTrackMonitoringEnded?.BeginInvoke(mediaDetail, null, null);

                                    if (!isPaused)
                                    {
                                        // Fire the 'scrobble the item' event for the previous item
                                        _onScrobbleTrack?.BeginInvoke(_currentMediaItem, null, null);

                                        //_currentMediaItem = null;
                                    }
                                }

                                // Set the persisted pause state
                                _lastStatePaused = isPaused;

                                // If we're not paused (FF, Rewind)
                                if (!isPaused)
                                {
                                    // Reset the state tracking how long we played this track for
                                    _lastStatePaused          = false;
                                    _currentMediaTrackingTime = 0;
                                    _currentMediaWasScrobbled = false;
                                }
                            }
                        }

                            #if DebugWMPScrobbler
                        Console.WriteLine("Windows Media Plugin checking media state complete.");
                            #endif
                    }
                    else if (_currentMediaItem != null)
                    {
                        _onTrackMonitoringEnded?.BeginInvoke(_currentMediaItem, null, null);
                        _currentMediaItem         = null;
                        _currentMediaWasScrobbled = false;
                    }

                    _scrobbleTimer?.Start();
                };
            }
            catch (Exception ex)
            {
                try
                {
                    _scrobbleTimer?.Start();
                }
                catch (Exception exception)
                {
                    // Can occur if you close the application as it's starting up
                }
            }
        }
        // Plugin intialization function
        public void InitializeSource(int minimumScrobbleSeconds, TrackMonitoringStarted onTrackMonitoringStarted, TrackMonitoring onTrackMonitoring, TrackMonitoringEnded onTrackMonitoringEnded, ScrobbleTrack onScrobbleTrack)
        {
            _minimumScrobbleSeconds = minimumScrobbleSeconds;

            _onTrackMonitoringStarted = onTrackMonitoringStarted;
            _onTrackMonitoring        = onTrackMonitoring;
            _onTrackMonitoringEnded   = onTrackMonitoringEnded;
            _onScrobbleTrack          = onScrobbleTrack;

            _isIntialized = true;

            try
            {
                // Create a new scrobbler timer, to fire at the specified number of seconds
                _scrobbleTimer          = new Timer();
                _scrobbleTimer.Interval = 1000 * _timerInterval;

                // The ananoymous delegate event that occurs every time the timer fires (elapses)
                _scrobbleTimer.Elapsed += async(o, e) =>
                {
                    // Stop the timer to prevent multiple executions at the same time
                    _scrobbleTimer.Stop();

                    // Check for the iTunes process to ensure it's running.
                    // If we don't check for it, the plugin would end up launching it when we connect, which we don't want
                    Process[] iTunesProcesses = Process.GetProcessesByName("iTunes");

                    if (iTunesProcesses.Length > 0)
                    {
                        try
                        {
                            if (_isEnabled)
                            {
                                iTunesApp iTunesApp = new iTunesApp();

                                    #if DebugiTunes
                                Console.WriteLine("iTunes Plugin successfully connected to iTunes COM library.");
                                Console.WriteLine("iTunes Plugin checking media state...");
                                    #endif

                                // Get the current media from iTunes itself (using our helper function)
                                MediaItem mediaDetail = await GetMediaDetail(iTunesApp).ConfigureAwait(false);

                                ITPlayerState playerState    = ITPlayerState.ITPlayerStateStopped;
                                double        playerPosition = 0;

                                try
                                {
                                    // Get the iTunes media player state
                                    playerState    = iTunesApp?.PlayerState ?? ITPlayerState.ITPlayerStateStopped;
                                    playerPosition = iTunesApp?.PlayerPosition ?? 0;
                                }
                                catch (COMException comEx)
                                {
                                    // If the player is in an invalid state, this is going to happen!
                                }

                                // Determine if there is any media loaded
                                bool hasMedia = mediaDetail != null;

                                // Determine if the current track is deemed to have 'ended' as it's been fully listened to
                                bool hasReachedTrackEnd = hasMedia && (int)playerPosition + _timerInterval >= (int)mediaDetail?.TrackLength && mediaDetail?.TrackLength > 0;

                                // Determine if the current track playing isn't the last one we knew about
                                bool hasTrackChanged = _currentMediaItem?.TrackName != mediaDetail?.TrackName;

                                // Determine if the media player is in the 'Playing' state
                                bool isPlaying = playerState == ITPlayerState.ITPlayerStatePlaying;

                                // Determine if the media player is in the 'Stopped' (paused) state
                                bool isPaused = playerState == ITPlayerState.ITPlayerStateStopped;

                                // Determine if the current media item is scrobbleable
                                bool canScrobble = _currentMediaTrackingTime >= _minimumScrobbleSeconds &&
                                                   (_currentMediaTrackingTime >= Convert.ToInt32(Math.Min(Convert.ToInt32(_currentMediaItem?.TrackLength) / 2, 4 * 60)) && !_currentMediaWasScrobbled);

#if DebugiTunes
                                Console.WriteLine($"iTunes Media Player Plugin: Position {playerPosition} of { mediaDetail?.TrackLength }, Tracker time: {_currentMediaTrackingTime}...");
#endif

                                // If we have reached the point where the item has been tracked beyond the minimum number of tracking seconds
                                // and the item hasn't already been added to the scrobble queue
                                if (canScrobble && !_currentMediaWasScrobbled)
                                {
                                    // Safely add the media item to the scrobble queue
                                    lock (_mediaLock)
                                    {
                                        _mediaToScrobble.Add(_currentMediaItem);
                                    }

                                    // Fire the 'we are still tracking this item' event
                                    _onTrackMonitoring?.BeginInvoke(_currentMediaItem, (int)playerPosition, null, null);

                                    // Mark the item as having been added to the scrobble queue
                                    //(potential improvement, move this property to _currentMediaItem and remove the local variable)
                                    _currentMediaWasScrobbled = true;

                                    Console.WriteLine($"Track {mediaDetail.TrackName} queued for Scrobbling.");
                                }

                                // If the media player is still playing and the track has changed, or the current media has reached it's end (and therefore the media player has stopped)
                                if ((isPlaying && hasMedia && hasTrackChanged) || hasReachedTrackEnd)
                                {
                                    // Reset the last paused state
                                    _lastStatePaused = false;

                                    // Reset the current tracking time to the default number of timer seconds
                                    _currentMediaTrackingTime = _timerInterval;

                                    // If we knew about a media item before we got here
                                    if (_currentMediaItem != null)
                                    {
                                        // Fire the 'track monitoring has ended' event for the previous item
                                        _onTrackMonitoringEnded?.BeginInvoke(_currentMediaItem, null, null);

                                        // Fire the 'scrobble the item' event for the previous item
                                        _onScrobbleTrack?.BeginInvoke(_currentMediaItem, null, null);
                                    }

                                    Console.WriteLine("iTunes: Raising Track Change Method.");

                                    // If the reason we are here is because there is a new track being monitored
                                    if (hasTrackChanged)
                                    {
                                        // Set the current monitor item, to what the media player has told us is playing
                                        _currentMediaItem = mediaDetail;

                                        // Fire the 'track monitoring has started' even for the new item
                                        _onTrackMonitoringStarted?.BeginInvoke(mediaDetail, false, null, null);

                                        // Track when we started monitoring the new item (to pass to the Last.fm API)
                                        mediaDetail.StartedPlaying = DateTime.Now;
                                    }

                                    // Otherwise if we got here because the current item has ended, and no new item is playing
                                    else if (hasReachedTrackEnd)
                                    {
                                        // Clear the currently tracked media item, so that if the user starts playing it again, it is treated
                                        // as an entirely new scrobble
                                        _currentMediaItem = null;
                                    }

                                    // Reset the flag determining if the current item has been added to the Scrobble queue
                                    _currentMediaWasScrobbled = false;
                                }
                                // The media player is playing, and is still playing the same track
                                else if (isPlaying && !hasTrackChanged)
                                {
                                    // If the media player wasn't last in the paused state
                                    if (_lastStatePaused)
                                    {
                                        // Fire the 'we started monitoring this item' event
                                        _onTrackMonitoringStarted?.BeginInvoke(_currentMediaItem, _lastStatePaused, null, null);

                                        // Reset the pause state flag
                                        _lastStatePaused = false;
                                    }

                                    // Fire the 'we are still monitoring this item event' (possibly should be inside an else, although won't hurt
                                    // where it is)
                                    _onTrackMonitoring?.BeginInvoke(_currentMediaItem, (int)playerPosition, null, null);

                                    // Update the current media tracking time
                                    _currentMediaTrackingTime += _timerInterval;
                                }
                                // The media player is not playing
                                else if (!isPlaying)
                                {
                                    // If we had been playing, invoke the Track Ended callback
                                    if (_currentMediaTrackingTime > _timerInterval && !_lastStatePaused)
                                    {
                                        // Fire the 'we've stopped tracking this item' event
                                        _onTrackMonitoringEnded?.BeginInvoke(mediaDetail, null, null);
                                    }

                                    // Set the persisted pause state
                                    _lastStatePaused = isPaused;

                                    // If we're not paused (FF, Rewind)
                                    if (!isPaused)
                                    {
                                        // Reset the state tracking how long we played this track for
                                        _lastStatePaused          = false;
                                        _currentMediaTrackingTime = 0;
                                        _currentMediaWasScrobbled = false;
                                    }
                                }

                                // Release the iTunes COM library, so that the user _might_ be able to exit iTunes without getting a warning
                                if (iTunesApp != null)
                                {
                                    Marshal.ReleaseComObject(iTunesApp);
                                    iTunesApp = null;
                                }
                                System.GC.Collect();
                            }
#if DebugiTunes
                            Console.WriteLine("iTunes Plugin checking media state complete.");
#endif
                        }
                        catch (COMException cEx)
                        {
                            // Ignore the COM exception, the library is either trying to communicate with a property
                            // that isn't available.  IE PlayerPosition is not available when the player is stopped.

                            // It might also be tearing down
                        }
                        catch (Exception)
                        {
                            // Some other exception occured, at some point consider logging it...?
                        }
                    }
                    else if (iTunesProcesses.Length == 0 && _currentMediaItem != null)
                    {
                        _onTrackMonitoringEnded?.BeginInvoke(_currentMediaItem, null, null);
                        _currentMediaItem         = null;
                        _currentMediaWasScrobbled = false;
                        Console.WriteLine("iTunes process not detected.  Waiting for iTunes process to start...");
                    }


                    _scrobbleTimer?.Start();
                };
            }
            catch (Exception ex)
            {
                try
                {
                    // If an unexpected error occured, don't let that stop us from performing any tracking,
                    // as the error might only be temporary
                    _scrobbleTimer?.Start();
                }
                catch (Exception exception)
                {
                    // Can occur if you close the application as it's starting up
                }
            }
        }