From 2af078b23dbdb5f74ae2073a8b2f9b7377aaca0b Mon Sep 17 00:00:00 2001
From: markus101 <markus.mcd5@gmail.com>
Date: Sun, 6 Mar 2011 12:45:35 -0800
Subject: [PATCH] ExternalNotifications, XBMC notification, building the
 framework for these, UI not implemented.

---
 NzbDrone.Core/Helpers/EpisodeRenameHelper.cs  |  22 ++++
 NzbDrone.Core/Helpers/ServerHelper.cs         |  18 +++
 NzbDrone.Core/Model/EpisodeRenameModel.cs     |   1 +
 .../Providers/ExternalNotificationProvider.cs | 105 ++++++++++++++++++
 .../Providers/IExtenalNotificationProvider.cs |  15 +++
 NzbDrone.Core/Providers/IRenameProvider.cs    |   2 +-
 NzbDrone.Core/Providers/IXbmcProvider.cs      |  14 +++
 .../Providers/PostProcessingProvider.cs       |   2 +-
 NzbDrone.Core/Providers/RenameProvider.cs     |  14 ++-
 NzbDrone.Core/Providers/XbmcProvider.cs       |  79 +++++++++++++
 NzbDrone.Web/Content/XbmcNotification.png     | Bin 0 -> 6280 bytes
 NzbDrone.Web/Views/Settings/Index-Copy.aspx   |  27 -----
 12 files changed, 268 insertions(+), 31 deletions(-)
 create mode 100644 NzbDrone.Core/Helpers/ServerHelper.cs
 create mode 100644 NzbDrone.Core/Providers/ExternalNotificationProvider.cs
 create mode 100644 NzbDrone.Core/Providers/IExtenalNotificationProvider.cs
 create mode 100644 NzbDrone.Core/Providers/IXbmcProvider.cs
 create mode 100644 NzbDrone.Core/Providers/XbmcProvider.cs
 create mode 100644 NzbDrone.Web/Content/XbmcNotification.png
 delete mode 100644 NzbDrone.Web/Views/Settings/Index-Copy.aspx

diff --git a/NzbDrone.Core/Helpers/EpisodeRenameHelper.cs b/NzbDrone.Core/Helpers/EpisodeRenameHelper.cs
index 3879893ae..f401c221a 100644
--- a/NzbDrone.Core/Helpers/EpisodeRenameHelper.cs
+++ b/NzbDrone.Core/Helpers/EpisodeRenameHelper.cs
@@ -33,5 +33,27 @@ namespace NzbDrone.Core.Helpers
         {
             return seasonFolderFormat.Replace("%s", seasonNumber.ToString()).Replace("%0s", seasonNumber.ToString("00"));
         }
+
+        public static string GetNameForNotify(EpisodeRenameModel erm)
+        {
+            if (erm.EpisodeFile.Episodes.Count == 1)
+            {
+                return String.Format("{0} - S{1:00}E{2:00} - {3}", erm.SeriesName,
+                                     erm.EpisodeFile.Episodes[0].SeasonNumber, erm.EpisodeFile.Episodes[0].EpisodeNumber,
+                                     erm.EpisodeFile.Episodes[0].Title);
+            }
+
+            var epNumberString = String.Empty;
+            var epNameString = String.Empty;
+
+            foreach (var episode in erm.EpisodeFile.Episodes)
+            {
+                epNumberString = epNumberString + String.Format("E{0:00}", episode.EpisodeNumber);
+                epNameString = epNameString + String.Format("+ {0}", episode.Title).Trim(' ', '+');
+            }
+
+            return String.Format("{0} - S{1:00}E{2} - {3}", erm.SeriesName, erm.EpisodeFile.Episodes[0].SeasonNumber,
+                                 epNumberString, epNameString);
+        }
     }
 }
\ No newline at end of file
diff --git a/NzbDrone.Core/Helpers/ServerHelper.cs b/NzbDrone.Core/Helpers/ServerHelper.cs
new file mode 100644
index 000000000..aeb91bb42
--- /dev/null
+++ b/NzbDrone.Core/Helpers/ServerHelper.cs
@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net;
+using System.Text;
+
+namespace NzbDrone.Core.Helpers
+{
+    public static class ServerHelper
+    {
+        public static string GetServerHostname()
+        {
+            //Both these seem to return the same result... Is on better than the other?
+            return Environment.MachineName;
+            //return Dns.GetHostName();
+        }
+    }
+}
diff --git a/NzbDrone.Core/Model/EpisodeRenameModel.cs b/NzbDrone.Core/Model/EpisodeRenameModel.cs
index 9583ce3e2..9a965a8e1 100644
--- a/NzbDrone.Core/Model/EpisodeRenameModel.cs
+++ b/NzbDrone.Core/Model/EpisodeRenameModel.cs
@@ -11,5 +11,6 @@ namespace NzbDrone.Core.Model
         public string SeriesName { get; set; }
         public string Folder { get; set; }
         public EpisodeFile EpisodeFile { get; set; }
+        public bool NewDownload { get; set; }
     }
 }
diff --git a/NzbDrone.Core/Providers/ExternalNotificationProvider.cs b/NzbDrone.Core/Providers/ExternalNotificationProvider.cs
new file mode 100644
index 000000000..fd6238157
--- /dev/null
+++ b/NzbDrone.Core/Providers/ExternalNotificationProvider.cs
@@ -0,0 +1,105 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using NLog;
+using NzbDrone.Core.Helpers;
+using NzbDrone.Core.Model;
+using NzbDrone.Core.Repository;
+
+namespace NzbDrone.Core.Providers
+{
+    public class ExternalNotificationProvider : IExtenalNotificationProvider
+    {
+        private readonly IConfigProvider _configProvider;
+
+
+        private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
+
+        public ExternalNotificationProvider(IConfigProvider configProvider)
+        {
+            _configProvider = configProvider;
+        }
+
+        #region IExternalNotificationProvider Members
+        public void OnGrab(string message)
+        {
+            var header = "NzbDrone [TV] - Grabbed";
+
+            if (Convert.ToBoolean(_configProvider.GetValue("XbmcEnabled", false, true)))
+            {
+                if (Convert.ToBoolean(_configProvider.GetValue("XbmcNotifyOnGrab", false, true)))
+                {
+                    Logger.Trace("Sending Notifcation to XBMC");
+
+                    return;
+                }
+                Logger.Trace("XBMC NotifyOnGrab is not enabled");
+            }
+
+            Logger.Trace("XBMC Notifier is not enabled");
+        }
+
+        public void OnDownload(EpisodeRenameModel erm)
+        {
+            var header = "NzbDrone [TV] - Downloaded";
+            var message = EpisodeRenameHelper.GetNewName(erm);
+
+            if (Convert.ToBoolean(_configProvider.GetValue("XbmcEnabled", false, true)))
+            {
+                if (Convert.ToBoolean(_configProvider.GetValue("XbmcNotifyOnDownload", false, true)))
+                {
+                    Logger.Trace("Sending Notifcation to XBMC");
+                    //Send to XBMC
+                }
+
+                if (Convert.ToBoolean(_configProvider.GetValue("XbmcUpdateOnDownload", false, true)))
+                {
+                    Logger.Trace("Sending Update Request to XBMC");
+                    //Send to XBMC
+                    //Send SeriesID
+                }
+
+                if (Convert.ToBoolean(_configProvider.GetValue("XbmcCleanOnDownload", false, true)))
+                {
+                    Logger.Trace("Sending Clean DB Request to XBMC");
+                    //Send to XBMC
+                }
+            }
+
+            Logger.Trace("XBMC Notifier is not enabled");
+
+
+            throw new NotImplementedException();
+        }
+
+        public void OnRename(EpisodeRenameModel erm)
+        {
+            var header = "NzbDrone [TV] - Renamed";
+            var message = EpisodeRenameHelper.GetNewName(erm);
+
+            if (Convert.ToBoolean(_configProvider.GetValue("XbmcNotifyOnRename", false, true)))
+            {
+                Logger.Trace("Sending Notifcation to XBMC");
+                //Send to XBMC
+            }
+
+            if (Convert.ToBoolean(_configProvider.GetValue("XbmcUpdateOnRename", false, true)))
+            {
+                Logger.Trace("Sending Update Request to XBMC");
+                //Send to XBMC
+                //Send SeriesID
+            }
+
+            if (Convert.ToBoolean(_configProvider.GetValue("XbmcCleanOnRename", false, true)))
+            {
+                Logger.Trace("Sending Clean DB Request to XBMC");
+                //Send to XBMC
+            }
+
+
+            throw new NotImplementedException();
+        }
+        #endregion
+    }
+}
diff --git a/NzbDrone.Core/Providers/IExtenalNotificationProvider.cs b/NzbDrone.Core/Providers/IExtenalNotificationProvider.cs
new file mode 100644
index 000000000..83d2752a2
--- /dev/null
+++ b/NzbDrone.Core/Providers/IExtenalNotificationProvider.cs
@@ -0,0 +1,15 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using NzbDrone.Core.Repository;
+
+namespace NzbDrone.Core.Providers
+{
+    public interface IExtenalNotificationProvider
+    {
+        void OnGrab(string message);
+        void OnDownload(EpisodeFile episodeFile);
+        void OnRename(EpisodeFile episodeFile);
+    }
+}
diff --git a/NzbDrone.Core/Providers/IRenameProvider.cs b/NzbDrone.Core/Providers/IRenameProvider.cs
index a3f691c7c..764608d0e 100644
--- a/NzbDrone.Core/Providers/IRenameProvider.cs
+++ b/NzbDrone.Core/Providers/IRenameProvider.cs
@@ -11,6 +11,6 @@ namespace NzbDrone.Core.Providers
         void RenameSeries(int seriesId);
         void RenameSeason(int seasonId);
         void RenameEpisode(int episodeId);
-        void RenameEpisodeFile(int episodeFileId);
+        void RenameEpisodeFile(int episodeFileId, bool newDownload);
     }
 }
diff --git a/NzbDrone.Core/Providers/IXbmcProvider.cs b/NzbDrone.Core/Providers/IXbmcProvider.cs
new file mode 100644
index 000000000..81c50696b
--- /dev/null
+++ b/NzbDrone.Core/Providers/IXbmcProvider.cs
@@ -0,0 +1,14 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace NzbDrone.Core.Providers
+{
+    public interface IXbmcProvider
+    {
+        void Notify(string header, string message);
+        void Update(int seriesId);
+        void Clean();
+    }
+}
diff --git a/NzbDrone.Core/Providers/PostProcessingProvider.cs b/NzbDrone.Core/Providers/PostProcessingProvider.cs
index 103303b8e..4345528a5 100644
--- a/NzbDrone.Core/Providers/PostProcessingProvider.cs
+++ b/NzbDrone.Core/Providers/PostProcessingProvider.cs
@@ -40,7 +40,7 @@ namespace NzbDrone.Core.Providers
             foreach (var file in fileList)
             {
                 //Todo: Where should we handle XBMC notifying/library updating etc? RenameProvider seems like a likely place, since we want to update XBMC after renaming (might as well)
-                _renameProvider.RenameEpisodeFile(file.EpisodeFileId);
+                _renameProvider.RenameEpisodeFile(file.EpisodeFileId, true);
             }
         }
 
diff --git a/NzbDrone.Core/Providers/RenameProvider.cs b/NzbDrone.Core/Providers/RenameProvider.cs
index ec319b4ba..1329be90b 100644
--- a/NzbDrone.Core/Providers/RenameProvider.cs
+++ b/NzbDrone.Core/Providers/RenameProvider.cs
@@ -19,6 +19,8 @@ namespace NzbDrone.Core.Providers
         private readonly IMediaFileProvider _mediaFileProvider;
         private readonly IDiskProvider _diskProvider;
         private readonly IConfigProvider _configProvider;
+        private readonly IExtenalNotificationProvider _externalNotificationProvider;
+
         private Thread _renameThread;
         private List<EpisodeRenameModel> _epsToRename = new List<EpisodeRenameModel>();
 
@@ -26,7 +28,8 @@ namespace NzbDrone.Core.Providers
 
         public RenameProvider(ISeriesProvider seriesProvider, ISeasonProvider seasonProvider,
             IEpisodeProvider episodeProvider, IMediaFileProvider mediaFileProvider,
-            IDiskProvider diskProvider, IConfigProvider configProvider)
+            IDiskProvider diskProvider, IConfigProvider configProvider,
+            IExtenalNotificationProvider extenalNotificationProvider)
         {
             _seriesProvider = seriesProvider;
             _seasonProvider = seasonProvider;
@@ -34,6 +37,7 @@ namespace NzbDrone.Core.Providers
             _mediaFileProvider = mediaFileProvider;
             _diskProvider = diskProvider;
             _configProvider = configProvider;
+            _externalNotificationProvider = extenalNotificationProvider;
         }
 
         #region IRenameProvider Members
@@ -122,7 +126,7 @@ namespace NzbDrone.Core.Providers
             StartRename();
         }
 
-        public void RenameEpisodeFile(int episodeFileId)
+        public void RenameEpisodeFile(int episodeFileId, bool newDownload)
         {
             //This will properly rename multi-episode files if asked to rename either of the episode
             var episodeFile = _mediaFileProvider.GetEpisodeFile(episodeFileId);
@@ -193,6 +197,12 @@ namespace NzbDrone.Core.Providers
                 erm.EpisodeFile.Path = newFilename;
                 _mediaFileProvider.Update(erm.EpisodeFile);
 
+                if (erm.NewDownload)
+                    _externalNotificationProvider.OnDownload();
+
+                else
+                    _externalNotificationProvider.OnRename();
+
             }
             catch (Exception ex)
             {
diff --git a/NzbDrone.Core/Providers/XbmcProvider.cs b/NzbDrone.Core/Providers/XbmcProvider.cs
new file mode 100644
index 000000000..d044a0ed0
--- /dev/null
+++ b/NzbDrone.Core/Providers/XbmcProvider.cs
@@ -0,0 +1,79 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net;
+using System.Text;
+using NLog;
+
+namespace NzbDrone.Core.Providers
+{
+    public class XbmcProvider : IXbmcProvider
+    {
+        private readonly IConfigProvider _configProvider;
+
+        private WebClient _webClient;
+        private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
+
+        public XbmcProvider(IConfigProvider configProvider)
+        {
+            _webClient = new WebClient();
+            _configProvider = configProvider;
+        }
+
+        #region IXbmcProvider Members
+
+        public void Notify(string header, string message)
+        {
+            //Get time in seconds and convert to ms
+            var time = Convert.ToInt32(_configProvider.GetValue("XbmcDisplayTime", "3", true)) * 1000;
+
+            var command = String.Format("ExecBuiltIn(Notification({0},{1},{2}))", header, message, time);
+
+            foreach (var host in _configProvider.GetValue("XbmcHosts", "localhost:80", true).Split(','))
+            {
+                Logger.Trace("Sending Notifcation to XBMC Host: {0}", host);
+
+            }
+
+
+            throw new NotImplementedException();
+        }
+
+        public void Update(int seriesId)
+        {
+            throw new NotImplementedException();
+        }
+
+        public void Clean()
+        {
+            throw new NotImplementedException();
+        }
+
+        #endregion
+
+        private string SendCommand(string host, string command)
+        {
+            var username = _configProvider.GetValue("XbmcUsername", String.Empty, true);
+            var password = _configProvider.GetValue("XbmcPassword", String.Empty, true);
+
+            if (!String.IsNullOrEmpty(username))
+            {
+                _webClient.Credentials = new NetworkCredential(username, password);
+            }
+
+            var url = String.Format("http://{0}/xbmcCmds/xbmcHttp?command={1}", host, command);
+
+            try
+            {
+                return _webClient.DownloadString(url);
+            }
+            catch (Exception ex)
+            {
+                Logger.Warn("Unable to Connect to XBMC Host: {0}", host);
+                Logger.DebugException(ex.Message, ex);
+            }
+
+            return string.Empty;
+        }
+    }
+}
diff --git a/NzbDrone.Web/Content/XbmcNotification.png b/NzbDrone.Web/Content/XbmcNotification.png
new file mode 100644
index 0000000000000000000000000000000000000000..abbbe37bc0c0d5bc23c4fd396cebc84af691ec0b
GIT binary patch
literal 6280
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

literal 0
HcmV?d00001

diff --git a/NzbDrone.Web/Views/Settings/Index-Copy.aspx b/NzbDrone.Web/Views/Settings/Index-Copy.aspx
deleted file mode 100644
index 166186ae9..000000000
--- a/NzbDrone.Web/Views/Settings/Index-Copy.aspx
+++ /dev/null
@@ -1,27 +0,0 @@
-<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<NzbDrone.Web.Models.SettingsModel>" %>
-
-<%@ Import Namespace="NzbDrone.Web.Controllers" %>
-<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
-    Settings
-</asp:Content>
-<asp:Content ID="General" ContentPlaceHolderID="MainContent" runat="server">
-    <% using (Html.BeginForm())
-       { %>
-    <%: Html.ValidationSummary(true, "Unable to save your settings. Please correct the errors and try again.") %>
-    <div>
-        <fieldset>
-            <legend>General</legend>
-            <div class="editor-label">
-                <%: Html.LabelFor(m => m.TvFolder) %>
-            </div>
-            <div class="editor-field">
-                <%: Html.TextBoxFor(m => m.TvFolder) %>
-                <%: Html.ValidationMessageFor(m => m.TvFolder) %>
-            </div>
-            <p>
-                <input type="submit" value="Save" />
-            </p>
-        </fieldset>
-    </div>
-    <% } %>
-</asp:Content>