private void WebServiceProcess(string action, ref BrowserSender browserSender, ref string PostObjects)
        {
            if (Settings.Default.DebugFullAPI)
            {
                Functions.WriteLineToLogFile("\r\n\r\nAPI: Incoming API Call: " + action);
                if (PostObjects.Length > 0)
                    Functions.WriteLineToLogFile("API: Post Object String: [" + PostObjects + "]");
                else
                    Functions.WriteLineToLogFile("API: Post Object String: Blank.");
            }

            try
            {

                // Pre-process, e.g. to correct '%2B replaced by + sign' bug
                action = preProcessActionString(action);

                // LOGIN - GET TOKEN
                if (action.StartsWith("xml/login"))
                {
                    if (
                        (!qsParams.HasParameter("un")) &&
                        (!qsParams.HasParameter("hashedpw") || (!qsParams.HasParameter("pw")))
                        )
                    {
                        // not enough params
                        XMLresponse = "<?xml version=\"1.0\"?><loginresponse result=\"NOT_ENOUGH_PARAMETERS\" />";
                        browserSender.SendXMLToBrowser(XMLresponse);
                        return;
                    }

                    string UN = "", PW = "", HPW = "", client = "";
                    bool passwordIsHashed = qsParams.HasParameter("hashedpw");

                    // Client (optional)
                    if (qsParams.HasParameter("client"))
                    {
                        client = qsParams["client"].Trim();
                        client = HttpUtility.UrlDecode(client);
                    }

                    UN = qsParams["un"].Trim();
                    UN = HttpUtility.UrlDecode(UN);
                    if (passwordIsHashed)
                    {
                        HPW = qsParams["hashedpw"].Trim();
                        HPW = HttpUtility.UrlDecode(HPW);
                    }
                    else
                    {
                        PW = qsParams["pw"].Trim();
                        PW = HttpUtility.UrlDecode(PW);
                    }

                    if (action.StartsWith("xml/login64"))
                    {
                        UN = Functions.DecodeFromBase64(UN);
                        if (passwordIsHashed)
                            HPW = Functions.DecodeFromBase64(PW);
                        else
                            PW = Functions.DecodeFromBase64(PW);

                        client = Functions.DecodeFromBase64(client);
                    }

                    if ((!UN.Equals(Settings.Default.UserName)) ||
                        (!Functions.StringHashesToPasswordHash(PW, passwordIsHashed))
                        )
                    {
                        // incorrect credentials - always log
                        Functions.WriteLineToLogFile("API: Failed login attempt from client " + client + " with username " + UN);

                        XMLresponse = "<?xml version=\"1.0\"?><loginresponse result=\"INCORRECT_CREDENTIALS\" />";
                        browserSender.SendXMLToBrowser(XMLresponse);
                        return;
                    }

                    // Success!
                    if (Settings.Default.DebugBasic)
                        Functions.WriteLineToLogFile("API: User " + UN + " logged in OK using client " + client);

                    string token = AuthSessionHelper.Default.AddClient(currentClientIP);  // Store session, get token
                    XMLresponse = "<?xml version=\"1.0\"?><loginresponse result=\"OK\" token=\"" + token + "\" />";
                    browserSender.SendXMLToBrowser(XMLresponse);
                    return;
                }

                // ************ REMAINING METHODS MAY REQUIRE AUTHENTICATION
                if (!AuthenticatedByToken)
                {
                    Functions.logAPIoutputString("ASending 403 Incorrect Authentication");
                    browserSender.SendGenericStatusCodePage("403", "Incorrect authentication");
                    spoolMessage("API: Must provide a valid authentication token.  Use /xml/login first.");
                    return;
                }

                // Should we zip up afterwards
                bool zipContent = false;
                if (action.EndsWith("/zip"))
                {
                    zipContent = true;
                    action = action.Replace("/zip", "");
                }
                if (txtActionOriginalCase.EndsWith("/zip"))
                {
                    txtActionOriginalCase = txtActionOriginalCase.Replace("/zip", "");
                }

                if (action.StartsWith("xml/channels/setasfavorite/"))
                {
                    string chanID = action.Replace("xml/channels/setasfavorite/", "");

                    string strResponse = (EPGManager.MakeChannelFavorite(chanID)) ? "OK" : "ERROR";
                    XMLresponse = XMLHelper.XMLReponseWithOutputString(strResponse);
                    if (Settings.Default.DebugChannels) Functions.WriteLineToLogFile("API: Set channel " + chanID + " as favorite OK.");
                }
                else if (action.StartsWith("xml/channels/unsetasfavorite/"))
                {
                    string chanID = action.Replace("xml/channels/unsetasfavorite/", "");

                    string strResponse = (EPGManager.MakeChannelNotFavorite(chanID)) ? "OK" : "ERROR";
                    XMLresponse = XMLHelper.XMLReponseWithOutputString(strResponse);
                    if (Settings.Default.DebugChannels) Functions.WriteLineToLogFile("API: Unset channel " + chanID + " as not favorite OK.");
                }
                else if (action == "xml/channels/all")
                {
                    // New 2011:  Update channels first from media center (MediaCenter can randomly change internal IDs)
                    EPGManager.UpdateTVChannels();

                    XMLresponse = EPGExporter.AllChannelsAsXML();
                    if (Settings.Default.DebugAdvanced) Functions.WriteLineToLogFile("Exporting all channels via XML web request...");
                }
                else if (action.StartsWith("xml/programmes"))
                {
                    string subAction = action.Replace("xml/programmes/", "");

                    // No description?  (turbo mode)
                    bool omitDescriptions = (subAction.StartsWith("nodescription"));
                    if (omitDescriptions)
                    {
                        subAction = subAction.Replace("nodescription/", "");
                    }

                    // If a programme type is specified, restrict to this type, otherwise use all
                    TVProgrammeType restrictProgrammesToType = (qsParams.HasParameter("programmetype")) ?
                        (TVProgrammeType)Enum.Parse(new TVProgrammeType().GetType(), qsParams["programmetype"], true) :
                        TVProgrammeType.All;

                    // 2. CHANNELS
                    List<string> TVServiceIDs = new List<string>();
                    if (subAction.StartsWith("limitchannels/"))
                    {
                        subAction = subAction.Replace("limitchannels/", "");
                        TVServiceIDs = Functions.StringListFromXML(PostObjects);
                    }
                    else if (subAction.StartsWith("favoritechannels/"))
                    {
                        subAction = subAction.Replace("favoritechannels/", "");
                        TVServiceIDs = EPGManager.EPGDisplayedTVChannelsServiceIDs;
                    }
                    else if (subAction.StartsWith("byepgrequest"))
                    {

                        List<EPGRequest> EPGRequests = EPGRequest.ArrayFromXML(PostObjects);

                        try
                        {
                            XMLresponse = EPGExporter.EPGwithEPGRequests(EPGRequests, omitDescriptions, restrictProgrammesToType);
                            if (Settings.Default.DebugAdvanced) Functions.WriteLineToLogFile("Exporting tv programmes (using " + EPGRequests.Count.ToString() + " epg requests) via XML web request...");
                        }
                        catch (Exception ex)
                        {
                            Functions.WriteLineToLogFile("CRITICAL ERROR - could not parse array of EPG requests.  Date passed was " + PostObjects);
                            Functions.WriteExceptionToLogFile(ex);
                        }
                    }

                    // 3. DATE / DAYRANGE
                    if (subAction.StartsWith("date/"))
                    {
                        string strDate = subAction.Replace("date/", "");
                        DateTime localDate = new DateTime();
                        if (DateTime.TryParse(strDate, out localDate))
                        {

                            XMLresponse = EPGExporter.EPGForLocalDate(localDate, TVServiceIDs, omitDescriptions, restrictProgrammesToType);
                            if (Settings.Default.DebugAdvanced) Functions.WriteLineToLogFile("Exporting tv programmes on " + TVServiceIDs.Count.ToString() + " channels for date " + strDate + " via XML web request...");
                        }
                        else
                        {
                            Functions.WriteLineToLogFile("CRITICAL ERROR - could not parse local date to export shows.  Date passed was " + strDate + ".");
                        }
                    }
                    else if (subAction.StartsWith("daterange/"))
                    {
                        string strDate = subAction.Replace("daterange/", "");
                        string[] dateRanges = strDate.Split(new string[] { "/" }, StringSplitOptions.None);
                        if (dateRanges.Count() > 1)
                        {
                            DateTime startDateTime, endDateTime;
                            if (DateTime.TryParse(dateRanges[0], out startDateTime) &&
                                DateTime.TryParse(dateRanges[1], out endDateTime)
                                )
                            {
                                if (Settings.Default.DebugAdvanced) Functions.WriteLineToLogFile("Exporting tv programmes on " + TVServiceIDs.Count.ToString() + " channels for date range " + strDate + " via XML web request...");
                                XMLresponse = EPGExporter.EPGForDateRange(startDateTime, endDateTime, TVServiceIDs, omitDescriptions, restrictProgrammesToType);
                            }
                            else
                            {
                                Functions.WriteLineToLogFile("CRITICAL ERROR - could not parse day ranges.");
                            }
                        }
                    }
                    else if (subAction.StartsWith("dayrange/"))
                    {
                        string strDate = subAction.Replace("dayrange/", "");

                        string[] dayRanges = strDate.Split(new string[] { "/" }, StringSplitOptions.None);
                        if (dayRanges.Count() > 1)
                        {
                            int startDaysAhead, numberOfDays;
                            if (int.TryParse(dayRanges[0], out startDaysAhead) &&
                                int.TryParse(dayRanges[1], out numberOfDays)
                                )
                            {
                                if (Settings.Default.DebugAdvanced) Functions.WriteLineToLogFile("Exporting tv programmes on " + TVServiceIDs.Count.ToString() + " channels for day range " + strDate + " via XML web request...");
                                XMLresponse = EPGExporter.EPGForDaysRange(startDaysAhead, numberOfDays, TVServiceIDs, omitDescriptions, restrictProgrammesToType);
                            }
                            else
                            {
                                Functions.WriteLineToLogFile("CRITICAL ERROR - could not parse day ranges.");
                            }
                        }
                    }
                    else if (subAction.StartsWith("search"))
                    {
                        EPGSearch theSearch = EPGSearch.FromXML(PostObjects);
                        if (theSearch != null)
                        {
                            XMLresponse = EPGExporter.TVProgrammesMatchingSearch(theSearch);

                            if (Settings.Default.DebugAdvanced) Functions.WriteLineToLogFile("Exporting all programmes matching search.");
                        }
                        else
                        {
                            Functions.WriteLineToLogFile("CRITICAL ERROR - could not parse search request XML");
                        }
                    }
                }
                else if (action.StartsWith("xml/programme/getinfo/"))
                {
                    string strUID = action.Replace("xml/programme/getinfo/", "");
                    if (Settings.Default.DebugAdvanced) Functions.WriteLineToLogFile("Exporting programme info blob for prog ID " + strUID + " via XML web request...");
                    XMLresponse = EPGExporter.TVProgrammeInfoBlobForProgID(strUID);
                }
                else if (action.StartsWith("xml/filebrowse/dir"))
                {
                    FileBrowseRequest fbrequest = FileBrowseRequest.FromXML(PostObjects);
                    if (fbrequest != null)
                    {
                        XMLresponse = FileBrowseExporter.FileBrowseUsingRequestAsXML(fbrequest);

                        if (Settings.Default.DebugAdvanced) Functions.WriteLineToLogFile("Exporting list of files matching request (path " + fbrequest.FullPath + ")");
                    }
                    else
                    {
                        Functions.WriteLineToLogFile("CRITICAL ERROR - could not parse file browse request XML");
                    }
                }
                else if (action.StartsWith("xml/recordings"))
                {
                    // FOR NOW.. ..refresh each time, although strictly may not be necessary
                    if (Settings.Default.RecordingsRetrieveAsParanoid) EPGManager.ReloadAllRecordings();

                    XMLresponse = EPGExporter.RecordingsBlobAsXML();
                    if (Settings.Default.DebugAdvanced) Functions.WriteLineToLogFile("Exporting all recordings via XML web request...");
                }
                else if (action.StartsWith("xml/settings"))
                {
                    XMLresponse = EPGExporter.AllSettingsAsXML();
                    if (Settings.Default.DebugAdvanced) Functions.WriteLineToLogFile("Exporting all settings via XML web request...");
                }
                else if (action.StartsWith("xml/record/byrecordingrequest"))
                {
                    RecordingRequest tReq = RecordingRequest.FromXML(PostObjects);

                    XMLresponse = EPGManager.ScheduleRecording(RecordingRequest.FromXML(PostObjects)).ToXML();
                }
                else if (action.StartsWith("xml/recordedtv"))
                {
                    /*if (action.Contains("refreshnow"))
                        RecTV.Default.RefreshCache(); */

                    XMLresponse = EPGExporter.AllRecordedTVAsXML();
                    if (Settings.Default.DebugAdvanced) Functions.WriteLineToLogFile("Exporting all recorded TV via XML web request...");
                }
                else if (action.StartsWith("xml/cancelrequest/"))
                {
                    string txtID = action.Replace("xml/cancelrequest/", "");
                    XMLresponse = WebSvcCancelRequest(txtID);
                }
                else if (action.StartsWith("xml/sendremotekey/"))
                {
                    string txtCmd = action.Replace("xml/sendremotekey/", "");

                    string strResponse = IRCommunicator.Default.SendIRCommand(txtCmd); // Returns OK or HELPER_NOT_RUNNING.  Doesn't return socket errors (it's ASync)
                    XMLresponse = XMLHelper.XMLReponseWithOutputString(strResponse);
                }
                else if (action.StartsWith("xml/showlog"))
                {
                    XMLresponse = "<?xml version=\"1.0\"?><log ";
                    if (Settings.Default.AllowRemoteLogRetrieval)
                    {
                        XMLresponse += "result=\"OK\" contents=\"" + FileCache.ReadTextFileFromDisk(Functions.DebugLogFileFN) + "\">";
                    }
                    else
                    {
                        XMLresponse += "result=\"Error\" contents=\"RemoteLoggingDisabled\">";
                    }

                    XMLresponse += "</log>";
                }
                else if (action.StartsWith("xml/cancelrecording/"))
                {
                    string txtID = action.Replace("xml/cancelrecording/", "");
                    XMLresponse = WebSvcCancelRecording(txtID);
                }
                else if (action.StartsWith("xml/deletefile64"))
                {
                    string filePath = "";
                    if (PostObjects.Trim().Length > 0)
                    {
                        filePath = HttpUtility.UrlDecode(PostObjects);
                        filePath = Functions.DecodeFromBase64(filePath, Encoding.UTF8);
                    }

                    XMLresponse = WebSvcDeleteFileByFilePath(filePath);
                }
                else if (action.StartsWith("xml/deletefile"))
                {
                    string filePath = "";
                    if (PostObjects.Trim().Length > 0)
                        filePath = HttpUtility.UrlDecode(PostObjects);
                    else
                    {
                        // LEGACY - use URL path
                        filePath = action.Replace("xml/deletefile/", "");
                    }

                    XMLresponse = WebSvcDeleteFileByFilePath(filePath);
                }
                else if (action.StartsWith("xml/mediastream/start/bymediastreamingrequest"))
                {
                    MediaStreamingResult streamResult;
                    MediaStreamingRequest streamRq = XMLHelper.Deserialize<MediaStreamingRequest>(PostObjects);

                    if (streamRq != null)
                        streamResult = StreamingManager.Default.StartStreamer(streamRq, Request.UserHostName);
                    else
                        streamResult = new MediaStreamingResult(MediaStreamingResultCodes.NamedError, "Error in streaming request.");

                    XMLresponse = XMLHelper.Serialize<MediaStreamingResult>(streamResult);
                }
                else if (action.StartsWith("xml/mediastream/probe/byfilename"))
                {
                    string strFileName = HttpUtility.UrlDecode(PostObjects);
                    strFileName = strFileName.Trim();

                    if (action.StartsWith("xml/mediastream/probe/byfilename64"))
                        strFileName = Functions.DecodeFromBase64(strFileName);

                    List<AVStream> result;
                    if (strFileName.Length > 0)
                        result = StreamingManager.Default.ProbeFile(strFileName);
                    else
                        result = new List<AVStream>();

                    if (Settings.Default.DebugStreaming)
                        Functions.WriteLineToLogFile("Probed file " + strFileName + ": sending back details of " + result.Count.ToString() + " AV streams.");

                    XMLresponse = XMLHelper.Serialize<List<AVStream>>(result);
                }
                else if (action.StartsWith("xml/mediastream/keepalive/"))
                {
                    string strStreamerID = action.Replace("xml/mediastream/keepalive/", "");
                    int streamerID;
                    string strmStatus;
                    if (int.TryParse(strStreamerID, out streamerID))
                    {
                        strmStatus = StreamingManager.Default.KeepStreamerAliveAndReturnStatus(streamerID);
                    }
                    else
                    {
                        Functions.WriteLineToLogFile("Warning: Could not parse streamer ID " + strStreamerID);
                        strmStatus = "invalid_id";
                    }

                    //XMLresponse = XMLHelper.XMLReponseWithOutputString(strmStatus);
                    XMLresponse = strmStatus;
                    if (Settings.Default.DebugAdvanced)
                        Functions.WriteLineToLogFile("MediaStreaming: GetStatus  (" + strStreamerID + "): " + strmStatus);
                }
                else if (action.StartsWith("xml/mediastream/stop/"))
                {
                    string strStreamerID = action.Replace("xml/mediastream/stop/", "");
                    int streamerID;
                    try
                    {
                        if (int.TryParse(strStreamerID, out streamerID))
                        {
                            if (!StreamingManager.Default.StopStreamer(streamerID))
                                Functions.WriteLineToLogFile("Warning: Could not stop streamer ID " + strStreamerID);
                        }
                        else
                        {
                            Functions.WriteLineToLogFile("Warning: Could not parse streamer ID " + strStreamerID);
                        }
                    }
                    catch (Exception ex)
                    {
                        Functions.WriteExceptionToLogFileIfAdvanced(ex);
                    }

                    XMLresponse = XMLHelper.XMLReponseWithOutputString("No Data");
                }
                else if (action.StartsWith("xml/stream/start"))
                {
                    WTVStreamingVideoResult streamResult;
                    WTVStreamingVideoRequest streamRq = XMLHelper.Deserialize<WTVStreamingVideoRequest>(PostObjects);
                    if (streamRq == null)
                    {
                        streamResult = new WTVStreamingVideoResult(DSStreamResultCodes.ErrorInStreamRequest);
                    }
                    else
                    {
                        try
                        {
                            streamResult = DSStreamingManager.Default.StartStreamer(streamRq);
                        }
                        catch (Exception e)
                        {
                            Functions.WriteLineToLogFile("Exception setting up streaming object:");
                            Functions.WriteExceptionToLogFile(e);
                            streamResult = new WTVStreamingVideoResult(DSStreamResultCodes.ErrorExceptionOccurred, e.Message);
                        }
                    }

                    XMLresponse = XMLHelper.Serialize<WTVStreamingVideoResult>(streamResult);
                }
                else if (action.StartsWith("xml/stream/stop"))
                {
                    XMLresponse = XMLHelper.XMLReponseWithOutputString("ERROR (DEPRECATED)");
                }
                else if (action.StartsWith("xml/picture/thumbnailzip/"))
                {
                    FileBrowseRequest fbrequest = FileBrowseRequest.FromXML(PostObjects);
                    if (fbrequest != null)
                    {
                        if (PictureExporter.SendThumbnailsAsZipFile(fbrequest, FatAttitude.ThumbnailSizes.Small, ref browserSender))
                            return;
                        else
                        {
                            if (Settings.Default.DebugAdvanced) Functions.WriteLineToLogFile("Could not export zip of thumbnails.");
                            browserSender.Send404Page();
                        }
                    }
                    else
                    {
                        Functions.WriteLineToLogFile("ThumbnailZip: Error in requestprocessor- could not parse file browse request XML");
                    }
                }
                else if (action.StartsWith("xml/picture/get"))  // matches /xml/picture/getrequest too
                {
                    string strSubAction = txtActionOriginalCase.Replace("xml/picture/", "");

                    // URL DECODE
                    strSubAction = HttpUtility.UrlDecode(strSubAction);

                    string strParams;
                    string strFileName = "";
                    bool fileNameAtEndOfUri = false;
                    bool fileNameAtEndOfUriIsBase64Encoded = false;
                    if (strSubAction.StartsWith("getwithfilename"))  // GET FILENAME FROM URL
                    {
                        fileNameAtEndOfUri = true;

                        fileNameAtEndOfUriIsBase64Encoded = strSubAction.StartsWith("getwithfilename64");

                        if (fileNameAtEndOfUriIsBase64Encoded)
                            strParams = strSubAction.Replace("getwithfilename64/", "");
                        else
                            strParams = strSubAction.Replace("getwithfilename/", "");
                    }
                    else
                    // GET FILENAME FROM POST STRING
                    {
                        fileNameAtEndOfUri = false;
                        strFileName = PostObjects;
                        strParams = strSubAction.Replace("get/", "");
                    }

                    string[] Params = strParams.Split(new string[] { "/" }, StringSplitOptions.None);

                    bool haveFrameSizes = false;
                    int frameWidth = 0;
                    int frameHeight = 0;
                    if (Params.Count() > 1)
                    {
                        if ((int.TryParse(Params[0], out frameWidth) &&
                                 int.TryParse(Params[1], out frameHeight)
                                ))
                            haveFrameSizes = ((frameWidth > 0) && (frameHeight > 0));
                        else
                            haveFrameSizes = false;
                    }
                    else
                        // Send full picture
                        haveFrameSizes = false;

                    if (!haveFrameSizes) Functions.WriteLineToLogFile("Xml/Picture: invalid frame size (or none supplied): using full picture");

                    if (Settings.Default.DebugAdvanced) Functions.WriteLineToLogFile("Exporting picture " + strFileName + " resized to frame " + frameWidth.ToString() + "x" + frameHeight.ToString());

                    // Get Filename if not got already
                    // File name from Uri ?
                    if (fileNameAtEndOfUri)
                    {
                        if (fileNameAtEndOfUriIsBase64Encoded)
                        {
                            // Take final component and un-encode to produce filename
                            strFileName = Params[Params.Count() - 1];
                            strFileName = HttpUtility.UrlDecode(strFileName);
                            strFileName = Functions.DecodeFromBase64(strFileName);
                        }
                        else
                        {
                            // Reconstruct filename by putting /slashed/ components back together
                            for (int pCount = 2; pCount < Params.Count(); pCount++)
                            {
                                strFileName = strFileName + Params[pCount];
                                if (pCount < (Params.Count() - 1))
                                    strFileName = strFileName + "/";

                                strFileName = HttpUtility.UrlDecode(strFileName);
                            }
                        }

                    }

                    if (string.IsNullOrEmpty(strFileName))
                    {
                        Functions.WriteLineToLogFile("Xml/Picture : No filename specified in POST request, sending 404");
                        browserSender.Send404Page();
                        return;
                    }

                    // Send
                    if (haveFrameSizes)
                    {

                        byte[] resizedPictureData = new byte[] { };
                        if (ImageResizer.ResizePicture(strFileName, new Size(frameWidth, frameHeight), out resizedPictureData, ImageFormat.Jpeg, false))
                        {
                            browserSender.SendDataToBrowser(Functions.MimeTypeForFileName(strFileName), resizedPictureData);
                            return;
                        }
                        else
                        {
                            Functions.WriteLineToLogFile("Xml/Picture: Could not resize picture.");
                            browserSender.Send404Page();
                            return;
                        }
                    }
                    else  // No frame sizes, send full image
                    {
                        browserSender.SendFileToBrowser(strFileName);
                        return;
                    }

                }
                else if (action.StartsWith("xml/music/framework"))
                {
                    using (WMPManager manager = new WMPManager())
                    {
                        XMLresponse = manager.MusicFrameworkAsXML();
                        if (Settings.Default.DebugAdvanced) Functions.WriteLineToLogFile("Exporting music framework blob via XML web request...");
                    }
                }
                else if (action.StartsWith("xml/music/songs/artist"))
                {
                    bool isBase64Encoded = (action.Contains("artist64/"));
                    action = action.Replace("artist64", "artist");
                    txtActionOriginalCase = txtActionOriginalCase.Replace("artist64", "artist");

                    string strArtistID = txtActionOriginalCase.Replace("xml/music/songs/artist/", "");
                    strArtistID = HttpUtility.UrlDecode(strArtistID);

                    if (isBase64Encoded)
                        strArtistID = Functions.DecodeFromBase64(strArtistID);

                    using (WMPManager manager = new WMPManager())
                    {
                        XMLresponse = manager.GetSongsForArtistAsXML(strArtistID);
                        if (Settings.Default.DebugAdvanced) Functions.WriteLineToLogFile("Exporting songs for artist " + strArtistID + " via XML web request...");
                    }
                }
                else if (action.StartsWith("xml/music/songs/album"))
                {
                    bool isBase64Encoded = (action.Contains("album64/"));
                    action = action.Replace("album64", "album");
                    txtActionOriginalCase = txtActionOriginalCase.Replace("album64", "album");

                    // USE case sensitive action string for match
                    string strAlbumID = txtActionOriginalCase.Replace("xml/music/songs/album/", "");
                    strAlbumID = HttpUtility.UrlDecode(strAlbumID);

                    if (isBase64Encoded)
                        strAlbumID = Functions.DecodeFromBase64(strAlbumID);

                    using (WMPManager manager = new WMPManager())
                    {
                        XMLresponse = manager.GetSongsForAlbumAsXML(strAlbumID);
                        if (Settings.Default.DebugAdvanced) Functions.WriteLineToLogFile("Exporting songs for album " + strAlbumID + " via XML web request...");
                    }
                }
                else if (action.StartsWith("xml/music/songs/genre"))
                {
                    bool isBase64Encoded = (action.Contains("genre64/"));
                    action = action.Replace("genre64", "genre");
                    txtActionOriginalCase = txtActionOriginalCase.Replace("genre64", "genre");

                    // USE case sensitive action string for match
                    string strGenreID = txtActionOriginalCase.Replace("xml/music/songs/genre/", "");
                    strGenreID = HttpUtility.UrlDecode(strGenreID);

                    if (isBase64Encoded)
                        strGenreID = Functions.DecodeFromBase64(strGenreID);

                    using (WMPManager manager = new WMPManager())
                    {
                        XMLresponse = manager.GetSongsForGenreAsXML(strGenreID);
                        if (Settings.Default.DebugAdvanced) Functions.WriteLineToLogFile("Exporting songs for genre " + strGenreID + " via XML web request...");
                    }
                }
                else if (action.StartsWith("xml/music/songs/all"))
                {

                    using (WMPManager manager = new WMPManager())
                    {
                        XMLresponse = manager.GetAllSongsAsXML();
                        if (Settings.Default.DebugAdvanced) Functions.WriteLineToLogFile("Exporting all songs in library via XML web request...");
                    }
                }
                else if (action.StartsWith("xml/music/songs/checkexists"))
                {
                    bool isBase64Encoded = (action.Contains("checkexists64/"));
                    action = action.Replace("checkexists64", "checkexists");
                    txtActionOriginalCase = txtActionOriginalCase.Replace("checkexists64", "checkexists");

                    // USE case sensitive action string for match
                    string strSongID = txtActionOriginalCase.Replace("xml/music/songs/checkexists/", "");
                    strSongID = HttpUtility.UrlDecode(strSongID);

                    if (isBase64Encoded)
                        strSongID = Functions.DecodeFromBase64(strSongID);

                    using (WMPManager manager = new WMPManager())
                    {
                        XMLresponse = manager.WMPItemFileExistsAsXML(strSongID);
                        if (Settings.Default.DebugAdvanced) Functions.WriteLineToLogFile("Exporting whether song exists... " + XMLresponse);
                    }
                }
                else
                {

                    Functions.WriteLineToLogFile("XML: Unknown request");
                    XMLresponse = "";
                }

                if (String.IsNullOrEmpty(XMLresponse))
                {
                    Functions.WriteLineToLogFile("NULL xmlresponse - nothing to send out to Silverlight client.  Sending error string.");
                    browserSender.SendStringToBrowser(XMLHelper.XMLReponseWithOutputString("No Data"));
                    return;
                }

                // Strip out any UTF-16 encoding
                XMLresponse = Functions.StripIllegalXmlCharacters(XMLresponse);

                // Zip up ?
                if (zipContent)
                {
                    Functions.logAPIoutputString(XMLresponse);
                    XMLresponse = ZipHelper.ZipString(XMLresponse);

                    if (Settings.Default.DebugServer)
                        Functions.WriteLineToLogFile("Zipped String to base64 string.  Length:" + XMLresponse.Length.ToString() + " characters. ");

                    browserSender.SendZipStringToBrowser(XMLresponse);
                }
                else
                    browserSender.SendXMLToBrowser(XMLresponse);
            }
            catch (Exception e)
            {
                string errorResponse = XMLHelper.XMLReponseWithOutputString("An error occurred - " + e.Message + " - check the debug log on the server.");

                Functions.WriteLineToLogFile("Exception while processing XML request:");
                Functions.WriteExceptionToLogFile(e);

                browserSender.SendXMLToBrowser(errorResponse);
            }
        }
        private void WebServiceProcess(string action, ref BrowserSender browserSender, ref string PostObjects)
        {
            if (Settings.Default.DebugFullAPI)
            {
                Functions.WriteLineToLogFile("\r\n\r\nAPI: Incoming API Call: " + action);
                if (PostObjects.Length > 0)
                    Functions.WriteLineToLogFile("API: Post Object String: [" + PostObjects + "]");
                else
                    Functions.WriteLineToLogFile("API: Post Object String: Blank.");
            }

            try
            {

                // Pre-process, e.g. to correct '%2B replaced by + sign' bug
                action = preProcessActionString(action);

                // LOGIN - GET TOKEN
                if (action.StartsWith("xml/login"))
                {
                    if (
                        (!qsParams.HasParameter("un")) &&
                        (!qsParams.HasParameter("hashedpw") || (!qsParams.HasParameter("pw")))
                        )
                    {
                        // not enough params
                        XMLresponse = "<?xml version=\"1.0\"?><loginresponse result=\"NOT_ENOUGH_PARAMETERS\" />";
                        browserSender.SendXMLToBrowser(XMLresponse);
                        return;
                    }

                    string UN = "", PW = "", HPW = "", client = "";
                    bool passwordIsHashed = qsParams.HasParameter("hashedpw");

                    // Client (optional)
                    if (qsParams.HasParameter("client"))
                    {
                        client = qsParams["client"].Trim();
                        client = HttpUtility.UrlDecode(client);
                    }

                    UN = qsParams["un"].Trim();
                    UN = HttpUtility.UrlDecode(UN);
                    if (passwordIsHashed)
                    {
                        HPW = qsParams["hashedpw"].Trim();
                        HPW = HttpUtility.UrlDecode(HPW);
                    }
                    else
                    {
                        PW = qsParams["pw"].Trim();
                        PW = HttpUtility.UrlDecode(PW);
                    }

                    if (action.StartsWith("xml/login64"))
                    {
                        UN = Functions.DecodeFromBase64(UN);
                        if (passwordIsHashed)
                            HPW = Functions.DecodeFromBase64(PW);
                        else
                            PW = Functions.DecodeFromBase64(PW);

                        client = Functions.DecodeFromBase64(client);
                    }

                    if ((!UN.Equals(Settings.Default.UserName)) ||
                        (!Functions.StringHashesToPasswordHash(PW, passwordIsHashed))
                        )
                    {
                        // incorrect credentials - always log
                        Functions.WriteLineToLogFile("API: Failed login attempt from client " + client + " with username " + UN);

                        XMLresponse = "<?xml version=\"1.0\"?><loginresponse result=\"INCORRECT_CREDENTIALS\" />";
                        browserSender.SendXMLToBrowser(XMLresponse);
                        return;
                    }

                    // Success!
                    if (Settings.Default.DebugBasic)
                        Functions.WriteLineToLogFile("API: User " + UN + " logged in OK using client " + client);

                    string token = AuthSessionHelper.Default.AddClient(currentClientIP);  // Store session, get token
                    XMLresponse = "<?xml version=\"1.0\"?><loginresponse result=\"OK\" token=\"" + token + "\" />";
                    browserSender.SendXMLToBrowser(XMLresponse);
                    return;
                }

                // ************ REMAINING METHODS MAY REQUIRE AUTHENTICATION
                if (!AuthenticatedByToken)
                {
                    Functions.logAPIoutputString("ASending 403 Incorrect Authentication");
                    browserSender.SendGenericStatusCodePage("403", "Incorrect authentication");
                    spoolMessage("API: Must provide a valid authentication token.  Use /xml/login first.");
                    return;
                }

                // Should we zip up afterwards
                bool zipContent = false;
                if (action.EndsWith("/zip"))
                {
                    zipContent = true;
                    action = action.Replace("/zip", "");
                }
                if (txtActionOriginalCase.EndsWith("/zip"))
                {
                    txtActionOriginalCase = txtActionOriginalCase.Replace("/zip", "");
                }

                if (action.StartsWith("xml/channels/setasfavorite/"))
                {
                    string chanID = action.Replace("xml/channels/setasfavorite/", "");

                    string strResponse = (EPGManager.MakeChannelFavorite(chanID)) ? "OK" : "ERROR";
                    XMLresponse = XMLHelper.XMLReponseWithOutputString(strResponse);
                    if (Settings.Default.DebugChannels) Functions.WriteLineToLogFile("API: Set channel " + chanID + " as favorite OK.");
                }
                else if (action.StartsWith("xml/channels/unsetasfavorite/"))
                {
                    string chanID = action.Replace("xml/channels/unsetasfavorite/", "");

                    string strResponse = (EPGManager.MakeChannelNotFavorite(chanID)) ? "OK" : "ERROR";
                    XMLresponse = XMLHelper.XMLReponseWithOutputString(strResponse);
                    if (Settings.Default.DebugChannels) Functions.WriteLineToLogFile("API: Unset channel " + chanID + " as not favorite OK.");
                }
                else if (action == "xml/channels/all")
                {
                    // New 2011:  Update channels first from media center (MediaCenter can randomly change internal IDs)
                    EPGManager.UpdateTVChannels();

                    XMLresponse = EPGExporter.AllChannelsAsXML();
                    if (Settings.Default.DebugAdvanced) Functions.WriteLineToLogFile("Exporting all channels via XML web request...");
                }
                else if (action.StartsWith("xml/programmes"))
                {
                    string subAction = action.Replace("xml/programmes/", "");

                    // No description?  (turbo mode)
                    bool omitDescriptions = (subAction.StartsWith("nodescription"));
                    if (omitDescriptions)
                    {
                        subAction = subAction.Replace("nodescription/", "");
                    }

                    // If a programme type is specified, restrict to this type, otherwise use all
                    TVProgrammeType restrictProgrammesToType = (qsParams.HasParameter("programmetype")) ?
                        (TVProgrammeType)Enum.Parse(new TVProgrammeType().GetType(), qsParams["programmetype"], true) :
                        TVProgrammeType.All;

                    // 2. CHANNELS
                    List<string> TVServiceIDs = new List<string>();
                    if (subAction.StartsWith("limitchannels/"))
                    {
                        subAction = subAction.Replace("limitchannels/", "");
                        TVServiceIDs = Functions.StringListFromXML(PostObjects);
                    }
                    else if (subAction.StartsWith("favoritechannels/"))
                    {
                        subAction = subAction.Replace("favoritechannels/", "");
                        TVServiceIDs = EPGManager.EPGDisplayedTVChannelsServiceIDs;
                    }
                    else if (subAction.StartsWith("byepgrequest"))
                    {

                        List<EPGRequest> EPGRequests = EPGRequest.ArrayFromXML(PostObjects);

                        try
                        {
                            XMLresponse = EPGExporter.EPGwithEPGRequests(EPGRequests, omitDescriptions, restrictProgrammesToType);
                            if (Settings.Default.DebugAdvanced) Functions.WriteLineToLogFile("Exporting tv programmes (using " + EPGRequests.Count.ToString() + " epg requests) via XML web request...");
                        }
                        catch (Exception ex)
                        {
                            Functions.WriteLineToLogFile("CRITICAL ERROR - could not parse array of EPG requests.  Date passed was " + PostObjects);
                            Functions.WriteExceptionToLogFile(ex);
                        }
                    }

                    // 3. DATE / DAYRANGE
                    if (subAction.StartsWith("date/"))
                    {
                        string strDate = subAction.Replace("date/", "");
                        DateTime localDate = new DateTime();
                        if (DateTime.TryParse(strDate, out localDate))
                        {

                            XMLresponse = EPGExporter.EPGForLocalDate(localDate, TVServiceIDs, omitDescriptions, restrictProgrammesToType);
                            if (Settings.Default.DebugAdvanced) Functions.WriteLineToLogFile("Exporting tv programmes on " + TVServiceIDs.Count.ToString() + " channels for date " + strDate + " via XML web request...");
                        }
                        else
                        {
                            Functions.WriteLineToLogFile("CRITICAL ERROR - could not parse local date to export shows.  Date passed was " + strDate + ".");
                        }
                    }
                    else if (subAction.StartsWith("daterange/"))
                    {
                        string strDate = subAction.Replace("daterange/", "");
                        string[] dateRanges = strDate.Split(new string[] { "/" }, StringSplitOptions.None);
                        if (dateRanges.Count() > 1)
                        {
                            DateTime startDateTime, endDateTime;
                            if (DateTime.TryParse(dateRanges[0], out startDateTime) &&
                                DateTime.TryParse(dateRanges[1], out endDateTime)
                                )
                            {
                                if (Settings.Default.DebugAdvanced) Functions.WriteLineToLogFile("Exporting tv programmes on " + TVServiceIDs.Count.ToString() + " channels for date range " + strDate + " via XML web request...");
                                XMLresponse = EPGExporter.EPGForDateRange(startDateTime, endDateTime, TVServiceIDs, omitDescriptions, restrictProgrammesToType);
                            }
                            else
                            {
                                Functions.WriteLineToLogFile("CRITICAL ERROR - could not parse day ranges.");
                            }
                        }
                    }
                    else if (subAction.StartsWith("dayrange/"))
                    {
                        string strDate = subAction.Replace("dayrange/", "");

                        string[] dayRanges = strDate.Split(new string[] { "/" }, StringSplitOptions.None);
                        if (dayRanges.Count() > 1)
                        {
                            int startDaysAhead, numberOfDays;
                            if (int.TryParse(dayRanges[0], out startDaysAhead) &&
                                int.TryParse(dayRanges[1], out numberOfDays)
                                )
                            {
                                if (Settings.Default.DebugAdvanced) Functions.WriteLineToLogFile("Exporting tv programmes on " + TVServiceIDs.Count.ToString() + " channels for day range " + strDate + " via XML web request...");
                                XMLresponse = EPGExporter.EPGForDaysRange(startDaysAhead, numberOfDays, TVServiceIDs, omitDescriptions, restrictProgrammesToType);
                            }
                            else
                            {
                                Functions.WriteLineToLogFile("CRITICAL ERROR - could not parse day ranges.");
                            }
                        }
                    }
                    else if (subAction.StartsWith("search"))
                    {
                        EPGSearch theSearch = EPGSearch.FromXML(PostObjects);
                        if (theSearch != null)
                        {
                            XMLresponse = EPGExporter.TVProgrammesMatchingSearch(theSearch);

                            if (Settings.Default.DebugAdvanced) Functions.WriteLineToLogFile("Exporting all programmes matching search.");
                        }
                        else
                        {
                            Functions.WriteLineToLogFile("CRITICAL ERROR - could not parse search request XML");
                        }
                    }
                }
                else if (action.StartsWith("xml/programme/getinfo/"))
                {
                    string strUID = action.Replace("xml/programme/getinfo/", "");
                    if (Settings.Default.DebugAdvanced) Functions.WriteLineToLogFile("Exporting programme info blob for prog ID " + strUID + " via XML web request...");
                    XMLresponse = EPGExporter.TVProgrammeInfoBlobForProgID(strUID);
                }
                else if (action.StartsWith("xml/filebrowse/dir"))
                {
                    FileBrowseRequest fbrequest = FileBrowseRequest.FromXML(PostObjects);
                    if (fbrequest != null)
                    {
                        XMLresponse = FileBrowseExporter.FileBrowseUsingRequestAsXML(fbrequest);

                        if (Settings.Default.DebugAdvanced) Functions.WriteLineToLogFile("Exporting list of files matching request (path " + fbrequest.FullPath + ")");
                    }
                    else
                    {
                        Functions.WriteLineToLogFile("CRITICAL ERROR - could not parse file browse request XML");
                    }
                }
                else if (action.StartsWith("xml/recordings"))
                {
                    // FOR NOW.. ..refresh each time, although strictly may not be necessary
                    if (Settings.Default.RecordingsRetrieveAsParanoid) EPGManager.ReloadAllRecordings();

                    XMLresponse = EPGExporter.RecordingsBlobAsXML();
                    if (Settings.Default.DebugAdvanced) Functions.WriteLineToLogFile("Exporting all recordings via XML web request...");
                }
                else if (action.StartsWith("xml/settings"))
                {
                    XMLresponse = EPGExporter.AllSettingsAsXML();
                    if (Settings.Default.DebugAdvanced) Functions.WriteLineToLogFile("Exporting all settings via XML web request...");
                }
                else if (action.StartsWith("xml/record/byrecordingrequest"))
                {
                    RecordingRequest tReq = RecordingRequest.FromXML(PostObjects);

                    XMLresponse = EPGManager.ScheduleRecording(RecordingRequest.FromXML(PostObjects)).ToXML();
                }
                else if (action.StartsWith("xml/recordedtv"))
                {
                    /*if (action.Contains("refreshnow"))
                        RecTV.Default.RefreshCache(); */

                    XMLresponse = EPGExporter.AllRecordedTVAsXML();
                    if (Settings.Default.DebugAdvanced) Functions.WriteLineToLogFile("Exporting all recorded TV via XML web request...");
                }
                else if (action.StartsWith("xml/cancelrequest/"))
                {
                    string txtID = action.Replace("xml/cancelrequest/", "");
                    XMLresponse = WebSvcCancelRequest(txtID);
                }
                else if (action.StartsWith("xml/sendremotekey/"))
                {
                    string txtCmd = action.Replace("xml/sendremotekey/", "");

                    string strResponse = IRCommunicator.Default.SendIRCommand(txtCmd); // Returns OK or HELPER_NOT_RUNNING.  Doesn't return socket errors (it's ASync)
                    XMLresponse = XMLHelper.XMLReponseWithOutputString(strResponse);
                }
                else if (action.StartsWith("xml/showlog"))
                {
                    XMLresponse = "<?xml version=\"1.0\"?><log ";
                    if (Settings.Default.AllowRemoteLogRetrieval)
                    {
                        XMLresponse += "result=\"OK\" contents=\"" + FileCache.ReadTextFileFromDisk(Functions.DebugLogFileFN) + "\">";
                    }
                    else
                    {
                        XMLresponse += "result=\"Error\" contents=\"RemoteLoggingDisabled\">";
                    }

                    XMLresponse += "</log>";
                }
                else if (action.StartsWith("xml/cancelrecording/"))
                {
                    string txtID = action.Replace("xml/cancelrecording/", "");
                    XMLresponse = WebSvcCancelRecording(txtID);
                }
                else if (action.StartsWith("xml/realcancelrecording64/"))
                {
                    string filePath = "";
                    if (PostObjects.Trim().Length > 0)
                    {
                        filePath = HttpUtility.UrlDecode(PostObjects);
                        filePath = Functions.DecodeFromBase64(filePath, Encoding.UTF8);
                    }

                    XMLresponse = WebSvcRealCancelRecording64(filePath);
                }
                else if (action.StartsWith("xml/deletefile64"))
                {
                    string filePath = "";
                    if (PostObjects.Trim().Length > 0)
                    {
                        filePath = HttpUtility.UrlDecode(PostObjects);
                        filePath = Functions.DecodeFromBase64(filePath, Encoding.UTF8);
                    }

                    XMLresponse = WebSvcDeleteFileByFilePath(filePath);
                }
                else if (action.StartsWith("xml/deletefile"))
                {
                    string filePath = "";
                    if (PostObjects.Trim().Length > 0)
                        filePath = HttpUtility.UrlDecode(PostObjects);
                    else
                    {
                        // LEGACY - use URL path
                        filePath = action.Replace("xml/deletefile/", "");
                    }

                    XMLresponse = WebSvcDeleteFileByFilePath(filePath);
                }
                else if (action.StartsWith("xml/deletebackgroundtranscoded"))
                {
                    StreamingManager.Default.DeleteAllBackgroundTranscodedStreamingFiles();
                }
                else if (action.StartsWith("xml/mediastream/start/bymediastreamingrequestgetid"))
                {
                    MediaStreamingResult streamResult2 = new MediaStreamingResult();
                    MediaStreamingRequest streamRq = XMLHelper.Deserialize<MediaStreamingRequest>(PostObjects);

                    if (streamRq != null)
                    {
                        streamResult2.StreamerID = StreamingManager.Default.newUniqueID(streamRq, true);
                        streamResult2.LiveStreamingIndexPath = "/httplivestream/" + streamResult2.StreamerID + "/index.m3u8";
                        streamResult2.Success = true;
                    }
                    else
                    {
                        streamResult2.StreamerID = 0;
                        streamResult2.Success = false;
                    }

                    XMLresponse = XMLHelper.Serialize<MediaStreamingResult>(streamResult2);
                }
                else if (action.StartsWith("xml/mediastream/start/bymediastreamingrequest"))
                {
                    MediaStreamingResult streamResult;
                    MediaStreamingRequest streamRq = XMLHelper.Deserialize<MediaStreamingRequest>(PostObjects);

                    if (streamRq != null)
                        streamResult = StreamingManager.Default.StartStreamer(streamRq, Request.UserHostName);
                    else
                        streamResult = new MediaStreamingResult(MediaStreamingResultCodes.NamedError, "Error in streaming request.");

                    XMLresponse = XMLHelper.Serialize<MediaStreamingResult>(streamResult);
                }
                else if (action.StartsWith("xml/restartrp"))
                {
                    //88888
                    if (RestartRP != null)
                    {
                        RestartRP(this, e);
                        XMLresponse = XMLHelper.Serialize<String>("success");
                    }
                    else
                    {
                        XMLresponse = XMLHelper.Serialize<String>("failed");
                    }
                }
                else if (action.StartsWith("xml/killffmpeglatest"))
                {
                    Process[] workers = Process.GetProcessesByName("ffmpeglatest");
                    foreach (Process worker in workers)
                    {
                        worker.Kill();
                        worker.WaitForExit();
                        worker.Dispose();
                    }
                }
                else if (action.StartsWith("xml/livetvstop"))
                {
                    //foreach (string recTVFolder in Settings.Default.RecordedTVFolders)
                    //{
                    //    DirectoryInfo di = new DirectoryInfo(recTVFolder);
                    //    FileInfo[] files = null;
                    //    try
                    //    {
                    //        files = di.GetFiles("RMCLiveTV*.wtv");
                    //    }
                    //    catch (Exception e)
                    //    {
                    //        if (Settings.Default.DebugAdvanced) Functions.WriteLineToLogFile("You probably have a path defined in Recorded TV (RP settings) that does not exist. Exception " + e.ToString());
                    //    }
                    //    if (files != null)
                    //    {
                    //        for (int index = 0; index < files.Length; index++)
                    //        {
                    //            try
                    //            {
                    //                files[index].Delete();
                    //            }
                    //            catch (Exception)
                    //            {
                    //                //file was currently being read or something, just ignore
                    //            }
                    //        }
                    //    }
                    //}

                    Int32 ID;
                    action = action.Replace("xml/livetvstop/", "");

                    action = action.Replace("streamerid=", "");

                    Int32.TryParse(action, out ID);

                    bool stopped;
                    if (ID == 0)
                    {
                        stopped = false;
                    }
                    else
                    {
                        stopped = StreamingManager.Default.StopStreamer(ID, 4);
                    }

                    XMLresponse = XMLHelper.Serialize<string>("LiveTV does not always really stop, but stream " + ID + " is stopped=" + stopped);
                }
                else if (action.StartsWith("xml/getshowschedule"))
                //else if (action.StartsWith("livetv/getshowschedule"))        //suggestion as new syntax
                {
                    action = action.Replace("xml/getshowschedule/", "");
                    //action = action.Replace("livetv/getshowschedule/", "");

                    action = action.Replace("serviceid=", "");
                    string serviceID = action.Substring(0, action.IndexOf("starttime="));
                    action = action.Replace(serviceID, "");
                    action = action.Replace("starttime=", "");
                    long startTime = 0;
                    long.TryParse(action.Substring(0, action.IndexOf("duration=")), out startTime);

                    action = action.Replace("" + startTime, "");
                    action = action.Replace("duration=", "");
                    long duration = 0;
                    long.TryParse(action, out duration);

                    //ShowDebuggingInformationShowProgress:
                    EPGRequest request = new EPGRequest(serviceID, startTime, (startTime + duration));
                    List<EPGRequest> requests = new List<EPGRequest>();
                    requests.Add(request);

                    //TVService ds = new TVService();
                    //List<TVService> dss = new List<TVService>();
                    ////List<string> ServiceIDs = new List<string>();
                    ////List<string> _channels = new List<string>();
                    //TVProgramme progtvchannel = new TVProgramme();
                    //List<TVProgramme> progtvchannelz = new List<TVProgramme>();
                    //progtvchannelz.Add(progtvchannel);

                    var tvProgs = EPGManager.mcData.GetTVProgrammes(requests, false, TVProgrammeType.All);
                    List<string> scheduledshows = new List<string>();
                    string showinfo = "";
                    int firstshow = 0;
                    foreach (var tvProg in tvProgs)
                    {
                        TimeZone localzone = TimeZone.CurrentTimeZone;
                        var startingTime = localzone.ToLocalTime(new DateTime(tvProg.StartTime));
                        var endingTime = localzone.ToLocalTime(new DateTime(tvProg.StopTime));

                        if (firstshow == 0)
                        {
                            DateTime now = DateTime.Now;
                            TimeSpan currShowTime = now.Subtract(startingTime);
                            TimeSpan durationLeft = endingTime.Subtract(now);

                            showinfo = "Show Title: " + tvProg.Title + " Start time: " + String.Format("{0:MMM dd yyyy hh:mm:ss tt}", startingTime) + ". Ends at: " + String.Format("{0:MMM dd yyyy hh:mm:ss tt}", endingTime) + ". Current time: " + String.Format("{0:g}", currShowTime) + ". Time left: " + String.Format("{0:c}", durationLeft) + ". Timezone " + localzone.StandardName;
                            Functions.WriteLineToLogFile(showinfo);
                            firstshow++;
                            scheduledshows.Add(showinfo);
                        }
                        else
                        {
                            showinfo = "Show Title: " + tvProg.Title + ". Start time: " + String.Format("{0:MMM dd yyyy hh:mm:ss tt}", startingTime) + ". Ends at: " + String.Format("{0:MMM dd yyyy hh:mm:ss tt}", endingTime);
                            Functions.WriteLineToLogFile(showinfo);
                            scheduledshows.Add(showinfo);
                        }
                    }
                    XMLresponse = XMLHelper.Serialize<List<string>>(scheduledshows);

                }

                else if (action.StartsWith("xml/checkexists"))
                {
                    Int32 ID;
                    action = action.Replace("xml/checkexists/", "");

                    bool CheckInBackgroundTranscodedDirectory = action.Contains("streamtranscodedinbackground=");

                    if (CheckInBackgroundTranscodedDirectory)
                    {
                        int pos = action.IndexOf("streamtranscodedinbackground=", 0);
                        string action2 = action.Replace(action.Substring(0, "streamtranscodedinbackground=".Length), "");
                        action2 = action2.Replace("/index.m3u8", "");
                        action2 = action2.Replace("/index2.m3u8", "");

                        Int32.TryParse(action2, out ID);
                        action = "segment-0.ts";
                    }
                    else
                    {
                        action = action.Replace("streamid=", "");

                        int pos = action.IndexOf("/segment=", 0);
                        string action2 = action.Replace(action.Substring(pos, action.Length - pos), "");

                        Int32.TryParse(action2, out ID);

                        action = action.Replace(ID + "/segment=", "");
                    }
                    string dir = Functions.AppDataFolder;
                    string streamPath;
                    if (CheckInBackgroundTranscodedDirectory)
                    {
                        streamPath = Path.Combine(dir, "static\\BackgroundTranscodedMediastreams\\");
                    }
                    else
                    {
                        streamPath = Path.Combine(dir, "static\\mediastreams\\");
                    }

                    DirectoryInfo di = new DirectoryInfo(streamPath + ID);
                    FileInfo[] files = null;
                    try
                    {
                        files = di.GetFiles(action);
                    }
                    catch (Exception e)
                    {
                        if (Settings.Default.DebugAdvanced) Functions.WriteLineToLogFile(e.ToString());
                        XMLresponse = XMLHelper.Serialize<string>("failure");
                    }
                    try
                    {
                        if (files != null && files[0].Exists)
                        {
                            XMLresponse = XMLHelper.Serialize<string>("success");
                        }
                        else
                        {
                            XMLresponse = XMLHelper.Serialize<string>("failure");
                        }
                    }
                    catch (Exception e)
                    {
                        XMLresponse = XMLHelper.Serialize<string>("failure");
                    }
                }
                else if (action.StartsWith("xml/setrprecstreamid/"))
                {
                    //ToDo: Have to define an API that conforms to the rest of the API!
                    //

                    // GET rprec ID and streamID
                    action = action.Replace("xml/setrprecstreamid/", "");

                    long rprecId = 0;
                    long.TryParse((action.Substring(0, action.IndexOf("streamid="))), out rprecId);

                    action = action.Replace("" + rprecId, "");
                    action = action.Replace("streamid=", "");

                    long streamId = 0;
                    long.TryParse(action, out streamId);

                    EPGManager.setStreamID(rprecId, streamId);
                    if (Settings.Default.DebugAdvanced)
                        Functions.WriteLineToLogFile("Setting recording " + rprecId + " to streamID " + streamId);
                }
                //else if (action.StartWith("xml/startlivetv"))     //suggestion
                else if (action.StartsWith("xml/livetv"))
                {
                    //ToDo: Have to define an API that conforms to the rest of the API!
                    //

                    XMLresponse = "";
                    RecordingRequest newRR = null;
                    bool failedValidation = false;
                    string failedValidationReason = "";

                    string filenameId = "RMCLiveTV";

                    // GET SERVICE ID (Channel) and length
                    action = action.Replace("xml/livetv/", "");

                    string serviceId = action.Substring(0, action.IndexOf("uniqueandroid="));

                    action = action.Replace(serviceId, "");
                    action = action.Replace("uniqueandroid=", "");

                    string uniqueAndroidId = action.Substring(0, action.IndexOf("length="));

                    // DURATION
                    Int32 tryDuration;
                    Int32.TryParse(action.Substring(action.IndexOf("length=") + 7), out tryDuration);
                    DateTime tryStartTime = DateTime.Now;

                    //  Schedule manual recording
                    // DATE TIME

                    if ((tryDuration == 0) | (tryDuration > 720))
                    {
                        failedValidation = true;
                        failedValidationReason += "Invalid duration, must be between 1 and 720 minutes.<br>";
                    }

                    // In the unliklely event a file already exist with a certain random nr, try again:
                    bool randomFileAlreadyExists = false;
                    do
                    {
                        Random r = new Random();
                        filenameId = filenameId + uniqueAndroidId + r.Next(0, int.MaxValue);
                        string[] filePaths = null;
                        foreach (string recTVFolder in Settings.Default.RecordedTVFolders)
                        {
                            try
                            {
                                filePaths = Directory.GetFiles(recTVFolder, filenameId + "*.wtv");
                            }
                            catch (Exception e)
                            {
                                if (Settings.Default.DebugAdvanced)
                                    Functions.WriteLineToLogFile(
                                        "You probably have a path defined in Recorded TV (RP settings) that does not exist. Exception " +
                                        e.ToString());
                            }
                            if (filePaths.Length > 0)
                            {
                                randomFileAlreadyExists = true;
                                break;
                            }
                        }
                    } while (randomFileAlreadyExists);

                    // Create a new recording request
                    newRR = new RecordingRequest(tryStartTime.ToUniversalTime(), long.Parse(serviceId), tryDuration,
                                                 filenameId);

                    // Passed validation?
                    if (failedValidation)
                    {
                        if (Settings.Default.DebugAdvanced) Functions.WriteLineToLogFile("FailedValidation");
                        txtResponse += "<p class='recorderror'>Error in recording request: " + failedValidationReason +
                                       "</p>";
                        XMLresponse = XMLHelper.Serialize<string>(txtResponse);
                    }
                    else
                    {
                        if (Settings.Default.DebugAdvanced) Functions.WriteLineToLogFile("Did not fail Validation");

                        qsParams.Add("queueid", RecordingQueue.AddToQueue(newRR));
                        string txtRecSummary2;
                        if (RecordFromQueue(out txtRecSummary2))
                        {
                            bool found = false;
                            if (txtRecSummary2.Contains("The scheduling was successful"))
                            {
                                if (RecordFromQueueResult != null)
                                {
                                    if (Settings.Default.DebugAdvanced) Functions.WriteLineToLogFile(RecordFromQueueResult);
                                    if (!RecordFromQueueResult.StartsWith("Recording not scheduled"))
                                    {
                                        if (Settings.Default.DebugAdvanced)
                                            Functions.WriteLineToLogFile("RecordFromQueue=True");
                                        int waittimeforfiletoappear = 20; // seconds
                                        //int waittimeforfiletoappear = 200; // seconds, testing whether setting needs high value for certain tv card like Ceton
                                        DateTime begin = DateTime.Now;
                                        string[] filepaths = null;
                                        int i = 0;
                                        do
                                        {
                                            foreach (string rectvfolder in Settings.Default.RecordedTVFolders)
                                            {
                                                if ((i % 1000 == 0) && (Settings.Default.DebugAdvanced))
                                                    Functions.WriteLineToLogFile("Checking " + rectvfolder + " for " +
                                                                                 filenameId + "*.wtv");
                                                i++;
                                                try
                                                {
                                                    filepaths = Directory.GetFiles(rectvfolder, filenameId + "*.wtv");
                                                }
                                                catch (Exception e)
                                                {
                                                    if (Settings.Default.DebugAdvanced)
                                                        Functions.WriteLineToLogFile(
                                                            "You probably have a path defined in Recorded TV (RP settings) that does not exist. Exception " +
                                                            e.ToString());
                                                }
                                                if (filepaths != null && filepaths.Length > 0)
                                                {
                                                    if (Settings.Default.DebugAdvanced)
                                                        Functions.WriteLineToLogFile("Found recording tv folder..." +
                                                                                     filepaths[0]);
                                                    break;
                                                }
                                            }

                                            if (filepaths != null && filepaths.Length > 0)
                                            {
                                                XMLresponse = XMLHelper.Serialize<string>(filepaths[0]);
                                                found = true;
                                                break;
                                            }

                                            if (DateTime.Compare(begin.AddSeconds(waittimeforfiletoappear), DateTime.Now) <
                                                0) //not found after 20 seconds
                                            {
                                                if (Settings.Default.DebugAdvanced)
                                                {
                                                    foreach (string rectvfolder in Settings.Default.RecordedTVFolders)
                                                    {
                                                        string[] filepaths2 = Directory.GetFiles(rectvfolder, "*.*");
                                                        foreach (string fp in filepaths2)
                                                        {
                                                            Functions.WriteLineToLogFile("However, this does exist :" + fp);
                                                        }
                                                    }
                                                }
                                                break;
                                            }
                                        } while (true);
                                    }
                                }
                                else
                                {
                                    if (Settings.Default.DebugAdvanced)
                                        Functions.WriteLineToLogFile("strange: RecordFromQueueResult is null");
                                }
                            }
                            if (!found)
                            {
                                List<string> errors = new List<string>();
                                if (Settings.Default.DebugAdvanced)
                                    Functions.WriteLineToLogFile("All tuners are busy somewhere in between now and " +
                                                                 tryDuration + " minutes from now");
                                errors.Add("All tuners are busy somewhere in between now and " + tryDuration +
                                           " minutes from now");
                                DateRange dateRange = new DateRange(DateTime.UtcNow,
                                                                    DateTime.UtcNow.AddMinutes(tryDuration));
                                if (Settings.Default.DebugAdvanced)
                                    Functions.WriteLineToLogFile("Going to find conflicting recordings");
                                List<RPRecording> recsToday = EPGManager.AllRecordingsRunningInTimeFrame(dateRange);
                                //List<RPRecording> oldLiveTVrecs = EPGManager.AllRecordingsContainsTitle("RMCLiveTV");
                                foreach (RPRecording rec in recsToday)
                                {
                                    if (Settings.Default.DebugAdvanced)
                                        Functions.WriteLineToLogFile("Recording: not found!, conflicting: " + rec.Title +
                                                                     " Are your recording folders in Remote Potato RP server (the general tab click on \"recorded TV\") and Media Center (tasks/setings/TV/Recorder) the same?");
                                    //if (rec.TVProgramme().StartTime <= (tryStartTime.Ticks + tryDuration * TimeSpan.TicksPerMinute))
                                    {
                                        errors.Add(rec.Id.ToString());
                                        errors.Add(rec.Title);
                                        errors.Add(rec.TVProgramme().TVService().Callsign);
                                        errors.Add(rec.TVProgramme().StartTime.ToString());
                                        errors.Add(rec.TVProgramme().StopTime.ToString());
                                        //errors.Add(rec.TVProgramme().Filename);
                                    }
                                }
                                if (Settings.Default.DebugAdvanced && errors.Count == 0)
                                    Functions.WriteLineToLogFile(
                                        "mmm, this is strange: no recordings in recording folder beginning with RMCLiveTV");
                                XMLresponse = XMLHelper.Serialize<List<string>>(errors);
                            }
                            //Could wait for event (for file to appear) instead...
                            //WTVfse = new FileSystemEventHandler(OnChanged);
                            //foreach (string location in Settings.Default.RecordedTVFolders)
                            //{
                            //    FileSystemWatcher w = new FileSystemWatcher();
                            //    w.Path = location;
                            //    /* Watch for changes in LastAccess and LastWrite times, and
                            //       the renaming of files or directories. */
                            //    w.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite
                            //       | NotifyFilters.FileName | NotifyFilters.DirectoryName;
                            //    // Only watch filter.
                            //    w.Filter = filenameID + "*.wtv";

                            //    w.Created += WTVfse;
                            //    WTVwatcher.Add(w);
                            //}
                            //// Begin watching.
                            //foreach (FileSystemWatcher w in WTVwatcher)
                            //{
                            //    w.EnableRaisingEvents = true;
                            //}
                            //do { } while (!LiveTVScheduled);
                            //XMLresponse = XMLHelper.Serialize<string>(LiveTVFilename);
                        }
                        else
                        {
                            if (Settings.Default.DebugAdvanced) Functions.WriteLineToLogFile("RecordFromQueue=False");
                        }
                    }

                }
                else if (action.StartsWith("xml/mediastream/probe/byfilename"))
                {
                    string strFileName = HttpUtility.UrlDecode(PostObjects);
                    strFileName = strFileName.Trim();

                    if (action.StartsWith("xml/mediastream/probe/byfilename64"))
                        strFileName = Functions.DecodeFromBase64(strFileName);

                    List<AVStream> result;
                    if (strFileName.Length > 0)
                        result = StreamingManager.Default.ProbeFile(strFileName);
                    else
                        result = new List<AVStream>();

                    if (Settings.Default.DebugStreaming)
                        Functions.WriteLineToLogFile("Probed file " + strFileName + ": sending back details of " +
                                                     result.Count.ToString() + " AV streams.");

                    XMLresponse = XMLHelper.Serialize<List<AVStream>>(result);
                }
                else if (action.StartsWith("xml/mediastream/keepalive/"))
                {
                    string strStreamerID = action.Replace("xml/mediastream/keepalive/", "");
                    int streamerID;
                    string strmStatus;
                    if (int.TryParse(strStreamerID, out streamerID))
                    {
                        strmStatus = StreamingManager.Default.KeepStreamerAliveAndReturnStatus(streamerID);
                    }
                    else
                    {
                        Functions.WriteLineToLogFile("Warning: Could not parse streamer ID " + strStreamerID);
                        strmStatus = "invalid_id";
                    }

                    //XMLresponse = XMLHelper.XMLReponseWithOutputString(strmStatus);
                    XMLresponse = strmStatus;
                    if (Settings.Default.DebugAdvanced)
                        Functions.WriteLineToLogFile("MediaStreaming: GetStatus  (" + strStreamerID + "): " + strmStatus);
                }
                else if (action.StartsWith("xml/mediastream/stop/"))
                {
                    string strStreamerID = action.Replace("xml/mediastream/stop/", "");
                    int streamerID;
                    try
                    {
                        if (int.TryParse(strStreamerID, out streamerID))
                        {
                            if (!StreamingManager.Default.StopStreamer(streamerID, 5))
                                Functions.WriteLineToLogFile("Warning in stopping mediastream: Could not stop streamer ID " + strStreamerID);
                        }
                        else
                        {
                            Functions.WriteLineToLogFile("Warningin stopping mediastream2: Could not parse streamer ID " + strStreamerID);
                        }
                    }
                    catch (Exception ex)
                    {
                        Functions.WriteExceptionToLogFileIfAdvanced(ex);
                    }

                    XMLresponse = XMLHelper.XMLReponseWithOutputString("No Data");
                }
                else if (action.StartsWith("xml/stream/start"))
                {
                    WTVStreamingVideoResult streamResult;
                    WTVStreamingVideoRequest streamRq = XMLHelper.Deserialize<WTVStreamingVideoRequest>(PostObjects);
                    if (streamRq == null)
                    {
                        streamResult = new WTVStreamingVideoResult(DSStreamResultCodes.ErrorInStreamRequest);
                    }
                    else
                    {
                        try
                        {
                            streamResult = DSStreamingManager.Default.StartStreamer(streamRq);
                        }
                        catch (Exception e)
                        {
                            Functions.WriteLineToLogFile("Exception setting up streaming object:");
                            Functions.WriteExceptionToLogFile(e);
                            streamResult = new WTVStreamingVideoResult(DSStreamResultCodes.ErrorExceptionOccurred,
                                                                       e.Message);
                        }
                    }

                    XMLresponse = XMLHelper.Serialize<WTVStreamingVideoResult>(streamResult);
                }
                else if (action.StartsWith("xml/stream/stop"))
                {
                    XMLresponse = XMLHelper.XMLReponseWithOutputString("ERROR (DEPRECATED)");
                }
                else if (action.StartsWith("xml/picture/thumbnailzip/"))
                {
                    FileBrowseRequest fbrequest = FileBrowseRequest.FromXML(PostObjects);
                    if (fbrequest != null)
                    {
                        if (PictureExporter.SendThumbnailsAsZipFile(fbrequest, FatAttitude.ThumbnailSizes.Small,
                                                                    ref browserSender))
                            return;
                        else
                        {
                            if (Settings.Default.DebugAdvanced)
                                Functions.WriteLineToLogFile("Could not export zip of thumbnails.");
                            browserSender.Send404Page();
                        }
                    }
                    else
                    {
                        Functions.WriteLineToLogFile(
                            "ThumbnailZip: Error in requestprocessor- could not parse file browse request XML");
                    }
                }
                else if (action.StartsWith("xml/picture/get")) // matches /xml/picture/getrequest too
                {
                    string strSubAction = txtActionOriginalCase.Replace("xml/picture/", "");

                    // URL DECODE
                    strSubAction = HttpUtility.UrlDecode(strSubAction);

                    string strParams;
                    string strFileName = "";
                    bool fileNameAtEndOfUri = false;
                    bool fileNameAtEndOfUriIsBase64Encoded = false;
                    if (strSubAction.StartsWith("getwithfilename")) // GET FILENAME FROM URL
                    {
                        fileNameAtEndOfUri = true;

                        fileNameAtEndOfUriIsBase64Encoded = strSubAction.StartsWith("getwithfilename64");

                        if (fileNameAtEndOfUriIsBase64Encoded)
                            strParams = strSubAction.Replace("getwithfilename64/", "");
                        else
                            strParams = strSubAction.Replace("getwithfilename/", "");
                    }
                    else
                    // GET FILENAME FROM POST STRING
                    {
                        fileNameAtEndOfUri = false;
                        strFileName = PostObjects;
                        strParams = strSubAction.Replace("get/", "");
                    }

                    string[] Params = strParams.Split(new string[] { "/" }, StringSplitOptions.None);

                    bool haveFrameSizes = false;
                    int frameWidth = 0;
                    int frameHeight = 0;
                    if (Params.Count() > 1)
                    {
                        if ((int.TryParse(Params[0], out frameWidth) &&
                             int.TryParse(Params[1], out frameHeight)
                            ))
                            haveFrameSizes = ((frameWidth > 0) && (frameHeight > 0));
                        else
                            haveFrameSizes = false;
                    }
                    else
                        // Send full picture
                        haveFrameSizes = false;

                    if (!haveFrameSizes)
                        Functions.WriteLineToLogFile(
                            "Xml/Picture: invalid frame size (or none supplied): using full picture");

                    if (Settings.Default.DebugAdvanced)
                        Functions.WriteLineToLogFile("Exporting picture " + strFileName + " resized to frame " +
                                                     frameWidth.ToString() + "x" + frameHeight.ToString());

                    // Get Filename if not got already
                    // File name from Uri ?
                    if (fileNameAtEndOfUri)
                    {
                        if (fileNameAtEndOfUriIsBase64Encoded)
                        {
                            // Take final component and un-encode to produce filename
                            strFileName = Params[Params.Count() - 1];
                            strFileName = HttpUtility.UrlDecode(strFileName);
                            strFileName = Functions.DecodeFromBase64(strFileName);
                        }
                        else
                        {
                            // Reconstruct filename by putting /slashed/ components back together
                            for (int pCount = 2; pCount < Params.Count(); pCount++)
                            {
                                strFileName = strFileName + Params[pCount];
                                if (pCount < (Params.Count() - 1))
                                    strFileName = strFileName + "/";

                                strFileName = HttpUtility.UrlDecode(strFileName);
                            }
                        }

                    }

                    if (string.IsNullOrEmpty(strFileName))
                    {
                        Functions.WriteLineToLogFile("Xml/Picture : No filename specified in POST request, sending 404");
                        browserSender.Send404Page();
                        return;
                    }

                    // Send
                    if (haveFrameSizes)
                    {

                        byte[] resizedPictureData = new byte[] { };
                        if (ImageResizer.ResizePicture(strFileName, new Size(frameWidth, frameHeight),
                                                       out resizedPictureData, ImageFormat.Jpeg, false))
                        {
                            browserSender.SendDataToBrowser(Functions.MimeTypeForFileName(strFileName),
                                                            resizedPictureData);
                            return;
                        }
                        else
                        {
                            Functions.WriteLineToLogFile("Xml/Picture: Could not resize picture.");
                            browserSender.Send404Page();
                            return;
                        }
                    }
                    else // No frame sizes, send full image
                    {
                        browserSender.SendFileToBrowser(strFileName);
                        return;
                    }

                }
                else if (action.StartsWith("xml/music/framework"))
                {
                    using (WMPManager manager = new WMPManager())
                    {
                        XMLresponse = manager.MusicFrameworkAsXML();
                        if (Settings.Default.DebugAdvanced)
                            Functions.WriteLineToLogFile("Exporting music framework blob via XML web request...");
                    }
                }
                else if (action.StartsWith("xml/music/songs/artist"))
                {
                    bool isBase64Encoded = (action.Contains("artist64/"));
                    action = action.Replace("artist64", "artist");
                    txtActionOriginalCase = txtActionOriginalCase.Replace("artist64", "artist");

                    string strArtistID = txtActionOriginalCase.Replace("xml/music/songs/artist/", "");
                    strArtistID = HttpUtility.UrlDecode(strArtistID);

                    if (isBase64Encoded)
                        strArtistID = Functions.DecodeFromBase64(strArtistID);

                    using (WMPManager manager = new WMPManager())
                    {
                        XMLresponse = manager.GetSongsForArtistAsXML(strArtistID);
                        if (Settings.Default.DebugAdvanced)
                            Functions.WriteLineToLogFile("Exporting songs for artist " + strArtistID +
                                                         " via XML web request...");
                    }
                }
                else if (action.StartsWith("xml/music/songs/album"))
                {
                    bool isBase64Encoded = (action.Contains("album64/"));
                    action = action.Replace("album64", "album");
                    txtActionOriginalCase = txtActionOriginalCase.Replace("album64", "album");

                    // USE case sensitive action string for match
                    string strAlbumID = txtActionOriginalCase.Replace("xml/music/songs/album/", "");
                    strAlbumID = HttpUtility.UrlDecode(strAlbumID);

                    if (isBase64Encoded)
                        strAlbumID = Functions.DecodeFromBase64(strAlbumID);

                    using (WMPManager manager = new WMPManager())
                    {
                        XMLresponse = manager.GetSongsForAlbumAsXML(strAlbumID);
                        if (Settings.Default.DebugAdvanced)
                            Functions.WriteLineToLogFile("Exporting songs for album " + strAlbumID +
                                                         " via XML web request...");
                    }
                }
                else if (action.StartsWith("xml/music/songs/genre"))
                {
                    bool isBase64Encoded = (action.Contains("genre64/"));
                    action = action.Replace("genre64", "genre");
                    txtActionOriginalCase = txtActionOriginalCase.Replace("genre64", "genre");

                    // USE case sensitive action string for match
                    string strGenreID = txtActionOriginalCase.Replace("xml/music/songs/genre/", "");
                    strGenreID = HttpUtility.UrlDecode(strGenreID);

                    if (isBase64Encoded)
                        strGenreID = Functions.DecodeFromBase64(strGenreID);

                    using (WMPManager manager = new WMPManager())
                    {
                        XMLresponse = manager.GetSongsForGenreAsXML(strGenreID);
                        if (Settings.Default.DebugAdvanced)
                            Functions.WriteLineToLogFile("Exporting songs for genre " + strGenreID +
                                                         " via XML web request...");
                    }
                }
                else if (action.StartsWith("xml/music/songs/all"))
                {

                    using (WMPManager manager = new WMPManager())
                    {
                        XMLresponse = manager.GetAllSongsAsXML();
                        if (Settings.Default.DebugAdvanced)
                            Functions.WriteLineToLogFile("Exporting all songs in library via XML web request...");
                    }
                }
                else if (action.StartsWith("xml/music/songs/checkexists"))
                {
                    bool isBase64Encoded = (action.Contains("checkexists64/"));
                    action = action.Replace("checkexists64", "checkexists");
                    txtActionOriginalCase = txtActionOriginalCase.Replace("checkexists64", "checkexists");

                    // USE case sensitive action string for match
                    string strSongID = txtActionOriginalCase.Replace("xml/music/songs/checkexists/", "");
                    strSongID = HttpUtility.UrlDecode(strSongID);

                    if (isBase64Encoded)
                        strSongID = Functions.DecodeFromBase64(strSongID);

                    using (WMPManager manager = new WMPManager())
                    {
                        XMLresponse = manager.WMPItemFileExistsAsXML(strSongID);
                        if (Settings.Default.DebugAdvanced)
                            Functions.WriteLineToLogFile("Exporting whether song exists... " + XMLresponse);
                    }
                }
                else
                {

                    Functions.WriteLineToLogFile("XML: Unknown request");
                    XMLresponse = "";
                }

                if (String.IsNullOrEmpty(XMLresponse))
                {
                    Functions.WriteLineToLogFile("NULL xmlresponse - nothing to send out to Silverlight client.  Sending error string.");
                    browserSender.SendStringToBrowser(XMLHelper.XMLReponseWithOutputString("No Data"));
                    return;
                }

                // Strip out any UTF-16 encoding
                XMLresponse = Functions.StripIllegalXmlCharacters(XMLresponse);

                // Zip up ?
                if (zipContent)
                {
                    Functions.logAPIoutputString(XMLresponse);
                    XMLresponse = ZipHelper.ZipString(XMLresponse);

                    if (Settings.Default.DebugServer)
                        Functions.WriteLineToLogFile("Zipped String to base64 string.  Length:" + XMLresponse.Length.ToString() + " characters. ");

                    browserSender.SendZipStringToBrowser(XMLresponse);
                }
                else
                    browserSender.SendXMLToBrowser(XMLresponse);
            }
            catch (Exception e)
            {
                string errorResponse = XMLHelper.XMLReponseWithOutputString("An error occurred - " + e.Message + " - check the debug log on the server.");

                Functions.WriteLineToLogFile("Exception while processing XML request:");
                Functions.WriteExceptionToLogFile(e);

                browserSender.SendXMLToBrowser(errorResponse);

            }
        }
Example #3
0
        // Main public method - Begin Streaming
        public WTVStreamingVideoResult StreamWithFileAndPort(WTVStreamingVideoRequest svrq, int streamPort, bool removeReferenceClock, bool autodetectPal)
        {
            WTVStreamingVideoResult result = new WTVStreamingVideoResult();
            // Attempting this port
            result.Port = streamPort.ToString();

            // Store values locally for use by other class methods
            StreamingRequest = svrq;
            StreamPort = streamPort;
            RemoveReferenceClock = removeReferenceClock;

            // Build the graph using the base class
            DSStreamResultCodes resultCode = base.InitWithFile( StreamingRequest);
            if (resultCode != DSStreamResultCodes.OK)
                return new WTVStreamingVideoResult(resultCode);

            // Add streaming
            try
            {
                AddStreamSinkToCurrentOutputFilter(StreamPort);
            }
            catch (Exception ex)
            {
                result.ResultCode = DSStreamResultCodes.ErrorAlreadyStreaming;
                result.ResultString = ex.Message;
                return result;
            }

            // Remove clock?
            try
            {
                if (RemoveReferenceClock)
                    RemoveRefClockFromGraph();
            }
            catch (Exception ex)
            {
                result.ResultCode = DSStreamResultCodes.Error;
                result.ResultString = "Error removing reference clock: " + ex.Message;
                return result;
            }

            // Seek?
            try
            {
                if (StreamingRequest.StartAt.TotalSeconds > 0)
                    SeekGraphToTime(StreamingRequest.StartAt);
                else
                    SeekGraphToTime(TimeSpan.FromSeconds(5)); // EXPERIMENTAL
            }
            catch
            {
                // Ignore non-seeking errors for now
            }

            // Begin streaming the graph in a separate thread
            graphStartedEvent.Reset();
            thStreamThread = new Thread(new ThreadStart(DoStreamWithFileAndPort));
            thStreamThread.SetApartmentState(ApartmentState.MTA);  // NetworkSink fails in STA threads - avoid!
            thStreamThread.Name = "StreamFile1";
            thStreamThread.Start();

            // Wait for graph to attempt to start so we can report back
            bool gotSignal = ( graphStartedEvent.WaitOne(6000));

            if (gotSignal)
            {
                if (graphIsRunning)
                {
                    result.ResultCode = DSStreamResultCodes.OK;
                    return result;
                }
                else
                {
                    result.ResultCode = DSStreamResultCodes.Error;
                    result.ResultString = "DSStreamer: Graph could not run - see server log for more information.";
                    return result;
                }
            }
            else
            {
                result.ResultCode = DSStreamResultCodes.Error;
                result.ResultString = "DSStreamer: Timed out waiting for graph to run - there may be more information in the server log.";
                return result;
            }
        }
Example #4
0
        // Main public method - Begin Streaming
        public WTVStreamingVideoResult StreamWithFileAndPort(WTVStreamingVideoRequest svrq, int streamPort, bool removeReferenceClock, bool autodetectPal)
        {
            WTVStreamingVideoResult result = new WTVStreamingVideoResult();

            // Attempting this port
            result.Port = streamPort.ToString();

            // Store values locally for use by other class methods
            StreamingRequest     = svrq;
            StreamPort           = streamPort;
            RemoveReferenceClock = removeReferenceClock;

            // Build the graph using the base class
            DSStreamResultCodes resultCode = base.InitWithFile(StreamingRequest);

            if (resultCode != DSStreamResultCodes.OK)
            {
                return(new WTVStreamingVideoResult(resultCode));
            }

            // Add streaming
            try
            {
                AddStreamSinkToCurrentOutputFilter(StreamPort);
            }
            catch (Exception ex)
            {
                result.ResultCode   = DSStreamResultCodes.ErrorAlreadyStreaming;
                result.ResultString = ex.Message;
                return(result);
            }

            // Remove clock?
            try
            {
                if (RemoveReferenceClock)
                {
                    RemoveRefClockFromGraph();
                }
            }
            catch (Exception ex)
            {
                result.ResultCode   = DSStreamResultCodes.Error;
                result.ResultString = "Error removing reference clock: " + ex.Message;
                return(result);
            }

            // Seek?
            try
            {
                if (StreamingRequest.StartAt.TotalSeconds > 0)
                {
                    SeekGraphToTime(StreamingRequest.StartAt);
                }
                else
                {
                    SeekGraphToTime(TimeSpan.FromSeconds(5)); // EXPERIMENTAL
                }
            }
            catch
            {
                // Ignore non-seeking errors for now
            }


            // Begin streaming the graph in a separate thread
            graphStartedEvent.Reset();
            thStreamThread = new Thread(new ThreadStart(DoStreamWithFileAndPort));
            thStreamThread.SetApartmentState(ApartmentState.MTA);  // NetworkSink fails in STA threads - avoid!
            thStreamThread.Name = "StreamFile1";
            thStreamThread.Start();

            // Wait for graph to attempt to start so we can report back
            bool gotSignal = (graphStartedEvent.WaitOne(6000));

            if (gotSignal)
            {
                if (graphIsRunning)
                {
                    result.ResultCode = DSStreamResultCodes.OK;
                    return(result);
                }
                else
                {
                    result.ResultCode   = DSStreamResultCodes.Error;
                    result.ResultString = "DSStreamer: Graph could not run - see server log for more information.";
                    return(result);
                }
            }
            else
            {
                result.ResultCode   = DSStreamResultCodes.Error;
                result.ResultString = "DSStreamer: Timed out waiting for graph to run - there may be more information in the server log.";
                return(result);
            }
        }