Example #1
0
        public bool ScheduleRecording(RecordingRequest rr, out RPRequest rpRequest, out RecordingResult earlyFailureResult)
        {
            EventWaitHandle ewhScheduleRecording = new EventWaitHandle(false, EventResetMode.AutoReset);

            storeManager.ScheduleRecording(rr, ewhScheduleRecording);
            ewhScheduleRecording.WaitOne(TimeSpan.FromSeconds(500));

            // Destroy the stargate
            ewhScheduleRecording = null;

            DebugNormal("MCData: schedulerecording finished, storeManager.ScheduleInitialSucceeded:" + storeManager.ScheduleInitialSucceeded);
            if (!storeManager.ScheduleInitialSucceeded)
            {
                rpRequest          = null;
                earlyFailureResult = storeManager.ScheduleInitialFailureResult;
                return(false);
            }
            else
            {
                // Retrieve the shared objects that were generated

                rpRequest = Conversion.RPRequestFromRequest(storeManager.requestInProgress);  // THIS IS ERRORING

                earlyFailureResult = null;
            }

            return(true);
        }
        public static bool ExtractFromQueue(int id, ref RecordingRequest rr)
        {
            if (!RQueue.ContainsKey(id))
                return false;

            rr = RQueue[id];
            return true;
        }
        public static string AddToQueue(RecordingRequest rr)
        {
            int newID = idCounter++;

            RQueue.Add(newID, rr);

            return newID.ToString();
        }
Example #4
0
        public static RecordingRequest FromXML(string theXML)
        {
            RecordingRequest newRR      = new RecordingRequest();
            XmlSerializer    serializer = new XmlSerializer(newRR.GetType());
            StringReader     sr         = new StringReader(theXML);

            try
            {
                return((RecordingRequest)serializer.Deserialize(sr));
            }
            catch
            {
                return(newRR);
            }
        }
Example #5
0
 public static RecordingRequest FromXML(string theXML)
 {
     RecordingRequest newRR = new RecordingRequest();
     XmlSerializer serializer = new XmlSerializer(newRR.GetType());
     StringReader sr = new StringReader(theXML);
     try
     {
         return (RecordingRequest)serializer.Deserialize(sr);
     }
     catch
     {
         return newRR;
     }
 }
        private static bool scheduleRecordingForHTML(RecordingRequest rr, out string txtScheduleResult)
        {
            txtScheduleResult = "Unknown result.";
            if (!EPGManager.isWMCOnline) return false;

            RecordingResult recresult = EPGManager.ScheduleRecording(rr);

            if (recresult.Success)
            {
                txtScheduleResult = RecordingResult.FriendlySuccessReport(recresult);

                if (rr.RequestType != RecordingRequestType.Manual)
                    txtScheduleResult += ListOfRecordingsAsHTML(ref recresult.GeneratedRecordingsBlob.RPRecordings, DateRangeType.All, false, true, true, true);
            }
            else
            {
                txtScheduleResult = RecordingResult.FriendlyFailureReason(recresult);
            }

            return true;
        }
        private bool ViewEPGProgramme()
        {
            txtPageTitle = "Programme Details";

            if (!EPGManager.isWMCOnline)
            {
                txtResponse = "No EPG is configured.  You will need to enable this option in settings on the server and ensure that you have a valid provider of EPG information set up.";
                return false;
            }

            if (!(qsParams.HasParameter("programmeid")))
            {
                txtResponse += "No programme ID parameter specified.";
                return false;
            }

            bool getFromFile = (qsParams.HasParameter("getfromrecordedtvfiles"));
            string programmeID = qsParams["programmeid"];

            if (programmeID == "-10")
            {
                txtResponse = "Details of manual recordings cannot currently be viewed within Remote Potato.";
                return true;
            }

            CommonEPG.TVProgramme tvp = null;
            if (getFromFile)
                RecTV.Default.RecordedTVProgrammes.TryGetValue(programmeID, out tvp);
            else
                tvp = EPGManager.mcData.GetTVProgramme(programmeID);

            if (tvp == null)
            {
                txtResponse += "Could not find this show in the EPG.";
                return false;
            }

            CommonEPG.TVService tvs = tvp.TVService();
            if ( (!getFromFile) & ( tvs == null) )
            {
                txtResponse += "Could not find the TV channel for this programme in the EPG.";
                return false;
            }

            // Get table for display
            string tblShow = FileCache.ReadSkinTextFile("page_show.htm");
            string tagThumbnails = HTMLHelper.imgTagDefault();
            if (getFromFile)
            {
                tagThumbnails = HTMLHelper.imgTagRecordedTVProgramme(tvp);
            }

            if (Settings.Default.ShowChannelLogos)
                tagThumbnails += tvs.HTMLForLogoImageOrCallsign("showchannellogo", false);

            tblShow = tblShow.Replace("**THUMBNAIL**", tagThumbnails);
            tblShow = tblShow.Replace("**STARTTIME**", tvp.ToPrettyDayNameAndDate() + ", " + tvp.ToPrettyStartStopLocalTimes());
            tblShow = tblShow.Replace("**TITLE**", tvp.Title);
            tblShow = tblShow.Replace("**EPISODETITLE**", tvp.EpisodeTitle);
            tblShow = tblShow.Replace("**DESCRIPTION**", tvp.Description);

            // Original Air Date
            string strOriginalAirDate = "";
            if (tvp.OriginalAirDate > 0)
            {
                DateTime dtOriginalAirDate = tvp.OriginalAirDateDT();
                strOriginalAirDate = "Original Air Date: " + dtOriginalAirDate.ToPrettyDayNameAndDate();
                if (dtOriginalAirDate.ToLocalTime().Year != DateTime.Now.Year)
                    strOriginalAirDate += " " + dtOriginalAirDate.ToLocalTime().Year.ToString();
            }
            tblShow = tblShow.Replace("**ORIGINALAIRDATE**", strOriginalAirDate );

            if (tvs != null)
                tblShow = tblShow.Replace("**CHANNEL**", tvs.Callsign);
            else
                tblShow = tblShow.Replace("**CHANNEL**", "");

            // RATINGS
            // Star Rating
            StringBuilder sbStarRating = new StringBuilder();
            int starCounter = tvp.StarRating;
            if (tvp.StarRating > 0)
            {
                for (int i = 0; i < 4; i++)
                {
                    if (starCounter > 1) // full star
                        sbStarRating.Append("<div class=\"showstarrating_star_on\"> </div>");
                    else if (starCounter == 1)  // half star
                        sbStarRating.Append("<div class=\"showstarrating_star_half\"> </div>");
                    else
                        sbStarRating.Append("<div class=\"showstarrating_star_off\"> </div>");

                    starCounter = starCounter - 2;
                }
                sbStarRating.Append("<div class=\"showstarrating_endstars\"> </div>");
            }
            tblShow = tblShow.Replace("**STARRATING**", sbStarRating.ToString());
            // MPAA Rating
            string txtMPAARating;
            if (!string.IsNullOrEmpty(tvp.MPAARating))
                txtMPAARating = "<br />MPAA Rating: " + tvp.MPAARating;
            else
                txtMPAARating = "";
            tblShow = tblShow.Replace("**GUIDANCERATING**", txtMPAARating);

            // PROGRAMME TYPE IMAGE
            StringBuilder sbShowProgrammeType = new StringBuilder();
            switch (tvp.ProgramType)
            {
                case CommonEPG.TVProgrammeType.None:
                    break;

                case CommonEPG.TVProgrammeType.All:
                    break;

                default:
                    sbShowProgrammeType.Append(Functions.imgTag("/static/images/showtype" + tvp.ProgramType.ToString().ToLowerInvariant() + ".png", "showprogrammetypeimg"));
                    break;
            }
            tblShow = tblShow.Replace("**SHOWTYPE**", sbShowProgrammeType.ToString());

            // PROGRAMME EXTRA INFO  (series, repeat, etc.)
            StringBuilder sbShowInfo = new StringBuilder();
            if (tvp.IsSeries) sbShowInfo.Append("Series, ");
            if (!tvp.IsFirstShowing) sbShowInfo.Append("Repeat, ");
            if (tvp.IsHD) sbShowInfo.Append("HD, ");
            if (tvp.HasSubtitles) sbShowInfo.Append("Subtitles, ");
            if (sbShowInfo.ToString().EndsWith(", "))
                sbShowInfo.Remove(sbShowInfo.Length - 2, 2);
            tblShow = tblShow.Replace("**INFORMATION**", sbShowInfo.ToString());

            // Is show from a file
            if (getFromFile)
            {
                tblShow = tblShow.Replace("**RECORDINGTYPE**", "This information is retrieved from a recorded TV file.");

                string txtDeleteLink = string.IsNullOrEmpty(tvp.Filename) ? "" :
                    " <a " + Functions.LinkConfirmClick("Are you sure?  This will permanently delete the file from disk.") + " href='deletefile64?filename=" + HttpUtility.UrlEncode( Functions.EncodeToBase64(tvp.Filename) )  + "'>" + "(Delete Show)</a>";

                tblShow = tblShow.Replace("**RECORDINGSTATE**", "This show was recorded." + txtDeleteLink);

                StringBuilder sbStreamLinks = new StringBuilder(250);
                sbStreamLinks.AppendLine("Stream show: <a href=\"streamprogramme?quality=0&framesize=0.32&programmeid=" + tvp.Id.ToString() + "\">low</a> | ");
                sbStreamLinks.AppendLine("<a href=\"streamprogramme?quality=1&framesize=0.4&programmeid=" + tvp.Id.ToString() + "\">normal</a> | ");
                sbStreamLinks.AppendLine("<a href=\"streamprogramme?quality=2&framesize=0.5&programmeid=" + tvp.Id.ToString() + "\">medium</a> | ");
                sbStreamLinks.AppendLine("<a href=\"streamprogramme?quality=3&framesize=0.5&programmeid=" + tvp.Id.ToString() + "\">high</a>");
                tblShow = tblShow.Replace("**STREAMLINK**", sbStreamLinks.ToString() ); // no streaming
            }
            else
            {

                tblShow = tblShow.Replace("**STREAMLINK**", ""); // no streaming

                // is show being recorded?
                RPRecording rec = tvp.Recording();
                if (rec != null)
                {
                    RPRequest rq = rec.Request();

                    // Info about the recording state & optional link to cancel recording.
                    string txtAboutShowRecording = rec.State.ToPrettyString();

                    // If it's not already happened
                    if (
                        (rec.State == RPRecordingStates.Scheduled) ||
                        (rec.State == RPRecordingStates.Recording))
                    {
                        // Link to cancel this recording
                        txtAboutShowRecording += " <a " + Functions.LinkConfirmClick("Are you sure?  This will cancel the recording.") + " href='cancelrecording?recordingid=" + rec.Id.ToString() + "'>" + "(Cancel Recording)</a>";
                    }

                    // And, if a series, link to Cancel series
                    if (rec.IsRecurring())
                        txtAboutShowRecording += " <a " + Functions.LinkConfirmClick("Are you sure?  This will cancel the whole " + rec.RequestType.ToString() + " request.") + " href='cancelseriesrequest?requestid=" + rq.ID.ToString() + "'>" + "(Cancel Series)</a>";

                    // Commit ABOUT text
                    tblShow = tblShow.Replace("**RECORDINGSTATE**", txtAboutShowRecording);

                    // Info about recording request type: Series recording / etc
                    string txtRecordingTypeInfo = "";
                    if (rq != null)
                    {
                        txtRecordingTypeInfo += "This is a ";
                        if (rec.IsRecurring())
                        {
                            txtRecordingTypeInfo += "<a href='viewseriesrequest?requestid=" + rq.ID.ToString() + "'>";
                            txtRecordingTypeInfo += rq.RequestType.ToString().ToLower() + " recording.";
                            txtRecordingTypeInfo += "</a>";
                        }
                        else
                        {
                            txtRecordingTypeInfo += rq.RequestType.ToString().ToLower() + " recording.";
                        }

                        // One time recording - link to record series
                        if (rq.RequestType == RPRequestTypes.OneTime)
                        {
                            if (tvp.IsSeries)
                            {
                                RecordingRequest rrSeries2 = new RecordingRequest(long.Parse(programmeID), SeriesRequestSubTypes.ThisChannelAnyTime);
                                txtRecordingTypeInfo += " <a href=\"recordshow_series?queueid=" + RecordingQueue.AddToQueue(rrSeries2) + "\">(Record Series)</a>";
                            }
                        }

                    }
                    else
                        txtRecordingTypeInfo += "";

                    tblShow = tblShow.Replace("**RECORDINGTYPE**", txtRecordingTypeInfo);

                }
                else  // SHOW IS NOT SCHEDULED TO RECORD
                {
                    tblShow = tblShow.Replace("**RECORDINGTYPE**", "");

                    // Link to record - only if in the future
                    string txtRecordingState;
                    if (!tvp.HasEndedYet())  // (extension method)
                    {
                        txtRecordingState = "This show will not be recorded. ";

                        if (tvs == null)
                        {
                            txtRecordingState += "<br />(cannot record - no matching channel found)";
                        }
                        else
                        {
                            RecordingRequest rr = new RecordingRequest(long.Parse(programmeID));
                            txtRecordingState += " <a href=\"recordfromqueue?queueid=" + RecordingQueue.AddToQueue(rr) + "\">(Record Show)</a>";

                            if (tvp.IsSeries)
                            {
                                if (tvp.HasSeriesRequest())
                                {
                                    RPRequest req = tvp.SeriesRequest();

                                    txtRecordingState += " <a href='viewseriesrequest?requestid=" + req.ID.ToString() + "'>";
                                    txtRecordingState += "(Series Info)";
                                    txtRecordingState += "</a>";
                                }
                                else
                                {
                                    RecordingRequest rrSeries = new RecordingRequest(long.Parse(programmeID), SeriesRequestSubTypes.ThisChannelAnyTime);
                                    txtRecordingState += " <a href=\"recordshow_series?queueid=" + RecordingQueue.AddToQueue(rrSeries) + "\">(Record Series)</a>";
                                }
                            }
                        }
                    }
                    else
                    {
                        txtRecordingState = "This show was not recorded.";
                    }

                    tblShow = tblShow.Replace("**RECORDINGSTATE**", txtRecordingState);
                } // end if recording else
            }  // end if not get from file

            // Commit to displaying show info
            txtResponse += tblShow;

            return true;
        }
        private bool TryManualRecording()
        {
            txtPageTitle = "Record by Time and Date";

            // Not enough parameters - display form
            if ((qsParams.Count) < 2)  // Due to the way QueryString class works, the Count will be 1 even if there are no actual name/value pairs
            {
                // Display Record Form
                string requestForm = FileCache.ReadSkinTextFile("page_recordmanual.htm");
                processRequestForm(ref requestForm);

                txtResponse += requestForm;
                requestForm = null;

                return true;
            }

            RecordingRequest newRR = null;

            bool failedValidation = false;
            string failedValidationReason = "";
            if (
                (!qsParams.HasParameter("channelcallsign")) |
                (!qsParams.HasParameter("datecomponent")) |
                (!qsParams.HasParameter("timecomponent")) |
                (!qsParams.HasParameter("duration"))
                )
            {
                failedValidation = true;
                failedValidationReason = "To schedule a recording, you must provide a channel, start time and duration.";
            }
            else
            {
                // Get parameters
                string serviceID = qsParams["channelcallsign"];  // it's actually the service ID

                // DATE TIME
                string dateTimeString = qsParams["datecomponent"] + " " + qsParams["timecomponent"];
                DateTime tryStartTime = new DateTime();
                if (DateTime.TryParse(dateTimeString, out tryStartTime))
                    tryStartTime = DateTime.SpecifyKind(tryStartTime, DateTimeKind.Local);
                else
                {
                    failedValidation = true; failedValidationReason += "Invalid start time or date.<br>";
                }

                // in the past?
                if (tryStartTime.ToUniversalTime() < DateTime.Now.ToUniversalTime())
                {
                    failedValidation = true; failedValidationReason += "Start time must be in the future.<br>";
                }

                // DURATION
                Int32 tryDuration = 0;
                if (Int32.TryParse(qsParams["duration"], out tryDuration))
                if ((tryDuration == 0) | (tryDuration > 720)) { failedValidation = true; failedValidationReason += "Invalid duration, must be between 1 and 720 minutes.<br>"; }

                // Create a new recording request
                newRR = new RecordingRequest(tryStartTime.ToUniversalTime(), long.Parse(serviceID), tryDuration, Settings.Default.DefaultManualRecordingName);
            }

            // Passed validation?
            if (failedValidation)
            {
                txtResponse += "<p class='recorderror'>Error in recording request: " + failedValidationReason + "</p>";
            }
            else
            {
                qsParams.Add("queueid", RecordingQueue.AddToQueue(newRR));
                return RecordFromQueue();
            }

            return true;
        }
        //Request rqInProgress;
        public void ScheduleRecording(RecordingRequest rr, EventWaitHandle _ewh)
        {
            // Store pointer to handle locally
            ewhScheduleRecording = _ewh;
            ScheduleInitialFailureResult = new RecordingResult();  // For now, set shared result to assume failure  (in case of time outs etc)
            ScheduleInitialFailureResult.ErrorMessage = "An error message was never generated.";
            ScheduleInitialSucceeded = false;

            // Channel check
            if (rr.MCChannelID < 1)
            {
                ScheduleInitialFailureResult.ErrorMessage = "No MC Channel ID was specified.";
                ScheduleInitialFailureResult.RequestResult = RecordingResult.RequestResults.FailedWithError;
                ScheduleRecordingCompleted();
                return;
            }

            // Too much padding
            if ((rr.Postpadding > 1800) && (rr.Prepadding > 1800))
            {
                ScheduleInitialFailureResult.ErrorMessage = "Pre or Post padding must be less than 30 minutes.";
                ScheduleInitialFailureResult.RequestResult = RecordingResult.RequestResults.FailedWithError;
                ScheduleRecordingCompleted();
                return;
            }

            // Get service
            StoredObject so = os.Fetch(rr.MCChannelID);
            if (!(so is Channel))
            {
                ScheduleInitialFailureResult.ErrorMessage = "The retrieved TV channel was not valid.";
                DebugError("OSM: Retrieved TV channel not valid: ID is [" + rr.MCChannelID.ToString() + "] and so is [" + so.ToString() + "]");
                ScheduleInitialFailureResult.RequestResult = RecordingResult.RequestResults.FailedWithError;
                ScheduleRecordingCompleted();
                return;
            }

            Channel channel = (Channel)so;

            // Get TV programme (ie schedule entry)
            ScheduleEntry schedEntry = null;
            if (rr.RequestType != RecordingRequestType.Manual)
            {
                StoredObject sto = os.Fetch(rr.TVProgrammeID);
                if (!(sto is ScheduleEntry))
                {
                    ScheduleRecordingCompleted();
                    return;
                }

                schedEntry = (ScheduleEntry)sto;
            }

            // Store request
            requestInProgress = null;
            switch (rr.RequestType)
            {
                case RecordingRequestType.Series:
                    // Check schedentry has series info
                    if (schedEntry.Program != null)
                        if (schedEntry.Program.Series == null)
                        {
                            ScheduleInitialFailureResult.ErrorMessage = "This show is not part of a recognised series within Media Center.";
                            ScheduleInitialFailureResult.RequestResult = RecordingResult.RequestResults.FailedWithError;
                            ScheduleRecordingCompleted();
                            return;
                        }
                    SeriesRequest sreq = recScheduler.CreateSeriesRequest(schedEntry, channel);
                    sreq.RunType = (rr.FirstRunOnly) ? RunType.FirstRunOnly : RunType.Any;

                    // sreq.IsRecurring = true  ??
                    sreq.AnyChannel = (rr.SeriesRequestSubType == SeriesRequestSubTypes.AnyChannelAnyTime);
                    // Series request HAS to have IsRecurring set to TRUE.  Series requests CANNOT be non recurring!
                    sreq.IsRecurring = true; //= ((rr.SeriesRequestSubType == SeriesRequestSubTypes.AnyChannelAnyTime) || (rr.SeriesRequestSubType == SeriesRequestSubTypes.ThisChannelAnyTime));

                    /*
                    // Experimental - AIR TIME
                    string strAirtimecheck = "";
                        if (!sreq.Airtime.HasValue)
                            strAirtimecheck += "null";
                        else
                            strAirtimecheck += sreq.Airtime.Value.ToString();

                        DebugNormal("Airtime (before alteration) is:" + strAirtimecheck);

                    // 12 hour window
                    if (rr.SeriesRequestSubType == SeriesRequestSubTypes.ThisChannelAnyTime)
                    {
                        sreq.Airtime = TimeSpan.FromHours(12);
                    }
                    else if (rr.SeriesRequestSubType == SeriesRequestSubTypes.ThisChannelThisTime)
                    {
                        sreq.Airtime = TimeSpan.FromHours(3);
                    }
                    */
                    // Look also at...
                    //sreq.Airtime
                    //sreq.DaysOfWeek
                    // sreq.ScheduleLimit - maximum number to schedule

                    // If keep until is 'latest episodes', set the number here...
                    if (rr.KeepUntil == KeepUntilTypes.LatestEpisodes)
                    {
                        if (rr.KeepNumberOfEpisodes > 0)
                            sreq.RecordingLimit = rr.KeepNumberOfEpisodes;
                    }

                    requestInProgress = (Request)sreq;
                    break;

                case RecordingRequestType.OneTime:
                    OneTimeRequest oreq = recScheduler.CreateOneTimeRequest(schedEntry, channel);
                    requestInProgress = (Request)oreq;
                    requestInProgress.AnyChannel = false;
                    //requestInProgress.ScheduleLimit = 5; // This didn't do anything!
                    break;

                case RecordingRequestType.Manual:

                    ManualRequest mreq = recScheduler.CreateManualRequest(rr.StartTime, TimeSpan.FromMinutes(rr.Duration), channel, rr.ManualRecordingName, "", "", "", (System.Globalization.CultureInfo.CurrentCulture.LCID), false);
                    requestInProgress = (Request)mreq;
                    break;
            }

            // Universal Request Settings - all types of recording
            requestInProgress.PostPaddingRequested = TimeSpan.FromSeconds(rr.Postpadding);
            requestInProgress.PrePaddingRequested = TimeSpan.FromSeconds(rr.Prepadding);
            // Keep Until
            if (rr.KeepUntil != KeepUntilTypes.NotSet)
            {
                try
                {
                    DebugNormal("OSM: Setting 7MC request keeplength using string " + rr.KeepUntil.ToString());
                    requestInProgress.KeepLength = (KeepLength)Enum.Parse(typeof(KeepLength), rr.KeepUntil.ToString(), true);
                    DebugNormal("OSM: 7MC request keepLength is now " + requestInProgress.KeepLength.ToString());
                }
                catch { DebugNormal("ERROR: Couldn't parse KeepUntil value."); }
            }
            // ELSE ...  ASSUME media center uses KeepUntil default when creating recording?  If not, SET HERE ===>

            requestInProgress.Quality = rr.Quality;

            // Update request... (TODO is this step strictly necessary?)
            //rqInProgress.Updated += new StoredObjectEventHandler(ScheduleRecording_2);
            //rqInProgress.UpdateRequest();
            requestInProgress.UpdateRequestedPrograms();
            UpdateDelegate upd = new UpdateDelegate(ScheduleRecording_Done);
            requestInProgress.UpdateAndSchedule(upd, recScheduler);
        }
Example #10
0
        public bool ScheduleRecording(RecordingRequest rr, out RPRequest rpRequest, out RecordingResult earlyFailureResult)
        {
            EventWaitHandle ewhScheduleRecording = new EventWaitHandle(false, EventResetMode.AutoReset);
            storeManager.ScheduleRecording(rr, ewhScheduleRecording);
            ewhScheduleRecording.WaitOne(TimeSpan.FromSeconds(500));

            // Destroy the stargate
            ewhScheduleRecording = null;

            DebugNormal("MCData: schedulerecording finished, storeManager.ScheduleInitialSucceeded:" + storeManager.ScheduleInitialSucceeded);
            if (!storeManager.ScheduleInitialSucceeded)
            {
                rpRequest = null;
                earlyFailureResult = storeManager.ScheduleInitialFailureResult;
                return false;
            }
            else
            {
                // Retrieve the shared objects that were generated

                rpRequest = Conversion.RPRequestFromRequest(storeManager.requestInProgress);  // THIS IS ERRORING

                earlyFailureResult = null;
            }

            return true;
        }
        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);

            }
        }