From 6f482f14d398a883b8b67398a5a7a7b3ee33479b Mon Sep 17 00:00:00 2001 From: andy Date: Tue, 28 Sep 2021 21:14:52 +0100 Subject: [PATCH] added volume and device change event --- Selector.Tests/Helper.cs | 33 ++++ Selector.Tests/PlayerWatcher.cs | 146 +++++++++++------- Selector/Equality/UriEquality.cs | 4 +- Selector/Watcher/Interfaces/Events.cs | 4 +- Selector/Watcher/Interfaces/IPlayerWatcher.cs | 6 +- Selector/Watcher/PlayerWatcher.cs | 74 +++++---- 6 files changed, 180 insertions(+), 87 deletions(-) diff --git a/Selector.Tests/Helper.cs b/Selector.Tests/Helper.cs index bb658a5..4d61751 100644 --- a/Selector.Tests/Helper.cs +++ b/Selector.Tests/Helper.cs @@ -80,6 +80,17 @@ namespace Selector.Tests }; } + public static CurrentlyPlayingContext CurrentPlayback(FullTrack track, Device device = null, bool isPlaying = true, string context = null) + { + return new CurrentlyPlayingContext() + { + Context = Context(context ?? track.Uri), + Device = device ?? Device("device"), + IsPlaying = isPlaying, + Item = track + }; + } + public static CurrentlyPlaying CurrentlyPlaying(FullEpisode episode, bool isPlaying = true, string context = null) { return new CurrentlyPlaying() @@ -90,6 +101,17 @@ namespace Selector.Tests }; } + public static CurrentlyPlayingContext CurrentPlayback(FullEpisode episode, Device device = null, bool isPlaying = true, string context = null) + { + return new CurrentlyPlayingContext() + { + Context = Context(context ?? episode.Uri), + Device = device ?? Device("device"), + IsPlaying = isPlaying, + Item = episode + }; + } + public static Context Context(string uri) { return new Context() @@ -97,5 +119,16 @@ namespace Selector.Tests Uri = uri }; } + + public static Device Device(string name, string id = null, int volume = 50) + { + return new Device() + { + Name = name, + Id = id ?? name, + Type = "computer", + VolumePercent = volume + }; + } } } diff --git a/Selector.Tests/PlayerWatcher.cs b/Selector.Tests/PlayerWatcher.cs index 8edc8a1..0a39010 100644 --- a/Selector.Tests/PlayerWatcher.cs +++ b/Selector.Tests/PlayerWatcher.cs @@ -14,24 +14,24 @@ namespace Selector.Tests public static IEnumerable NowPlayingData => new List { - new object[] { new List(){ - Helper.CurrentlyPlaying(Helper.FullTrack("track1", "album1", "artist1")), - Helper.CurrentlyPlaying(Helper.FullTrack("track2", "album2", "artist2")), - Helper.CurrentlyPlaying(Helper.FullTrack("track3", "album3", "artist3")), + new object[] { new List(){ + Helper.CurrentPlayback(Helper.FullTrack("track1", "album1", "artist1")), + Helper.CurrentPlayback(Helper.FullTrack("track2", "album2", "artist2")), + Helper.CurrentPlayback(Helper.FullTrack("track3", "album3", "artist3")), } } }; [Theory] [MemberData(nameof(NowPlayingData))] - public async void NowPlaying(List playing) + public async void NowPlaying(List playing) { - var playingQueue = new Queue(playing); + var playingQueue = new Queue(playing); var spotMock = new Mock(); var eq = new UriEquality(); - spotMock.Setup(s => s.GetCurrentlyPlaying(It.IsAny()).Result).Returns(playingQueue.Dequeue); + spotMock.Setup(s => s.GetCurrentPlayback().Result).Returns(playingQueue.Dequeue); var watcher = new PlayerWatcher(spotMock.Object, eq); @@ -47,108 +47,150 @@ namespace Selector.Tests new List { // NO CHANGING - new object[] { new List(){ - Helper.CurrentlyPlaying(Helper.FullTrack("track1", "album1", "artist1"), isPlaying: true, context: "context1"), - Helper.CurrentlyPlaying(Helper.FullTrack("track1", "album1", "artist1"), isPlaying: true, context: "context1"), - Helper.CurrentlyPlaying(Helper.FullTrack("track1", "album1", "artist1"), isPlaying: true, context: "context1"), + new object[] { new List(){ + Helper.CurrentPlayback(Helper.FullTrack("track1", "album1", "artist1"), isPlaying: true, context: "context1"), + Helper.CurrentPlayback(Helper.FullTrack("track1", "album1", "artist1"), isPlaying: true, context: "context1"), + Helper.CurrentPlayback(Helper.FullTrack("track1", "album1", "artist1"), isPlaying: true, context: "context1"), }, // to raise new List(){ }, // to not raise - new List(){ "ItemChange", "AlbumChange", "ArtistChange", "ContextChange", "PlayingChange" } + new List(){ "ItemChange", "AlbumChange", "ArtistChange", "ContextChange", "PlayingChange", "DeviceChange", "VolumeChange" } }, // TRACK CHANGE - new object[] { new List(){ - Helper.CurrentlyPlaying(Helper.FullTrack("track1", "album1", "artist1")), - Helper.CurrentlyPlaying(Helper.FullTrack("track2", "album1", "artist1")) + new object[] { new List(){ + Helper.CurrentPlayback(Helper.FullTrack("track1", "album1", "artist1")), + Helper.CurrentPlayback(Helper.FullTrack("track2", "album1", "artist1")) }, // to raise new List(){ "ItemChange" }, // to not raise - new List(){ "AlbumChange", "ArtistChange" } + new List(){ "AlbumChange", "ArtistChange", "DeviceChange", "VolumeChange" } }, // ALBUM CHANGE - new object[] { new List(){ - Helper.CurrentlyPlaying(Helper.FullTrack("track1", "album1", "artist1")), - Helper.CurrentlyPlaying(Helper.FullTrack("track1", "album2", "artist1")) + new object[] { new List(){ + Helper.CurrentPlayback(Helper.FullTrack("track1", "album1", "artist1")), + Helper.CurrentPlayback(Helper.FullTrack("track1", "album2", "artist1")) }, // to raise new List(){ "ItemChange", "AlbumChange" }, // to not raise - new List(){ "ArtistChange" } + new List(){ "ArtistChange", "DeviceChange", "VolumeChange" } }, // ARTIST CHANGE - new object[] { new List(){ - Helper.CurrentlyPlaying(Helper.FullTrack("track1", "album1", "artist1")), - Helper.CurrentlyPlaying(Helper.FullTrack("track1", "album1", "artist2")) + new object[] { new List(){ + Helper.CurrentPlayback(Helper.FullTrack("track1", "album1", "artist1")), + Helper.CurrentPlayback(Helper.FullTrack("track1", "album1", "artist2")) }, // to raise new List(){ "ItemChange", "AlbumChange", "ArtistChange" }, // to not raise - new List(){ } + new List(){ "DeviceChange", "VolumeChange" } }, // CONTEXT CHANGE - new object[] { new List(){ - Helper.CurrentlyPlaying(Helper.FullTrack("track1", "album1", "artist1"), context: "context1"), - Helper.CurrentlyPlaying(Helper.FullTrack("track1", "album1", "artist1"), context: "context2") + new object[] { new List(){ + Helper.CurrentPlayback(Helper.FullTrack("track1", "album1", "artist1"), context: "context1"), + Helper.CurrentPlayback(Helper.FullTrack("track1", "album1", "artist1"), context: "context2") }, // to raise new List(){ "ContextChange" }, // to not raise - new List(){ "ItemChange", "AlbumChange", "ArtistChange" } + new List(){ "ItemChange", "AlbumChange", "ArtistChange", "DeviceChange", "VolumeChange" } }, // PLAYING CHANGE - new object[] { new List(){ - Helper.CurrentlyPlaying(Helper.FullTrack("track1", "album1", "artist1"), isPlaying: true, context: "context1"), - Helper.CurrentlyPlaying(Helper.FullTrack("track1", "album1", "artist1"), isPlaying: false, context: "context1") + new object[] { new List(){ + Helper.CurrentPlayback(Helper.FullTrack("track1", "album1", "artist1"), isPlaying: true, context: "context1"), + Helper.CurrentPlayback(Helper.FullTrack("track1", "album1", "artist1"), isPlaying: false, context: "context1") }, // to raise new List(){ "PlayingChange" }, // to not raise - new List(){ "ItemChange", "AlbumChange", "ArtistChange", "ContextChange" } + new List(){ "ItemChange", "AlbumChange", "ArtistChange", "ContextChange", "DeviceChange", "VolumeChange" } }, // PLAYING CHANGE - new object[] { new List(){ - Helper.CurrentlyPlaying(Helper.FullTrack("track1", "album1", "artist1"), isPlaying: false, context: "context1"), - Helper.CurrentlyPlaying(Helper.FullTrack("track1", "album1", "artist1"), isPlaying: true, context: "context1") + new object[] { new List(){ + Helper.CurrentPlayback(Helper.FullTrack("track1", "album1", "artist1"), isPlaying: false, context: "context1"), + Helper.CurrentPlayback(Helper.FullTrack("track1", "album1", "artist1"), isPlaying: true, context: "context1") }, // to raise new List(){ "PlayingChange" }, // to not raise - new List(){ "ItemChange", "AlbumChange", "ArtistChange", "ContextChange" } + new List(){ "ItemChange", "AlbumChange", "ArtistChange", "ContextChange", "DeviceChange", "VolumeChange" } }, // CONTENT CHANGE - new object[] { new List(){ - Helper.CurrentlyPlaying(Helper.FullTrack("track1", "album1", "artist1"), isPlaying: true, context: "context1"), - Helper.CurrentlyPlaying(Helper.FullEpisode("ep1", "show1", "pub1"), isPlaying: true, context: "context2") + new object[] { new List(){ + Helper.CurrentPlayback(Helper.FullTrack("track1", "album1", "artist1"), isPlaying: true, context: "context1"), + Helper.CurrentPlayback(Helper.FullEpisode("ep1", "show1", "pub1"), isPlaying: true, context: "context2") }, // to raise new List(){ "ContentChange", "ContextChange", "ItemChange" }, // to not raise - new List(){ "AlbumChange", "ArtistChange", "PlayingChange" } + new List(){ "AlbumChange", "ArtistChange", "PlayingChange", "DeviceChange", "VolumeChange" } }, // CONTENT CHANGE - new object[] { new List(){ - Helper.CurrentlyPlaying(Helper.FullEpisode("ep1", "show1", "pub1"), isPlaying: true, context: "context2"), - Helper.CurrentlyPlaying(Helper.FullTrack("track1", "album1", "artist1"), isPlaying: true, context: "context1") + new object[] { new List(){ + Helper.CurrentPlayback(Helper.FullEpisode("ep1", "show1", "pub1"), isPlaying: true, context: "context2"), + Helper.CurrentPlayback(Helper.FullTrack("track1", "album1", "artist1"), isPlaying: true, context: "context1") }, // to raise new List(){ "ContentChange", "ContextChange", "ItemChange" }, // to not raise - new List(){ "AlbumChange", "ArtistChange", "PlayingChange" } - } + new List(){ "AlbumChange", "ArtistChange", "PlayingChange", "DeviceChange", "VolumeChange" } + }, + // DEVICE CHANGE + new object[] { new List(){ + Helper.CurrentPlayback(Helper.FullTrack("track1", "album1", "artist1"), device: Helper.Device("dev1")), + Helper.CurrentPlayback(Helper.FullTrack("track1", "album1", "artist1"), device: Helper.Device("dev2")) + }, + // to raise + new List(){ "DeviceChange" }, + // to not raise + new List(){ "AlbumChange", "ArtistChange", "PlayingChange", "ContentChange", "ContextChange", "ItemChange", "VolumeChange" } + }, + // VOLUME CHANGE + new object[] { new List(){ + Helper.CurrentPlayback(Helper.FullTrack("track1", "album1", "artist1"), device: Helper.Device("dev1", volume: 50)), + Helper.CurrentPlayback(Helper.FullTrack("track1", "album1", "artist1"), device: Helper.Device("dev1", volume: 60)) + }, + // to raise + new List(){ "VolumeChange" }, + // to not raise + new List(){ "AlbumChange", "ArtistChange", "PlayingChange", "ContentChange", "ContextChange", "ItemChange", "DeviceChange" } + }, + // // STARTED PLAYBACK + // new object[] { new List(){ + // null, + // Helper.CurrentPlayback(Helper.FullTrack("track1", "album1", "artist1"), isPlaying: true, context: "context1") + // }, + // // to raise + // new List(){ "PlayingChange" }, + // // to not raise + // new List(){ "AlbumChange", "ArtistChange", "ContentChange", "ContextChange", "ItemChange" } + // }, + // // STARTED PLAYBACK + // new object[] { new List(){ + // Helper.CurrentPlayback(Helper.FullTrack("track1", "album1", "artist1"), isPlaying: true, context: "context1"), + // null + // }, + // // to raise + // new List(){ "PlayingChange" }, + // // to not raise + // new List(){ "AlbumChange", "ArtistChange", "ContentChange", "ContextChange", "ItemChange" } + // } }; [Theory] [MemberData(nameof(EventsData))] - public async void Events(List playing, List toRaise, List toNotRaise) + public async void Events(List playing, List toRaise, List toNotRaise) { - var playingQueue = new Queue(playing); + var playingQueue = new Queue(playing); var spotMock = new Mock(); var eq = new UriEquality(); - spotMock.Setup(s => s.GetCurrentlyPlaying(It.IsAny()).Result).Returns(playingQueue.Dequeue); + spotMock.Setup( + s => s.GetCurrentPlayback().Result + ).Returns(playingQueue.Dequeue); var watcher = new PlayerWatcher(spotMock.Object, eq); using var monitoredWatcher = watcher.Monitor(); @@ -158,12 +200,8 @@ namespace Selector.Tests await watcher.WatchOne(); } - foreach(var raise in toRaise){ - monitoredWatcher.Should().Raise(raise).WithSender(watcher); - } - foreach(var notRraise in toNotRaise){ - monitoredWatcher.Should().NotRaise(notRraise); - } + toRaise.ForEach(r => monitoredWatcher.Should().Raise(r).WithSender(watcher)); + toNotRaise.ForEach(r => monitoredWatcher.Should().NotRaise(r)); } // [Fact] diff --git a/Selector/Equality/UriEquality.cs b/Selector/Equality/UriEquality.cs index d5472f2..0bfc039 100644 --- a/Selector/Equality/UriEquality.cs +++ b/Selector/Equality/UriEquality.cs @@ -63,12 +63,12 @@ namespace Selector { public bool Context(Context context1, Context context2) { - return context1.Uri == context2.Uri; + return context1?.Uri == context2?.Uri; } public bool Device(Device device1, Device device2) { - return device1.Id == device2.Id; + return device1?.Id == device2?.Id; } } } \ No newline at end of file diff --git a/Selector/Watcher/Interfaces/Events.cs b/Selector/Watcher/Interfaces/Events.cs index a6df283..e05f4da 100644 --- a/Selector/Watcher/Interfaces/Events.cs +++ b/Selector/Watcher/Interfaces/Events.cs @@ -4,7 +4,7 @@ using SpotifyAPI.Web; namespace Selector { public class ListeningChangeEventArgs: EventArgs { - public CurrentlyPlaying Previous; - public CurrentlyPlaying Current; + public CurrentlyPlayingContext Previous; + public CurrentlyPlayingContext Current; } } diff --git a/Selector/Watcher/Interfaces/IPlayerWatcher.cs b/Selector/Watcher/Interfaces/IPlayerWatcher.cs index 46c38fd..fffd787 100644 --- a/Selector/Watcher/Interfaces/IPlayerWatcher.cs +++ b/Selector/Watcher/Interfaces/IPlayerWatcher.cs @@ -12,11 +12,11 @@ namespace Selector public event EventHandler ContextChange; public event EventHandler ContentChange; - // public event EventHandler VolumeChange; - // public event EventHandler DeviceChange; + public event EventHandler VolumeChange; + public event EventHandler DeviceChange; public event EventHandler PlayingChange; - public CurrentlyPlaying NowPlaying(); + public CurrentlyPlayingContext NowPlaying(); // recently playing } } diff --git a/Selector/Watcher/PlayerWatcher.cs b/Selector/Watcher/PlayerWatcher.cs index 66f6e8b..b62d6c8 100644 --- a/Selector/Watcher/PlayerWatcher.cs +++ b/Selector/Watcher/PlayerWatcher.cs @@ -17,12 +17,12 @@ namespace Selector public event EventHandler ContextChange; public event EventHandler ContentChange; - // public event EventHandler VolumeChange; - // public event EventHandler DeviceChange; + public event EventHandler VolumeChange; + public event EventHandler DeviceChange; public event EventHandler PlayingChange; - private CurrentlyPlaying live { get; set; } - private List> lastPlays { get; set; } + private CurrentlyPlayingContext live { get; set; } + private List> lastPlays { get; set; } private int _pollPeriod; public int PollPeriod { @@ -38,17 +38,17 @@ namespace Selector this.equalityChecker = equalityChecker; this.PollPeriod = pollPeriod; - lastPlays = new List>(); + lastPlays = new List>(); } public async Task WatchOne() { try{ - var polledCurrent = await spotifyClient.GetCurrentlyPlaying(new PlayerCurrentlyPlayingRequest()); + var polledCurrent = await spotifyClient.GetCurrentPlayback(); - if (polledCurrent != null) StoreCurrentPlaying(polledCurrent); + if (polledCurrent != null) StoreCurrentPlaying(live, polledCurrent); - CurrentlyPlaying previous; + CurrentlyPlayingContext previous; if(live is null) { live = polledCurrent; previous = polledCurrent; @@ -69,13 +69,19 @@ namespace Selector if(previous is null && (live.Item is FullTrack || live.Item is FullEpisode)) { // Console.WriteLine("started playing"); - + OnPlayingChange(new ListeningChangeEventArgs(){ + Previous = previous, + Current = live + }); } // STOPPED PLAYBACK else if((previous.Item is FullTrack || previous.Item is FullEpisode) && live is null) { // Console.WriteLine("stopped playing"); - + OnPlayingChange(new ListeningChangeEventArgs(){ + Previous = previous, + Current = live + }); } else { @@ -144,6 +150,14 @@ namespace Selector }); } + // DEVICE + if(!equalityChecker.Device(previous?.Device, live?.Device)) { + OnDeviceChange(new ListeningChangeEventArgs(){ + Previous = previous, + Current = live + }); + } + // IS PLAYING if(previous.IsPlaying != live.IsPlaying) { OnPlayingChange(new ListeningChangeEventArgs(){ @@ -151,6 +165,14 @@ namespace Selector Current = live }); } + + // VOLUME + if(previous.Device.VolumePercent != live.Device.VolumePercent) { + OnVolumeChange(new ListeningChangeEventArgs(){ + Previous = previous, + Current = live + }); + } } } } @@ -177,7 +199,7 @@ namespace Selector } } - public CurrentlyPlaying NowPlaying() + public CurrentlyPlayingContext NowPlaying() { return live; } @@ -186,7 +208,7 @@ namespace Selector /// Store currently playing in last plays. Determine whether new list or appending required /// /// New currently playing to store - private void StoreCurrentPlaying(CurrentlyPlaying current) + private void StoreCurrentPlaying(CurrentlyPlayingContext previous, CurrentlyPlayingContext current) { if(lastPlays.Count > 0) { @@ -212,11 +234,11 @@ namespace Selector } else { - StoreNewTrack(current); + StoreNewTrack(previous, current); } } else { - StoreNewTrack(current); + StoreNewTrack(previous, current); } } @@ -224,11 +246,11 @@ namespace Selector /// Store currently playing at front of last plays list. Pushes new list to hold same track /// /// New currently playing to store - private void StoreNewTrack(CurrentlyPlaying current) + private void StoreNewTrack(CurrentlyPlayingContext previous, CurrentlyPlayingContext current) { - if (live != null) { - var newPlayingList = new List(); - newPlayingList.Add(live); + if (previous != null) { + var newPlayingList = new List(); + newPlayingList.Add(previous); lastPlays.Insert(0, newPlayingList); } } @@ -258,15 +280,15 @@ namespace Selector ContentChange?.Invoke(this, args); } - // protected virtual void OnVolumeChange(ListeningChangeEventArgs args) - // { - // ArtistChange?.Invoke(this, args); - // } + protected virtual void OnVolumeChange(ListeningChangeEventArgs args) + { + VolumeChange?.Invoke(this, args); + } - // protected virtual void OnDeviceChange(ListeningChangeEventArgs args) - // { - // ContextChange?.Invoke(this, args); - // } + protected virtual void OnDeviceChange(ListeningChangeEventArgs args) + { + DeviceChange?.Invoke(this, args); + } protected virtual void OnPlayingChange(ListeningChangeEventArgs args) {