diff --git a/NzbDrone.Common/NzbDrone.Common.csproj b/NzbDrone.Common/NzbDrone.Common.csproj
index 62a0028a6..e1bb25519 100644
--- a/NzbDrone.Common/NzbDrone.Common.csproj
+++ b/NzbDrone.Common/NzbDrone.Common.csproj
@@ -138,7 +138,7 @@
     
     
     
-    
+    
     
     
     
@@ -155,7 +155,6 @@
     
     
     
-    
   
   
     
diff --git a/NzbDrone.Common/StringExtention.cs b/NzbDrone.Common/StringExtension.cs
similarity index 100%
rename from NzbDrone.Common/StringExtention.cs
rename to NzbDrone.Common/StringExtension.cs
diff --git a/NzbDrone.Common/UdpProvider.cs b/NzbDrone.Common/UdpProvider.cs
deleted file mode 100644
index 94956c125..000000000
--- a/NzbDrone.Common/UdpProvider.cs
+++ /dev/null
@@ -1,191 +0,0 @@
-using System.Linq;
-using System;
-using System.Net;
-using System.Net.Sockets;
-using NLog;
-
-namespace NzbDrone.Common
-{
-    public class UdpProvider
-    {
-        private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
-
-        public UdpProvider()
-        {
-            
-        }
-
-        private const int StandardPort = 9777;
-        private const int MaxPacketSize = 1024;
-        private const int HeaderSize = 32;
-        private const int MaxPayloadSize = MaxPacketSize - HeaderSize;
-        private const byte MajorVersion = 2;
-        private const byte MinorVersion = 0;
-
-        public enum PacketType
-        {
-            Helo = 0x01,
-            Bye = 0x02,
-            Button = 0x03,
-            Mouse = 0x04,
-            Ping = 0x05,
-            Broadcast = 0x06,  //Currently not implemented
-            Notification = 0x07,
-            Blob = 0x08,
-            Log = 0x09,
-            Action = 0x0A,
-            Debug = 0xFF //Currently not implemented
-        }
-
-        private byte[] Header(PacketType packetType, int numberOfPackets, int currentPacket, int payloadSize, uint uniqueToken)
-        {
-            byte[] header = new byte[HeaderSize];
-
-            header[0] = (byte)'X';
-            header[1] = (byte)'B';
-            header[2] = (byte)'M';
-            header[3] = (byte)'C';
-
-            header[4] = MajorVersion;
-            header[5] = MinorVersion;
-
-            if (currentPacket == 1)
-            {
-                header[6] = (byte)(((ushort)packetType & 0xff00) >> 8);
-                header[7] = (byte)((ushort)packetType & 0x00ff);
-            }
-            else
-            {
-                header[6] = ((ushort)PacketType.Blob & 0xff00) >> 8;
-                header[7] = (ushort)PacketType.Blob & 0x00ff;
-            }
-
-            header[8] = (byte)((currentPacket & 0xff000000) >> 24);
-            header[9] = (byte)((currentPacket & 0x00ff0000) >> 16);
-            header[10] = (byte)((currentPacket & 0x0000ff00) >> 8);
-            header[11] = (byte)(currentPacket & 0x000000ff);
-
-            header[12] = (byte)((numberOfPackets & 0xff000000) >> 24);
-            header[13] = (byte)((numberOfPackets & 0x00ff0000) >> 16);
-            header[14] = (byte)((numberOfPackets & 0x0000ff00) >> 8);
-            header[15] = (byte)(numberOfPackets & 0x000000ff);
-
-            header[16] = (byte)((payloadSize & 0xff00) >> 8);
-            header[17] = (byte)(payloadSize & 0x00ff);
-
-            header[18] = (byte)((uniqueToken & 0xff000000) >> 24);
-            header[19] = (byte)((uniqueToken & 0x00ff0000) >> 16);
-            header[20] = (byte)((uniqueToken & 0x0000ff00) >> 8);
-            header[21] = (byte)(uniqueToken & 0x000000ff);
-
-            return header;
-
-        }
-
-        public virtual bool Send(string address, PacketType packetType, byte[] payload)
-        {
-            var uniqueToken = (uint)DateTime.Now.TimeOfDay.Milliseconds;
-
-            var socket = Connect(address, StandardPort);
-
-            if (socket == null || !socket.Connected)
-            {
-                return false;
-            }
-
-            try
-            {
-                bool successfull = true;
-                int packetCount = (payload.Length / MaxPayloadSize) + 1;
-                int bytesToSend = 0;
-                int bytesSent = 0;
-                int bytesLeft = payload.Length;
-
-                for (int Package = 1; Package <= packetCount; Package++)
-                {
-
-                    if (bytesLeft > MaxPayloadSize)
-                    {
-                        bytesToSend = MaxPayloadSize;
-                        bytesLeft -= bytesToSend;
-                    }
-                    else
-                    {
-                        bytesToSend = bytesLeft;
-                        bytesLeft = 0;
-                    }
-
-                    byte[] header = Header(packetType, packetCount, Package, bytesToSend, uniqueToken);
-                    byte[] packet = new byte[MaxPacketSize];
-
-                    Array.Copy(header, 0, packet, 0, header.Length);
-                    Array.Copy(payload, bytesSent, packet, header.Length, bytesToSend);
-
-                    int sendSize = socket.Send(packet, header.Length + bytesToSend, SocketFlags.None);
-
-                    if (sendSize != (header.Length + bytesToSend))
-                    {
-                        successfull = false;
-                        break;
-                    }
-
-                    bytesSent += bytesToSend;
-                }
-                Disconnect(socket);
-                return successfull;
-            }
-
-            catch
-            {
-                Disconnect(socket);
-                return false;
-            }
-        }
-
-        private Socket Connect(string address, int port)
-        {
-            try
-            {
-                var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
-
-                IPAddress ip;
-                if (!IPAddress.TryParse(address, out ip))
-                {
-                    IPHostEntry ipHostEntry = Dns.GetHostEntry(address);
-                    foreach (IPAddress ipAddress in ipHostEntry.AddressList)
-                    {
-                        if (ipAddress.AddressFamily == AddressFamily.InterNetwork)
-                        {
-                            ip = ipAddress;
-                            break;
-                        }
-                    }
-                }
-
-                socket.Connect(new IPEndPoint(ip, port));
-                return socket;
-            }
-
-            catch (Exception exc)
-            {
-                Logger.TraceException(exc.Message, exc);
-                return null;
-            }
-        }
-
-        private void Disconnect(Socket socket)
-        {
-            try
-            {
-                if (socket != null)
-                {
-                    socket.Shutdown(SocketShutdown.Both);
-                    socket.Close();
-                }
-            }
-            catch
-            {
-            }
-        }
-    }
-}
diff --git a/NzbDrone.Core.Test/ProviderTests/GrowlProviderTest.cs b/NzbDrone.Core.Test/NotificationTests/GrowlProviderTest.cs
similarity index 100%
rename from NzbDrone.Core.Test/ProviderTests/GrowlProviderTest.cs
rename to NzbDrone.Core.Test/NotificationTests/GrowlProviderTest.cs
diff --git a/NzbDrone.Core.Test/NotificationTests/NotificationServiceFixture.cs b/NzbDrone.Core.Test/NotificationTests/NotificationServiceFixture.cs
index 8ad4812f4..2c0d86add 100644
--- a/NzbDrone.Core.Test/NotificationTests/NotificationServiceFixture.cs
+++ b/NzbDrone.Core.Test/NotificationTests/NotificationServiceFixture.cs
@@ -25,7 +25,7 @@ namespace NzbDrone.Core.Test.NotificationTests
         {
             _notifications = new List();
 
-            _notifications.Add(new Xbmc(null, null));
+            _notifications.Add(new Notifications.Xbmc.Xbmc(null, null));
             _notifications.Add(new PlexClient(null));
             _notifications.Add(new PlexServer(null));
             _notifications.Add(new Email(null));
@@ -49,8 +49,8 @@ namespace NzbDrone.Core.Test.NotificationTests
         {
             Mocker.SetConstant(Mocker.Resolve());
 
-            Mocker.GetMock().Setup(s => s.Resolve(typeof (Xbmc)))
-                  .Returns(new Xbmc(null, null));
+            Mocker.GetMock().Setup(s => s.Resolve(typeof(Notifications.Xbmc.Xbmc)))
+                  .Returns(new Notifications.Xbmc.Xbmc(null, null));
 
             Mocker.GetMock().Setup(s => s.Resolve(typeof(PlexClient)))
                   .Returns(new PlexClient(null));
diff --git a/NzbDrone.Core.Test/ProviderTests/PlexProviderTest.cs b/NzbDrone.Core.Test/NotificationTests/PlexProviderTest.cs
similarity index 100%
rename from NzbDrone.Core.Test/ProviderTests/PlexProviderTest.cs
rename to NzbDrone.Core.Test/NotificationTests/PlexProviderTest.cs
diff --git a/NzbDrone.Core.Test/ProviderTests/ProwlProviderTest.cs b/NzbDrone.Core.Test/NotificationTests/ProwlProviderTest.cs
similarity index 100%
rename from NzbDrone.Core.Test/ProviderTests/ProwlProviderTest.cs
rename to NzbDrone.Core.Test/NotificationTests/ProwlProviderTest.cs
diff --git a/NzbDrone.Core.Test/NotificationTests/Xbmc/GetJsonVersionFixture.cs b/NzbDrone.Core.Test/NotificationTests/Xbmc/GetJsonVersionFixture.cs
new file mode 100644
index 000000000..388c1cccc
--- /dev/null
+++ b/NzbDrone.Core.Test/NotificationTests/Xbmc/GetJsonVersionFixture.cs
@@ -0,0 +1,80 @@
+using System;
+using System.Linq;
+using FizzWare.NBuilder;
+using FluentAssertions;
+using Moq;
+using NUnit.Framework;
+using NzbDrone.Common;
+using NzbDrone.Core.Configuration;
+using NzbDrone.Core.Notifications.Xbmc;
+using NzbDrone.Core.Tv;
+using NzbDrone.Core.Model.Xbmc;
+using NzbDrone.Core.Providers;
+using NzbDrone.Core.Test.Framework;
+using NzbDrone.Test.Common.AutoMoq;
+
+namespace NzbDrone.Core.Test.NotificationTests.Xbmc
+{
+    [TestFixture]
+    public class GetJsonVersionFixture : CoreTest
+    {
+        private XbmcSettings _settings;
+
+        [SetUp]
+        public void Setup()
+        {
+            _settings = new XbmcSettings
+                            {
+                                Host = "localhost",
+                                Port = 8080,
+                                Username = "xbmc",
+                                Password = "xbmc",
+                                AlwaysUpdate = false,
+                                CleanLibrary = false,
+                                UpdateLibrary = true
+                            };
+        }
+
+        [TestCase(3)]
+        [TestCase(2)]
+        [TestCase(0)]
+        public void should_get_version_from_major_only(int number)
+        {
+            var message = "{\"id\":10,\"jsonrpc\":\"2.0\",\"result\":{\"version\":" + number + "}}";
+
+            var fakeHttp = Mocker.GetMock();
+            fakeHttp.Setup(s => s.PostCommand("localhost:8080", "xbmc", "xbmc", It.IsAny()))
+                .Returns(message);
+
+            Subject.GetJsonVersion(_settings).Should().Be(new XbmcVersion(number));
+        }
+
+        [TestCase(5, 0, 0)]
+        [TestCase(6, 0, 0)]
+        [TestCase(6, 1, 0)]
+        [TestCase(6, 0, 23)]
+        [TestCase(0, 0, 0)]
+        public void should_get_version_from_semantic_version(int major, int minor, int patch)
+        {
+            var message = "{\"id\":10,\"jsonrpc\":\"2.0\",\"result\":{\"version\":{\"major\":" + major + ",\"minor\":" + minor + ",\"patch\":" + patch + "}}}";
+
+            var fakeHttp = Mocker.GetMock();
+            fakeHttp.Setup(s => s.PostCommand("localhost:8080", "xbmc", "xbmc", It.IsAny()))
+                .Returns(message);
+
+            Subject.GetJsonVersion(_settings).Should().Be(new XbmcVersion(major, minor, patch));
+        }
+
+        [Test]
+        public void should_get_version_zero_when_an_error_is_received()
+        {
+            var message = "{\"error\":{\"code\":-32601,\"message\":\"Method not found.\"},\"id\":10,\"jsonrpc\":\"2.0\"}";
+
+            var fakeHttp = Mocker.GetMock();
+            fakeHttp.Setup(s => s.PostCommand("localhost:8080", "xbmc", "xbmc", It.IsAny()))
+                .Returns(message);
+
+            Subject.GetJsonVersion(_settings).Should().Be(new XbmcVersion(0));
+        }
+    }
+}
\ No newline at end of file
diff --git a/NzbDrone.Core.Test/NotificationTests/Xbmc/Http/ActivePlayersFixture.cs b/NzbDrone.Core.Test/NotificationTests/Xbmc/Http/ActivePlayersFixture.cs
new file mode 100644
index 000000000..ca412a3c1
--- /dev/null
+++ b/NzbDrone.Core.Test/NotificationTests/Xbmc/Http/ActivePlayersFixture.cs
@@ -0,0 +1,74 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using FluentAssertions;
+using Moq;
+using NUnit.Framework;
+using NzbDrone.Common;
+using NzbDrone.Core.Notifications.Xbmc;
+using NzbDrone.Core.Test.Framework;
+
+namespace NzbDrone.Core.Test.NotificationTests.Xbmc.Http
+{
+    [TestFixture]
+    public class ActivePlayersFixture : CoreTest
+    {
+        private XbmcSettings _settings;
+        private string _expectedUrl;
+
+        private void WithNoActivePlayers()
+        {
+            Mocker.GetMock()
+                  .Setup(s => s.DownloadString(_expectedUrl, _settings.Username, _settings.Password))
+                  .Returns("Filename:[Nothing Playing]");
+        }
+
+        private void WithVideoPlayerActive()
+        {
+            var activePlayers = @"Filename:C:\Test\TV\2 Broke Girls\Season 01\2 Broke Girls - S01E01 - Pilot [SDTV].avi" +
+                              "PlayStatus:PlayingVideoNo:0Type:VideoThumb:special://masterprofile/Thumbnails/Video/a/auto-a664d5a2.tbn" +
+                              "Time:00:06Duration:21:35Percentage:0File size:183182590Changed:True";
+
+            Mocker.GetMock()
+                  .Setup(s => s.DownloadString(_expectedUrl, _settings.Username, _settings.Password))
+                  .Returns(activePlayers);
+        }
+
+        [SetUp]
+        public void Setup()
+        {
+            _settings = new XbmcSettings
+            {
+                Host = "localhost",
+                Port = 8080,
+                Username = "xbmc",
+                Password = "xbmc",
+                AlwaysUpdate = false,
+                CleanLibrary = false,
+                UpdateLibrary = true
+            };
+
+            _expectedUrl = String.Format("http://{0}/xbmcCmds/xbmcHttp?command={1}", _settings.Address, "getcurrentlyplaying");
+        }
+
+        [Test]
+        public void _should_be_empty_when_no_active_players()
+        {
+            WithNoActivePlayers();
+
+            Subject.GetActivePlayers(_settings).Should().BeEmpty();
+        }
+
+        [Test]
+        public void should_have_active_video_player()
+        {
+            WithVideoPlayerActive();
+
+            var result = Subject.GetActivePlayers(_settings);
+
+            result.Should().HaveCount(1);
+            result.First().Type.Should().Be("video");
+        }
+    }
+}
diff --git a/NzbDrone.Core.Test/NotificationTests/Xbmc/Http/CheckForErrorFixture.cs b/NzbDrone.Core.Test/NotificationTests/Xbmc/Http/CheckForErrorFixture.cs
new file mode 100644
index 000000000..db4aeeb1d
--- /dev/null
+++ b/NzbDrone.Core.Test/NotificationTests/Xbmc/Http/CheckForErrorFixture.cs
@@ -0,0 +1,41 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using FluentAssertions;
+using Moq;
+using NUnit.Framework;
+using NzbDrone.Common;
+using NzbDrone.Core.Notifications.Xbmc;
+using NzbDrone.Core.Test.Framework;
+
+namespace NzbDrone.Core.Test.NotificationTests.Xbmc.Http
+{
+    [TestFixture]
+    public class CheckForErrorFixture : CoreTest
+    {
+        [Test]
+        public void should_be_true_when_the_response_contains_an_error()
+        {
+            const string response = "html>Error:Unknown command