async Task LoadThreadDataForMyThreadsAsync(int pageNo, CancellationTokenSource cts) { int count = _threadDataForMyThreads.Count(t => t.PageNo == pageNo); if (count == _pageSize) { return; } else { _threadDataForMyThreads.RemoveAll(t => t.PageNo == pageNo); } // 读取数据 string url = string.Format("http://www.hi-pda.com/forum/my.php?item=threads&page={0}&_={1}", pageNo, DateTime.Now.Ticks.ToString("x")); string htmlContent = await _httpClient.GetAsync(url, cts); // 实例化 HtmlAgilityPack.HtmlDocument 对象 HtmlDocument doc = new HtmlDocument(); // 载入HTML doc.LoadHtml(htmlContent); // 最先读取提醒数据 var promptContentNode = doc.DocumentNode.Descendants().FirstOrDefault(n => n.Name.Equals("div") && n.GetAttributeValue("class", "").Equals("promptcontent")); PromptService.GetPromptData(promptContentNode); // 读取主内容 var dataTable = doc.DocumentNode.Descendants().FirstOrDefault(n => n.GetAttributeValue("class", "").Equals("datatable")); if (dataTable == null) { return; } // 读取最大页码 var pagesNode = doc.DocumentNode.Descendants().FirstOrDefault(n => n.GetAttributeValue("class", "").Equals("pages")); _threadMaxPageNoForMyThreads = CommonService.GetMaxPageNo(pagesNode); if (pageNo > _threadMaxPageNoForMyThreads) { return; } var rows = dataTable.ChildNodes[3].Descendants().Where(n => n.Name.Equals("tr")); if (rows == null) { return; } int i = _threadDataForMyThreads.Count; foreach (var item in rows) { var th = item.Descendants().FirstOrDefault(n => n.Name.Equals("th")); var a = th.Descendants().FirstOrDefault(n => n.Name.Equals("a")); string threadName = a.InnerText.Trim(); int threadId = Convert.ToInt32(a.GetAttributeValue("href", "").Substring("viewthread.php?tid=".Length)); var forumNameNode = item.Descendants().FirstOrDefault(n => n.GetAttributeValue("class", "").Equals("forum")); string forumName = forumNameNode.InnerText.Trim(); var lastPostNode = item.Descendants().FirstOrDefault(n => n.GetAttributeValue("class", "").Equals("lastpost")); string lastPostAuthorName = "匿名"; string lastPostTime = string.Empty; string[] lastPostInfo = lastPostNode.InnerText.Trim().Replace("\n", "@").Split('@'); if (lastPostInfo.Length == 2) { lastPostAuthorName = lastPostInfo[0].Trim(); lastPostTime = lastPostInfo[1].Trim() .Replace(string.Format("{0}-{1}-{2} ", DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day), string.Empty) .Replace(string.Format("{0}-", DateTime.Now.Year), string.Empty); } var threadItem = new ThreadItemForMyThreadsModel(i, forumName, threadId, pageNo, threadName, lastPostAuthorName, lastPostTime); _threadDataForMyThreads.Add(threadItem); i++; } }
/// <summary> /// 用于“刷新到尾页”等功能 /// 直接打开指定主题的最后一页加载数据并返回最后一个回复的Index等数据,以便直接跳到此回复 /// </summary> /// <param name="threadId"></param> /// <param name="cts"></param> /// <returns></returns> public async Task <int[]> LoadReplyDataForRedirectToLastPostAsync(int threadId, CancellationTokenSource cts) { // 读取数据 string url = string.Format("http://www.hi-pda.com/forum/viewthread.php?tid={0}&page=9999999&_={1}", threadId, DateTime.Now.Ticks.ToString("x")); string htmlStr = await _httpClient.GetAsync(url, cts); // 实例化 HtmlAgilityPack.HtmlDocument 对象 HtmlDocument doc = new HtmlDocument(); // 载入HTML doc.LoadHtml(htmlStr); // 先清空本贴的回复数据,以便重新加载 _replyData.RemoveAll(r => r.ThreadId == threadId); var threadReply = new ReplyPageModel { ThreadId = threadId, Replies = new List <ReplyItemModel>() }; _replyData.Add(threadReply); // 获取当前页码,及最大页码 int pageNo = 1; var forumControlNode = doc.DocumentNode.Descendants().FirstOrDefault(n => n.Name.Equals("div") && n.GetAttributeValue("class", "").Equals("forumcontrol s_clear")); var pagesNode = forumControlNode.Descendants().FirstOrDefault(n => n.Name.Equals("div") && n.GetAttributeValue("class", "").Equals("pages")); if (pagesNode != null) { var nodeList = pagesNode.Descendants().Where(n => n.Name.Equals("a") || n.Name.Equals("strong")).ToList(); nodeList.RemoveAll(n => n.InnerText.Equals("下一页")); string lastPageNodeValue = nodeList.Last().InnerText.Replace("... ", string.Empty); _maxPageNo = Convert.ToInt32(lastPageNodeValue); var currentPageNode = nodeList.FirstOrDefault(n => n.Name.Equals("strong")); if (currentPageNode != null) { pageNo = Convert.ToInt32(currentPageNode.InnerText); } } int threadAuthorUserId = 0; string threadAuthorUsername = string.Empty; string threadTitle = string.Empty; #region 如果第一项没有贴子及作者数据,则加载第一页读取贴子标题及作者数据 if (pageNo > 1) { var item = threadReply.Replies.FirstOrDefault(); if (item == null || item.ThreadAuthorUserId == 0 || string.IsNullOrEmpty(item.ThreadTitle)) { string val = await LoadTopReplyDataAsync(threadId, cts); string[] ary = val.Split(','); threadAuthorUserId = Convert.ToInt32(ary[0]); threadAuthorUsername = ary[1]; threadTitle = ary[2]; } else { threadAuthorUserId = item.ThreadAuthorUserId; threadAuthorUsername = item.AuthorUsername; threadTitle = item.ThreadTitle; } } #endregion // 读取所属版块之名称及ID int forumId = 0; string forumName = string.Empty; var navNode = doc.DocumentNode.Descendants().FirstOrDefault(n => n.Name.Equals("div") && n.GetAttributeValue("id", "").Equals("nav")); if (navNode != null) { var forumLinkNode = navNode.ChildNodes[3]; forumId = Convert.ToInt32(forumLinkNode.Attributes[0].Value.Substring("forumdisplay.php?fid=".Length).Split('&')[0]); forumName = forumLinkNode.InnerText.Trim(); } var data = doc.DocumentNode.Descendants().FirstOrDefault(n => n.Name.Equals("div") && n.GetAttributeValue("id", "").Equals("postlist")).ChildNodes; int i = 0; int j = 1; foreach (var item in data) { var mainTable = item.Descendants().FirstOrDefault(n => n.Name.Equals("table") && n.GetAttributeValue("summary", "").StartsWith("pid")); var tableRowNode = mainTable.ChildNodes[1]; // tr var postAuthorNode = tableRowNode.ChildNodes[1]; // td.postauthor if (string.IsNullOrEmpty(postAuthorNode.InnerText)) { tableRowNode = mainTable.ChildNodes[3]; // tr postAuthorNode = tableRowNode.ChildNodes[1]; // td.postauthor } var postContentNode = tableRowNode.ChildNodes[3]; // td.postcontent int authorUserId = 0; string authorUsername = string.Empty; var authorNode = postAuthorNode.ChildNodes.FirstOrDefault(n => n.GetAttributeValue("class", "").Equals("postinfo")); if (authorNode != null) { authorNode = authorNode.ChildNodes[1]; // a string authorUserIdStr = authorNode.Attributes[1].Value.Substring("space.php?uid=".Length); if (authorUserIdStr.Contains("&")) { authorUserId = Convert.ToInt32(authorUserIdStr.Split('&')[0]); } else { authorUserId = Convert.ToInt32(authorUserIdStr); } authorUsername = authorNode.InnerText; } // 判断当前用户是否已被屏蔽,是则跳过 if (_myRoamingSettings.BlockUsers.Any(u => u.UserId == authorUserId && u.ForumId == forumId)) { j++; continue; } var floorPostInfoNode = postContentNode.ChildNodes.FirstOrDefault(n => n.GetAttributeValue("class", "").StartsWith("postinfo")); // div var floorLinkNode = floorPostInfoNode.ChildNodes[1].ChildNodes[0]; // a int postId = Convert.ToInt32(floorLinkNode.Attributes["id"].Value.Replace("postnum", string.Empty)); var floorNumNode = floorLinkNode.ChildNodes[0]; // em int floor = Convert.ToInt32(floorNumNode.InnerText); if (floor == 1) { threadAuthorUserId = authorUserId; threadAuthorUsername = authorUsername; var threadTitleNode = postContentNode.Descendants().FirstOrDefault(n => n.Name.Equals("div") && n.GetAttributeValue("id", "").Equals("threadtitle")); if (threadTitleNode != null) { var h1 = threadTitleNode.ChildNodes[1]; var a = h1.Descendants().FirstOrDefault(n => n.Name.Equals("a")); if (a != null) { h1.RemoveChild(a); // 移除版块名称 } threadTitle = h1.InnerText.Trim(); threadTitle = CommonService.MyHtmlDecodeForLoad(threadTitle); } } string postTime = string.Empty; var postTimeNode = postContentNode.Descendants().FirstOrDefault(n => n.Name.Equals("em") && n.GetAttributeValue("id", "").StartsWith("authorposton")); // em if (postTimeNode != null) { postTime = postTimeNode.InnerText .Replace("发表于 ", string.Empty) .Replace(string.Format("{0}-{1}-{2} ", DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day), string.Empty) .Replace(string.Format("{0}-", DateTime.Now.Year), string.Empty); } string textContent = string.Empty; string xamlContent = string.Empty; int imageCount = 0; int inAppLinkCount = 0; var contentNode = postContentNode.Descendants().FirstOrDefault(n => n.Name.Equals("div") && n.GetAttributeValue("class", "").Equals("t_msgfontfix")); if (contentNode != null) { // 用于回复引用 textContent = contentNode.InnerText.Trim(); textContent = new Regex("\r\n").Replace(textContent, "↵"); textContent = new Regex("\r").Replace(textContent, "↵"); textContent = new Regex("\n").Replace(textContent, "↵"); textContent = new Regex(@"↵{1,}").Replace(textContent, "\r\n"); textContent = textContent.Replace(" ", " "); // 转换HTML为XAML string htmlContent = contentNode.InnerHtml.Trim(); var ary = Html.HtmlToXaml.ConvertPost(postId, threadId, forumId, forumName, htmlContent, _floorNoDic, ref InAppLinkUrlDic); xamlContent = ary[0]; inAppLinkCount = Convert.ToInt32(ary[1]); } else { xamlContent = $@"<StackPanel xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation""><RichTextBlock><Paragraph>作者被禁止或删除 内容自动屏蔽</Paragraph></RichTextBlock></StackPanel>"; } var reply = new ReplyItemModel(i, j, floor, postId, pageNo, forumId, forumName, threadId, threadTitle, threadAuthorUserId, authorUserId, authorUsername, textContent, xamlContent, postTime, imageCount, false, inAppLinkCount); threadReply.Replies.Add(reply); if (!_floorNoDic.ContainsKey(postId)) { _floorNoDic.Add(postId, new string[] { authorUserId.ToString(), floor.ToString() }); } i++; j++; } // 如果本次有加载到数据,则为数据列表的末尾添加一项“载入已完成”的标记项 // 方便在加载完成时显示“---完---” // 注意在下一页开始加载前移除此标记项 if (i > 0) { var lastItem = threadReply.Replies.Last(); var flag = new ReplyItemModel(lastItem.Index + 1, lastItem.Index2, -1, -1, lastItem.PageNo, -1, string.Empty, lastItem.ThreadId, string.Empty, -1, -1, string.Empty, string.Empty, string.Empty, string.Empty, -1, false, 0); flag.IsLast = true; threadReply.Replies.Add(flag); } // 加入历史记录 ApplicationView.GetForCurrentView().Title = $"{CommonService.ReplaceEmojiLabel(threadTitle)} - {CommonService.ReplaceEmojiLabel(forumName)}"; _threadHistoryListBoxViewModel.Add(new ThreadItemModelBase { ThreadId = threadId, Title = threadTitle, ForumId = forumId, ForumName = forumName, AuthorUserId = threadAuthorUserId, AuthorUsername = threadAuthorUsername }); int index = threadReply.Replies.Last().Index; return(new int[] { pageNo, index, threadId }); }
public static async Task <PostEditDataModel> LoadContentForEditAsync(CancellationTokenSource cts, int postId, int threadId) { string url = $"http://www.hi-pda.com/forum/post.php?action=edit&tid={threadId}&pid={postId}&_={DateTime.Now.Ticks.ToString("x")}"; string htmlContent = await _httpClient.GetAsync(url, cts); // 实例化 HtmlAgilityPack.HtmlDocument 对象 HtmlDocument doc = new HtmlDocument(); // 载入HTML doc.LoadHtml(htmlContent); // 标题 string title = string.Empty; var subjectInput = doc.DocumentNode.Descendants().FirstOrDefault(n => n.Name.Equals("input") && n.GetAttributeValue("prompt", string.Empty).Equals("post_subject")); if (subjectInput != null) { title = subjectInput.Attributes["value"].Value; title = CommonService.MyHtmlDecodeForLoad(title); } // 内容 string content = string.Empty; var contentTextArea = doc.DocumentNode.Descendants().FirstOrDefault(n => n.Name.Equals("textarea") && n.GetAttributeValue("prompt", string.Empty).Equals("post_message")); if (contentTextArea != null) { content = contentTextArea.InnerText.Replace(SendService.MessageTail, string.Empty).TrimEnd(); content = CommonService.MyHtmlDecodeForLoad(content); } // 读取图片附件 var attachFileList = new ObservableCollection <AttachFileItemModel>(); var uploadFileListNodes = doc.DocumentNode.Descendants().Where(n => n.Name.Equals("div") && n.GetAttributeValue("class", string.Empty).Equals("upfilelist")); var imgList = uploadFileListNodes.First()?.ChildNodes.FirstOrDefault(n => n.Name.Equals("table") && n.GetAttributeValue("class", string.Empty).Equals("imglist")); if (imgList != null) { var images = imgList.Descendants().Where(n => n.Name.Equals("img") && n.GetAttributeValue("src", string.Empty).StartsWith("attachments/day_") && n.GetAttributeValue("id", string.Empty).StartsWith("image_")); if (images != null) { foreach (var img in images) { string id = img.GetAttributeValue("id", string.Empty).Replace("image_", string.Empty); string src = img.GetAttributeValue("src", string.Empty); //src = $"http://www.hi-pda.com/forum/{src}"; attachFileList.Add(new AttachFileItemModel(0, id, src, true)); } } } // 读取文件附件 var fileList = uploadFileListNodes.Last()?.ChildNodes.FirstOrDefault(n => n.Name.Equals("table") && n.GetAttributeValue("summary", string.Empty).Equals("post_attachbody")); if (fileList != null) { var fileLinks = fileList.Descendants().Where(n => n.Name.Equals("a") && (n.GetAttributeValue("onclick", string.Empty).StartsWith("insertAttachTag(") || n.GetAttributeValue("onclick", string.Empty).StartsWith("insertAttachimgTag("))); if (fileLinks != null) { foreach (var link in fileLinks) { string attr = link.GetAttributeValue("onclick", string.Empty); if (attr.StartsWith("insertAttachTag(")) { string id = attr.Replace("insertAttachTag('", string.Empty).Replace("')", string.Empty); string fileName = link.InnerText.Trim(); attachFileList.Add(new AttachFileItemModel(1, id, fileName, true)); } else if (attr.StartsWith("insertAttachimgTag(")) { string id = attr.Replace("insertAttachimgTag('", string.Empty).Replace("')", string.Empty); var imgNode = fileList.Descendants().FirstOrDefault(f => f.Name.Equals("img") && f.GetAttributeValue("id", string.Empty).StartsWith($"image_{id}")); string src = imgNode.Attributes[0].Value; //src = $"http://www.hi-pda.com/forum/{src}"; attachFileList.Add(new AttachFileItemModel(0, id, src, true)); } } } } return(new PostEditDataModel(postId, threadId, title, content, attachFileList)); }
async Task <string> LoadTopReplyDataAsync(int threadId, CancellationTokenSource cts) { string threadTitle = string.Empty; int threadAuthorUserId = 0; string threadAuthorUsername = string.Empty; // 读取数据 string url = string.Format("http://www.hi-pda.com/forum/viewthread.php?tid={0}&page=1", threadId); string htmlStr = await _httpClient.GetAsync(url, cts); // 实例化 HtmlAgilityPack.HtmlDocument 对象 HtmlDocument doc = new HtmlDocument(); // 载入HTML doc.LoadHtml(htmlStr); var data = doc.DocumentNode.Descendants().FirstOrDefault(n => n.Name.Equals("div") && n.GetAttributeValue("id", "").Equals("postlist"))?.ChildNodes; if (data == null) { return(null); } var item = data[0]; var mainTable = item.Descendants().FirstOrDefault(n => n.Name.Equals("table") && n.GetAttributeValue("summary", "").StartsWith("pid") && n.GetAttributeValue("id", "").Equals(n.GetAttributeValue("summary", ""))); var postAuthorNode = mainTable // table .ChildNodes[1] // tr .ChildNodes[1]; // td.postauthor var postContentNode = mainTable // table .ChildNodes[1] // tr .ChildNodes[3]; // td.postcontent int authorUserId = 0; var authorNode = postAuthorNode.ChildNodes.FirstOrDefault(n => n.GetAttributeValue("class", "").Equals("postinfo")); if (authorNode != null) { authorNode = authorNode.ChildNodes[1]; // a string authorUserIdStr = authorNode.Attributes[1].Value.Substring("space.php?uid=".Length); if (authorUserIdStr.Contains("&")) { authorUserId = Convert.ToInt32(authorUserIdStr.Split('&')[0]); } else { authorUserId = Convert.ToInt32(authorUserIdStr); } threadAuthorUserId = authorUserId; threadAuthorUsername = authorNode.InnerText.Trim(); } var threadTitleNode = postContentNode.Descendants().FirstOrDefault(n => n.Name.Equals("div") && n.GetAttributeValue("id", "").Equals("threadtitle")); if (threadTitleNode != null) { var h1 = threadTitleNode.ChildNodes[1]; var a = h1.Descendants().FirstOrDefault(n => n.Name.Equals("a")); if (a != null) { h1.RemoveChild(a); // 移除版块名称 } threadTitle = h1.InnerText.Trim(); threadTitle = CommonService.MyHtmlDecodeForLoad(threadTitle); } return($"{threadAuthorUserId},{threadAuthorUsername},{threadTitle}"); }
async Task LoadThreadDataAsync(int typeId, int forumId, int pageNo, CancellationTokenSource cts) { var d = _threadData.Where(t => t.ForumId == forumId && t.PageNo == pageNo); if (d != null && d.Count() > 0) { int indexInPage = d.Last().Index2; if (indexInPage == _pageSize) { return; } else { _threadData.RemoveAll(t => t.ForumId == forumId && t.PageNo == pageNo); } } if (pageNo == 1) { // 第一次打开或刷新时,先请求一下,看看是否有新私信 // 这是论坛的一种机制,否则APP过了一段时间之后不能从HTML中解析私人消息的数量 await _httpClient.GetAsync(string.Format("http://www.hi-pda.com/forum/pm.php?checknewpm={0}&inajax=1&ajaxtarget=myprompt_check", DateTime.Now.Ticks.ToString("x")), cts); } // 读取数据 string _orderBy = RoamingSettingsService.GetOrderByDateline(forumId) == true ? "dateline" : string.Empty; string url = string.Format("http://www.hi-pda.com/forum/forumdisplay.php?fid={0}&orderby={1}&page={2}&_={3}", forumId, _orderBy, pageNo, DateTime.Now.Ticks.ToString("x")); if (typeId > 0) { url += $"&filter=type&typeid={typeId}"; } string htmlContent = await _httpClient.GetAsync(url, cts); // 实例化 HtmlAgilityPack.HtmlDocument 对象 HtmlDocument doc = new HtmlDocument(); // 载入HTML doc.LoadHtml(htmlContent); // 最先读取提醒数据 var promptContentNode = doc.DocumentNode.Descendants().FirstOrDefault(n => n.Name.Equals("div") && n.GetAttributeValue("class", "").Equals("promptcontent")); PromptService.GetPromptData(promptContentNode); // 读取主内容 var dataTable = doc.DocumentNode.Descendants().FirstOrDefault(n => n.Name.Equals("table") && n.GetAttributeValue("class", "").Equals("datatable")); if (dataTable == null) { _maxPageNo = -1; // 找不到目标数据,一般为得到的是提示登录的页面的HTML,故在此将最大页标记为-1,以便增量加载不再继续 return; } // 读取所属版块之名称 string forumName = string.Empty; var titleNode = doc.DocumentNode.Descendants().FirstOrDefault(n => n.Name.Equals("title")); if (titleNode != null) { string[] tary = titleNode.InnerText.Trim().Split('-'); forumName = tary[0].Trim(); } // 读取最大页码 var pagesNode = doc.DocumentNode.Descendants().FirstOrDefault(n => n.Name.Equals("div") && n.GetAttributeValue("class", "").Equals("pages")); _maxPageNo = CommonService.GetMaxPageNo(pagesNode); if (pageNo > _maxPageNo) { return; } // 如果置顶贴数过多,只取非置顶贴的话,第一页数据项过少,会导致不会自动触发加载下一页数据 var tbodies = dataTable.ChildNodes.Where(n => n.GetAttributeValue("id", "").Contains("stickthread_") || n.GetAttributeValue("id", "").Contains("normalthread_")); if (tbodies == null) { return; } int i = _threadData.Count(t => t.ForumId == forumId); int j = 1; foreach (var item in tbodies) { var tr = item.ChildNodes[1]; var th = tr.ChildNodes[5]; var span = th.ChildNodes.FirstOrDefault(n => n.Name.Equals("span") && n.GetAttributeValue("id", "").StartsWith("thread_")); var a = span.ChildNodes[0]; var tdAuthor = tr.ChildNodes[7]; var tdNums = tr.ChildNodes[9]; var tdLastPost = tr.ChildNodes[11]; int threadId = Convert.ToInt32(span.Attributes[0].Value.Substring("thread_".Length)); string title = a.InnerText.Trim(); title = WebUtility.HtmlDecode(title); // 判断当前主题是否已被屏蔽,是则跳过 if (_myRoamingSettings.BlockThreads.Any(t => t.ThreadId == threadId)) { j++; continue; } var authorName = string.Empty; int authorUserId = 0; var authorNameNode = tdAuthor.ChildNodes[1]; // cite 此节点有出“匿名”的可能 var authorNameLink = authorNameNode.ChildNodes.FirstOrDefault(n => n.Name.Equals("a")); if (authorNameLink == null) { authorName = authorNameNode.InnerText.Trim(); } else { authorName = authorNameLink.InnerText; string authorUserIdStr = authorNameLink.Attributes[0].Value.Substring("space.php?uid=".Length); if (authorUserIdStr.Contains("&")) { authorUserId = Convert.ToInt32(authorUserIdStr.Split('&')[0]); } else { authorUserId = Convert.ToInt32(authorUserIdStr); } } // 判断当前版块下的当前用户是否已被屏蔽,是则跳过 if (_myRoamingSettings.BlockUsers.Any(u => u.UserId == authorUserId && u.ForumId == forumId)) { j++; continue; } bool isTop = item.GetAttributeValue("id", "").StartsWith("stickthread_"); // 根据“是否显示置顶贴”的设置值来决定是否跳过当前主题 if (!_myRoamingSettings.CanShowTopThread && isTop) { j++; continue; } int attachType = -1; var attachIconNode = th.ChildNodes.FirstOrDefault(n => n.Name.Equals("img") && n.GetAttributeValue("class", "").Equals("attach")); if (attachIconNode != null) { string attachString = attachIconNode.Attributes[1].Value; if (attachString.Equals("图片附件")) { attachType = 1; } if (attachString.Equals("附件")) { attachType = 2; } } var authorCreateTime = tdAuthor.ChildNodes[3].InnerText; string[] nums = tdNums.InnerText.Split('/'); var replyNum = nums[0].Trim(); var viewNum = nums[1].Trim(); string lastPostAuthorName = "匿名"; string lastPostTime = string.Empty; string[] lastPostInfo = tdLastPost.InnerText.Trim().Replace("\n", "@").Split('@'); if (lastPostInfo.Length == 2) { lastPostAuthorName = lastPostInfo[0].Trim(); lastPostTime = lastPostInfo[1].Trim() .Replace(string.Format("{0}-{1}-{2} ", DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day), string.Empty) .Replace(string.Format("{0}-", DateTime.Now.Year), string.Empty); } var threadItem = new ThreadItemModel(i, j, forumId, forumName, threadId, pageNo, title, attachType, replyNum, viewNum, isTop, authorName, authorUserId, authorCreateTime, lastPostAuthorName, lastPostTime, AccountService.UserId == authorUserId); _threadData.Add(threadItem); i++; j++; } }
async Task LoadThreadDataForMyPostsAsync(int pageNo, CancellationTokenSource cts) { int count = _threadDataForMyPosts.Count(t => t.PageNo == pageNo); if (count == _pageSize) { return; } else { _threadDataForMyPosts.RemoveAll(t => t.PageNo == pageNo); } // 读取数据 string url = string.Format("http://www.hi-pda.com/forum/my.php?item=posts&page={0}&_={1}", pageNo, DateTime.Now.Ticks.ToString("x")); string htmlContent = await _httpClient.GetAsync(url, cts); // 实例化 HtmlAgilityPack.HtmlDocument 对象 HtmlDocument doc = new HtmlDocument(); // 载入HTML doc.LoadHtml(htmlContent); // 最先读取提醒数据 var promptContentNode = doc.DocumentNode.Descendants().FirstOrDefault(n => n.Name.Equals("div") && n.GetAttributeValue("class", "").Equals("promptcontent")); PromptService.GetPromptData(promptContentNode); // 读取主内容 var dataTable = doc.DocumentNode.Descendants().FirstOrDefault(n => n.GetAttributeValue("class", "").Equals("datatable")); if (dataTable == null) { return; } // 读取最大页码 var pagesNode = doc.DocumentNode.Descendants().FirstOrDefault(n => n.GetAttributeValue("class", "").Equals("pages")); _maxPageNo = CommonService.GetMaxPageNo(pagesNode); if (pageNo > _maxPageNo) { return; } var rows = dataTable.ChildNodes[3].Descendants().Where(n => n.Name.Equals("tr")).ToList(); if (rows == null) { return; } int i = _threadDataForMyPosts.Count; for (int j = 0; j < rows.Count - 1; j += 2) { var tr = rows[j]; var tr2 = rows[j + 1]; var th = tr.Descendants().FirstOrDefault(n => n.Name.Equals("th")); var a = th.Descendants().FirstOrDefault(n => n.Name.Equals("a")); string threadName = a.InnerText.Trim(); string[] pramaStr = a.GetAttributeValue("href", "").Substring("redirect.php?goto=findpost&pid=".Length).Replace("&ptid=", ",").Split(','); int threadId = Convert.ToInt32(pramaStr[1]); int postId = Convert.ToInt32(pramaStr[0]); var th2 = tr2.Descendants().FirstOrDefault(n => n.Name.Equals("th")); string lastPostContent = th2.InnerText.Trim(); lastPostContent = lastPostContent.Replace("\n", string.Empty); lastPostContent = lastPostContent.Replace("\r", string.Empty); var forumNameNode = tr.Descendants().FirstOrDefault(n => n.GetAttributeValue("class", "").Equals("forum")); string forumName = forumNameNode.InnerText.Trim(); var lastPostNode = tr.Descendants().FirstOrDefault(n => n.GetAttributeValue("class", "").Equals("lastpost")); string lastPostTime = lastPostNode.InnerText.Trim(); lastPostTime = lastPostTime .Replace(string.Format("{0}-{1}-{2} ", DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day), string.Empty) .Replace(string.Format("{0}-", DateTime.Now.Year), string.Empty); var threadItem = new ThreadItemForMyPostsModel(i, forumName, threadId, postId, pageNo, threadName, lastPostContent, lastPostTime); _threadDataForMyPosts.Add(threadItem); i++; } }
async Task LoadThreadDataForSearchTitleAsync(string searchKeyword, string searchAuthor, int searchTimeSpan, int searchForumSpan, int pageNo, CancellationTokenSource cts) { int count = _threadDataForSearchTitle.Count(t => t.PageNo == pageNo); if (count == _pageSize) { return; } else { _threadDataForSearchTitle.RemoveAll(t => t.PageNo == pageNo); } // 读取数据 string searchTimeSpanStr = string.Empty; switch (searchTimeSpan) { case 1: searchTimeSpanStr = "604800"; // 一周 break; case 2: searchTimeSpanStr = "2592000"; // 一个月 break; case 3: searchTimeSpanStr = "7776000"; // 三个月 break; case 4: searchTimeSpanStr = "31536000"; // 一年 break; default: searchTimeSpanStr = "0"; // 全部时间 break; } string searchForumSpanStr = searchForumSpan == -1 ? "all" : searchForumSpan.ToString(); string url = string.Format("http://www.hi-pda.com/forum/search.php?srchtype={2}&srchtxt={0}&searchsubmit=%CB%D1%CB%F7&st=on&srchuname={1}&srchfilter=all&srchfrom={3}&before=&orderby={5}&ascdesc=desc&srchfid%5B0%5D={4}&page={6}&_={7}", _httpClient.GetEncoding(searchKeyword), _httpClient.GetEncoding(searchAuthor), "title", searchTimeSpanStr, searchForumSpanStr, "lastpost", pageNo, DateTime.Now.Ticks.ToString("x")); string htmlContent = await _httpClient.GetAsync(url, cts); // 实例化 HtmlAgilityPack.HtmlDocument 对象 HtmlDocument doc = new HtmlDocument(); // 载入HTML doc.LoadHtml(htmlContent); // 最先读取提醒数据 var promptContentNode = doc.DocumentNode.Descendants().FirstOrDefault(n => n.Name.Equals("div") && n.GetAttributeValue("class", "").Equals("promptcontent")); PromptService.GetPromptData(promptContentNode); // 读取主内容 var dataTable = doc.DocumentNode.Descendants().FirstOrDefault(n => n.GetAttributeValue("class", "").Equals("datatable")); if (dataTable == null || dataTable.ChildNodes[2].InnerText.Trim().Equals("对不起,没有找到匹配结果。")) { return; } // 读取最大页码 var pagesNode = doc.DocumentNode.Descendants().FirstOrDefault(n => n.GetAttributeValue("class", "").Equals("pages")); _threadMaxPageNoForSearchTitle = CommonService.GetMaxPageNo(pagesNode); if (pageNo > _threadMaxPageNoForSearchTitle) { return; } var tbodies = dataTable.Descendants().Where(n => n.Name.Equals("tbody")); if (tbodies == null) { return; } int i = _threadDataForSearchTitle.Count; foreach (var item in tbodies) { var tr = item.ChildNodes[1]; var th = tr.ChildNodes[5]; var a = th.ChildNodes[3]; var tdAuthor = tr.ChildNodes[9]; var tdNums = tr.ChildNodes[11]; var tdLastPost = tr.ChildNodes[13]; int threadId = 0; string threadIdStr = a.Attributes[0].Value.Substring("viewthread.php?tid=".Length); threadIdStr = threadIdStr.Split('&')[0]; int.TryParse(threadIdStr, out threadId); string title = a.InnerHtml; int attachType = -1; var attachIconNode = th.Descendants().FirstOrDefault(n => n.GetAttributeValue("class", "").Equals("attach")); if (attachIconNode != null) { string attachString = attachIconNode.Attributes[1].Value; if (attachString.Equals("图片附件")) { attachType = 1; } if (attachString.Equals("附件")) { attachType = 2; } } var forumNameNode = item.Descendants().FirstOrDefault(n => n.GetAttributeValue("class", "").Equals("forum")); string forumName = forumNameNode.InnerText.Trim(); var authorUsername = string.Empty; int authorUserId = 0; var authorNameNode = tdAuthor.ChildNodes[1]; // cite 此节点有出“匿名”的可能 var authorNameLink = authorNameNode.Descendants().FirstOrDefault(n => n.Name.Equals("a")); if (authorNameLink == null) { authorUsername = authorNameNode.InnerText.Trim(); } else { authorUsername = authorNameLink.InnerText; string authorUserIdStr = authorNameLink.Attributes[0].Value.Substring("space.php?uid=".Length); authorUserIdStr = authorUserIdStr.Split('&')[0]; authorUserId = Convert.ToInt32(authorUserIdStr); } var authorCreateTime = tdAuthor.ChildNodes[3].InnerText; string[] nums = tdNums.InnerText.Split('/'); var replyCount = nums[0].Trim(); var viewCount = nums[1].Trim(); string lastReplyUsername = "******"; string lastReplyTime = string.Empty; string[] lastPostInfo = tdLastPost.InnerText.Trim().Replace("\n", "@").Split('@'); if (lastPostInfo.Length == 2) { lastReplyUsername = lastPostInfo[0]; lastReplyTime = lastPostInfo[1] .Replace(string.Format("{0}-{1}-{2} ", DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day), string.Empty) .Replace(string.Format("{0}-", DateTime.Now.Year), string.Empty); } var threadItem = new ThreadItemForSearchTitleModel(i, searchKeyword, forumName, threadId, pageNo, title, attachType, replyCount, viewCount, authorUsername, authorUserId, authorCreateTime, lastReplyUsername, lastReplyTime); _threadDataForSearchTitle.Add(threadItem); i++; } }
async Task LoadThreadDataForSearchFullTextAsync(string searchKeyword, string searchAuthor, int searchTimeSpan, int searchForumSpan, int pageNo, CancellationTokenSource cts) { int count = _threadDataForSearchFullText.Count(t => t.PageNo == pageNo); if (count == _pageSize) { return; } else { _threadDataForSearchFullText.RemoveAll(t => t.PageNo == pageNo); } // 读取数据 string searchTimeSpanStr = string.Empty; switch (searchTimeSpan) { case 1: searchTimeSpanStr = "604800"; // 一周 break; case 2: searchTimeSpanStr = "2592000"; // 一个月 break; case 3: searchTimeSpanStr = "7776000"; // 三个月 break; case 4: searchTimeSpanStr = "31536000"; // 一年 break; default: searchTimeSpanStr = "0"; // 全部时间 break; } string searchForumSpanStr = searchForumSpan == -1 ? "all" : searchForumSpan.ToString(); string url = string.Format("http://www.hi-pda.com/forum/search.php?srchtype={2}&srchtxt={0}&searchsubmit=%CB%D1%CB%F7&st=on&srchuname={1}&srchfilter=all&srchfrom={3}&before=&orderby={5}&ascdesc=desc&srchfid%5B0%5D={4}&page={6}&_={7}", _httpClient.GetEncoding(searchKeyword), _httpClient.GetEncoding(searchAuthor), "fulltext", searchTimeSpanStr, searchForumSpanStr, "lastpost", pageNo, DateTime.Now.Ticks.ToString("x")); string htmlContent = await _httpClient.GetAsync(url, cts); // 实例化 HtmlAgilityPack.HtmlDocument 对象 HtmlDocument doc = new HtmlDocument(); // 载入HTML doc.LoadHtml(htmlContent); // 最先读取提醒数据 var promptContentNode = doc.DocumentNode.Descendants().FirstOrDefault(n => n.Name.Equals("div") && n.GetAttributeValue("class", "").Equals("promptcontent")); PromptService.GetPromptData(promptContentNode); // 读取主内容 var dataTable = doc.DocumentNode.Descendants().FirstOrDefault(n => n.GetAttributeValue("class", "").Equals("datatable")); if (dataTable == null || dataTable.InnerText.Trim().Equals("对不起,没有找到匹配结果。")) { return; } // 读取最大页码 var pagesNode = doc.DocumentNode.Descendants().FirstOrDefault(n => n.GetAttributeValue("class", "").Equals("pages")); _threadMaxPageNoForSearchFullText = CommonService.GetMaxPageNo(pagesNode); if (pageNo > _threadMaxPageNoForSearchFullText) { return; } var rows = dataTable.Descendants().Where(n => n.Name.Equals("tr")); if (rows == null) { return; } int i = _threadDataForSearchFullText.Count; foreach (var r in rows) { string titleHtml = string.Empty; int postId = 0; string summaryHtml = string.Empty; string forumName = string.Empty; string replyCount = string.Empty; string viewCount = string.Empty; string authorUsername = string.Empty; int authorUserId = 0; string lastReplyTime = string.Empty; try { var div = r.ChildNodes[0].ChildNodes[0]; var div1 = div.ChildNodes[1]; var div2 = div.ChildNodes[3]; var div3 = div.ChildNodes[5]; var titleNode = div1.ChildNodes[2]; string postIdStr = titleNode.Attributes[0].Value.Substring("gotopost.php?pid=".Length).Split('&')[0]; if (!string.IsNullOrEmpty(postIdStr)) { postId = Convert.ToInt32(postIdStr); titleHtml = WebUtility.HtmlDecode(titleNode.InnerHtml); summaryHtml = WebUtility.HtmlDecode(div2.InnerHtml); forumName = div3.ChildNodes[1].ChildNodes[1].InnerText.Trim(); var authorNode = div3.ChildNodes[3]; authorUsername = authorNode.InnerText.Replace("作者: ", string.Empty).Trim(); authorUserId = Convert.ToInt32(authorNode.ChildNodes[1].Attributes[0].Value.Substring("space.php?uid=".Length).Split('&')[0]); viewCount = div3.ChildNodes[5].InnerText.Trim().Replace("查看: ", string.Empty).Trim(); replyCount = div3.ChildNodes[7].InnerText.Trim().Replace("回复: ", string.Empty).Trim(); lastReplyTime = div3.ChildNodes[9].InnerText.Trim().Replace("最后发表: ", string.Empty).Trim(); } var threadItem = new ThreadItemForSearchFullTextModel(i, postId, summaryHtml, forumName, pageNo, titleHtml, replyCount, viewCount, authorUsername, authorUserId, lastReplyTime); _threadDataForSearchFullText.Add(threadItem); i++; } catch (Exception ex) { string errorDetails = "k: {0};p: {1};i: {2};t: {3};d: {4}"; errorDetails = string.Format(errorDetails, searchKeyword, pageNo, i, titleHtml, ex.Message); CommonService.PostErrorEmailToDeveloper("全文搜索解析出现异常", errorDetails); } } }