private void CheckTitle() { string currentTitle = Spotify.GetCurrentTrack(); if (!string.IsNullOrEmpty(currentTitle) && currentTitle != previousTitle) { string part1, part2; // set the previous title asap so that the next timer call to this function will // fail fast (setting it at the end may cause multiple web requests) previousTitle = currentTitle; if (SplitTitle(currentTitle, out part1, out part2)) { this.Dispatcher.Invoke((Action) delegate { Title1.Text = part2; Title2.Text = part1; }, System.Windows.Threading.DispatcherPriority.Normal); foreach (var p in this.Plugins) { try { p.TrackChanged(part1, part2); } catch (Exception) { //For now we swallow any plugin errors. } } } try { //Use the iTunes API to get the cover art String url = "https://itunes.apple.com/search?term=" + part2 + "&attribute=songTerm&entity=album"; var json = new WebClient().DownloadString(url); iTunesResult deserializedJson = JsonConvert.DeserializeObject <iTunesResult>(json); //Filter tracks by artist List <iTunesTrack> resultsForArtist = getResultsForArtist(deserializedJson, part1); //Get the oldest track (filters out all the "best of" albums, etc.) iTunesTrack oldestTrack = getOldestTitle(resultsForArtist); coverUrl = oldestTrack.artworkUrl100; } catch (Exception) { coverUrl = "SpotifyToastifyLogo.png"; } this.Dispatcher.Invoke((Action) delegate { FadeIn(); }, System.Windows.Threading.DispatcherPriority.Normal); } }
internal static void ActionHookCallback(Hotkey hotkey) { // Bug 9421: ignore this keypress if it is the same as the previous one and it's been less than // WAIT_BETWEEN_HOTKEY_PRESS since the last press. Note that we do not update // _lastHotkeyPressTime in this case to avoid being trapped in a never ending cycle of // ignoring keypresses if the user (for some reason) decides to press really quickly, // really often on the hotkey if (hotkey == _lastHotkey && DateTime.Now.Subtract(_lastHotkeyPressTime).TotalMilliseconds < WAIT_BETWEEN_HOTKEY_PRESS) { return; } _lastHotkey = hotkey; _lastHotkeyPressTime = DateTime.Now; try { Song songBeforeAction = Toast.Current.currentSong; if (hotkey.Action == SpotifyAction.CopyTrackInfo && songBeforeAction != null) { Telemetry.TrackEvent(TelemetryCategory.Action, Telemetry.TelemetryEvent.Action.CopyTrackInfo); CopySongToClipboard(songBeforeAction); } else if (hotkey.Action == SpotifyAction.PasteTrackInfo && songBeforeAction != null) { Telemetry.TrackEvent(TelemetryCategory.Action, Telemetry.TelemetryEvent.Action.PasteTrackInfo); CopySongToClipboard(songBeforeAction); SendPasteKey(); } else { Spotify.SendAction(hotkey.Action); } Toast.Current.DisplayAction(hotkey.Action, songBeforeAction); } catch (Exception ex) { if (System.Diagnostics.Debugger.IsAttached) { System.Diagnostics.Debugger.Break(); } System.Diagnostics.Debug.WriteLine("Exception with hooked key! " + ex); Toast.Current.Title1.Text = "Unable to communicate with Spotify"; Toast.Current.Title2.Text = ""; Toast.Current.FadeIn(); } }
private static void ShowSpotifyWithNoActivate() { var hWnd = Spotify.GetSpotify(); // check Spotify's current window state var placement = new Win32.WINDOWPLACEMENT(); Win32.GetWindowPlacement(hWnd, ref placement); var flags = Win32.SetWindowPosFlags.DoNotActivate | Win32.SetWindowPosFlags.DoNotChangeOwnerZOrder | Win32.SetWindowPosFlags.ShowWindow; Win32.SetWindowPos(hWnd, (IntPtr)0, placement.rcNormalPosition.Left, placement.rcNormalPosition.Top, 0, 0, flags); }
private void Window_MouseDown(object sender, MouseButtonEventArgs e) { if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)) { dragging = true; DragMove(); return; } FadeOut(now: true); Spotify.SendAction(SpotifyAction.ShowSpotify); }
public static string GetCurrentTrack() { if (!Spotify.IsAvailable()) { return(string.Empty); } IntPtr hWnd = GetSpotify(); int length = Win32.GetWindowTextLength(hWnd); StringBuilder sb = new StringBuilder(length + 1); Win32.GetWindowText(hWnd, sb, sb.Capacity); return(sb.ToString().Replace("Spotify", "").TrimStart(' ', '-').Trim()); }
public static string GetCurrentTrack() { if (!Spotify.IsAvailable()) { return(string.Empty); } string song = ""; string artist = ""; try { var links = _spotifyDriver.FindElementsByTagName("a"); foreach (var link in links) { if (string.IsNullOrEmpty(link.Text)) { continue; } // TODO: could use CSS selectors? var databind = link.GetAttribute("data-bind"); if (databind == null) { continue; } System.Diagnostics.Debug.WriteLine(databind); if (databind.Contains("href: trackURI")) { song = link.Text; } else if (databind.Contains("trackURI") && link.GetAttribute("href").Contains("artist")) { artist = link.Text; } } return(artist + " - " + song); } catch { // exceptions will occur if the Spotify content changes while it's being enumerated // for example, if the song occurs while we're looking for the song title return(""); } }
private void AskUserToStartSpotify() { SettingsXml settings = SettingsXml.Current; // Thanks to recent changes in Spotify that removed the song Artist + Title from the titlebar // we are forced to launch Spotify ourselves (under WebDriver), so we no longer ask the user try { Spotify.StartSpotify(); } catch (Exception e) { MessageBox.Show("An unknown error occurred when trying to start Spotify.\nPlease start Spotify manually.\n\nTechnical Details: " + e.Message, "Toastify", MessageBoxButton.OK, MessageBoxImage.Information); } }
public static Song GetCurrentSong() { if (!Spotify.IsRunning()) { return(null); } string song = ""; string artist = ""; string album = ""; IntPtr hWnd = GetSpotify(); int length = Win32.GetWindowTextLength(hWnd); StringBuilder sb = new StringBuilder(length + 1); Win32.GetWindowText(hWnd, sb, sb.Capacity); //float spotifyVolume = VolumeHelper.GetSpotifyInstaVolume(); string title = sb.ToString(); if (!string.IsNullOrWhiteSpace(title) && title != "Spotify") { // Unfortunately we don't have a great way to get the title from Spotify // so we need to do some gymnastics. // Music played from an artist's page is usually in the format "artist - song" // while music played from a playlist is often in the format "artist - song - album" // unfortunately this means that some songs that actually have a " - " in either the artist name // or in the song name will potentially display incorrectly var portions = title.Split(new string[] { " - " }, StringSplitOptions.None); song = (portions.Length > 1 ? portions[1] : null); artist = portions[0]; album = (portions.Length > 2 ? string.Join(" ", portions.Skip(2).ToArray()) : null); // take everything else that's left return(new Song(artist, song, album)); } else if (title == "Spotify") { float spotifyVolume = VolumeHelper.GetSpotifyInstaVolume(); if (!float.IsNaN(spotifyVolume) && spotifyVolume > 0.00001f) { // Most Probably an ad return(new Song("SpotifyAds", "SpotifyAds", "SpotifyAds")); } } return(null); }
private void CheckTitle() { string currentTitle = Spotify.GetCurrentTrack(); if (!string.IsNullOrEmpty(currentTitle) && currentTitle != previousTitle) { string artist, title; // set the previous title asap so that the next timer call to this function will // fail fast (setting it at the end may cause multiple web requests) previousTitle = currentTitle; if (SplitTitle(currentTitle, out artist, out title)) { this.Dispatcher.Invoke((Action) delegate { Title1.Text = title; Title2.Text = artist; }, System.Windows.Threading.DispatcherPriority.Normal); foreach (var p in this.Plugins) { try { p.TrackChanged(artist, title); } catch (Exception) { //For now we swallow any plugin errors. } } } CheckTitle(artist, title); this.Dispatcher.Invoke((Action) delegate { FadeIn(); }, System.Windows.Threading.DispatcherPriority.Normal); if (SettingsXml.Current.SaveTrackToFile) { if (!string.IsNullOrEmpty(SettingsXml.Current.SaveTrackToFilePath)) { try { string trackText = GetClipboardText(currentTitle); File.WriteAllText(SettingsXml.Current.SaveTrackToFilePath, trackText); } catch { } // ignore errors writing out the album } } } }
private static bool IsMinimized() { if (!Spotify.IsRunning()) { return(false); } var hWnd = Spotify.GetSpotify(); // check Spotify's current window state var placement = new Win32.WINDOWPLACEMENT(); Win32.GetWindowPlacement(hWnd, ref placement); return(placement.showCmd == Win32.Constants.SW_SHOWMINIMIZED); }
private void EnsureSpotify() { SettingsXml settings = SettingsXml.Current; //Make sure Spotify is running when starting Toastify. //If not ask the user and try to start it. if (!Spotify.IsAvailable()) { if ((settings.AlwaysStartSpotify.HasValue && settings.AlwaysStartSpotify.Value) || (MessageBox.Show("Spotify doesn't seem to be running.\n\nDo you want Toastify to try and start it for you?", "Toastify", MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes)) { string spotifyPath = Microsoft.Win32.Registry.GetValue(@"HKEY_CURRENT_USER\Software\Spotify", string.Empty, string.Empty) as string; //string.Empty = (Default) value // try in the secondary location if (string.IsNullOrEmpty(spotifyPath)) { spotifyPath = Microsoft.Win32.Registry.GetValue(@"HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Uninstall\Spotify", "InstallLocation", string.Empty) as string; //string.Empty = (Default) value } if (string.IsNullOrEmpty(spotifyPath)) { MessageBox.Show("Unable to find Spotify. Make sure it is installed and/or start it manually.", "Toastify", MessageBoxButton.OK, MessageBoxImage.Information); } else { try { System.Diagnostics.Process.Start(System.IO.Path.Combine(spotifyPath, "Spotify.exe")); if (!settings.AlwaysStartSpotify.HasValue) { var ret = MessageBox.Show("Do you always want to start Spotify if it's not already running?", "Toastify", MessageBoxButton.YesNo, MessageBoxImage.Question); settings.AlwaysStartSpotify = (ret == MessageBoxResult.Yes); settings.Save(); } } catch (Exception) { MessageBox.Show("An unknown error occurd when trying to start Spotify.\nPlease start Spotify manually.", "Toastify", MessageBoxButton.OK, MessageBoxImage.Information); } } } } }
private void Window_MouseDown(object sender, MouseButtonEventArgs e) { if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)) { dragging = true; DragMove(); return; } FadeOut(now: true); if (isUpdateToast) { Process.Start(new ProcessStartInfo(versionChecker.UpdateUrl)); } else { Spotify.SendAction(SpotifyAction.ShowSpotify); } }
internal static void ActionHookCallback(Hotkey hotkey) { // Bug 9421: ignore this keypress if it is the same as the previous one and it's been less than // WAIT_BETWEEN_HOTKEY_PRESS since the last press. Note that we do not update // _lastHotkeyPressTime in this case to avoid being trapped in a never ending cycle of // ignoring keypresses if the user (for some reason) decides to press really quickly, // really often on the hotkey if (hotkey == _lastHotkey && DateTime.Now.Subtract(_lastHotkeyPressTime).TotalMilliseconds < WAIT_BETWEEN_HOTKEY_PRESS) { return; } _lastHotkey = hotkey; _lastHotkeyPressTime = DateTime.Now; string currentTrack = string.Empty; try { string trackBeforeAction = Spotify.GetCurrentTrack(); if (hotkey.Action == SpotifyAction.CopyTrackInfo && !string.IsNullOrEmpty(trackBeforeAction)) { Clipboard.SetText(string.Format(SettingsXml.Current.ClipboardTemplate, trackBeforeAction)); } else { Spotify.SendAction(hotkey.Action); } Toast.Current.DisplayAction(hotkey.Action, trackBeforeAction); } catch (Exception ex) { System.Diagnostics.Debug.WriteLine("Exception with hooked key! " + ex); Toast.Current.Title1.Text = "Unable to communicate with Spotify"; Toast.Current.Title2.Text = ""; Toast.Current.FadeIn(); } }
public static void SendAction(SpotifyAction a) { if (!Spotify.IsAvailable()) { return; } switch (a) { case SpotifyAction.CopyTrackInfo: case SpotifyAction.ShowToast: //Nothing break; case SpotifyAction.ShowSpotify: ShowSpotify(); break; default: Win32.SendMessage(GetSpotify(), Win32.Constants.WM_APPCOMMAND, IntPtr.Zero, new IntPtr((long)a)); break; } }
private static void Minimize() { var remainingSleep = 2000; IntPtr hWnd; // Since Minimize is often called during startup, the hWnd is often not created yet // wait a maximum of remainingSleep for it to appear and then minimize it if it did. while ((hWnd = Spotify.GetSpotify()) == IntPtr.Zero && remainingSleep > 0) { Thread.Sleep(100); remainingSleep -= 100; } if (hWnd != IntPtr.Zero) { // disgusting but sadly neccessary. Let Spotify initialize a bit before minimizing it // otherwise the window hides itself and doesn't respond to taskbar clicks. // I tried to work around this by waiting for the window size to initialize (via GetWindowRect) // but that didn't work, there is some internal initialization that needs to occur. Thread.Sleep(500); Win32.ShowWindow(hWnd, Win32.Constants.SW_SHOWMINIMIZED); } }
private void MuteSpotify() { Spotify.SendAction(SpotifyAction.Mute); isMute = !isMute; }
public void DisplayAction(SpotifyAction action, Song trackBeforeAction) { //Anything that changes track doesn't need to be handled since //that will be handled in the timer event. const string VOLUME_UP_TEXT = "Volume ++"; const string VOLUME_DOWN_TEXT = "Volume --"; const string MUTE_ON_OFF_TEXT = "Mute On/Off"; const string NOTHINGS_PLAYING = "Nothing's playing"; const string PAUSED_TEXT = "Paused"; const string STOPPED_TEXT = "Stopped"; const string SETTINGS_TEXT = "Settings saved"; if (!Spotify.IsRunning() && action != SpotifyAction.SettingsSaved) { toastIcon = DEFAULT_ICON; Title1.Text = "Spotify not available!"; Title2.Text = string.Empty; FadeIn(); return; } Song currentTrack = trackBeforeAction; string prevTitle1 = Title1.Text; string prevTitle2 = Title2.Text; switch (action) { case SpotifyAction.PlayPause: if (trackBeforeAction != null) { //We pressed pause Title1.Text = "Paused"; Title2.Text = trackBeforeAction.ToString(); FadeIn(); } currentSong = null; //If we presses play this will force a toast to display in next timer event. break; case SpotifyAction.Stop: currentSong = null; Title1.Text = "Stopped"; Title2.Text = trackBeforeAction.ToString(); FadeIn(); break; case SpotifyAction.SettingsSaved: Title1.Text = SETTINGS_TEXT; Title2.Text = "Here is a preview of your settings!"; FadeIn(); break; case SpotifyAction.NextTrack: //No need to handle break; case SpotifyAction.PreviousTrack: //No need to handle break; case SpotifyAction.VolumeUp: Title1.Text = VOLUME_UP_TEXT; Title2.Text = currentTrack.ToString(); FadeIn(); break; case SpotifyAction.VolumeDown: Title1.Text = VOLUME_DOWN_TEXT; Title2.Text = currentTrack.ToString(); FadeIn(); break; case SpotifyAction.Mute: Title1.Text = MUTE_ON_OFF_TEXT; Title2.Text = currentTrack.ToString(); FadeIn(); break; case SpotifyAction.ShowToast: if (currentTrack == null || !currentTrack.IsValid()) { toastIcon = DEFAULT_ICON; Title1.Text = NOTHINGS_PLAYING; Title2.Text = string.Empty; } else { if (currentTrack != null && currentTrack.IsValid()) { toastIcon = currentTrack.CoverArtUrl; Title1.Text = currentTrack.Artist; Title2.Text = currentTrack.Track; } } FadeIn(force: true); break; case SpotifyAction.ShowSpotify: //No need to handle break; case SpotifyAction.ThumbsUp: toastIcon = "Resources/thumbs_up.png"; Title1.Text = "Thumbs Up!"; Title2.Text = currentTrack.ToString(); FadeIn(); break; case SpotifyAction.ThumbsDown: toastIcon = "Resources/thumbs_down.png"; Title1.Text = "Thumbs Down :("; Title2.Text = currentTrack.ToString(); FadeIn(); break; } }
private void CheckTitle() { Song currentSong = Spotify.GetCurrentSong(); if (currentSong != null && currentSong.IsValid() && !currentSong.Equals(this.currentSong) && !currentSong.IsAnAd()) { // set the previous title asap so that the next timer call to this function will // fail fast (setting it at the end may cause multiple web requests) if (adsFlag) { adsFlag = false; VolumeHelper.SetApplicationMute("Spotify", false); //Debug.WriteLine("UnMuted-Ad finish"); } this.currentSong = currentSong; //Debug.WriteLine(currentSong.ToString()); try { Spotify.SetCoverArt(currentSong); } catch { // Exceptions will be handled (for telemetry etc.) within SetCoverArt, but they will be rethrown // so that we can set custom artwork here currentSong.CoverArtUrl = ALBUM_ACCESS_DENIED_ICON; } // Toastify-specific custom logic around album art (if it's missing, or an ad) UpdateSongForToastify(currentSong); toastIcon = currentSong.CoverArtUrl; this.Dispatcher.Invoke((Action) delegate { Title1.Text = currentSong.Track; Title2.Text = currentSong.Artist; }, System.Windows.Threading.DispatcherPriority.Normal); foreach (var p in this.Plugins) { try { p.TrackChanged(currentSong.Artist, currentSong.Track); } catch (Exception) { //For now we swallow any plugin errors. } } this.Dispatcher.Invoke((Action) delegate { FadeIn(); }, System.Windows.Threading.DispatcherPriority.Normal); if (SettingsXml.Current.SaveTrackToFile) { if (!string.IsNullOrEmpty(SettingsXml.Current.SaveTrackToFilePath)) { try { string trackText = GetClipboardText(currentSong); File.WriteAllText(SettingsXml.Current.SaveTrackToFilePath, trackText); } catch { } // ignore errors writing out the album } } } else if (currentSong != null && currentSong.IsAnAd() && !adsFlag) { adsFlag = true; VolumeHelper.SetApplicationMute("Spotify", true); Debug.WriteLine("Muted-Probably an Ad"); } }
public static void SendAction(SpotifyAction a) { if (!Spotify.IsRunning()) { return; } // bah. Because control cannot fall through cases we need to special case volume if (SettingsXml.Current.ChangeSpotifyVolumeOnly) { if (a == SpotifyAction.VolumeUp) { Telemetry.TrackEvent(TelemetryCategory.Action, Telemetry.TelemetryEvent.Action.VolumeUp); VolumeHelper.IncrementVolume("Spotify"); return; } else if (a == SpotifyAction.VolumeDown) { Telemetry.TrackEvent(TelemetryCategory.Action, Telemetry.TelemetryEvent.Action.VolumeDown); VolumeHelper.DecrementVolume("Spotify"); return; } else if (a == SpotifyAction.Mute) { Telemetry.TrackEvent(TelemetryCategory.Action, Telemetry.TelemetryEvent.Action.Mute); VolumeHelper.ToggleApplicationMute("Spotify"); return; } } switch (a) { case SpotifyAction.CopyTrackInfo: case SpotifyAction.ShowToast: //Nothing break; case SpotifyAction.ShowSpotify: Telemetry.TrackEvent(TelemetryCategory.Action, Telemetry.TelemetryEvent.Action.ShowSpotify); if (Spotify.IsMinimized()) { ShowSpotify(); } else { Minimize(); } break; case SpotifyAction.FastForward: Telemetry.TrackEvent(TelemetryCategory.Action, Telemetry.TelemetryEvent.Action.FastForward); SendComplexKeys("+{Right}"); break; case SpotifyAction.Rewind: Telemetry.TrackEvent(TelemetryCategory.Action, Telemetry.TelemetryEvent.Action.Rewind); SendComplexKeys("+{Left}"); break; default: Telemetry.TrackEvent(TelemetryCategory.Action, Telemetry.TelemetryEvent.Action.Default + a.ToString()); Win32.SendMessage(GetSpotify(), Win32.Constants.WM_APPCOMMAND, IntPtr.Zero, new IntPtr((long)a)); break; } }
public void DisplayAction(SpotifyAction action, string trackBeforeAction) { //Anything that changes track doesn't need to be handled since //that will be handled in the timer event. const string VOLUME_UP_TEXT = "Volume ++"; const string VOLUME_DOWN_TEXT = "Volume --"; const string MUTE_ON_OFF_TEXT = "Mute On/Off"; const string NOTHINGS_PLAYING = "Nothing's playing"; const string PAUSED_TEXT = "Paused"; const string STOPPED_TEXT = "Stopped"; const string SETTINGS_TEXT = "Settings saved"; if (!Spotify.IsAvailable() && action != SpotifyAction.SettingsSaved) { coverUrl = "SpotifyToastifyLogo.png"; Title1.Text = "Spotify not available!"; Title2.Text = string.Empty; FadeIn(); return; } string currentTrack = Spotify.GetCurrentTrack(); string prevTitle1 = Title1.Text; string prevTitle2 = Title2.Text; switch (action) { case SpotifyAction.PlayPause: if (!string.IsNullOrEmpty(trackBeforeAction)) { //We pressed pause Title1.Text = "Paused"; Title2.Text = trackBeforeAction; FadeIn(); } previousTitle = string.Empty; //If we presses play this will force a toast to display in next timer event. break; case SpotifyAction.Stop: previousTitle = string.Empty; Title1.Text = "Stopped"; Title2.Text = trackBeforeAction; FadeIn(); break; case SpotifyAction.SettingsSaved: Title1.Text = SETTINGS_TEXT; Title2.Text = "Here is a preview of your settings!"; FadeIn(); break; case SpotifyAction.NextTrack: //No need to handle break; case SpotifyAction.PreviousTrack: //No need to handle break; case SpotifyAction.VolumeUp: Title1.Text = VOLUME_UP_TEXT; Title2.Text = currentTrack; FadeIn(); break; case SpotifyAction.VolumeDown: Title1.Text = VOLUME_DOWN_TEXT; Title2.Text = currentTrack; FadeIn(); break; case SpotifyAction.Mute: Title1.Text = MUTE_ON_OFF_TEXT; Title2.Text = currentTrack; FadeIn(); break; case SpotifyAction.ShowToast: if (string.IsNullOrEmpty(currentTrack) && Title1.Text != PAUSED_TEXT && Title1.Text != STOPPED_TEXT) { coverUrl = "SpotifyToastifyLogo.png"; Title1.Text = NOTHINGS_PLAYING; Title2.Text = string.Empty; } else { string part1, part2; if (SplitTitle(currentTrack, out part1, out part2)) { Title1.Text = part2; Title2.Text = part1; } } FadeIn(force: true); break; case SpotifyAction.ShowSpotify: //No need to handle break; } }
private void Window_MouseDown(object sender, MouseButtonEventArgs e) { FadeOut(); Spotify.SendAction(SpotifyAction.ShowSpotify); }
private static void Minimize() { var hWnd = Spotify.GetSpotify(); Win32.ShowWindow(hWnd, Win32.Constants.SW_SHOWMINIMIZED); }