internal HtmlPage(WebBytes wb, WebString prelimContent) : base(wb.Location) { HeadersCharset = wb.CharacterSet; EncHeaders = prelimContent.UsedEncoding; DetermineEncoding(wb.Data, prelimContent.Document); }
/// <summary> /// Get post associated with post number. /// </summary> /// <returns><see cref="ChanPost">ChanPost</see> detailing the post</returns> /// /// <exception cref="ArgumentNullException">Thrown if board is null.</exception> /// <exception cref="ArgumentException">Thrown if board is empty or whitespace.</exception> /// <exception cref="ArgumentOutOfRangeException">Thrown if postNo <= 0.</exception> /// /// <param name="board">Board where post is located.</param> /// <param name="postNo">Post number.</param> public static ChanPost GetPost(string board, int postNo) { board.ThrowIfNullOrWhiteSpace("board"); if (postNo < 1) { throw new ArgumentOutOfRangeException("post", "Cannot be 0 or negative."); } var jsonReq = string.Format("http://archive.moe/_/api/chan/post/?board={0}&num={1}", board, postNo); var json = WebString.Download(jsonReq); if (!json.Success) { return(new ChanPost(json)); } dynamic postJson = JsonConvert.DeserializeObject(json.Document); int threadNo = postJson.thread_num; string subject = postJson.title; string comment = postJson.comment_sanitized; return(new ChanPost(json.Location, board, ChanTools.GetBoardName(board), threadNo, postNo, subject, comment)); }
public WeatherConditions GetConditions(WeatherLocation location) { if (location == null) { throw new ArgumentNullException(nameof(location)); } if (!location.IsValidQuery) { throw new ArgumentException("WeatherLocation must have a valid value.", nameof(location)); } var queryResult = WebString.Download(MakeQuery(location)); if (!queryResult.Success) { return(new WeatherConditions(queryResult)); } var json = JObject.Parse(queryResult.Document); var message = (string)json["message"]; if (string.IsNullOrEmpty(message)) { return(new WeatherConditions(queryResult.Location, json)); } else { var ex = new JsonErrorException(message); return(new WeatherConditions(queryResult.Location, ex)); } }
FetcherResult Load(Uri uri, bool useCookies, int redirects, string previousPage) { var req = SetupRequest(uri, useCookies); var wb = WebBytes.Create(req, MaxSizeHtml, MaxSizeNonHtml); if (wb.ContentIsHtml) { var page = WebString.Create(wb, EncHelp.Windows1252); Uri refreshUrl; if (redirects < MaxRefreshes && TryGetMetaRefresh(page, out refreshUrl) && VerifyRefresh(page.Location, refreshUrl)) { // If during the redirects we get a different page/HTML string, refrain from following more // redirects. It probably means we've arrived, but only more real world testing will tell us // if that's true. // Otherwise keep trying to follow the redirects. if (redirects == 0 || page.Document == previousPage) { return(Load(refreshUrl, useCookies, (redirects + 1), page.Document)); } } return(new FetcherResult(wb, page)); } // Silently handle cookie exceptions, Mono/.NET can be very strict with which cookies it accepts. if (!wb.Success && wb.Exception.InnerException is CookieException) { return(Load(uri, false, redirects, previousPage)); } // If either not HTML or there was an error in getting the resource, return as-is. return(new FetcherResult(wb)); }
/// <summary> /// Get info of a Danbooru post. /// </summary> /// <returns><see cref="DanboPost">DanboPost</see> detailing a post.</returns> /// <exception cref="ArgumentOutOfRangeException">Thrown if postNo is <= 0.</exception> /// <param name="postNo">Post number.</param> public static DanboPost GetPostInfo(int postNo) { if (postNo < 1) { throw new ArgumentOutOfRangeException(nameof(postNo), "Can't be 0 or negative."); } var jsonReq = string.Format("https://danbooru.donmai.us/posts/{0}.json", postNo); var json = WebString.Download(jsonReq); if (!json.Success) { return(new DanboPost(json)); } dynamic postJson = JsonConvert.DeserializeObject(json.Document); string copyrights = postJson.tag_string_copyright; string characters = postJson.tag_string_character; string artists = postJson.tag_string_artist; string general = postJson.tag_string_general; string meta = postJson.tag_string_meta; string all = postJson.tag_string; string rating = postJson.rating; return(new DanboPost(json.Location, postNo, copyrights, characters, artists, general, meta, all, rating)); }
/// <summary> /// Get post associated with post number. /// </summary> /// <returns><see cref="ChanPost">ChanPost</see> detailing the post.</returns> /// /// <exception cref="ArgumentNullException">Thrown if board is null.</exception> /// <exception cref="ArgumentException">Thrown if board is empty or whitespace.</exception> /// <exception cref="ArgumentOutOfRangeException">Thrown if threadNo and/or postNo <= 0.</exception> /// /// <param name="board">Board where thread/post is located.</param> /// <param name="threadNo">Thread number.</param> /// <param name="postNo">Post number.</param> public static ChanPost GetPost(string board, int threadNo, int postNo) { board.ThrowIfNullOrWhiteSpace("board"); if (threadNo < 1) { throw new ArgumentOutOfRangeException("thread", "Cannot be 0 or negative."); } else if (postNo < 1) { throw new ArgumentOutOfRangeException("post", "Cannot be 0 or negative."); } var jsonReq = string.Format("http://a.4cdn.org/{0}/res/{1}.json", board, threadNo); var json = WebString.Download(jsonReq); if (!json.Success) { return(new ChanPost(json)); } dynamic threadJson = JsonConvert.DeserializeObject(json.Document); string subject = null; string comment = null; // Simple linear search, seems fast enough for the 100s of posts it needs to look through. foreach (var post in threadJson.posts) { if (post.no == postNo) { subject = post.sub; if (!string.IsNullOrEmpty(subject)) { subject = HttpUtility.HtmlDecode(subject); } comment = post.com; if (!string.IsNullOrEmpty(comment)) { comment = Fix4chanPost(comment); } break; } } return(new ChanPost(json.Location, board, ChanTools.GetBoardName(board), threadNo, postNo, subject, comment)); }
public static SearchResults Search(string query) { if (query == null) { throw new ArgumentNullException(nameof(query)); } var results = WebString.Download(GoogleUrl(query)); if (!results.Success) { return(new SearchResults(results)); } var matches = resultsRegexp.Matches(results.Document); var parsedResults = ParseMatches(matches); return(new SearchResults(results, Deduplication(parsedResults))); }
/// <summary> /// Get info of a Gelbooru post. /// </summary> /// <returns><see cref="BooruPost">BooruPost</see> detailing a post.</returns> /// <exception cref="ArgumentOutOfRangeException">Thrown if postNo is <= 0.</exception> /// <param name="postNo">Post number.</param> public static BooruPost GetPostInfo(int postNo) { if (postNo < 1) { throw new ArgumentOutOfRangeException(nameof(postNo), "Can't be 0 or negative."); } var xmlReq = string.Format("https://gelbooru.com/index.php?page=dapi&s=post&q=index&id={0}", postNo); var xml = WebString.Download(xmlReq); if (!xml.Success) { return(new BooruPost(xml)); } var postXml = XElement.Parse(xml.Document).Element("post"); string tags = postXml.Attribute("tags").Value; string rated = postXml.Attribute("rating").Value; return(new BooruPost(xml.Location, postNo, tags, rated)); }
static bool TryGetMetaRefresh(WebString page, out Uri refreshUrl) { string metaRefresh = HtmlTagExtract.GetMetaRefresh(page.Document); if (metaRefresh != null) { // Relative refresh URL. // Try this one first, because creating an absolute URL out of a relative one starting with a '/' can // lead to it being interpreted as a file:/// URI. if (Uri.TryCreate(page.Location, metaRefresh, out refreshUrl)) { return(true); } // Absolute refresh URL. if (Uri.TryCreate(metaRefresh, UriKind.Absolute, out refreshUrl)) { return(true); } } refreshUrl = null; return(false); }
internal FetcherResult(WebBytes bytes, WebString page) { Bytes = bytes; Page = new HtmlPage(bytes, page); }