diff --git a/Installer/WifiRemote_1_2_Installer.xmp2 b/Installer/WifiRemote_1_2_Installer.xmp2 index 9209845..608c7d0 100644 --- a/Installer/WifiRemote_1_2_Installer.xmp2 +++ b/Installer/WifiRemote_1_2_Installer.xmp2 @@ -168,8 +168,8 @@ Click Next to continue or Cancel to exit Setup. 6 27644 - true - This version of WifiRemote requires MediaPortal 1.2.0 Beta or higher! + false + This version of WifiRemote requires MediaPortal 1.6 or higher! MediaPortal @@ -181,13 +181,13 @@ Click Next to continue or Cancel to exit Setup. WifiRemote d2277c74-fdce-4146-9e23-d080d1799f72 Shukuyen, DieBagger - http://code.google.com/p/wifiremote/ + https://github.com/MPExtended/WifiRemote http://forum.team-mediaportal.com/mediaportal-plugins-47/wifiremote-tcp-remote-control-server-0-1-2011-05-05-a-96251 - http://wifiremote.googlecode.com/svn/trunk/Installer/update.xml + https://raw.github.com/MPExtended/WifiRemote/master/Installer/update.xml 0 - 7 - 1 + 8 + 0 0 WifiRemote is a process plugin for the popular opensource mediacenter software "MediaPortal". @@ -195,14 +195,30 @@ Click Next to continue or Cancel to exit Setup. It publishes a Bonjour Service on your local network which allows clients (for example an iPhone or Android app) to list all found MediaPortal installations and connect to it. - - fixes problems with installed 4tr/argus tv plugins (oxan) -- Improve playback of playlist items (albums, artists, folders), reduce ui -refreshing (DieBagger) + Developers: The WifiRemote source code moved to github! Please go to https://github.com/MPExtended/WifiRemote to check it out and feel free to fork and submit pull requests! + +New in 0.8: +- api level increased to 14 +- MediaPortal 1.6 only, switched to .NET 4 +- Request a screenshot with the screenshot command +- Fixed missing text in dialogs +- Fixed crash related to music db changes in MediaPortal 1.6 (thanks, sebastiii!) +- Fixed crash when encountering music with special chars in it (thanks, Martin K.!) +- Added Artist to now playing radio message (thanks, johanj!) +- Added methods for setting playlist repeat and shuffle (thanks, johanj!) +- Improved starting radio channel (thanks, johanj!) +- Send open dialogs to connecting clients +- Send facade info to connecting clients +- Added ViewType property to FacadeInfo message +- Added support for the trakt plugin rating dialog + + + Stable - http://wifiremote.googlecode.com/files/WifiRemote_0.6.1.mpe1 - 2012-11-25T20:16:04 + https://github.com/MPExtended/WifiRemote/releases/download/Release_0_8/WifiRemote_0.8.mpe1 + 2014-01-03T20:16:04 remote, wifi, json, client control - WifiRemote_0.7.1.mpe1 + WifiRemote_0.8.mpe1 @@ -255,14 +271,14 @@ refreshing (DieBagger) OverwriteIfOlder installer_logo.gif - Installer{CopyFile}\{f8f8413e-7b79-4951-a9e2-dc8617a03a55}-installer_logo.gif + Installer{CopyFile}\{5c4acac1-409f-40b4-bdcb-fb143f49472d}-installer_logo.gif OverwriteIfOlder logo_radio.png - Installer{CopyFile}\{5ab6c11c-a4ab-4d16-a13d-8f87806b783f}-logo_radio.png + Installer{CopyFile}\{76c05d6b-86b7-4bbc-9b74-e13e536cba88}-logo_radio.png @@ -270,7 +286,7 @@ refreshing (DieBagger) WifiRemote_1_2_Installer.xmp2 - D:\Documents\Visual Studio 2010\Projects\PluginDev\WifiRemote\WifiRemote\Installer\update.xml + D:\temp\wifiremote\Installer\update.xml diff --git a/Installer/update.xml b/Installer/update.xml index 568fbad..3175e23 100644 --- a/Installer/update.xml +++ b/Installer/update.xml @@ -73,12 +73,12 @@ 1 0 - WifiRemote is a process plugin for the popular opensource mediacenter software "MediaPortal". - - - + WifiRemote is a process plugin for the popular opensource mediacenter software "MediaPortal". + + + It publishes a Bonjour Service on your local network which allows clients (for example an iPhone or Android app) to list all found MediaPortal installations and connect to it. - * fixes problems with installed 4tr/argus tv plugins (oxan) + * fixes problems with installed 4tr/argus tv plugins (oxan) * Improve playback of playlist items (albums, artists, folders), reduce ui refreshing (DieBagger) Stable http://wifiremote.googlecode.com/files/WifiRemote_0.7.1.mpe1 @@ -95,8 +95,144 @@ It publishes a Bonjour Service on your local network which allows clients (for e %Plugins%\process\WifiRemote.dll Template - The file used to configure the extension. - If have .exe extension the will be executed + The file used to configure the extension. + If have .exe extension the will be executed + If have .dll extension used like MP plugin configuration + + + + String + Online stored screenshot urls separated by ; + + + YES + Bool + Show dialog and force to uninstall previous version when updating an extension. Should only be disabled if you are using an NSIS/MSI installer. + + + + + + + + + + + false + + + 2.0 + + + + Default + true + Default + + + + + + plugin_files + true + plugin_files + + + + + + config_files + true + config_files + + + + + + + + + + + + + MediaPortal + + + 1 + 1 + 6 + 27644 + + + 1 + 1 + 6 + 27644 + + false + This version of WifiRemote requires MediaPortal 1.6 or higher! + MediaPortal + + + + + + + + WifiRemote + d2277c74-fdce-4146-9e23-d080d1799f72 + Shukuyen, DieBagger + https://github.com/MPExtended/WifiRemote + http://forum.team-mediaportal.com/mediaportal-plugins-47/wifiremote-tcp-remote-control-server-0-1-2011-05-05-a-96251 + https://raw.github.com/MPExtended/WifiRemote/master/Installer/update.xml + + 0 + 8 + 0 + 0 + + WifiRemote is a process plugin for the popular opensource mediacenter software "MediaPortal". + + + +It publishes a Bonjour Service on your local network which allows clients (for example an iPhone or Android app) to list all found MediaPortal installations and connect to it. + Developers: The WifiRemote source code moved to github! Please go to https://github.com/MPExtended/WifiRemote to check it out and feel free to fork and submit pull requests! + +New in 0.8: +- api level increased to 14 +- MediaPortal 1.6 only, switched to .NET 4 +- Request a screenshot with the screenshot command +- Fixed missing text in dialogs +- Fixed crash related to music db changes in MediaPortal 1.6 (thanks, sebastiii!) +- Fixed crash when encountering music with special chars in it (thanks, Martin K.!) +- Added Artist to now playing radio message (thanks, johanj!) +- Added methods for setting playlist repeat and shuffle (thanks, johanj!) +- Improved starting radio channel (thanks, johanj!) +- Send open dialogs to connecting clients +- Send facade info to connecting clients +- Added ViewType property to FacadeInfo message +- Added support for the trakt plugin rating dialog + + + + Stable + https://github.com/MPExtended/WifiRemote/releases/download/Release_0_8/WifiRemote_0.8.mpe1 + 2014-01-03T20:16:04 + remote, wifi, json, client control + WifiRemote_0.8.mpe1 + + + + + String + The icon file of the package stored online (jpg,png,bmp) + + + %Plugins%\process\WifiRemote.dll + Template + The file used to configure the extension. + If have .exe extension the will be executed If have .dll extension used like MP plugin configuration diff --git a/Libs/Common.Utils.dll b/Libs/Common.Utils.dll new file mode 100644 index 0000000..93c16d3 Binary files /dev/null and b/Libs/Common.Utils.dll differ diff --git a/Libs/Core.dll b/Libs/Core.dll new file mode 100644 index 0000000..ac5ce4c Binary files /dev/null and b/Libs/Core.dll differ diff --git a/Libs/Cornerstone.MP.dll b/Libs/Cornerstone.MP.dll new file mode 100644 index 0000000..fe4f538 Binary files /dev/null and b/Libs/Cornerstone.MP.dll differ diff --git a/Libs/Cornerstone.dll b/Libs/Cornerstone.dll new file mode 100644 index 0000000..fd51f71 Binary files /dev/null and b/Libs/Cornerstone.dll differ diff --git a/Libs/Databases.dll b/Libs/Databases.dll new file mode 100644 index 0000000..08022ad Binary files /dev/null and b/Libs/Databases.dll differ diff --git a/Libs/Dialogs.dll b/Libs/Dialogs.dll new file mode 100644 index 0000000..cb8bd36 Binary files /dev/null and b/Libs/Dialogs.dll differ diff --git a/Libs/Gentle.Common.dll b/Libs/Gentle.Common.dll index f6e2b60..1aa4f88 100644 Binary files a/Libs/Gentle.Common.dll and b/Libs/Gentle.Common.dll differ diff --git a/Libs/Gentle.Framework.dll b/Libs/Gentle.Framework.dll index cd71566..06d8b86 100644 Binary files a/Libs/Gentle.Framework.dll and b/Libs/Gentle.Framework.dll differ diff --git a/Libs/MP-TVSeries.dll b/Libs/MP-TVSeries.dll new file mode 100644 index 0000000..d58e225 Binary files /dev/null and b/Libs/MP-TVSeries.dll differ diff --git a/Libs/MPNotificationBar.dll b/Libs/MPNotificationBar.dll index 2a31a06..47610e8 100644 Binary files a/Libs/MPNotificationBar.dll and b/Libs/MPNotificationBar.dll differ diff --git a/Libs/MediaPortal.Support.dll b/Libs/MediaPortal.Support.dll new file mode 100644 index 0000000..cdcf474 Binary files /dev/null and b/Libs/MediaPortal.Support.dll differ diff --git a/Libs/MovingPictures.dll b/Libs/MovingPictures.dll new file mode 100644 index 0000000..96c9e97 Binary files /dev/null and b/Libs/MovingPictures.dll differ diff --git a/Libs/RemotePlugins.dll b/Libs/RemotePlugins.dll new file mode 100644 index 0000000..06f313e Binary files /dev/null and b/Libs/RemotePlugins.dll differ diff --git a/Libs/TVDatabase.dll b/Libs/TVDatabase.dll index 246fb68..973480e 100644 Binary files a/Libs/TVDatabase.dll and b/Libs/TVDatabase.dll differ diff --git a/Libs/TraktPlugin.dll b/Libs/TraktPlugin.dll new file mode 100644 index 0000000..72c3102 Binary files /dev/null and b/Libs/TraktPlugin.dll differ diff --git a/Libs/TvPlugin.dll b/Libs/TvPlugin.dll index 5d5162c..0c4c6a4 100644 Binary files a/Libs/TvPlugin.dll and b/Libs/TvPlugin.dll differ diff --git a/Libs/Utils.dll b/Libs/Utils.dll new file mode 100644 index 0000000..9911c06 Binary files /dev/null and b/Libs/Utils.dll differ diff --git a/Libs/WindowPlugins.dll b/Libs/WindowPlugins.dll new file mode 100644 index 0000000..8129cc5 Binary files /dev/null and b/Libs/WindowPlugins.dll differ diff --git a/Libs/taglib-sharp.dll b/Libs/taglib-sharp.dll new file mode 100644 index 0000000..744c36c Binary files /dev/null and b/Libs/taglib-sharp.dll differ diff --git a/README.md b/README.md index 2d64e19..d69cb13 100644 --- a/README.md +++ b/README.md @@ -15,9 +15,15 @@ At the moment you can build the plugin in Visual Studio and run it on your HTPC, Please copy the WifiRemote.xml file to your MediaPortal custom keymaps folder. ### Building a client -If you want to build a client app for this plugin please contact me via PM on the MediaPortal forum (user Shukuyen). In the future I will add complete information on how to build a client app to the wiki. I am developing a client app for iPhone myself, DieBagger is developing an Android remote app. +You should start by taking a look at the DemoClient app, included in the WifiRemote solution. +This app shows how you can discover a server via Bonjour, connect to it, issue commands and receive messages. It also introduces the concept of the autologin key. The DemoClient app is written in C# but should be relatively easy to understand. If you have questions about this please contact me via PM on the MediaPortal forum (user Shukuyen). + +JSON messages sent from your client to WifiRemote are called commands. You can find a list of available commands here: +http://wiki.team-mediaportal.com/1_MEDIAPORTAL_1/17_Extensions/3_Plugins/WifiRemote/Commands + +WifiRemote will send JSON messages to your client, a list can be found here: +http://wiki.team-mediaportal.com/1_MEDIAPORTAL_1/17_Extensions/3_Plugins/WifiRemote/Messages -[A list of messages sent from and to WifiRemote is available here.](http://code.google.com/p/wifiremote/wiki/APIDocumentation) ### Acknowledgements WifiRemote uses the following libraries: diff --git a/Sources/DemoClient/Messages/MessageScreenshot.cs b/Sources/DemoClient/Messages/MessageScreenshot.cs new file mode 100644 index 0000000..034b8a9 --- /dev/null +++ b/Sources/DemoClient/Messages/MessageScreenshot.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace DemoClient +{ + class MessageScreenshot : IMessage + { + string type = "screenshot"; + public string Type + { + get { return type; } + } + + public int Width + { + get { return 800; } + } + + public String AutologinKey + { + get; + set; + } + } +} diff --git a/Sources/WifiRemote/Core/SetupForm.cs b/Sources/WifiRemote/Core/SetupForm.cs index 125a6be..ab6aa57 100644 --- a/Sources/WifiRemote/Core/SetupForm.cs +++ b/Sources/WifiRemote/Core/SetupForm.cs @@ -172,8 +172,8 @@ public SetupForm() pluginsDataSource.Add(new WindowPlugin(aSavedPlugin.Value, aSavedPlugin.Key, (plugin.ActiveImage != null) - ? WifiRemote.imageToByteArray(plugin.ActiveImage, System.Drawing.Imaging.ImageFormat.Png) - : WifiRemote.imageToByteArray(Properties.Resources.NoPluginImage, System.Drawing.Imaging.ImageFormat.Png), + ? ImageHelper.imageToByteArray(plugin.ActiveImage, System.Drawing.Imaging.ImageFormat.Png) + : ImageHelper.imageToByteArray(Properties.Resources.NoPluginImage, System.Drawing.Imaging.ImageFormat.Png), !ignoredPluginsList.Contains(aSavedPlugin.Key))); } break; @@ -512,9 +512,9 @@ private void addPluginToList(ItemTag plugin) { pluginsDataSource.Add( new WindowPlugin(plugin.SetupForm.PluginName(), - plugin.WindowId, - (plugin.ActiveImage != null) ? WifiRemote.imageToByteArray(plugin.ActiveImage, System.Drawing.Imaging.ImageFormat.Png) - : WifiRemote.imageToByteArray(Properties.Resources.NoPluginImage, System.Drawing.Imaging.ImageFormat.Png), + plugin.WindowId, + (plugin.ActiveImage != null) ? ImageHelper.imageToByteArray(plugin.ActiveImage, System.Drawing.Imaging.ImageFormat.Png) + : ImageHelper.imageToByteArray(Properties.Resources.NoPluginImage, System.Drawing.Imaging.ImageFormat.Png), !ignoredPluginsList.Contains(plugin.WindowId))); } } diff --git a/Sources/WifiRemote/Core/SocketServer.cs b/Sources/WifiRemote/Core/SocketServer.cs index 11d04c7..b6acbbd 100644 --- a/Sources/WifiRemote/Core/SocketServer.cs +++ b/Sources/WifiRemote/Core/SocketServer.cs @@ -42,6 +42,8 @@ class SocketServer private List connectedSockets; private AuthMethod allowedAuth; private List loginTokens; + private Dictionary socketsWaitingForScreenshot; + private ImageHelper imageHelper; private MessageWelcome welcomeMessage; private MessageStatus statusMessage; @@ -415,6 +417,25 @@ internal void SendListViewStatusToClient(AsyncSocket sender) } } + /// + /// Send the current screenshot to the client as byte array + /// + public void SendScreenshotToClient(AsyncSocket sender, int width, ImageHelperError error) + { + MessageScreenshot screenshot = new MessageScreenshot(); + + if (error != null) + { + screenshot.Error = error; + } + else + { + screenshot.Screenshot = imageHelper.resizedScreenshot(width); + } + + SendMessageToClient(screenshot, sender); + } + /// /// A client connected. /// @@ -769,6 +790,30 @@ void newSocket_DidRead(AsyncSocket sender, byte[] data, long tag) SendImageToClient(sender, path, (string)message["UserTag"], imageWidth, imageHeight); } } + // screenshot action + else if (type == "screenshot") + { + if (socketsWaitingForScreenshot == null) + { + socketsWaitingForScreenshot = new Dictionary(); + } + + // Width to resize the image to, 0 to keep original width + int imageWidth = (message["Width"] != null) ? (int)message["Width"] : 0; + + // Requests are added to a "waiting queue" because taking the screenshot happens + // async. + socketsWaitingForScreenshot.Add(sender, imageWidth); + + if (imageHelper == null) + { + imageHelper = new ImageHelper(); + imageHelper.ScreenshotReady += new ImageHelper.ScreenshotReadyCallback(imageHelperScreenshotReady); + imageHelper.ScreenshotFailed += new ImageHelper.ScreenshotFailedCallback(imageHelperScreenshotFailed); + } + + imageHelper.TakeScreenshot(); + } //playlist actions else if (type == "playlist") { @@ -821,7 +866,7 @@ void newSocket_DidRead(AsyncSocket sender, byte[] data, long tag) else if (type == "showdialog") { ShowDialogMessageHandler.HandleShowDialogMessage(message, this, sender); - + } else { @@ -1157,6 +1202,13 @@ private void sendOverviewInformationToClient(AsyncSocket client) // Send facade info to client SendListViewStatusToClient(client); + + // Inform client about open dialogs + if (MpDialogsHelper.IsDialogShown) + { + MessageDialog msg = MpDialogsHelper.GetDialogMessage(MpDialogsHelper.CurrentDialog); + SendMessageToClient(msg, client); + } } /// @@ -1179,5 +1231,32 @@ private String getRandomMD5() return hash.ToString(); } + + /// + /// A requested screenshot is ready, send it to all interested clients + /// + void imageHelperScreenshotReady() + { + foreach (var pair in socketsWaitingForScreenshot) + { + SendScreenshotToClient(pair.Key, pair.Value, null); + } + + socketsWaitingForScreenshot = null; + } + + /// + /// The screenshot could not be taken. Inform clients. + /// + /// + void imageHelperScreenshotFailed(ImageHelperError error) + { + foreach (var pair in socketsWaitingForScreenshot) + { + SendScreenshotToClient(pair.Key, pair.Value, error); + } + + socketsWaitingForScreenshot = null; + } } } diff --git a/Sources/WifiRemote/Core/WifiRemote.cs b/Sources/WifiRemote/Core/WifiRemote.cs index 0519dd6..973e0f2 100644 --- a/Sources/WifiRemote/Core/WifiRemote.cs +++ b/Sources/WifiRemote/Core/WifiRemote.cs @@ -10,7 +10,6 @@ using System.Net.NetworkInformation; using System.Collections; using System.Drawing; -using System.IO; using System.Reflection; using System.Threading; using System.Collections.Generic; @@ -166,6 +165,15 @@ public static bool IsAvailableTVSeries set; } + /// + /// true if trakt plugin is available + /// + public static bool IsAvailableTrakt + { + get; + set; + } + /// /// true if Fanart Handler is available /// @@ -295,6 +303,7 @@ public void Start() !IsAssemblyAvailable("ForTheRecord.UI.MediaPortal", null); WifiRemote.IsAvailableMovingPictures = IsAssemblyAvailable("MovingPictures", new Version(1, 0, 6, 1116)); WifiRemote.IsAvailableTVSeries = IsAssemblyAvailable("MP-TVSeries", new Version(2, 6, 3, 1242)); + WifiRemote.IsAvailableTrakt = IsAssemblyAvailable("TraktPlugin", new Version(3, 0)); WifiRemote.IsAvailableFanartHandler = IsAssemblyAvailable("FanartHandler", new Version(2, 2, 1, 19191)); WifiRemote.IsAvailableNotificationBar = IsAssemblyAvailable("MPNotificationBar", new Version(0, 8, 2, 1)); @@ -829,26 +838,6 @@ public static string GetServiceName() } } - - /// - /// Returns an image as its byte array representation. - /// Used to make images encodable in JSON. - /// - /// - /// - public static byte[] imageToByteArray(Image img, System.Drawing.Imaging.ImageFormat format) - { - byte[] byteArray = new byte[0]; - using (MemoryStream stream = new MemoryStream()) - { - img.Save(stream, format); - stream.Close(); - byteArray = stream.ToArray(); - } - - return byteArray; - } - #endregion #region WifiRemote methods @@ -992,7 +981,7 @@ internal static ArrayList GetActiveWindowPluginsAndIDs(bool sendIcons) if (icon != null) { - iconBytes = WifiRemote.imageToByteArray(icon, System.Drawing.Imaging.ImageFormat.Png); + iconBytes = ImageHelper.imageToByteArray(icon, System.Drawing.Imaging.ImageFormat.Png); } } } diff --git a/Sources/WifiRemote/ILMerge.exe b/Sources/WifiRemote/ILMerge.exe index 5f4099f..9667425 100644 Binary files a/Sources/WifiRemote/ILMerge.exe and b/Sources/WifiRemote/ILMerge.exe differ diff --git a/Sources/WifiRemote/MPDialogs/MpDialog.cs b/Sources/WifiRemote/MPDialogs/MpDialog.cs index 380a089..857c7ec 100644 --- a/Sources/WifiRemote/MPDialogs/MpDialog.cs +++ b/Sources/WifiRemote/MPDialogs/MpDialog.cs @@ -58,12 +58,13 @@ public String GetLabel(GUIDialogWindow dialog, params int[] controlIds) String t = GetSingleLabel(dialog, control); if (t != null && !t.Equals("")) { - text.Append(t); if (index > 0) { text.AppendLine(); } index++; + + text.Append(t); } } @@ -81,20 +82,38 @@ private string GetSingleLabel(GUIDialogWindow dialog, int control) GUIControlCollection coll = dialog.controlList; foreach (GUIControl c in coll) { - if (c.GetID == control) + if (c.GetType() == typeof(GUIGroup)) { - if (c.GetType() == typeof(GUILabelControl)) - { - GUILabelControl l = (GUILabelControl)c; - return l.Label; - } - else if (c.GetType() == typeof(GUIFadeLabel)) + foreach (GUIControl subControl in ((GUIGroup)c).Children) { - GUIFadeLabel l = (GUIFadeLabel)c; - return l.Label; + if (subControl.GetID == control) + { + return GetSingleLabelFromControl(subControl); + } } } + else if (c.GetID == control) + { + return GetSingleLabelFromControl(c); + } } + + return null; + } + + private string GetSingleLabelFromControl(GUIControl control) + { + if (control.GetType() == typeof(GUILabelControl)) + { + GUILabelControl label = (GUILabelControl)control; + return label.Label; + } + else if (control.GetType() == typeof(GUIFadeLabel)) + { + GUIFadeLabel label = (GUIFadeLabel)control; + return label.Label; + } + return null; } diff --git a/Sources/WifiRemote/MPDialogs/MpDialogTraktRating.cs b/Sources/WifiRemote/MPDialogs/MpDialogTraktRating.cs new file mode 100644 index 0000000..b7c6fdc --- /dev/null +++ b/Sources/WifiRemote/MPDialogs/MpDialogTraktRating.cs @@ -0,0 +1,154 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using TraktPlugin; + +namespace WifiRemote.MPDialogs +{ + public class MpDialogTraktRating : MpDialog + { + TraktPlugin.GUI.GUIRateDialog mpDialog; + public MpDialogTraktRating(TraktPlugin.GUI.GUIRateDialog dialog) + : base(dialog) + { + this.mpDialog = dialog; + this.DialogType = dialog.GetModuleName(); + this.DialogId = dialog.GetID; + this.Rating = ratingFromTraktRateValue(dialog.Rated); + this.ShowAdvancedRatings = dialog.ShowAdvancedRatings; + GetHeading(dialog, 1); + GetText(dialog, 2, 3, 4, 5); + + this.AvailableActions.Add("cancel"); + this.AvailableActions.Add("setrating"); + this.AvailableActions.Add("confirmrating"); + } + + private int ratingFromTraktRateValue(TraktPlugin.TraktAPI.TraktRateValue rateValue) + { + switch (rateValue) + { + case TraktPlugin.TraktAPI.TraktRateValue.unrate: + return 0; + + case TraktPlugin.TraktAPI.TraktRateValue.one: + case TraktPlugin.TraktAPI.TraktRateValue.hate: + return 1; + + case TraktPlugin.TraktAPI.TraktRateValue.two: + return 2; + + case TraktPlugin.TraktAPI.TraktRateValue.three: + return 3; + + case TraktPlugin.TraktAPI.TraktRateValue.four: + return 4; + + case TraktPlugin.TraktAPI.TraktRateValue.five: + return 5; + + case TraktPlugin.TraktAPI.TraktRateValue.six: + return 6; + + case TraktPlugin.TraktAPI.TraktRateValue.seven: + return 7; + + case TraktPlugin.TraktAPI.TraktRateValue.eight: + return 8; + + case TraktPlugin.TraktAPI.TraktRateValue.nine: + return 9; + + case TraktPlugin.TraktAPI.TraktRateValue.ten: + case TraktPlugin.TraktAPI.TraktRateValue.love: + return 10; + } + + return 0; + } + + /// + /// Current Rating + /// + public int Rating { get; set; } + + /// + /// true if the dialog uses advanced rating (1-10), otherwise 'love' (1) and 'hate' (2) are used. + /// + public bool ShowAdvancedRatings { get; set; } + + /// + /// Handle actions which are available on this dialog + /// + /// Action to execute + /// Index (e.g. needed for lists) + public override void HandleAction(String action, int index) + { + base.HandleAction(action, index); + + if (action.Equals("setrating")) + { + SetRating(index); + } + + if (action.Equals("confirmrating")) + { + ConfirmRating(); + } + } + + public void ConfirmRating() + { + MediaPortal.GUI.Library.Action confirmAction = new MediaPortal.GUI.Library.Action(MediaPortal.GUI.Library.Action.ActionType.ACTION_SELECT_ITEM, 0, 0); + mpDialog.OnAction(confirmAction); + } + + /// + /// Set Rating for this dialog + /// + /// + public void SetRating(int rating) + { + MediaPortal.GUI.Library.Action ratingAction = null; ; + switch (rating) + { + case 1: + ratingAction = new MediaPortal.GUI.Library.Action(MediaPortal.GUI.Library.Action.ActionType.REMOTE_1, 0, 0); + break; + case 2: + ratingAction = new MediaPortal.GUI.Library.Action(MediaPortal.GUI.Library.Action.ActionType.REMOTE_2, 0, 0); + break; + case 3: + ratingAction = new MediaPortal.GUI.Library.Action(MediaPortal.GUI.Library.Action.ActionType.REMOTE_3, 0, 0); + break; + case 4: + ratingAction = new MediaPortal.GUI.Library.Action(MediaPortal.GUI.Library.Action.ActionType.REMOTE_4, 0, 0); + break; + case 5: + ratingAction = new MediaPortal.GUI.Library.Action(MediaPortal.GUI.Library.Action.ActionType.REMOTE_5, 0, 0); + break; + case 6: + ratingAction = new MediaPortal.GUI.Library.Action(MediaPortal.GUI.Library.Action.ActionType.REMOTE_6, 0, 0); + break; + case 7: + ratingAction = new MediaPortal.GUI.Library.Action(MediaPortal.GUI.Library.Action.ActionType.REMOTE_7, 0, 0); + break; + case 8: + ratingAction = new MediaPortal.GUI.Library.Action(MediaPortal.GUI.Library.Action.ActionType.REMOTE_8, 0, 0); + break; + case 9: + ratingAction = new MediaPortal.GUI.Library.Action(MediaPortal.GUI.Library.Action.ActionType.REMOTE_9, 0, 0); + break; + case 10: + ratingAction = new MediaPortal.GUI.Library.Action(MediaPortal.GUI.Library.Action.ActionType.REMOTE_0, 0, 0); + break; + } + + if (ratingAction != null) + { + mpDialog.OnAction(ratingAction); + } + } + } +} diff --git a/Sources/WifiRemote/MPDialogs/MpDialogsHelper.cs b/Sources/WifiRemote/MPDialogs/MpDialogsHelper.cs index 280a8e4..ec73cda 100644 --- a/Sources/WifiRemote/MPDialogs/MpDialogsHelper.cs +++ b/Sources/WifiRemote/MPDialogs/MpDialogsHelper.cs @@ -32,6 +32,11 @@ public class MpDialogsHelper /// public const int MOPI_PIN_ID = 9915; + /// + /// Id of the Trakt rating dialog + /// + public const int TRAKT_RATING_ID = 87300; + /// /// Is a dialog currently shown /// @@ -99,6 +104,13 @@ public static MpDialog GetDialog(GUIDialogWindow dialog) return GetDialogMovingPicturesPin(); } } + if (WifiRemote.IsAvailableTrakt) + { + if (TraktHelper.IsTraktRatingDialog(dialog)) + { + return GetDialogTraktRating(); + } + } return null; } @@ -125,7 +137,7 @@ public static MpDialogTvSeriesPin GetDialogMpTvSeriesPin() } /// - /// Get WifiRemote representation of the MpTvSeries rating dialog + /// Get WifiRemote representation of the MpMovingPictures rating dialog /// /// WifiRemote Dialog Instance public static MpDialogMovingPicturesRating GetDialogMovingPicturesRating() @@ -136,7 +148,7 @@ public static MpDialogMovingPicturesRating GetDialogMovingPicturesRating() } /// - /// Get WifiRemote representation of the MpTvSeries pin dialog + /// Get WifiRemote representation of the MpMovingPictures pin dialog /// /// WifiRemote Dialog Instance public static MpDialogMovingPicturesPin GetDialogMovingPicturesPin() @@ -146,6 +158,17 @@ public static MpDialogMovingPicturesPin GetDialogMovingPicturesPin() return pinDialog; } + /// + /// Get WifiRemote representation of the MpTrakt rating dialog + /// + /// WifiRemote Dialog Instance + public static MpDialogTraktRating GetDialogTraktRating() + { + TraktPlugin.GUI.GUIRateDialog menu = (TraktPlugin.GUI.GUIRateDialog)GUIWindowManager.GetWindow(TRAKT_RATING_ID); + MpDialogTraktRating ratingDialog = new MpDialogTraktRating(menu); + return ratingDialog; + } + /// /// Get WifiRemote representation of the select dialog /// diff --git a/Sources/WifiRemote/MPDialogs/MpDialogsMessageHandler.cs b/Sources/WifiRemote/MPDialogs/MpDialogsMessageHandler.cs index c2916aa..b7fd448 100644 --- a/Sources/WifiRemote/MPDialogs/MpDialogsMessageHandler.cs +++ b/Sources/WifiRemote/MPDialogs/MpDialogsMessageHandler.cs @@ -101,6 +101,14 @@ internal static void HandleDialogAction(Newtonsoft.Json.Linq.JObject message, So diag.HandleAction(action, index); } } + else if (dialogId == MpDialogsHelper.TRAKT_RATING_ID) + { + if (WifiRemote.IsAvailableTrakt) + { + MpDialogTraktRating dialog = MpDialogsHelper.GetDialogTraktRating(); + dialog.HandleAction(action, index); + } + } } } } diff --git a/Sources/WifiRemote/MPPlayList/PlaylistHelper.cs b/Sources/WifiRemote/MPPlayList/PlaylistHelper.cs index 9b258b7..31a477b 100644 --- a/Sources/WifiRemote/MPPlayList/PlaylistHelper.cs +++ b/Sources/WifiRemote/MPPlayList/PlaylistHelper.cs @@ -228,6 +228,24 @@ public static void Shuffle(string type) PlayListPlayer.SingletonPlayer.GetPlaylist(plType).Shuffle(); } + /// + /// Set repeat if type is of the current playlist type + /// + /// Type of the playlist + public static void Repeat(string type, bool repeat) + { + WifiRemote.LogMessage("Set playlist repeat:" + repeat, WifiRemote.LogType.Debug); + PlayListType plType = GetTypeFromString(type); + WifiRemote.LogMessage("plType:" + plType, WifiRemote.LogType.Debug); + WifiRemote.LogMessage("currentType:" + PlayListPlayer.SingletonPlayer.CurrentPlaylistType , WifiRemote.LogType.Debug); + if (plType == PlayListPlayer.SingletonPlayer.CurrentPlaylistType) + { + PlayListPlayer playListPlayer = PlayListPlayer.SingletonPlayer; + playListPlayer.RepeatPlaylist = repeat; + RefreshPlaylistIfVisible(); + } + } + /// /// Returns a playlistitem from a song /// @@ -329,6 +347,31 @@ public static void RemoveItemFromPlaylist(String type, int index) RefreshPlaylistIfVisible(); } + /// + /// Retrieves the name of the playlist + /// + /// Type of the playlist + public static String GetPlaylistName(String type) + { + PlayListType plType = GetTypeFromString(type); + PlayListPlayer playListPlayer = PlayListPlayer.SingletonPlayer; + PlayList playList = playListPlayer.GetPlaylist(plType); + WifiRemote.LogMessage("Playlist name test:" + playList.Name, WifiRemote.LogType.Debug); + + return playList.Name; + } + + /// + /// Retrieves the repeat mode of the playlist + /// + /// Type of the playlist + public static bool GetPlaylistRepeat(String type) + { + PlayListType plType = GetTypeFromString(type); + PlayListPlayer playListPlayer = PlayListPlayer.SingletonPlayer; + return playListPlayer.RepeatPlaylist; + } + /// /// Gets the playlist for a given type /// diff --git a/Sources/WifiRemote/MPPlayList/PlaylistMessageHandler.cs b/Sources/WifiRemote/MPPlayList/PlaylistMessageHandler.cs index 0d5a578..42b2987 100644 --- a/Sources/WifiRemote/MPPlayList/PlaylistMessageHandler.cs +++ b/Sources/WifiRemote/MPPlayList/PlaylistMessageHandler.cs @@ -108,6 +108,8 @@ internal static void HandlePlaylistMessage(Newtonsoft.Json.Linq.JObject message, MessagePlaylistDetails returnPlaylist = new MessagePlaylistDetails(); returnPlaylist.PlaylistType = playlistType; + returnPlaylist.PlaylistName = PlaylistHelper.GetPlaylistName(playlistType); + returnPlaylist.PlaylistRepeat = PlaylistHelper.GetPlaylistRepeat(playlistType); returnPlaylist.PlaylistItems = items; socketServer.SendMessageToClient(returnPlaylist, sender); @@ -158,6 +160,24 @@ internal static void HandlePlaylistMessage(Newtonsoft.Json.Linq.JObject message, } } + else if (action.Equals("shuffle")) + { + PlaylistHelper.Shuffle(playlistType); + } + else if (action.Equals("repeat")) + { + WifiRemote.LogMessage("Playlist action repeat", WifiRemote.LogType.Debug); + if (message["Repeat"] != null) + { + bool repeat = (bool)message["Repeat"]; + PlaylistHelper.Repeat(playlistType, repeat); + } + else + { + WifiRemote.LogMessage("Must specify repeat to change playlist repeat mode", WifiRemote.LogType.Warn); + } + + } } } } diff --git a/Sources/WifiRemote/Messages/MessageNowPlaying.cs b/Sources/WifiRemote/Messages/MessageNowPlaying.cs index 06e27ac..e57e2b0 100644 --- a/Sources/WifiRemote/Messages/MessageNowPlaying.cs +++ b/Sources/WifiRemote/Messages/MessageNowPlaying.cs @@ -158,11 +158,7 @@ public IAdditionalNowPlayingInfo MediaInfo // MyVideos movie if (movie.ID > 0) { -#if COMPILE_FOR_1_2_0 || COMPILE_FOR_1_1_2 // MyVideos extended info available since MediaPortal 1.1.2 (Rev 26532) return new NowPlayingVideo(movie); -#else - return null; -#endif } else // MovingPictures, TVSeries or something else diff --git a/Sources/WifiRemote/Messages/MessagePlaylistDetails.cs b/Sources/WifiRemote/Messages/MessagePlaylistDetails.cs index 541d203..73f086e 100644 --- a/Sources/WifiRemote/Messages/MessagePlaylistDetails.cs +++ b/Sources/WifiRemote/Messages/MessagePlaylistDetails.cs @@ -16,6 +16,16 @@ public string Type get { return "playlistdetails"; } } + /// + /// Repeat mode of the playlist + /// + public bool PlaylistRepeat { get; set; } + + /// + /// Name of the playlist + /// + public String PlaylistName { get; set; } + /// /// Type of the playlist (currently supported: music, video) /// diff --git a/Sources/WifiRemote/Messages/MessageScreenshot.cs b/Sources/WifiRemote/Messages/MessageScreenshot.cs new file mode 100644 index 0000000..c4afda2 --- /dev/null +++ b/Sources/WifiRemote/Messages/MessageScreenshot.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.IO; +using MediaPortal.GUI.Library; +using System.Drawing; + + +namespace WifiRemote +{ + /// + /// Sends a screenshot to the client that requested it with the + /// screenshot command. + /// + class MessageScreenshot : IMessage + { + public string Type + { + get { return "screenshot"; } + } + + byte[] screenshot = new byte[0]; + /// + /// The requested screenshot as byte array + /// + public byte[] Screenshot + { + get; + set; + } + + public ImageHelperError Error { get; set; } + } +} diff --git a/Sources/WifiRemote/Messages/MessageWelcome.cs b/Sources/WifiRemote/Messages/MessageWelcome.cs index b9518ee..66ceaaf 100644 --- a/Sources/WifiRemote/Messages/MessageWelcome.cs +++ b/Sources/WifiRemote/Messages/MessageWelcome.cs @@ -10,7 +10,7 @@ namespace WifiRemote class MessageWelcome : IMessage { string type = "welcome"; - int server_version = 13; + int server_version = 14; AuthMethod authMethod = AuthMethod.UserPassword; /// diff --git a/Sources/WifiRemote/Messages/Now Playing/NowPlayingMusic.cs b/Sources/WifiRemote/Messages/Now Playing/NowPlayingMusic.cs index 28e3237..7e4ffb7 100644 --- a/Sources/WifiRemote/Messages/Now Playing/NowPlayingMusic.cs +++ b/Sources/WifiRemote/Messages/Now Playing/NowPlayingMusic.cs @@ -88,7 +88,7 @@ public NowPlayingMusic(Song song) Track = song.Track; TrackTotal = song.TrackTotal; URL = song.URL; - WebImage = song.WebImage; + WebImage = String.Empty; Year = song.Year; ImageName = MediaPortal.Util.Utils.GetAlbumThumbName(song.Artist, song.Album); diff --git a/Sources/WifiRemote/Messages/Now Playing/NowPlayingRadio.cs b/Sources/WifiRemote/Messages/Now Playing/NowPlayingRadio.cs index 4eeffd8..5e26b17 100644 --- a/Sources/WifiRemote/Messages/Now Playing/NowPlayingRadio.cs +++ b/Sources/WifiRemote/Messages/Now Playing/NowPlayingRadio.cs @@ -7,6 +7,7 @@ using System.Drawing; using WifiRemote.MpExtended; using TvDatabase; +using MediaPortal.GUI.Library; namespace WifiRemote { @@ -51,6 +52,15 @@ public string ChannelName set; } + /// + /// Name of the current artits + /// + public string ArtistName + { + get; + set; + } + /// /// Id of current program /// @@ -165,20 +175,26 @@ public string CurrentUrl public NowPlayingRadio() { TvPlugin.TVHome.Navigator.UpdateCurrentChannel(); - TvDatabase.Channel current = TvPlugin.TVHome.Navigator.Channel; - if (current.IsWebstream()) - { - IList details = current.ReferringTuningDetail(); - TuningDetail detail = details[0]; - CurrentProgramName = detail.Name; - CurrentProgramId = detail.IdChannel; - CurrentUrl = detail.Url; + TvDatabase.Channel current = TvPlugin.Radio.CurrentChannel; + if (current != null && current.IsWebstream()) + { + if (current.ReferringTuningDetail() != null && current.ReferringTuningDetail().Count > 0) + { + IList details = current.ReferringTuningDetail(); + TuningDetail detail = details[0]; + CurrentProgramName = detail.Name; + CurrentProgramId = detail.IdChannel; + CurrentUrl = detail.Url; + ChannelName = GUIPropertyManager.GetProperty("#Play.Current.Album"); + ArtistName = GUIPropertyManager.GetProperty("#Play.Current.Artist"); + } } - else + else if (current != null && !current.IsWebstream()) { ChannelId = current.IdChannel; ChannelName = current.DisplayName; + ArtistName = GUIPropertyManager.GetProperty("#Play.Current.Artist"); if (current.CurrentProgram != null) { diff --git a/Sources/WifiRemote/PluginConnection/MpMusicHelper.cs b/Sources/WifiRemote/PluginConnection/MpMusicHelper.cs index 56f24f0..da74167 100644 --- a/Sources/WifiRemote/PluginConnection/MpMusicHelper.cs +++ b/Sources/WifiRemote/PluginConnection/MpMusicHelper.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Text; using MediaPortal.Music.Database; +using MediaPortal.Database; using WifiRemote.MPPlayList; using System.IO; using MediaPortal.Playlists; @@ -22,7 +23,8 @@ public class MpMusicHelper public static void PlayMusicTrack(int trackId, int startPos) { List songs = new List(); - string sql = "select * from tracks where idTrack=" + trackId; + + string sql = String.Format("select * from tracks where idTrack={0}", trackId); MusicDatabase.Instance.GetSongsByFilter(sql, out songs, "tracks"); if (songs.Count > 0) @@ -40,7 +42,9 @@ public static void PlayMusicTrack(int trackId, int startPos) public static void PlayAlbum(String albumArtist, String album, int startPos) { List songs = new List(); - string sql = "select * from tracks where strAlbumArtist like '%" + albumArtist + "%' AND strAlbum LIKE '%" + album + "%' order by iTrack ASC"; + string sql = String.Format("select * from tracks where strAlbumArtist like '%{0}%' AND strAlbum LIKE '%{1}%' order by iTrack ASC", + DatabaseUtility.RemoveInvalidChars(albumArtist), + DatabaseUtility.RemoveInvalidChars(album)); MusicDatabase.Instance.GetSongsByFilter(sql, out songs, "tracks"); if (songs.Count > 0) @@ -64,7 +68,8 @@ public static void PlayAlbum(String albumArtist, String album, int startPos) internal static void PlayArtist(string albumArtist, int startPos) { List songs = new List(); - string sql = "select * from tracks where strAlbumArtist like '%" + albumArtist + "%'"; + string sql = String.Format("select * from tracks where strAlbumArtist like '%{0}%'", + DatabaseUtility.RemoveInvalidChars(albumArtist)); MusicDatabase.Instance.GetSongsByFilter(sql, out songs, "tracks"); if (songs.Count > 0) @@ -212,6 +217,7 @@ internal static MediaPortal.Playlists.PlayListItem CreatePlaylistItemFromMusicTr List songs = new List(); string sql = "select * from tracks where idTrack=" + trackId; + DatabaseUtility.RemoveInvalidChars(sql); MusicDatabase.Instance.GetSongsByFilter(sql, out songs, "tracks"); if (songs.Count > 0) @@ -232,7 +238,9 @@ internal static List CreatePlaylistItemsFromMusicAlbum(string albu { List returnList = new List(); List songs = new List(); - string sql = "select * from tracks where strAlbumArtist like '%" + albumArtist + "%' AND strAlbum LIKE '%" + album + "%'"; + string sql = String.Format("select * from tracks where strAlbumArtist like '%{0}%' AND strAlbum LIKE '%{1}%'", + DatabaseUtility.RemoveInvalidChars(albumArtist), + DatabaseUtility.RemoveInvalidChars(album)); MusicDatabase.Instance.GetSongsByFilter(sql, out songs, "tracks"); if (songs.Count > 0) @@ -254,7 +262,8 @@ internal static List CreatePlaylistItemsFromMusicArtist(string alb { List returnList = new List(); List songs = new List(); - string sql = "select * from tracks where strAlbumArtist like '%" + albumArtist + "%'"; + string sql = String.Format("select * from tracks where strAlbumArtist like '%{0}%'", + DatabaseUtility.RemoveInvalidChars(albumArtist)); MusicDatabase.Instance.GetSongsByFilter(sql, out songs, "tracks"); if (songs.Count > 0) diff --git a/Sources/WifiRemote/PluginConnection/MpTvServerHelper.cs b/Sources/WifiRemote/PluginConnection/MpTvServerHelper.cs index c9db22e..eaffbfc 100644 --- a/Sources/WifiRemote/PluginConnection/MpTvServerHelper.cs +++ b/Sources/WifiRemote/PluginConnection/MpTvServerHelper.cs @@ -109,37 +109,65 @@ public static void PlayRadioChannel(int channelId) if (channel != null) { - if (g_Player.Playing && (!g_Player.IsTimeShifting || (g_Player.IsTimeShifting && channel.IsWebstream()))) + if (GUIWindowManager.ActiveWindow != (int)MediaPortal.GUI.Library.GUIWindow.Window.WINDOW_RADIO) { - WifiRemote.LogMessage("Stopping current media so we can start playing radio", WifiRemote.LogType.Debug); - g_Player.Stop(); - } - bool success; - if (channel.IsWebstream()) - { - IList details = channel.ReferringTuningDetail(); - TuningDetail detail = details[0]; - success = g_Player.PlayAudioStream(detail.Url); - } - else - { - success = TvPlugin.TVHome.ViewChannelAndCheck(channel); + WifiRemote.LogMessage("Radio Window not active, activating it", WifiRemote.LogType.Debug); + MediaPortal.GUI.Library.GUIWindowManager.ActivateWindow((int)MediaPortal.GUI.Library.GUIWindow.Window.WINDOW_RADIO); } + GUIPropertyManager.RemovePlayerProperties(); + GUIPropertyManager.SetProperty("#Play.Current.ArtistThumb", channel.DisplayName); + GUIPropertyManager.SetProperty("#Play.Current.Album", channel.DisplayName); + GUIPropertyManager.SetProperty("#Play.Current.Title", channel.DisplayName); + + GUIPropertyManager.SetProperty("#Play.Current.Title", channel.DisplayName); string strLogo = Utils.GetCoverArt(Thumbs.Radio, channel.DisplayName); if (string.IsNullOrEmpty(strLogo)) { strLogo = "defaultMyRadioBig.png"; } - GUIPropertyManager.SetProperty("#Play.Current.Thumb", strLogo); - - if (GUIWindowManager.ActiveWindow != (int)MediaPortal.GUI.Library.GUIWindow.Window.WINDOW_RADIO && !g_Player.Playing) + + if (g_Player.Playing && !channel.IsWebstream()) { - WifiRemote.LogMessage("Radio Window not active, activating it", WifiRemote.LogType.Debug); - MediaPortal.GUI.Library.GUIWindowManager.ActivateWindow((int)MediaPortal.GUI.Library.GUIWindow.Window.WINDOW_RADIO); - } - WifiRemote.LogMessage("Started radio channel " + channelId + " Success: " + success, WifiRemote.LogType.Info); + if (!g_Player.IsTimeShifting || (g_Player.IsTimeShifting && channel.IsWebstream())) + { + WifiRemote.LogMessage("Stopping current media so we can start playing radio", WifiRemote.LogType.Debug); + g_Player.Stop(); + } + } + bool success = false; + if (channel.IsWebstream()) + { + IList details = channel.ReferringTuningDetail(); + TuningDetail detail = details[0]; + WifiRemote.LogMessage("Play webStream:" +detail.Name + ", url:" + detail.Url, WifiRemote.LogType.Debug); + success = g_Player.PlayAudioStream(detail.Url); + GUIPropertyManager.SetProperty("#Play.Current.Title", channel.DisplayName); + } + else + { + // TV card radio channel + WifiRemote.LogMessage("Play TV card radio channel", WifiRemote.LogType.Debug); + //Check if same channel is alrady playing + if (g_Player.IsRadio && g_Player.Playing) + { + Channel currentlyPlaying = TvPlugin.TVHome.Navigator.Channel; + if (currentlyPlaying != null && currentlyPlaying.IdChannel == channel.IdChannel) + { + WifiRemote.LogMessage("Already playing TV card radio channel with id:" + channel.IdChannel + ", do not tune again", WifiRemote.LogType.Debug); + } + else + { + success = TvPlugin.TVHome.ViewChannelAndCheck(channel); + } + } + else + { + success = TvPlugin.TVHome.ViewChannelAndCheck(channel); + } + } + WifiRemote.LogMessage("Started radio channel " + channelId + " Success: " + success, WifiRemote.LogType.Debug); } else { diff --git a/Sources/WifiRemote/PluginConnection/TraktHelper.cs b/Sources/WifiRemote/PluginConnection/TraktHelper.cs new file mode 100644 index 0000000..8126dba --- /dev/null +++ b/Sources/WifiRemote/PluginConnection/TraktHelper.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using TraktPlugin.GUI; + +namespace WifiRemote +{ + class TraktHelper + { + /// + /// Check if a dialog is a trakt rating dialog + /// + /// Dialog + /// true/false ;) + internal static bool IsTraktRatingDialog(MediaPortal.Dialogs.GUIDialogWindow dialog) + { + if (dialog.GetType().Equals(typeof(TraktPlugin.GUI.GUIRateDialog))) + { + return true; + } + else + { + return false; + } + } + } +} diff --git a/Sources/WifiRemote/Properties/AssemblyInfo.cs b/Sources/WifiRemote/Properties/AssemblyInfo.cs index b400377..db485b5 100644 --- a/Sources/WifiRemote/Properties/AssemblyInfo.cs +++ b/Sources/WifiRemote/Properties/AssemblyInfo.cs @@ -1,20 +1,17 @@ using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; - -#if COMPILE_FOR_1_2_0 using MediaPortal.Common.Utils; // Version Compatibility // http://wiki.team-mediaportal.com/1_MEDIAPORTAL_1/18_Contribute/6_Plugins/Plugin_Related_Changes/1.1.0_to_1.2.0/Version_Compatibility -[assembly: CompatibleVersion("1.1.6.27644")] +[assembly: CompatibleVersion("1.5.100.0", "1.1.6.27644")] //[assembly: UsesSubsystem("MP.DB.Music")] //[assembly: UsesSubsystem("MP.DB.Videos")] //[assembly: UsesSubsystem("MP.Config")] //[assembly: UsesSubsystem("MP.Input.Mapping")] //[assembly: UsesSubsystem("MP.Players")] -#endif // Allgemeine Informationen über eine Assembly werden über die folgenden // Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern, @@ -46,5 +43,5 @@ // Sie können alle Werte angeben oder die standardmäßigen Build- und Revisionsnummern // übernehmen, indem Sie "*" eingeben: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("0.7.0.0")] -[assembly: AssemblyFileVersion("0.7.0.0")] +[assembly: AssemblyVersion("0.8.0.0")] +[assembly: AssemblyFileVersion("0.8.0.0")] diff --git a/Sources/WifiRemote/Properties/Resources.Designer.cs b/Sources/WifiRemote/Properties/Resources.Designer.cs index 2fea1da..2325733 100644 --- a/Sources/WifiRemote/Properties/Resources.Designer.cs +++ b/Sources/WifiRemote/Properties/Resources.Designer.cs @@ -1,7 +1,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.225 +// Runtime Version:4.0.30319.18052 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -60,6 +60,9 @@ internal Resources() { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// internal static System.Drawing.Bitmap NoPluginImage { get { object obj = ResourceManager.GetObject("NoPluginImage", resourceCulture); diff --git a/Sources/WifiRemote/Utility/ImageHelper.cs b/Sources/WifiRemote/Utility/ImageHelper.cs new file mode 100644 index 0000000..4e2685e --- /dev/null +++ b/Sources/WifiRemote/Utility/ImageHelper.cs @@ -0,0 +1,415 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Drawing; +using System.IO; +using MediaPortal.GUI.Library; + +namespace WifiRemote +{ + class ImageHelperError + { + public enum ImageHelperErrorType + { + WatcherCreate, + WatcherEnable, + DirectoryCreate, + Timeout, + ScreenshotRead + }; + + /// + /// Unique code for this error + /// + public int ErrorCode { get; set; } + + /// + /// Descriptive message of this error + /// + public String ErrorMessage { get; set; } + + public ImageHelperError(ImageHelperErrorType type) + { + setupExceptionWithType(type); + } + + protected void setupExceptionWithType(ImageHelperErrorType type) + { + switch (type) + { + case ImageHelperErrorType.WatcherCreate: + ErrorCode = 10; + ErrorMessage = "Could not watch for MediaPortal screenshots."; + break; + + case ImageHelperErrorType.WatcherEnable: + ErrorCode = 11; + ErrorMessage = "Error starting to watch for MediaPortal screenshots."; + break; + + case ImageHelperErrorType.DirectoryCreate: + ErrorCode = 20; + ErrorMessage = "Could not create screenshot directory."; + break; + + case ImageHelperErrorType.Timeout: + ErrorCode = 30; + ErrorMessage = "Timeout while waiting for MediaPortal to take the screenshot."; + break; + + case ImageHelperErrorType.ScreenshotRead: + ErrorCode = 40; + ErrorMessage = "Could not read MediaPortal screenshot"; + break; + + default: + ErrorCode = 0; + ErrorMessage = "An unexpected error occured."; + break; + } + } + } + + class ImageHelper + { + #region Take a MediaPortal screenshot + + /// + /// Callback for when the screenshot was taken and is stored as a + /// byte array in the Screenshot property. + /// + public delegate void ScreenshotReadyCallback(); + + /// + /// Callback for when the screenshot could not be taken or processed. + /// + public delegate void ScreenshotFailedCallback(ImageHelperError error); + + /// + /// Tracks if a screenshot is being made at the moment + /// + bool takingScreenshot; + + /// + /// FileSystemWatcher watching for new screenshots + /// + FileSystemWatcher watcher; + + /// + /// Path of the current screenshot + /// + String screenshotPath; + + /// + /// Number of times the screenshot was tried to open. + /// We abort after maximumScreenshotOpenTries times to avoid an + /// infinite loop. + /// + uint screenshotOpenTries; + + /// + /// Abort trying to open the screenshot after this number of tries. + /// + uint maximumScreenshotOpenTries; + + private Image screenshot; + /// + /// The screenshot taken with the takeScreenshot() method + /// + public Image Screenshot + { + get { return screenshot; } + set { screenshot = value; } + } + + public ImageHelper() + { + maximumScreenshotOpenTries = 20; + screenshotOpenTries = 0; + } + + /// + /// Make MediaPortal take a screenshot, take that and delete it + /// from disk. First we need to check if the screenshot folder already exists. + /// See https://github.com/MediaPortal/MediaPortal-1/blob/cae80bd6dd2241bd7182c39418373bee545bf464/mediaportal/MediaPortal.Application/MediaPortal.cs#L3611 + /// + public void TakeScreenshot() + { + // Only take one screenshot at a time, all requests + // will be served from that screenshot. + if (takingScreenshot) + { + return; + } + + takingScreenshot = true; + + // MediaPortal doesn't output events for new screenshots so we 'manually' + // watch the screenshot folder + setupFileSystemWatcher(); + + if (watcher == null) + { + // Something went wrong creating the filesystem watcher + takingScreenshot = false; + OnScreenshotFailed(new ImageHelperError(ImageHelperError.ImageHelperErrorType.WatcherCreate)); + return; + } + + if (!watcher.EnableRaisingEvents) + { + try + { + watcher.EnableRaisingEvents = true; + } + catch (Exception e) + { + WifiRemote.LogMessage(String.Format("Could not watch the screenshots folder: {0}", e.Message), WifiRemote.LogType.Error); + watcher = null; + takingScreenshot = false; + OnScreenshotFailed(new ImageHelperError(ImageHelperError.ImageHelperErrorType.WatcherEnable)); + return; + } + } + + // Take the screenshot + MediaPortal.GUI.Library.Action action = new MediaPortal.GUI.Library.Action(MediaPortal.GUI.Library.Action.ActionType.ACTION_TAKE_SCREENSHOT, 0, 0); + GUIGraphicsContext.OnAction(action); + } + + /// + /// Returns the resized screenshot as a byte array. + /// + /// Width to resize the screenshot proportionally to, 0 to keep original + /// + public byte[] resizedScreenshot(int width) + { + if (Screenshot == null) + { + return new byte[0]; + } + + Image image = (width > 0) ? ImageHelper.ResizedImage(Screenshot, width) : Screenshot; + return ImageHelper.imageToByteArray(image, System.Drawing.Imaging.ImageFormat.Jpeg); + } + + protected void setupFileSystemWatcher() + { + String directory = String.Format("{0}\\MediaPortal Screenshots\\{1:0000}-{2:00}-{3:00}", + Environment.GetFolderPath(Environment.SpecialFolder.MyPictures), + DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day); + + if (!Directory.Exists(directory)) + { + WifiRemote.LogMessage(String.Format("Creating screenshot directory: {0}", directory), WifiRemote.LogType.Info); + + try + { + Directory.CreateDirectory(directory); + } + catch (Exception e) + { + WifiRemote.LogMessage(String.Format("Could not create screenshot directory {0}: {1}", directory, e.Message), WifiRemote.LogType.Error); + watcher = null; + takingScreenshot = false; + OnScreenshotFailed(new ImageHelperError(ImageHelperError.ImageHelperErrorType.DirectoryCreate)); + return; + } + } + + if (watcher == null) + { + // Add a filesystem watcher to be informed when MediaPortal creates the screenshot + watcher = new FileSystemWatcher(directory, "*.png"); + watcher.Created += new FileSystemEventHandler(watcherCreated); + } + else if (!watcher.Path.Equals(directory)) + { + // Date changed, update path + watcher.Path = directory; + } + } + + /// + /// A screenshot was created + /// + /// + /// + protected void watcherCreated(object sender, FileSystemEventArgs e) + { + screenshotPath = e.FullPath; + + // Wait until the screenshot is written to disk + System.Timers.Timer timer = new System.Timers.Timer(100); + timer.AutoReset = false; + timer.Elapsed += new System.Timers.ElapsedEventHandler(screenshotReadyCheck); + timer.Start(); + } + + protected void screenshotReadyCheck(object sender, System.Timers.ElapsedEventArgs e) + { + ((System.Timers.Timer)sender).Stop(); + if (IsScreenshotReady(screenshotPath)) + { + // MediaPortal completed writing the screenshot to disk + // We can now grab and delete it + processScreenshot(); + screenshotOpenTries = 0; + } + else + { + if (screenshotOpenTries < maximumScreenshotOpenTries) + { + // Continue checking if the file is locked + WifiRemote.LogMessage("Waiting for screenshot to be written ...", WifiRemote.LogType.Debug); + screenshotOpenTries++; + ((System.Timers.Timer)sender).Start(); + } + else + { + WifiRemote.LogMessage("Maximum number of screenshot open tries reached, aborting.", WifiRemote.LogType.Debug); + OnScreenshotFailed(new ImageHelperError(ImageHelperError.ImageHelperErrorType.Timeout)); + screenshotOpenTries = 0; + } + } + } + + protected void processScreenshot() + { + try + { + using (FileStream stream = new FileStream(screenshotPath, FileMode.Open, FileAccess.Read)) + { + Screenshot = Image.FromStream(stream); + } + } + catch (Exception ex) + { + WifiRemote.LogMessage(String.Format("Could not open screenshot file {0}: {1}", screenshotPath, ex.Message), WifiRemote.LogType.Error); + takingScreenshot = false; + OnScreenshotFailed(new ImageHelperError(ImageHelperError.ImageHelperErrorType.ScreenshotRead)); + return; + } + + // Delete the screenshot from disk + try + { + File.Delete(screenshotPath); + + if (Directory.GetFiles(Path.GetDirectoryName(screenshotPath), "*.png").Length == 0) + { + // No screenshots in the screenshot folder, delete that as well + Directory.Delete(Path.GetDirectoryName(screenshotPath)); + } + } + catch (Exception ex) + { + WifiRemote.LogMessage(String.Format("Could not delete screenshot or screenshot folder {0}: {1}", screenshotPath, ex.Message), WifiRemote.LogType.Info); + } + + // Stop listening for new files + watcher.EnableRaisingEvents = false; + + // Inform observers that the screenshot is now ready + OnScreenshotReady(); + takingScreenshot = false; + } + + /// + /// Check if the screenshot is locked. + /// + /// + /// + protected static bool IsScreenshotReady(String path) + { + // If the file can be opened for exclusive access it means that the file + // is no longer locked by another process. + try + { + using (FileStream inputStream = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.None)) + { + long streamLength = inputStream.Length; + return streamLength > 0; + } + } + catch (Exception) + { + return false; + } + } + + #endregion + + #region Events + + /// + /// Screenshot ready event + /// + public event ScreenshotReadyCallback ScreenshotReady; + protected void OnScreenshotReady() + { + if (ScreenshotReady != null) + { + ScreenshotReady(); + } + } + + /// + /// Screenshot failed event + /// + public event ScreenshotFailedCallback ScreenshotFailed; + protected void OnScreenshotFailed(ImageHelperError error) + { + if (ScreenshotFailed != null) + { + ScreenshotFailed(error); + } + } + + #endregion + + #region Static utility methods + + /// + /// Returns an image as its byte array representation. + /// Used to make images encodable in JSON. + /// + /// + /// + public static byte[] imageToByteArray(Image img, System.Drawing.Imaging.ImageFormat format) + { + byte[] byteArray = new byte[0]; + using (MemoryStream stream = new MemoryStream()) + { + img.Save(stream, format); + stream.Close(); + byteArray = stream.ToArray(); + } + + return byteArray; + } + + /// + /// Resizes an image to the target with. The height is calculated + /// proportionally to the source image height. + /// + /// The source image to resize + /// Target width for the resized image + /// + public static Image ResizedImage(Image source, int width) + { + if (source.Width <= width) + { + return source; + } + + int height = (int)(source.Height / ((double)source.Width / (double)width)); + Image target = new Bitmap(source, width, height); + + return target; + } + + #endregion + } +} diff --git a/Sources/WifiRemote/WifiRemote.csproj b/Sources/WifiRemote/WifiRemote.csproj index 2c63d81..5c0e6c0 100644 --- a/Sources/WifiRemote/WifiRemote.csproj +++ b/Sources/WifiRemote/WifiRemote.csproj @@ -10,7 +10,7 @@ Properties WifiRemote WifiRemote - v3.5 + v4.0 512 @@ -39,7 +39,7 @@ full false bin\Debug\ - TRACE;DEBUG;COMPILE_FOR_1_2_0 + TRACE;DEBUG prompt 4 @@ -47,7 +47,7 @@ pdbonly true bin\Release\ - TRACE;COMPILE_FOR_1_1_2 + TRACE prompt 4 @@ -55,17 +55,18 @@ ..\..\Libs\Common.Utils.dll - + False ..\..\Libs\Core.dll - ..\..\..\..\..\..\..\..\..\Program Files (x86)\Team MediaPortal\MediaPortal\plugins\Windows\Cornerstone.dll + ..\..\Libs\Cornerstone.dll - ..\..\..\Libs\Cornerstone.MP.dll + ..\..\Libs\Cornerstone.MP.dll - + + False ..\..\Libs\Databases.dll @@ -106,6 +107,9 @@ + + ..\..\Libs\TraktPlugin.dll + False ..\..\Libs\TVDatabase.dll @@ -114,10 +118,12 @@ False ..\..\Libs\TvPlugin.dll - + + False ..\..\Libs\Utils.dll - + + False ..\..\Libs\WindowPlugins.dll @@ -145,6 +151,7 @@ + @@ -162,6 +169,7 @@ + @@ -192,6 +200,7 @@ + @@ -201,6 +210,7 @@ Resources.resx + diff --git a/Sources/WifiRemote/merge.bat b/Sources/WifiRemote/merge.bat index 18671da..3d61b35 100644 --- a/Sources/WifiRemote/merge.bat +++ b/Sources/WifiRemote/merge.bat @@ -1,7 +1,7 @@ @echo off IF EXIST WifiRemote_TMP.dll del WifiRemote_TMP.dll IF EXIST WifiRemote_TMP.pdb del WifiRemote_TMP.pdb -ilmerge /out:WifiRemote_TMP.dll WifiRemote.dll ZeroconfService.dll Newtonsoft.Json.Net35.dll zxing.dll +ilmerge /out:WifiRemote_TMP.dll WifiRemote.dll ZeroconfService.dll Newtonsoft.Json.Net35.dll zxing.dll /targetplatform:v4,"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0" IF EXIST WifiRemote.dll del WifiRemote.dll IF EXIST WifiRemote.pdb del WifiRemote.pdb