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 ProcessHTTPLSURL(string txtAction, ref BrowserSender browserSender) { // GET STREAMER ID int ID; if (txtAction.StartsWith("httplivestream/")) { txtAction = txtAction.Replace("httplivestream/",""); int nextSlash = txtAction.IndexOf("/"); if (nextSlash == -1) { browserSender.Send404Page(); return; } string strMediaStreamerID = txtAction.Substring(0, nextSlash); if (! int.TryParse(strMediaStreamerID, out ID)) { browserSender.Send404Page(); return; } // Make txtAction the final portion txtAction = txtAction.Replace(ID.ToString() + "/",""); } else { browserSender.Send404Page(); return; } if (txtAction.EndsWith("m3u8")) { string indexFile = StreamingManager.Default.IndexFileForStreamer(ID); browserSender.SendStringToBrowser(indexFile, "application/vnd.apple.mpegurl"); return; } if (txtAction.StartsWith("seg")) { txtAction = txtAction.Replace(".ts", ""); // remove extension // Get segment number string strSegNumber; List<string> parts = txtAction.Split('-').ToList(); if (parts.Count > 1) strSegNumber = parts[1]; else { browserSender.Send404Page(); return; } int iSegNumber = 0; if (!int.TryParse(strSegNumber, out iSegNumber)) { browserSender.Send404Page(); return; } byte[] TSdata = new byte[]{}; string txtError = ""; if (StreamingManager.Default.SegmentFromStreamer(ID, iSegNumber, ref TSdata, ref txtError)) { browserSender.SendDataToBrowser("video/mp2t", TSdata); return; } else { Functions.WriteLineToLogFileIfSetting(Settings.Default.DebugStreaming, "Could not get streaming segment number " + strSegNumber + ":" + txtError); browserSender.Send404Page(); } } }
private void ProcessHTTPLSURL(string txtAction, ref BrowserSender browserSender) { Functions.WriteLineToLogFileIfSetting(Settings.Default.DebugStreaming, "ProcesssHTTP: " + txtAction); // GET STREAMER ID int ID; if (txtAction.StartsWith("httplivestream/")) { txtAction = txtAction.Replace("httplivestream/", ""); int nextSlash = txtAction.IndexOf("/"); if (nextSlash == -1) { browserSender.Send404Page(); return; } string strMediaStreamerID = txtAction.Substring(0, nextSlash); if (!int.TryParse(strMediaStreamerID, out ID)) { browserSender.Send404Page(); return; } // Make txtAction the final portion txtAction = txtAction.Replace(ID.ToString() + "/", ""); } else { browserSender.Send404Page(); return; } //if (txtAction.EndsWith("index2.m3u8")) //{ // string workingFolderPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "RemotePotato"); // workingFolderPath = Path.Combine(workingFolderPath + "\\static\\mediastreams\\", ID.ToString()); // if (!Directory.Exists(workingFolderPath)) Directory.CreateDirectory(workingFolderPath); // string filePath2 = workingFolderPath + "\\index2.m3u8"; // string indexFile = "#EXTM3U\n#EXT-X-VERSION:3\n#EXT-X-MEDIA-SEQUENCE:0\n#EXT-X-ALLOW-CACHE:YES\n#EXT-X-TARGETDURATION:5\n#EXTINF:4,\nsegment-0.ts"; // if (File.Exists(filePath2)) // { // StreamReader streamReader = new StreamReader(new FileStream(filePath2, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)); // indexFile = streamReader.ReadToEnd(); // streamReader.Close(); // } // browserSender.SendStringToBrowser(indexFile, "application/vnd.apple.mpegurl"); // return; //} //else if (txtAction.EndsWith("livetv.m3u8")) { string workingFolderPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "RemotePotato"); workingFolderPath = Path.Combine(workingFolderPath + "\\static\\mediastreams\\", ID.ToString()); if (!Directory.Exists(workingFolderPath)) Directory.CreateDirectory(workingFolderPath); //string filePathNewFFMPeg = workingFolderPath + "\\index2.m3u8"; string filePathNewLiveTV = workingFolderPath + "\\livetvtemp0.m3u8"; string indexFile = ""; { if (File.Exists(filePathNewLiveTV)) // NewLiveTV: m3u8 indexfile exists { indexFile = StreamingManager.Default.IndexFileForStreamer(ID, false); browserSender.SendStringToBrowser(indexFile, "application/vnd.apple.mpegurl"); return; //old code: StreamReader streamReader = new StreamReader(new FileStream(filePathNewLiveTV, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)); indexFile = streamReader.ReadToEnd(); streamReader.Close(); } else if (txtAction.EndsWith("livetv.m3u8")) // new live TV { // Yeah, you can start me up, start me up, display waiting screen StringBuilder sbindexfile = new StringBuilder(1000); sbindexfile.AppendLine("#EXTM3U"); sbindexfile.AppendLine("#EXT-X-TARGETDURATION:" + 1); sbindexfile.AppendLine("#EXT-X-ALLOWCACHE:1"); // allow client to cache files // sbindexfile.AppendLine("#EXTINF:10,"); // sbindexfile.AppendLine("seg-0.ts"); //seg-0 does not exist this actually kicks off the ffmpeg runner, does not work sbindexfile.AppendLine("#EXTINF:" + 1 + ","); sbindexfile.AppendLine("seg!-99999.ts"); // sbindexfile.AppendLine("#EXTINF:1,"); // sbindexfile.AppendLine("seg-2.ts"); // sbindexfile.AppendLine("#ext-x-endlist"); indexFile = sbindexfile.ToString(); } browserSender.SendStringToBrowser(indexFile, "application/vnd.apple.mpegurl"); if (false) { //livetv.m3u8 might be written to and for a moment not exist so better is: //http://stackoverflow.com/questions/4238345/asynchronously-wait-for-taskt-to-complete-with-timeout // Your scheduler TaskScheduler scheduler = TaskScheduler.Default; BrowserSender browserSender2 = browserSender; Task nonblockingTask = new Task(() => { CancellationTokenSource source = new CancellationTokenSource(); Task t1 = new Task(() => { while (true) { // Do something if (File.Exists(filePathNewLiveTV)) { File.Delete(filePathNewLiveTV + "b"); File.Copy(filePathNewLiveTV, filePathNewLiveTV + "b"); StreamReader streamReader2 = new StreamReader(filePathNewLiveTV + "b"); indexFile = streamReader2.ReadToEnd(); streamReader2.Close(); } if (source.IsCancellationRequested) break; } }, source.Token); t1.Start(scheduler); // Wait for task 1 bool firstTimeout = t1.Wait(5000); if (!firstTimeout) { // If it hasn't finished at first timeout display message if (Settings.Default.DebugAdvanced) Functions.WriteLineToLogFile("livetv.m3u8 not generated after 5 seconds"); bool secondTimeout = t1.Wait(5000); if (!secondTimeout) { source.Cancel(); if (Settings.Default.DebugAdvanced) Functions.WriteLineToLogFile("livetv.m3u8 not generated after 10 seconds, Operation stopped!"); } } browserSender2.SendStringToBrowser(indexFile, "application/vnd.apple.mpegurl"); }); nonblockingTask.Start(); } } return; } else if (txtAction.EndsWith("m3u8")) { string indexFile = StreamingManager.Default.IndexFileForStreamer(ID, false); browserSender.SendStringToBrowser(indexFile, "application/vnd.apple.mpegurl"); return; } else if (txtAction.EndsWith("playtranscoded")) { string indexFile = StreamingManager.Default.IndexFileForStreamer(ID, true); browserSender.SendStringToBrowser(indexFile, "application/vnd.apple.mpegurl"); return; } else //for windows 8 app store support (metro) if (txtAction.EndsWith("bat")) { string indexFile = @"c:\ffmpeg\ffplay.exe http://" + Request.RemoteEndPoint.Address.ToString() + ":" + Request.LocalEndPoint.Port + "/httplivestream/" + ID + "/index.m3u8"; browserSender.SendStringToBrowser(indexFile, "application/vnd.apple.mpegurl"); return; } if (txtAction.EndsWith("onlytranscode")) { browserSender.Send404Page(); string indexFile = StreamingManager.Default.IndexFileForStreamer(ID, true); List<string> lines = indexFile.Split(Environment.NewLine.ToCharArray()).ToList(); MediaStreamer ms = StreamingManager.Default.GetStreamerByID(ID); foreach (string line in lines) { if (line.StartsWith("seg")) { SendSegmentData(line, ref browserSender, ID, false, true); ms.lastContactAtTime = DateTime.Now; //This counts as contact from the server } } //now move the data to a safe place, otherwise the janitor will clean up at its convenience StreamingManager.Default.MoveSegmentData(ID); return; } if (txtAction.StartsWith("segbackground")) { txtAction = txtAction.Replace("background", ""); SendSegmentData(txtAction, ref browserSender, ID, true, false); return; } else if (txtAction.StartsWith("seg") || txtAction.StartsWith("liveseg")) { SendSegmentData(txtAction, ref browserSender, ID, true, true); return; } }
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); } }
private void ProcessHTTPLSURL(string txtAction, ref BrowserSender browserSender) { Functions.WriteLineToLogFileIfSetting(Settings.Default.DebugStreaming, "ProcesssHTTP: " + txtAction); // GET STREAMER ID int ID; if (txtAction.StartsWith("httplivestream/")) { txtAction = txtAction.Replace("httplivestream/", ""); int nextSlash = txtAction.IndexOf("/"); if (nextSlash == -1) { browserSender.Send404Page(); return; } string strMediaStreamerID = txtAction.Substring(0, nextSlash); if (!int.TryParse(strMediaStreamerID, out ID)) { browserSender.Send404Page(); return; } // Make txtAction the final portion txtAction = txtAction.Replace(ID.ToString() + "/", ""); } else { browserSender.Send404Page(); return; } //if (txtAction.EndsWith("index2.m3u8")) //{ // string workingFolderPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "RemotePotato"); // workingFolderPath = Path.Combine(workingFolderPath + "\\static\\mediastreams\\", ID.ToString()); // if (!Directory.Exists(workingFolderPath)) Directory.CreateDirectory(workingFolderPath); // string filePath2 = workingFolderPath + "\\index2.m3u8"; // string indexFile = "#EXTM3U\n#EXT-X-VERSION:3\n#EXT-X-MEDIA-SEQUENCE:0\n#EXT-X-ALLOW-CACHE:YES\n#EXT-X-TARGETDURATION:5\n#EXTINF:4,\nsegment-0.ts"; // if (File.Exists(filePath2)) // { // StreamReader streamReader = new StreamReader(new FileStream(filePath2, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)); // indexFile = streamReader.ReadToEnd(); // streamReader.Close(); // } // browserSender.SendStringToBrowser(indexFile, "application/vnd.apple.mpegurl"); // return; //} //else if (txtAction.Contains("isshellcmdrunning")) { MediaStreamer ms = StreamingManager.Default.GetStreamerByID(ID); XMLresponse = (!ms.isPaused).ToString(); browserSender.SendXMLToBrowser(XMLresponse); return; } if (txtAction.EndsWith("livetv.m3u8")) { string indexFile = StreamingManager.Default.IndexFileForStreamer(ID, false, 0); browserSender.SendStringToBrowser(indexFile, "application/vnd.apple.mpegurl"); return; } else if (txtAction.EndsWith("m3u8")) { int segmnr = StreamingManager.Default.GetTimeForIndexFile(ID); string indexFile = StreamingManager.Default.IndexFileForStreamer(ID, false, segmnr); browserSender.SendStringToBrowser(indexFile, "application/vnd.apple.mpegurl"); //browserSender.SendStringToBrowser(indexFile, "application/x-mpegURL"); return; } else if (txtAction.EndsWith("playtranscoded.m3u8")) { int segmnr = StreamingManager.Default.GetTimeForIndexFile(ID); string indexFile = StreamingManager.Default.IndexFileForStreamer(ID, true, segmnr); browserSender.SendStringToBrowser(indexFile, "application/vnd.apple.mpegurl"); return; } //else //for windows 8 app store support (metro) // if (txtAction.EndsWith("streamlive.bat")) // { // string indexFile = @"c:\ffmpeg\ffplay.exe http://" + Request.RemoteEndPoint.Address.ToString() + ":" + Request.LocalEndPoint.Port + "/httplivestream/" + ID + "/livetv.m3u8"; // browserSender.SendStringToBrowser(indexFile, "application/vnd.apple.mpegurl"); // return; // } // else //for windows 8 app store support (metro) // if (txtAction.EndsWith("stream.bat")) // { // string indexFile = @"c:\ffmpeg\ffplay.exe http://" + Request.RemoteEndPoint.Address.ToString() + ":" + Request.LocalEndPoint.Port + "/httplivestream/" + ID + "/index.m3u8"; // browserSender.SendStringToBrowser(indexFile, "application/vnd.apple.mpegurl"); // return; // } if (txtAction.EndsWith("onlytranscode")) { browserSender.Send404Page(); StreamingManager.Default.DeleteBackgroundSegmentData(ID); string indexFile = StreamingManager.Default.IndexFileForStreamer(ID, true, 0); List<string> lines = indexFile.Split(Environment.NewLine.ToCharArray()).ToList(); MediaStreamer ms = StreamingManager.Default.GetStreamerByID(ID); string regel = ""; foreach (string line in lines) { if (line.StartsWith("seg"))//segbackground { regel = line; SendSegmentData(line, ref browserSender, ID, false, true); ms.lastContactAtTime = DateTime.Now; //This counts as contact from the server } } string streamPath = Functions.AppDataFolder + "\\static\\mediastreams\\" + ID + "\\"; string segfile = streamPath + regel.Replace("background", "ment"); waitForCopyToComplete(segfile); //sometimes an extra segment is generated 1 more than in the index.m3u8 file, this has also to be waited for completely copied before to be moved. int segmentNr = 0; Int32.TryParse(regel.Replace("segbackground-", "").Replace(".ts", ""), out segmentNr); string segmenttotest = "segbackground-" + (segmentNr + 1) + ".ts"; segfile = streamPath + segmenttotest.Replace("background", "ment"); if (File.Exists(segfile)) waitForCopyToComplete(segfile); //now move the data to a safe place, otherwise the janitor will clean up at its convenience StreamingManager.Default.MoveSegmentData(ID); return; } if (txtAction.StartsWith("segbackground")) { txtAction = txtAction.Replace("background", ""); SendSegmentData(txtAction, ref browserSender, ID, true, false); return; } else if (txtAction.StartsWith("seg") || txtAction.StartsWith("liveseg")) { SendSegmentData(txtAction, ref browserSender, ID, true, true); return; } }