Skip to content

Commit

Permalink
Merge branch 'development' of https://github.com/stijnvdb88/Snap.Net
Browse files Browse the repository at this point in the history
  • Loading branch information
stijnvdb88 committed Jan 3, 2022
2 parents 6f1534f + fb118fd commit 3e5343d
Show file tree
Hide file tree
Showing 6 changed files with 199 additions and 26 deletions.
62 changes: 62 additions & 0 deletions Snap.Net.ControlClient/JsonRpcData/Metadata.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
using System;
using System.Collections.Generic;
using System.Text;

namespace Snap.Net.ControlClient.JsonRpcData
{

public class Metadata
{
public ArtData artData { get; set; } // Base64 encoded image representing the track or album. if artUrl is not specified, Snapserver will decode and cache the image, and will publish the image via artUrl.
public string artUrl { get; set; } // The location of an image representing the track or album. Clients should not assume this will continue to exist when the media player stops giving out the URL.
public string title { get; set; } // The track title.
public float duration { get; set; } // The duration of the song in seconds; may contain a fractional part.

// see https://github.com/badaix/snapcast/blob/master/doc/json_rpc_api/stream_plugin.md#pluginstreamplayergetproperties
public string trackId { get; set; } // A unique identity for this track within the context of an MPRIS object (eg: tracklist).
public string file { get; set; } // The current song.
public string[] artist { get; set; } // The track artist(s).
public string[] artistSort { get; set; } // Same as artist, but for sorting. This usually omits prefixes such as “The”.
public string album { get; set; } // The album name.
public string albumSort { get; set; } // Same as album, but for sorting.
public string[] albumArtist { get; set; } // The album artist(s).
public string[] albumArtistSort { get; set; } // Same as albumartist, but for sorting.
public string name { get; set; } // A name for this song. This is not the song title. The exact meaning of this tag is not well-defined. It is often used by badly configured internet radio stations with broken tags to squeeze both the artist name and the song title in one tag.
public string date { get; set; } // The song’s release date. This is usually a 4-digit year.
public string originalDate { get; set; } // The song’s original release date.
public string[] composer { get; set; } // The composer(s) of the track.
public string performer { get; set; } // The artist who performed the song.
public string conductor { get; set; } // The conductor who conducted the song.
public string work { get; set; } // "a work is a distinct intellectual or artistic creation, which can be expressed in the form of one or more audio recordings"
public string grouping { get; set; } // |used if the sound belongs to a larger category of sounds/music| (from the IDv2.4.0 TIT1 description).
public string[] comment { get; set; } // A (list of) freeform comment(s)
public string label { get; set; } // The name of the label or publisher.
public string musicbrainzArtistId { get; set; } // The artist id in the MusicBrainz database.
public string musicbrainzAlbumId { get; set; } // The album id in the MusicBrainz database.
public string musicbrainzAlbumArtistId { get; set; } // The album artist id in the MusicBrainz database.
public string musicbrainzTrackId { get; set; } // The track id in the MusicBrainz database.
public string musicbrainzReleaseTrackId { get; set; } // The release track id in the MusicBrainz database.
public string musicbrainzWorkId { get; set; } // The work id in the MusicBrainz database.
public string[] lyrics { get; set; } // The lyricist(s) of the track
public int bpm { get; set; } // The speed of the music, in beats per minute.
public float autoRating { get; set; } // An automatically-generated rating, based on things such as how often it has been played. This should be in the range 0.0 to 1.0.
public string contentCreated { get; set; } // Date/Time: When the track was created. Usually only the year component will be useful.
public int discNumber { get; set; } // The disc number on the album that this track is from.
public string firstUsed { get; set; } // Date/Time When the track was first played.
public string[] genre { get; set; } // List of Strings: The genre(s) of the track.
public string lastUsed { get; set; } // Date/Time: When the track was last played.
public string[] lyricist { get; set; } // The lyricist(s) of the track.
public string trackNumber { get; set; } // The track number on the album disc.
public string url { get; set; } // The location of the media file.
public int useCount { get; set; } // The number of times the track has been played.
public float userRating { get; set; } // A user-specified rating. This should be in the range 0.0 to 1.0.
public string spotifyArtistId { get; set; } // The Spotify Artist ID (https://developer.spotify.com/documentation/web-api/#spotify-uris-and-ids)
public string spotifyTrackId { get; set; } // The Spotify Track ID (https://developer.spotify.com/documentation/web-api/#spotify-uris-and-ids)
}

public class ArtData
{
public string data { get; set; } // Base64 encoded image
public string extension { get; set; } // The image file extension (e.g. "png", "jpg", "svg")
}
}
17 changes: 17 additions & 0 deletions Snap.Net.ControlClient/JsonRpcData/Properties.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Text;

namespace Snap.Net.ControlClient.JsonRpcData
{
public class Properties
{
public bool canControl { get; set; }
public bool canGoNext { get; set; }
public bool canGoPrevious { get; set; }
public bool canPause { get; set; }
public bool canPlay { get; set; }
public bool canSeek { get; set; }
public Metadata metadata { get; set; }
}
}
13 changes: 13 additions & 0 deletions Snap.Net.ControlClient/JsonRpcData/Stream.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ You should have received a copy of the GNU General Public License
using System;
using System.Collections.Generic;
using System.Text;
using Snap.Net.ControlClient.JsonRpcData;

namespace SnapDotNet.ControlClient.JsonRpcData
{
Expand All @@ -30,10 +31,16 @@ public class Stream
/// </summary>
public event Action SERVER_OnStreamUpdated;

/// <summary>
/// OnStreamPropertiesUpdated event is used to update UI after server reports property (metadata) changes
/// </summary>
public event Action SERVER_OnStreamPropertiesUpdated;

public string id { get; set; }
public Meta meta { get; set; }
public string status { get; set; }
public Uri uri { get; set; }
public Properties properties { get; set; }

/// <summary>
/// We use this method to update the stream member my member
Expand All @@ -49,6 +56,12 @@ public void SERVER_Update(Stream stream)
SERVER_OnStreamUpdated?.Invoke();
}

public void SERVER_PropertiesUpdate(Properties properties)
{
this.properties = properties;
SERVER_OnStreamPropertiesUpdated?.Invoke();
}

/// <summary>
/// Called when server data is about to be fully refreshed
/// </summary>
Expand Down
24 changes: 23 additions & 1 deletion Snap.Net.ControlClient/SnapcastClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ You should have received a copy of the GNU General Public License
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
using Snap.Net.ControlClient.JsonRpcData;

namespace SnapDotNet.ControlClient
{
Expand Down Expand Up @@ -99,7 +100,7 @@ public async Task ConnectAsync(string ip, int port, int timeout = 3000)
// https://github.com/microsoft/vs-streamjsonrpc/compare/master...AArnott:sampleUnbatchingMessageHandler
m_JsonRpc = new StreamJsonRpc.JsonRpc(new UnbatchingNewLineDelimitedMessageHandler(m_Stream, m_Stream));

//m_JsonRpc.TraceSource.Switch.Level = SourceLevels.All; // uncomment if you need detailed json-rpc logs
m_JsonRpc.TraceSource.Switch.Level = SourceLevels.All; // uncomment if you need detailed json-rpc logs

// register methods (must be done before listening starts)
m_JsonRpc.AddLocalRpcMethod("Server.OnUpdate", new Action<JsonRpcData.ServerData>((server) =>
Expand Down Expand Up @@ -173,6 +174,11 @@ public async Task ConnectAsync(string ip, int port, int timeout = 3000)
_StreamUpdated(id, stream);
}));

m_JsonRpc.AddLocalRpcMethod("Stream.OnProperties", new Action<string, Properties>((id, properties) =>
{
Debug("Received Stream.OnProperties - id {0}, properties {1}", id, properties);
_StreamPropertiesUpdated(id, properties);
}));

m_JsonRpc.StartListening();
// call Server.GetStatus to get all metadata
Expand Down Expand Up @@ -490,6 +496,22 @@ private void _StreamUpdated(string id, Stream stream)
}
}

/// <summary>
/// Called when snapserver reports stream properties update
/// </summary>
/// <param name="id"></param>
/// <param name="properties"></param>
private void _StreamPropertiesUpdated(string id, Properties properties)
{
for (int i = 0; i < ServerData.streams.Length; i++)
{
if (ServerData.streams[i].id == id)
{
ServerData.streams[i].SERVER_PropertiesUpdate(properties);
}
}
}

/// <summary>
/// Called when snapserver reports group stream update
/// </summary>
Expand Down
53 changes: 28 additions & 25 deletions Views/SnapControl/Group.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,34 +7,37 @@
xmlns:Controls="http://metro.mahapps.com/winfx/xaml/controls"
mc:Ignorable="d" Width="Auto" Height="Auto" AllowDrop="True"
Drop="Group_OnDrop" Background="Transparent">
<Grid Height="Auto">
<Grid Height="312">
<local:VolumeControl x:Name="vcGroup" HorizontalAlignment="Left" Margin="10,73,0,10" Width="47" />
<StackPanel Orientation="Horizontal"
HorizontalAlignment="Center"
Margin="50,5,0,0"
Height="30"
VerticalAlignment="Top">
<Button x:Name="btGroup"
BorderThickness="0.9"
Style="{DynamicResource AccentedSquareButtonStyle}"
BorderBrush="{DynamicResource AccentColorBrush}"
VerticalContentAlignment="Center"
FontWeight="Thin"
HorizontalContentAlignment="Center" Click="btGroup_Click">
<Label x:Name="lbGroupName" Content="Label" FontWeight="Bold" HorizontalAlignment="Stretch" Padding="0" Margin="0,0,0,0" VerticalAlignment="Top" HorizontalContentAlignment="Center" FontSize="15" />
</Button>
<Button x:Name="btStream"
BorderThickness="0.9"
Style="{DynamicResource AccentedSquareButtonStyle}"
BorderBrush="{DynamicResource AccentColorBrush}"
VerticalContentAlignment="Center"
FontWeight="Thin"
HorizontalContentAlignment="Center" Click="btStream_Click">
<Label x:Name="lbStreamName" Content="Label" HorizontalAlignment="Stretch" Padding="0" Margin="0,0,0,0" VerticalAlignment="Top" HorizontalContentAlignment="Center" FontSize="15" />
</Button>
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal"
HorizontalAlignment="Center"
Margin="50,5,0,0"
Height="30"
VerticalAlignment="Top">
<Button x:Name="btGroup"
BorderThickness="0.9"
Style="{DynamicResource AccentedSquareButtonStyle}"
BorderBrush="{DynamicResource AccentColorBrush}"
VerticalContentAlignment="Center"
FontWeight="Thin"
HorizontalContentAlignment="Center" Click="btGroup_Click">
<Label x:Name="lbGroupName" Content="Label" FontWeight="Bold" HorizontalAlignment="Stretch" Padding="0" Margin="0,0,0,0" VerticalAlignment="Top" HorizontalContentAlignment="Center" FontSize="15" />
</Button>
<Button x:Name="btStream"
BorderThickness="0.9"
Style="{DynamicResource AccentedSquareButtonStyle}"
BorderBrush="{DynamicResource AccentColorBrush}"
VerticalContentAlignment="Center"
FontWeight="Thin"
HorizontalContentAlignment="Center" Click="btStream_Click">
<Label x:Name="lbStreamName" Content="Label" HorizontalAlignment="Stretch" Padding="0" Margin="0,0,0,0" VerticalAlignment="Top" HorizontalContentAlignment="Center" FontSize="15" />
</Button>
</StackPanel>
<Label x:Name="lbStreamNowPlaying" Margin="50,0,0,0" Content="Now playing" HorizontalAlignment="Stretch" HorizontalContentAlignment="Center" FontSize="10"></Label>
</StackPanel>

<Border Margin="55, 45, 10, 10"
<Border Margin="55,61,10,10"
BorderBrush="{DynamicResource AccentColorBrush}" BorderThickness="1,1,1,1" CornerRadius="1">
<StackPanel HorizontalAlignment="Center" Height="Auto" Margin="0,0,0,10" VerticalAlignment="Top" Width="Auto" Orientation="Horizontal" x:Name="spClients">
</StackPanel>
Expand Down
56 changes: 56 additions & 0 deletions Views/SnapControl/Group.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -91,15 +91,71 @@ private void _OnGroupUpdated()
if (m_Stream != null)
{
m_Stream.SERVER_OnStreamUpdated -= _OnStreamUpdated; // unhook event from old m_Stream object
m_Stream.SERVER_OnStreamPropertiesUpdated -= _OnStreamPropertiesUpdated;
}
m_Stream = m_SnapcastClient.GetStream(m_Group.stream_id);
if (m_Stream != null)
{
m_Stream.SERVER_OnStreamUpdated += _OnStreamUpdated; // hook up event to new m_Stream object
_OnStreamUpdated();

m_Stream.SERVER_OnStreamPropertiesUpdated += _OnStreamPropertiesUpdated;
_OnStreamPropertiesUpdated();
}
}

private void _OnStreamPropertiesUpdated()
{
Application.Current.Dispatcher.Invoke(() =>
{
if (m_Stream.properties.metadata == null)
{
lbStreamNowPlaying.Content = "";
return;
}
string title = m_Stream.properties.metadata.title;
string nowPlaying = "";
string[] artists = m_Stream.properties.metadata.albumArtist;
if (artists == null)
{
artists = m_Stream.properties.metadata.artist;
}
string artistText = "";
if (artists != null)
{
artistText = string.Join(", ", artists);
}
if (string.IsNullOrEmpty(artistText) == false)
{
nowPlaying = artistText;
}
if (string.IsNullOrEmpty(title) == false)
{
if (string.IsNullOrEmpty(nowPlaying) == false)
{
nowPlaying += $" - {title}";
}
else
{
nowPlaying = title;
}
}
float duration = m_Stream.properties.metadata.duration;
if (duration > 0 && string.IsNullOrEmpty(nowPlaying) == false)
{
TimeSpan timeSpan = TimeSpan.FromSeconds(duration);
nowPlaying += string.Format(" ({0:D2}:{1:D2})", timeSpan.Minutes, timeSpan.Seconds);
}
lbStreamNowPlaying.Content = nowPlaying;
});
}

private void _OnStreamUpdated()
{
Application.Current.Dispatcher.Invoke(() =>
Expand Down

0 comments on commit 3e5343d

Please sign in to comment.