I am getting ready to participate in the next Ludum Dare (LD35), and being my first time, I wanted to do it on Twitch as well. So I started setting things up, such as adjusting my screen and webcam layout and getting some music. I’ve found that there was no easy way to show my current playing track on spotify. Not the way I wanted, anyway.
What have I tried?
First, I tried capturing the Spotify App windows partially, but it hides part of the song if it’s longer than the widget size. It was kinda ugly. Then, I tried using their api, but it seems there is not such method to get the current playing track. Without any further options, I noticed that the song/artist names showed up on the title of the window. So I’ve come up with a quick and dirty C# wpf app to capture the title and format it to my needs.
The mini-app
First off, I’ve created a green window with the following parameters:
ResizeMode="NoResize" ShowInTaskbar="False" WindowStartupLocation="CenterScreen" Background="Lime" Height="60" Width="800"
Then, inside a grid, I’ve arranged some controls:
<Image Grid.Row="0" Grid.Column="1" Grid.RowSpan="2" Name="img" Source="img/Sound-on-icon.png"></Image> <Label Grid.Row="0" Grid.Column="2" Name="lblTitle" HorizontalAlignment="Right" Padding="0" FontSize="20" Margin="0,0,5,0" Foreground="White">Song Name</Label> <Label Grid.Row="1" Grid.Column="2" Name="lblAuthor" HorizontalAlignment="Right" Padding="0" FontSize="16" Margin="0,0,5,0" Foreground="White">Artist Name</Label>
So it looks like this:
The green is going to be chromakeyed when streaming. An important detail is that I set my grid to be right-aligned, so if I change its size, it will grow/shrink on its left side.
In the main window constructor, I’m setting up a timer that checks every 0.1 seconds if the process is there, and if its text changed. I’m also getting the current session Id, so we guarantee to get the process from the user who is currently logged in. Needless to say, you have to declare it beforehand (it’s an int).
currentSessionId = Process.GetCurrentProcess().SessionId; Timer timer = new Timer(100); timer.Elapsed += Timer_Elapsed; timer.Start();
And in the Timer_Elapsed method:
process = Process.GetProcessesByName("spotify").Concat(Process.GetProcessesByName("Spotify")) .FirstOrDefault(p => p.SessionId == currentSessionId); if (process == null) return; string title = process.MainWindowTitle; if (currentTitle == title) return; currentTitle = title; title = title.Replace("Spotify", "").Replace("spotify", "").Trim().TrimStart('-').Trim(); if (string.IsNullOrEmpty(title)) { lblTitle.Dispatcher.Invoke(() => { lblTitle.Content = "Not Playing"; lblAuthor.Content = "Not Playing"; img.Source = off; desiredWidth = (MeasureString("Not Playing") + img.ActualWidth); elapsedTime = 0; }); } else { string songName = new string(string.Join(" - ", title.Split(new string[] { " \u2013 ", " - " }, StringSplitOptions.None) .Skip(1)).ToArray()); string authorName = title.Split(new string[] { " \u2013 ", " - " }, StringSplitOptions.None).FirstOrDefault(); lblTitle.Dispatcher.Invoke(() => { lblTitle.Content = songName; lblAuthor.Content = authorName; img.Source = on; desiredWidth = (MeasureString(songName.Length > authorName.Length ? songName : authorName) + img.ActualWidth); elapsedTime = 0; }); }
I get the process by its name and session, and then the window title. I had to replace the word “Spotify” and trim the string because some versions of the spotify app have it in the title. After that, I set the title and author according to the resulting string, and adjust the size of the grid. Now, there are two things I put there just for extra effect. You see I’m not actually setting the width instantly, but setting a variable called desiredWidth. I’ll then interpolate the width across a specific interval so it grows/shrinks smoothly. In the constructor:
Timer adjustSize = new Timer(10); adjustSize.Elapsed += AdjustSize_Elapsed; adjustSize.Start();
And in the newly created AdjustSize_Method:
this.Dispatcher.Invoke(() => { if (grid.ActualWidth == this.desiredWidth) { elapsedTime = 0; return; } elapsedTime += 10; Console.WriteLine("elapsedTime: " + elapsedTime / 1000d); Console.WriteLine("lerp: " + lerp(grid.ActualWidth, desiredWidth, elapsedTime / 1000d)); grid.Width = Math.Abs(lerp(grid.ActualWidth, desiredWidth, elapsedTime / 1000d)); });
The lerp (linear interpolation) method is rather simple:
private double lerp(double source, double dest, double t) { return (1 - t) * source + t * dest; }
So I’m interpolating the ActualWidth to the desiredWidth, from 0 to 1, based on elapsedTime/1000 (so, 10/1000, 0.01 per millisecond). Note that i’m using the ActualWidth as the initial lerp parameter, so the movement will speed up as the time elapses. The final effect works like this:
Please note that there is no smoothing when the gif ends! And also, the gif fps rate is very low but the animation on the app itself is a lot smoother.
The full source code is available on https://github.com/ConradoClark/SpotifyPCAppMusicTracker. You can download a release of the working app there as well.