private bool ViewPicture(ref BrowserSender bSender, ref bool sentCompletePage) { string txtOutput = FileCache.ReadSkinTextFile("page_viewpicture.htm"); StringBuilder sbHTML = new StringBuilder(100); string FN = ""; string strSize = ""; bool shouldDownload = false; if ( (qsParams.HasParameter("FN")) && (qsParams.HasParameter("SIZE")) ) { string qsFN = qsParams["FN"]; FN = HttpUtility.UrlDecode(qsFN); FN = Functions.DecodeFromBase64(FN, Encoding.UTF8); // http uses UTF8 encoding txtPageTitle = Path.GetFileNameWithoutExtension(FN); strSize = qsParams["SIZE"]; shouldDownload = (qsParams.HasParameter("DOWNLOAD")); } else { bSender.Send404Page(); sentCompletePage = true; } // Thumbnail? string imgSrc; if (!strSize.Equals("full")) { // Assemble path to file imgSrc = "getfilethumbnail64?filename=" + qsParams["FN"] + "&size=" + strSize; HTMLImage image = new HTMLImage(imgSrc, "picturelibraryviewedpicture"); // Link string strLinkToFullImage = "viewpic?FN=" + qsParams["FN"] + "&size=full"; HTMLLink lnk = new HTMLLink(strLinkToFullImage, image.ToString()); // Commit to form sbHTML.Append(lnk.ToString()); sbHTML.Append("<br /><br />"); HTMLLink fullLink = new HTMLLink(strLinkToFullImage, "View original size"); sbHTML.Append(fullLink.ToString()); sbHTML.Append(" | "); fullLink = new HTMLLink(strLinkToFullImage + "&download=yes", "Download"); sbHTML.Append(fullLink.ToString()); } else { sentCompletePage = true; bSender.SendFileToBrowser(FN, false, false, shouldDownload); } txtOutput = txtOutput.Replace("**LIBRARYTABLE**", sbHTML.ToString()); txtResponse += txtOutput; 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/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); } }
public void Run() { #if !DEBUG try { #endif // To store headers and styles List<string> AdditionalStyles = new List<string>(); // Set HTTP response version to 1.1 (experimental) // Context.Response.ProtocolVersion = new Version("1.1"); BrowserSender browserSender = new BrowserSender(Context); currentClientIP = Request.RemoteEndPoint.Address.ToString(); qsParams = Request.QueryString; if (Settings.Default.DebugServer) spoolMessage("Client Connected (" + Request.RemoteEndPoint.Address.ToString() + ")"); if ((Settings.Default.DebugAdvanced) && (Settings.Default.DebugServer)) { spoolMessage("Headers from client:"); for (int i = 0; i < Request.Headers.Count; ++i) spoolMessage(string.Format("{0}: {1}", Request.Headers.Keys[i], Request.Headers[i])); } // Split request into lines string txtPostObjects = ""; if (Request.HttpMethod.Equals("POST")) { StreamReader sr = new StreamReader(Request.InputStream); txtPostObjects = sr.ReadToEnd(); } // User agent - detect mobile processUserAgentStringFromRequestHeaders(); // Get action string from Url string txtAction = GetActionFromBrowserRequest(); if (Settings.Default.DebugServer) { Functions.WriteLineToLogFile("From Client: " + txtAction); } // Build response txtResponse = ""; txtPageTitle = Settings.Default.MainMenuTitle; bool foo; // R.I.P. Open server (keep this for legacy compatibility) if (txtAction.StartsWith("open")) txtAction = txtAction.Substring(5); // Special cases / conversions if (txtAction.ToLowerInvariant().Equals("apple-touch-icon.png")) txtAction = "static/images/apple-touch-icon.png"; // Querystring authentication is one possible method that overrides all others if true: check for token (and renew) if (txtAction.StartsWith("xml/checktoken")) // Special open method - check a token { bool ignore = CheckForTokenAuthentication(); string checkForTokenResult = AuthenticatedByToken ? "GOOD" : "BAD"; string xCheckResponse = "<?xml version=\"1.0\"?><checktokenresponse result=\"" + checkForTokenResult + "\" />"; browserSender.SendXMLToBrowser(xCheckResponse); return; } else if (!CheckForTokenAuthentication()) { // invalid token browserSender.SendGenericStatusCodePage("403", "Incorrect authentication"); spoolMessage("API: failed authentication via token."); return; } // XML METHODS - no HTTP authentication required (uses token-based auth) if (txtAction.StartsWith("xml")) { XMLresponse = ""; WebServiceProcess(txtAction, ref browserSender, ref txtPostObjects); return; } // Any other non-authenticated methods switch (txtAction) { // SPECIAL FILE NAME SHORTCUTS - NO AUTH REQUIRED ************** case "robots.txt": if (!browserSender.SendFileToBrowser("static\\robots.txt")) Functions.WriteLineToLogFile("Could not send robots.txt to browser"); return; case "clientaccesspolicy.xml": if (!browserSender.SendFileToBrowser("static\\clientaccesspolicy.xml")) Functions.WriteLineToLogFile("Could not send clientaccesspolicy.xml to browser (presumably to Silverlight)"); return; case "silverlightsource": if (!browserSender.SendFileToBrowser("static\\silverlight\\SilverPotato.xap")) Functions.WriteLineToLogFile("Could not send SilverPotato XAP to browser"); return; //Ping is allowed case "ping": Version v = Functions.ServerVersion; string xResponse = "<?xml version=\"1.0\"?><pingresponse result=\"PING_RESULT\" serverversion=\"SERVER_VERSION\" serverrevision=\"SERVER_REVISION\" serverosversionstring=\"SERVER_OS_VERSION_STRING\" serverosversion=\"SERVER_OS_VERSION\" servercapabilities=\"CAP_FLAGS\" />"; xResponse = xResponse.Replace("PING_RESULT", Settings.Default.RequirePassword ? "NEED_PASSWORD" : "OK"); xResponse = xResponse.Replace("SERVER_VERSION", v.Major.ToString() + "." + v.Minor.ToString() ); // This is culture invariant xResponse = xResponse.Replace("SERVER_OS_VERSION_STRING", Environment.OSVersion.VersionString); xResponse = xResponse.Replace("SERVER_OS_VERSION", Environment.OSVersion.Version.ToString(2) ); xResponse = xResponse.Replace("SERVER_REVISION", v.Build.ToString()); xResponse = xResponse.Replace("CAP_FLAGS", Functions.ServerCapabilities); browserSender.SendXMLToBrowser(xResponse); return; // Fav Icon is allowed case "favicon.ico": browserSender.SendFileToBrowser(HttpUtility.UrlDecode("static\\images\\remotepotatoicon.ico")); return; default: break; } // Channel logos are allowed if ((txtAction.StartsWith("logo"))) { int hashlocation = txtAction.LastIndexOf("/"); if (hashlocation < 1) { bool fooa = browserSender.Send404Page(); } else { txtAction = txtAction.Replace("logo/", ""); string logoSvcID = HttpUtility.UrlDecode(txtAction); // Send logo to browser browserSender.SendLogoToBrowser(logoSvcID); } return; } // Special case 'static' files that aren't => legacy support for streaming if (txtAction.StartsWith("httplivestream")) { ProcessHTTPLSURL(txtAction, ref browserSender); return; } // Static Files if ( (txtAction.StartsWith("static")) ) { int hashlocation = txtAction.LastIndexOf("/"); if (hashlocation < 1) { bool fooa = browserSender.Send404Page(); } else { // Send file browserSender.SendFileToBrowser(HttpUtility.UrlDecode(txtAction)); } return; } // Skin files if ( (txtAction.StartsWith("skin"))) { int hashlocation = txtAction.LastIndexOf("/"); if (hashlocation < 1) { bool fooa = browserSender.Send404Page(); } else { // Send file browserSender.SendFileToBrowser(HttpUtility.UrlDecode(txtAction), true, false); } return; } // Thumbnails are allowed if (txtAction == "rectvthumbnail64") { GetRecTVThumbnail(ref browserSender, true); return; } else if (txtAction == "rectvthumbnail") { GetRecTVThumbnail(ref browserSender, false); return; } if (txtAction.StartsWith("getfilethumbnail64")) { GetFileThumbnailUsingQueryString(ref browserSender, true); return; } else if (txtAction.StartsWith("getfilethumbnail")) { GetFileThumbnailUsingQueryString(ref browserSender, false); return; } if (txtAction.StartsWith("filethumbnail")) { string txtSize = txtAction.Replace("filethumbnail/",""); FatAttitude.ThumbnailSizes size = (FatAttitude.ThumbnailSizes) Enum.Parse( (new FatAttitude.ThumbnailSizes().GetType() ), txtSize, true); SendFileThumbnail(txtPostObjects, size, ref browserSender); return; } if (txtAction.StartsWith("musicalbumthumbnail")) { GetAlbumThumbnail(ref browserSender, txtAction.Contains("musicalbumthumbnail64") ); return; } if (txtAction.StartsWith("musicsongthumbnail")) { GetSongThumbnail(ref browserSender, txtAction.Contains("musicsongthumbnail64")); return; } // Silverlight is allowed (no longer contains password info) bool showSilverlight = (txtAction.StartsWith("silverlight")); if (Settings.Default.SilverlightIsDefault) showSilverlight = showSilverlight | (txtAction.Trim().Equals("")); if (showSilverlight) { string silverTemplate = FileCache.ReadTextFile("static\\silverlight\\default_template.htm"); browserSender.SendNormalHTMLPageToBrowser(silverTemplate); return; } // MORE OPEN METHODS... if (txtAction.StartsWith("streamsong")) { bool isBase64Encoded = (txtAction.StartsWith("streamsong64")); if (!SendSongToBrowser(ref browserSender, isBase64Encoded, true, false)) browserSender.Send404Page(); return; } // MORE OPEN METHODS... if (txtAction.StartsWith("downloadsong")) { bool isBase64Encoded = (txtAction.StartsWith("downloadsong64")); if (!SendSongToBrowser(ref browserSender, isBase64Encoded, true, true)) browserSender.Send404Page(); return; } // ******************************************************************************************** // Cookie Authentication Required for all Methods below here ********************************** // ******************************************************************************************** bool processMoreActions = false; if (canProceedAuthenticatedByHTTPCookie()) { processMoreActions = true; } else { spoolMessage("Webserver: requesting login."); bool LoginSuccess = false; string destURL = ""; string destQueryString = ""; ViewLoginPage(txtPostObjects, ref LoginSuccess, ref destURL, ref destQueryString); // Successful login if (LoginSuccess) { processMoreActions = true; txtPageTitle = ""; // Assign new (old) action and querystring for further processing txtAction = destURL; qsParams = HttpUtility.ParseQueryString(destQueryString); // We've missed the silverlight check (it's up above), so check again if (Settings.Default.SilverlightIsDefault) { string silverTemplate = FileCache.ReadTextFile("static\\silverlight\\default_template.htm"); browserSender.SendNormalHTMLPageToBrowser(silverTemplate); return; } } } bool sentWholePage = false; if (processMoreActions) { switch (txtAction) { // Legacy Streamsong (secured) case "streamsong.mp3": if (!SendSongToBrowser(ref browserSender, false, true, false)) browserSender.Send404Page(); return; case "streamsong": if (!SendSongToBrowser(ref browserSender, false, true, false)) browserSender.Send404Page(); return; // MANUAL RECORDING ====================================================== case "recordmanual": foo = TryManualRecording(); break; // Remote Control case "remotecontrol": foo = ViewRemoteControl(); break; // Remote Control case "rc": bool haveSentHTMLPage = SendRemoteControlCommand(ref browserSender); if (haveSentHTMLPage) return; // Don't continue; this method sends a blank page break; // RECORD A SERIES case "recordshow_series": foo = RecordSeries(); break; // RECORD (FROM RecordingRequest): MULTIPURPOSE case "recordfromqueue": foo = RecordFromQueue(); break; // PICS case "browsepics": ViewPicturesLibrary(); break; case "viewpic": foo = ViewPicture(ref browserSender, ref sentWholePage); if (sentWholePage) return; // no more processing required break; case "picfolderaszip": foo = GetPicturesFolderAsZip(ref browserSender); return; // Don't continue, no Reponse left to output // VIDEOS case "browsevideos": ViewVideoLibrary(); break; case "streamvideo": foo = StreamVideo(); break; // MUSIC case "musicroot": ViewMusic(); break; case "musicartists": ViewMusicArtists(false); break; case "musicartist": ViewMusicArtist(); break; case "musicalbumartists": ViewMusicArtists(true); break; case "musicalbums": ViewMusicAlbums(); break; case "musicalbum": ViewMusicAlbum(); break; case "musicgenres": ViewMusicGenres(); break; case "musicgenre": ViewMusicGenre(); break; case "musicsong": ViewMusicSong(); break; // LIST RECORDINGS case "scheduledrecordings": foo = ViewScheduledRecordings(); break; case "log-out": DoLogOut(); break; // LIST RECORDINGS case "recordedtv": foo = ViewRecordedTVList(); AdditionalStyles.Add("rectv"); break; // VIEW A SPECIFIC SERIES case "viewseriesrequest": foo = ViewSeriesRequest(); AdditionalStyles.Add("showdetails"); break; // MANAGE ALL SERIES case "viewseriesrequests": foo = ViewSeriesRequests(); break; // VIEW AN EPG PAGE case "viewepglist": foo = ViewEPGList(); AdditionalStyles.Add("epg-list"); break; // VIEW AN EPG PAGE - GRID case "viewepggrid": Functions.WriteLineToLogFile("RP: (VEPG)"); foo = ViewEPGGrid(); AdditionalStyles.Add("epg-grid"); break; // Shift EPG Grid Up case "epgnavup": foo = EPGGridChannelRetreat(); AdditionalStyles.Add("epg-grid"); break; // Shift EPG Grid Down case "epgnavdown": foo = EPGGridChannelAdvance(); AdditionalStyles.Add("epg-grid"); break; // Shift EPG Grid Right case "epgnavright": foo = EPGGridTimeWindowShiftByMinutes(EPGManager.TimespanMinutes); AdditionalStyles.Add("epg-grid"); break; // Shift EPG Grid Left case "epgnavleft": foo = EPGGridTimeWindowShiftByMinutes(0 - EPGManager.TimespanMinutes); AdditionalStyles.Add("epg-grid"); break; // Shift EPG Grid Left case "epgnavtop": foo = EPGGridChannelSetAbsolute(true, false); AdditionalStyles.Add("epg-grid"); break; // Shift EPG Grid Left case "epgnavbottom": foo = EPGGridChannelSetAbsolute(false, true); AdditionalStyles.Add("epg-grid"); break; // Shift EPG To Page case "epgjumptopage": foo = EPGGridChannelJump(); AdditionalStyles.Add("epg-grid"); break; // VIEW AN EPG SHOW case "viewepgprogramme": foo = ViewEPGProgramme(); AdditionalStyles.Add("showdetails"); break; // STREAM A SHOW case "streamprogramme": foo = StreamRecordedProgramme(); AdditionalStyles.Add("showdetails"); break; // SEARCH BY TITLE case "searchbytitle": foo = SearchShowsByText(); break; // DELETE A RECORDING case "deletefile": foo = DeleteFileFromFilePath(false); break; case "deletefile64": foo = DeleteFileFromFilePath(true); break; // CANCEL A RECORDING case "cancelseriesrequest": foo = CancelRequest(); break; // CANCEL A RECORDING case "cancelrecording": foo = CancelRecording(); break; // VIEW MOVIES case "movies": foo = ViewMovies(); AdditionalStyles.Add("movies"); break; // VIEW MOVIES case "viewmovie": foo = ViewMovie(); AdditionalStyles.Add("showdetails"); AdditionalStyles.Add("movies"); break; case "info": txtResponse += "This is the Remote Potato Server v" + Functions.VersionText + " running on " + Environment.OSVersion.VersionString + "."; txtResponse += "<br/><br/>For help and support please visit the <a href='http://forums.fatattitude.com'>FatAttitude Forums</a>."; break; case "mainmenu": ShowMainMenu(); break; default: ShowMainMenu(); break; } } // Finalise response: convert to master page string txtOutputPage = FileCache.ReadSkinTextFile("masterpage.htm"); // Commit response txtOutputPage = txtOutputPage.Replace("**PAGECONTENT**", txtResponse); txtResponse = ""; // Style inclusion? (this line must be before the Skin section, as the returned string includes **SKINFOLDER** to be replaced txtOutputPage = txtOutputPage.Replace("**PAGEADDITIONALSTYLES**", AdditionalStyleLinks(AdditionalStyles)); // Orientation txtOutputPage = txtOutputPage.Replace("**PAGEORIENTATION**", txtOutputPage.Contains("PAGEORIENTATION=LANDSCAPE") ? "landscape" : "portrait"); // Skin txtOutputPage = txtOutputPage.Replace("**SKINFOLDER**", "/static/skins/" + Themes.ActiveThemeName); txtOutputPage = txtOutputPage.Replace("**HEADER**", "Remote Potato"); // Default Page Title txtOutputPage = txtOutputPage.Replace("**PAGETITLE**", txtPageTitle); // Copyright / Timestamp txtOutputPage = txtOutputPage.Replace("**TIMEANDVERSIONSTRING**", DateTime.Now.ToLongTimeString() + ", v" + Functions.VersionText); if (!browserSender.SendNormalHTMLPageToBrowser(txtOutputPage)) { spoolMessage("Webserver failed to send data."); } #if !DEBUG } catch (Exception e) { Functions.WriteExceptionToLogFile(e); spoolMessage("EXCEPTION OCCURRED: " + e.Message); BrowserSender exceptionBrowserSender = new BrowserSender(Context); exceptionBrowserSender.SendNormalHTMLPageToBrowser("<h1>Remote Potato Error</h1>An error occurred and remote potato was unable to serve this web page.<br /><br />Check the debug logs for more information."); } #endif }
private void SendFileThumbnail(string fileName, FatAttitude.ThumbnailSizes thumbSize, ref BrowserSender browserSender) { // Find file or folder? if ( (! File.Exists(fileName)) && (! Directory.Exists(fileName)) ) { bool foo = browserSender.Send404Page(); return; } FatAttitude.ShellHelper sh = new FatAttitude.ShellHelper(); string strLog = ""; // ignore Bitmap thumb = sh.ThumbnailForFile(fileName, thumbSize, ref strLog); if (thumb == null) { browserSender.SendFileToBrowser("thumbnail_default.png", true, false); return; } byte[] outputdata = ImageResizer.ImageToByteArray(thumb, ImageFormat.Jpeg); // Send to browser bool foo2 = browserSender.SendDataToBrowser("image/jpeg", outputdata); }
private void GetSongThumbnail(ref BrowserSender browserSender, bool isBase64Encoded) { // Any parameters? bool validated = true; validated &= qsParams.HasParameter("id"); validated &= qsParams.HasParameter("size"); if (!validated) { bool foo = browserSender.Send404Page(); return; } string itemID = HttpUtility.UrlDecode(qsParams["id"]); if (isBase64Encoded) itemID = Functions.DecodeFromBase64(itemID); string size = qsParams["size"]; WMPManager.Thumbnail_Sizes tSize = (WMPManager.Thumbnail_Sizes)Enum.Parse(typeof(WMPManager.Thumbnail_Sizes), size, true); using (WMPManager picManager = new WMPManager()) { string MimeType = ""; byte[] picBytes = picManager.ThumbnailForWMPItemAsByte("TrackingID", itemID, true, tSize, out MimeType); if ((picBytes == null) || (picBytes.Length < 1)) browserSender.Send404Page(); else browserSender.SendDataToBrowser(MimeType, picBytes); } }
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(); } } }
bool GetPicturesFolderAsZip(ref BrowserSender bSender) { string path; if (qsParams.HasParameter("PATH")) { string qsFN = qsParams["PATH"]; path = HttpUtility.UrlDecode(qsFN); path = Functions.DecodeFromBase64(path, Encoding.UTF8); // http uses UTF8 encoding FileBrowseResult fbr = FileBrowseExporter.BrowsePath(path, FileBrowseExporter.MediaFileTypes.Image); FileBrowseExporter.SendFolderFilesAsZipFile(fbr, ref bSender); } else { bSender.Send404Page(); } return true; }
private void GetRecTVThumbnail(ref BrowserSender browserSender, bool isBase64Encoded) { // Any parameters? bool validated = true; validated &= qsParams.HasParameter("filename"); if (!validated) { bool foo = browserSender.Send404Page(); return; } // This can fail with non-ASCII string qsFN = qsParams["filename"]; string fileName = HttpUtility.UrlDecode( qsFN ); if (isBase64Encoded) fileName = Functions.DecodeFromBase64(fileName, Encoding.UTF8); // http uses UTF8 encoding // Find file? string filePath = ""; bool foundFilePath = false; if (File.Exists(fileName)) // Fully qualified path was passed { foundFilePath = true; filePath = fileName; } else { foreach (string recTVFolder in Settings.Default.RecordedTVFolders) { filePath = Path.Combine(recTVFolder, fileName); // If just a filename is provided, then this appends it to the default record path from the registry if (File.Exists(filePath)) { foundFilePath = true; break; } } } if (! foundFilePath) { bool foo = browserSender.Send404Page(); return; } SendFileThumbnail(filePath, FatAttitude.ThumbnailSizes.Medium, ref browserSender); }
private void GetFileThumbnailUsingQueryString(ref BrowserSender browserSender, bool isBase64Encoded) { // Any parameters? bool validated = true; validated &= qsParams.HasParameter("filename"); validated &= qsParams.HasParameter("size"); if (!validated) { bool foo = browserSender.Send404Page(); return; } string size = qsParams["size"]; string qsFN = qsParams["filename"]; string fileName = HttpUtility.UrlDecode( qsFN ); if (isBase64Encoded) fileName = Functions.DecodeFromBase64(fileName, Encoding.UTF8); // http uses UTF8 encoding FatAttitude.ThumbnailSizes tSize = (FatAttitude.ThumbnailSizes)Enum.Parse(typeof(FatAttitude.ThumbnailSizes), size, true); SendFileThumbnail(fileName, tSize, ref browserSender); }
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 SendSegmentData(string txtAction, ref BrowserSender browserSender, int ID, bool sendToBrowser, bool doTranscode) { bool LatestFFmpeg = false; if (txtAction.StartsWith("seg!")) //first wait screen segment for NewLiveTV { txtAction = "seg-99999.ts"; } else if (txtAction.StartsWith("seg$")) //first wait screen segment for latest FFMPEG { LatestFFmpeg = true; txtAction = "seg-99999.ts"; } bool IsNewLiveTV = txtAction.StartsWith("liveseg"); 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 { if (!sendToBrowser) return; browserSender.Send404Page(); return; } int iSegNumber = 0; if (!int.TryParse(strSegNumber, out iSegNumber)) { if (!sendToBrowser) return; browserSender.Send404Page(); return; } int iIndexNumber = 0; //if (IsNewLiveTV) //{ // iIndexNumber = SegmentTabel.getIndex(""+ID, iSegNumber); // iSegNumber = SegmentTabel.getSegment(iIndexNumber, iSegNumber); //} byte[] TSdata = new byte[] { }; string txtError = ""; if (LatestFFmpeg && strSegNumber.Equals("99999")) { StreamingManager.Default.SegmentFromStreamer(iIndexNumber, ID, iSegNumber, ref TSdata, ref txtError, doTranscode); //start up the runners Functions.WriteLineToLogFileIfSetting(Settings.Default.DebugStreaming, "Sending please wait screen"); Segment s = new Segment(); string FN = Functions.ToolkitFolder + "\\pleasewait.ts"; if (!sendToBrowser) return; s.Data = FileToByteArray(FN); browserSender.SendDataToBrowser("video/mp2t", s.Data); } else { if (IsNewLiveTV && strSegNumber.Equals("99999")) { Functions.WriteLineToLogFileIfSetting(Settings.Default.DebugStreaming, "Could not get streaming segment number " + strSegNumber + "but live tv, so continuing"); if (!sendToBrowser) return; // browserSender.Send404Page(); Functions.WriteLineToLogFileIfSetting(Settings.Default.DebugStreaming, "Sending please wait screen"); Segment s = new Segment(); string FN = Functions.ToolkitFolder + "\\pleasewait.ts"; s.Data = FileToByteArray(FN); browserSender.SendDataToBrowser("video/mp2t", s.Data); } else if (StreamingManager.Default.SegmentFromStreamer(iIndexNumber, ID, iSegNumber, ref TSdata, ref txtError, doTranscode)) { { if (!sendToBrowser) return; browserSender.SendDataToBrowser("video/mp2t", TSdata); } return; } else { Functions.WriteLineToLogFileIfSetting(Settings.Default.DebugStreaming, "Could not get streaming segment number " + strSegNumber + ":" + txtError); if (!sendToBrowser) return; 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 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; } }