private void pollTimer_Tick(object sender, EventArgs e) { if (_iTunes.CurrentTrack == null) { return; } if (_currentArtist == _iTunes.CurrentTrack.Artist && _currentTitle == _iTunes.CurrentTrack.Name && _currentState == _iTunes.PlayerState) { return; } _currentArtist = _iTunes.CurrentTrack.Artist; _currentTitle = _iTunes.CurrentTrack.Name; _currentState = _iTunes.PlayerState; UpdatePresence(); }
public void Get() { this.Volume = this.app.SoundVolume; IITTrack currentTrack = this.app.CurrentTrack; if (currentTrack == null) { return; } ITPlayerState t = ITPlayerState.ITPlayerStateFastForward; if (currentPlayState != this.app.PlayerState) { currentPlayState = this.app.PlayerState; TrackPlayStateChanged?.Invoke(currentPlayState switch { ITPlayerState.ITPlayerStatePlaying => PlayState.Play, _ => PlayState.Pause });
/// <summary> /// Initializes the bridge and connects it to DiscordRPC /// </summary> /// <param name="applicationId">The Discord application ID for rich presence</param> public DiscordBridge(string applicationId) { var handlers = new DiscordRpc.EventHandlers(); DiscordRpc.Initialize(applicationId, ref handlers, true, null); Tokens = AppDomain.CurrentDomain.GetAssemblies().SelectMany(s => s.GetTypes()).Where(p => typeof(IToken).IsAssignableFrom(p) && p.IsClass).Select(Activator.CreateInstance).Select(i => (IToken)i).ToList(); _iTunes = new iTunesApp(); _timer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(15) }; _timer.Tick += Timer_OnTick; _timer.Start(); _currentArtist = ""; _currentTitle = ""; _currentState = ITPlayerState.ITPlayerStateStopped; _currentPosition = 0; }
private void UpdateStatus() { if (_started == false) { return; } if (_iTunesApplication == null) { return; } TimeSpan ts = DateTime.Now - _updateTimer; if (ts.TotalSeconds >= 1 || _duration < 0 || _started == false) { _playerState = _iTunesApplication.PlayerState; _duration = _iTunesApplication.CurrentTrack.Duration; _currentPosition = (double)_iTunesApplication.PlayerPosition; _updateTimer = DateTime.Now; } }
private void AllProps(iTunesAppClass itunes) { bool acmpEnabled = itunes.AppCommandMessageProcessingEnabled; IITEncoder encoder = itunes.CurrentEncoder; IITEQPreset eqPreset = itunes.CurrentEQPreset; IITPlaylist playlist = itunes.CurrentPlaylist; string streamTitle = itunes.CurrentStreamTitle; string streamURL = itunes.CurrentStreamURL; IITTrack track = itunes.CurrentTrack; IITVisual visual = itunes.CurrentVisual; IITEncoderCollection encoders = itunes.Encoders; bool eqEnabled = itunes.EQEnabled; IITEQPresetCollection eqPresets = itunes.EQPresets; // this always seems to raise a COM exception, whether playing or stopped... //IITWindow eqWindow = itunes.EQWindow; bool fgOnDialog = itunes.ForceToForegroundOnDialog; bool fsVisuals = itunes.FullScreenVisuals; IITLibraryPlaylist libPlaylist = itunes.LibraryPlaylist; IITSource libSource = itunes.LibrarySource; string libXmlPath = itunes.LibraryXMLPath; bool mute = itunes.Mute; // this will raise a COM exception when iTunes first started //int position = itunes.PlayerPosition; ITPlayerState state = itunes.PlayerState; IITTrackCollection selectedTracks = itunes.SelectedTracks; int volume = itunes.SoundVolume; bool volEnabled = itunes.SoundVolumeControlEnabled; IITSourceCollection sources = itunes.Sources; string version = itunes.Version; IITVisualCollection visuals = itunes.Visuals; bool visualsEnabled = itunes.VisualsEnabled; ITVisualSize visualSize = itunes.VisualSize; IITWindowCollection windows = itunes.Windows; }
/// <summary> /// Handles checking for playing status changes and pushing out presence updates /// </summary> /// <param name="sender">Sender of this event</param> /// <param name="e">Args of this event</param> private void Timer_OnTick(object sender, EventArgs e) { try { if (_iTunes == null) { _iTunes = new iTunesApp(); } if (_iTunes.CurrentTrack == null) { DiscordRpc.ClearPresence(); return; } } catch (COMException) { _iTunes = null; var newPresence = new DiscordRpc.RichPresence { largeImageKey = "itunes_logo_big", details = "Error connecting to iTunes", state = "Playback information unavailable" }; DiscordRpc.UpdatePresence(newPresence); return; } if (_currentArtist == _iTunes.CurrentTrack.Artist && _currentTitle == _iTunes.CurrentTrack.Name && _currentState == _iTunes.PlayerState && _currentPosition == _iTunes.PlayerPosition) { return; } _currentArtist = _iTunes.CurrentTrack.Artist; _currentTitle = _iTunes.CurrentTrack.Name; _currentState = _iTunes.PlayerState; _currentPosition = _iTunes.PlayerPosition; var presence = new DiscordRpc.RichPresence { largeImageKey = "itunes_logo_big" }; if (_currentState != ITPlayerState.ITPlayerStatePlaying) { presence.details = TruncateString(RenderString(Settings.Default.PausedTopLine)); presence.state = TruncateString(RenderString(Settings.Default.PausedBottomLine)); } else { presence.details = TruncateString(RenderString(Settings.Default.PlayingTopLine)); presence.state = TruncateString(RenderString(Settings.Default.PlayingBottomLine)); if (Settings.Default.DisplayPlaybackDuration) { presence.startTimestamp = DateTimeOffset.Now.ToUnixTimeSeconds() - _currentPosition; presence.endTimestamp = DateTimeOffset.Now.ToUnixTimeSeconds() + (_iTunes.CurrentTrack.Duration - _currentPosition); } } try { DiscordRpc.UpdatePresence(presence); } catch (Exception exception) { exception.Data.Add("CurrentArtist", _currentArtist); exception.Data.Add("CurrentTitle", _currentTitle); exception.Data.Add("CurrentState", _currentState.ToString()); exception.Data.Add("CurrentPosition", _currentPosition.ToString()); exception.Data.Add("Details", presence.details); exception.Data.Add("State", presence.state); Globals.RavenClient.Capture(new SentryEvent(exception)); Globals.Log($"An unhandled exception has occurred and been reported to Sentry: {exception.Message}"); } }
/// <summary> /// Handles checking for playing status changes and pushing out presence updates /// </summary> /// <param name="sender">Sender of this event</param> /// <param name="e">Args of this event</param> private void Timer_OnTick(object sender, EventArgs e) { try { if (ITunes == null) { ITunes = new iTunesApp(); } if (ITunes.CurrentTrack == null || (Settings.Default.ClearOnPause && ITunes.PlayerState != ITPlayerState.ITPlayerStatePlaying)) { DiscordRpc.ClearPresence(); return; } } catch (COMException) { ITunes = null; var newPresence = new DiscordRpc.RichPresence { largeImageKey = "itunes_logo_big", details = "Error connecting to iTunes", state = "Playback information unavailable" }; DiscordRpc.UpdatePresence(newPresence); return; } catch (EntryPointNotFoundException) { var newPresence = new DiscordRpc.RichPresence { largeImageKey = "itunes_logo_big", details = "No song playing", state = "Re-install iTunesRichPresence to clear this message" }; DiscordRpc.UpdatePresence(newPresence); return; } if (_currentArtist == ITunes.CurrentTrack.Artist && _currentTitle == ITunes.CurrentTrack.Name && _currentState == ITunes.PlayerState && _currentPosition == ITunes.PlayerPosition) { return; } _currentArtist = ITunes.CurrentTrack.Artist; _currentTitle = ITunes.CurrentTrack.Name; _currentState = ITunes.PlayerState; _currentPosition = ITunes.PlayerPosition; int _currentAlbumCoverCount = ITunes.CurrentTrack.Artwork.Count; string PREFIX = "itlps-"; foreach (var artT in ITunes.CurrentTrack.Artwork) { var art = artT as IITArtwork; string ext = ".tmp"; switch (art.Format) { case ITArtworkFormat.ITArtworkFormatBMP: ext = ".bmp"; break; case ITArtworkFormat.ITArtworkFormatJPEG: ext = ".jpg"; break; case ITArtworkFormat.ITArtworkFormatPNG: ext = ".png"; break; } string path = Path.Combine(Path.GetTempPath(), PREFIX + Path.GetRandomFileName() + ext); art.SaveArtworkToFile(path); //Debug.WriteLine(path); } Debug.WriteLine("DB ID: " + ITunes.CurrentTrack.TrackDatabaseID); Debug.WriteLine("Track ID: " + ITunes.CurrentTrack.trackID); Debug.WriteLine("Artwork: " + ITunes.CurrentTrack.Artwork); var presence = new DiscordRpc.RichPresence { largeImageKey = path }; if (_currentState != ITPlayerState.ITPlayerStatePlaying) { presence.details = TruncateString(RenderString(Settings.Default.PausedTopLine)); presence.state = TruncateString(RenderString(Settings.Default.PausedBottomLine)); } else { presence.details = "[" + _currentArtist + "](https://google.co.uk)"; //Embed top line presence.state = _currentTitle; //Embed bottom line. if (Settings.Default.DisplayPlaybackDuration) { presence.startTimestamp = DateTimeOffset.Now.ToUnixTimeSeconds() - _currentPosition; presence.endTimestamp = DateTimeOffset.Now.ToUnixTimeSeconds() + (ITunes.CurrentTrack.Duration - _currentPosition); } } try { DiscordRpc.UpdatePresence(presence); } catch (Exception exception) { exception.Data.Add("CurrentArtist", _currentArtist); exception.Data.Add("CurrentTitle", _currentTitle); exception.Data.Add("CurrentState", _currentState.ToString()); exception.Data.Add("CurrentPosition", _currentPosition.ToString()); exception.Data.Add("Details", presence.details); exception.Data.Add("State", presence.state); Globals.RavenClient.Capture(new SentryEvent(exception)); Globals.Log($"An unhandled exception has occurred and been reported to Sentry: {exception.Message}"); } }
public override bool Play(string strFile) { try { if (_iTunesApplication == null) { _iTunesApplication = new iTunesAppClass(); _iTunesApplication.OnPlayerPlayEvent += new _IiTunesEvents_OnPlayerPlayEventEventHandler(_iTunesApplication_OnPlayerPlayEvent); _iTunesApplication.OnPlayerStopEvent += new _IiTunesEvents_OnPlayerStopEventEventHandler(_iTunesApplication_OnPlayerStopEvent); _iTunesApplication.OnPlayerPlayingTrackChangedEvent += new _IiTunesEvents_OnPlayerPlayingTrackChangedEventEventHandler( _iTunesApplication_OnPlayerPlayingTrackChangedEvent); IITPlaylist playList = null; foreach (IITPlaylist pl in _iTunesApplication.LibrarySource.Playlists) { if (pl.Name.Equals("MediaPortalTemporaryPlaylist")) { playList = pl; break; } } if (playList == null) { _playList = (IITUserPlaylist)_iTunesApplication.CreatePlaylist("MediaPortalTemporaryPlaylist"); } else { _playList = (IITUserPlaylist)playList; } _playList.SongRepeat = ITPlaylistRepeatMode.ITPlaylistRepeatModeOff; } // stop other media which might be active until now. if (g_Player.Playing) { g_Player.Stop(); } GUIMessage msg = new GUIMessage(GUIMessage.MessageType.GUI_MSG_PLAYBACK_STARTED, 0, 0, 0, 0, 0, null); msg.Label = strFile; GUIWindowManager.SendThreadMessage(msg); _started = false; _ended = false; foreach (IITTrack track in _playList.Tracks) { track.Delete(); } _playList.AddFile(strFile); _playList.PlayFirstTrack(); _playerIsPaused = false; _currentFile = strFile; _duration = -1; _currentPosition = -1; _playerState = ITPlayerState.ITPlayerStateStopped; _updateTimer = DateTime.MinValue; UpdateStatus(); _notifyPlaying = true; return(true); } catch (Exception ex) { Log.Error("ITunesPlugin.Play: Exception"); Log.Error(ex); _notifyPlaying = false; _iTunesApplication = null; } return(false); }
private void DumpState(iTunesAppClass itunes) { IITPlaylist playlist = itunes.CurrentPlaylist; Debug.WriteLine("itunes.CurrentPlaylist"); if (itunes.CurrentPlaylist == null) { Debug.WriteLine("... NULL"); } else { Debug.WriteLine(String.Format("... Kind [{0}]", itunes.CurrentPlaylist.Kind)); Debug.WriteLine(String.Format("... Name [{0}]", itunes.CurrentPlaylist.Name)); Debug.WriteLine(String.Format("... Tracks.Count [{0}]", itunes.CurrentPlaylist.Tracks.Count)); } string streamTitle = itunes.CurrentStreamTitle; Debug.WriteLine(String.Format("iTunes.CurrentStreamTitle [{0}]", itunes.CurrentStreamTitle)); string streamURL = itunes.CurrentStreamURL; Debug.WriteLine(String.Format("iTunes.CurrentStreamURL [{0}]", itunes.CurrentStreamURL)); IITTrack currentTrack = itunes.CurrentTrack; Debug.WriteLine("itunes.CurrentTrack"); if (itunes.CurrentTrack == null) { Debug.WriteLine("... NULL"); } else { Debug.WriteLine(String.Format("... Album [{0}]", currentTrack.Album)); Debug.WriteLine(String.Format("... Artist [{0}]", currentTrack.Artist)); Debug.WriteLine(String.Format("... Kind [{0}]", currentTrack.Kind)); Debug.WriteLine(String.Format("... Name [{0}]", currentTrack.Name)); Debug.WriteLine(String.Format("... trackID [{0}]", currentTrack.trackID)); } int position = itunes.PlayerPosition; Debug.WriteLine(String.Format("iTunes.PlayerPosition [{0}]", itunes.PlayerPosition)); ITPlayerState state = itunes.PlayerState; Debug.WriteLine(String.Format("iTunes.PlayerState [{0}]", itunes.PlayerState)); IITTrackCollection selectedTracks = itunes.SelectedTracks; Debug.WriteLine("itunes.SelectedTracks"); if (itunes.SelectedTracks == null) { Debug.WriteLine("... NULL"); } else { foreach (IITTrack track in itunes.SelectedTracks) { Debug.WriteLine("... track"); Debug.WriteLine(String.Format("... Album [{0}]", itunes.CurrentTrack.Album)); Debug.WriteLine(String.Format("... Artist [{0}]", itunes.CurrentTrack.Artist)); Debug.WriteLine(String.Format("... Kind [{0}]", itunes.CurrentTrack.Kind)); Debug.WriteLine(String.Format("... Name [{0}]", itunes.CurrentTrack.Name)); Debug.WriteLine(String.Format("... trackID [{0}]", itunes.CurrentTrack.trackID)); } } }
public override bool Play(string strFile) { try { if (_iTunesApplication == null) { _iTunesApplication = new iTunesAppClass(); _iTunesApplication.OnPlayerPlayEvent += new _IiTunesEvents_OnPlayerPlayEventEventHandler(_iTunesApplication_OnPlayerPlayEvent); _iTunesApplication.OnPlayerStopEvent += new _IiTunesEvents_OnPlayerStopEventEventHandler(_iTunesApplication_OnPlayerStopEvent); _iTunesApplication.OnPlayerPlayingTrackChangedEvent += new _IiTunesEvents_OnPlayerPlayingTrackChangedEventEventHandler( _iTunesApplication_OnPlayerPlayingTrackChangedEvent); IITPlaylist playList = null; foreach (IITPlaylist pl in _iTunesApplication.LibrarySource.Playlists) { if (pl.Name.Equals("MediaPortalTemporaryPlaylist")) { playList = pl; break; } } if (playList == null) { _playList = (IITUserPlaylist)_iTunesApplication.CreatePlaylist("MediaPortalTemporaryPlaylist"); } else { _playList = (IITUserPlaylist)playList; } _playList.SongRepeat = ITPlaylistRepeatMode.ITPlaylistRepeatModeOff; } // stop other media which might be active until now. if (g_Player.Playing) { g_Player.Stop(); } GUIMessage msg = new GUIMessage(GUIMessage.MessageType.GUI_MSG_PLAYBACK_STARTED, 0, 0, 0, 0, 0, null); msg.Label = strFile; GUIWindowManager.SendThreadMessage(msg); _started = false; _ended = false; foreach (IITTrack track in _playList.Tracks) { track.Delete(); } _playList.AddFile(strFile); _playList.PlayFirstTrack(); _playerIsPaused = false; _currentFile = strFile; _duration = -1; _currentPosition = -1; _playerState = ITPlayerState.ITPlayerStateStopped; _updateTimer = DateTime.MinValue; UpdateStatus(); _notifyPlaying = true; return true; } catch (Exception ex) { Log.Error("ITunesPlugin.Play: Exception"); Log.Error(ex); _notifyPlaying = false; _iTunesApplication = null; } return false; }
// 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 } } }