async Task LoadUserDataAsync(int userId, CancellationTokenSource cts) { if (_userInfoData.ContainsKey(userId)) { return; } // 读取数据 string url = string.Format("http://www.hi-pda.com/forum/space.php?uid={0}&_={1}", userId, 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 node = doc.DocumentNode.Descendants().FirstOrDefault(n => n.Name.Equals("div") && n.GetAttributeValue("id", "").Equals("profilecontent")); if (node != null) { string xaml = Html.HtmlToXaml.ConvertUserInfo(node.InnerHtml); _userInfoData.Add(userId, xaml); } }
async Task LoadUserMessageListDataAsync(int pageNo, CancellationTokenSource cts) { if (pageNo == 1) { // 如果是新打开,则清空所有短消息列表数据 _userMessageListData.Clear(); } if (pageNo > _userMessageListMaxPageNo) { return; } // 读取数据 string url = string.Format("http://www.hi-pda.com/forum/pm.php?filter=privatepm&page={0}&_={1}", pageNo, DateTime.Now.Ticks.ToString("x")); string htmlStr = await _httpClient.GetAsync(url, cts); // 实例化 HtmlAgilityPack.HtmlDocument 对象 HtmlDocument doc = new HtmlDocument(); // 载入HTML doc.LoadHtml(htmlStr); // 最先读取提醒数据 var promptContentNode = doc.DocumentNode.Descendants().FirstOrDefault(n => n.Name.Equals("div") && n.GetAttributeValue("class", "").Equals("promptcontent")); PromptService.GetPromptData(promptContentNode); var items = doc.DocumentNode.Descendants().FirstOrDefault(n => n.Name.Equals("ul") && n.GetAttributeValue("class", "").Equals("pm_list"))?.ChildNodes; if (items == null) { return; } // 读取最大页码 var pagesNode = doc.DocumentNode.Descendants().FirstOrDefault(n => n.Name.Equals("div") && n.GetAttributeValue("class", "").Equals("pages")); _userMessageListMaxPageNo = CommonService.GetMaxPageNo(pagesNode); int i = _userMessageListData.Count; foreach (var item in items) { var isNew = item.ChildNodes[3].ChildNodes.Count >= 4 && item.ChildNodes[3].ChildNodes[3].Name.Equals("img"); var linkNode = item.ChildNodes[3].ChildNodes[1].ChildNodes[0]; int userId = Convert.ToInt32(linkNode.Attributes[0].Value.Substring("space.php?uid=".Length).Split('&')[0]); string username = linkNode.InnerText.Trim(); string lastMessageTime = item.ChildNodes[3].ChildNodes[2].InnerText.Trim().Replace(" ", string.Empty); string lastMessageText = item.ChildNodes[5].InnerText.Trim(); var userMessageListItem = new UserMessageListItemModel(i, isNew, pageNo, userId, username, lastMessageTime, lastMessageText); _userMessageListData.Add(userMessageListItem); i++; } }
async Task <UserMessageDataModel> LoadUserMessageDataAsync(int userId, int limitCount, CancellationTokenSource cts) { var listData = new ObservableCollection <UserMessageItemModel>(); int total = 0; // 读取数据 string url = string.Format("http://www.hi-pda.com/forum/pm.php?uid={0}&filter=privatepm&daterange=5&_={1}", userId, 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 messageListNode = doc.DocumentNode.Descendants().FirstOrDefault(n => n.GetAttributeValue("class", "").Equals("pm_list")); if (messageListNode != null) { var nodeList = messageListNode.Descendants().Where(n => n.GetAttributeValue("id", "").StartsWith("pm_")); if (nodeList != null) { total = nodeList.Count(); if (limitCount != -1 && total > limitCount) { nodeList = nodeList.Skip(total - limitCount); } foreach (var item in nodeList) { listData.Add(GetUserMessageItem(item)); } } } // 清除此用户的私信标识为“NEW”状态的 toast temp data ToastService.ClearPmToastTempData(userId); return(new UserMessageDataModel { ListData = listData, Total = total }); }
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 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++; } }
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); } } }
async Task LoadReplyDataAsync(int threadId, int pageNo, CancellationTokenSource cts) { if (pageNo > 1 && pageNo > _maxPageNo) { return; } int threadAuthorUserId = 0; string threadAuthorUsername = string.Empty; string threadTitle = string.Empty; // 如果页面已存在,则不重新从网站拉取数据,以便节省流量, var threadReply = _replyData.FirstOrDefault(r => r.ThreadId == threadId); if (threadReply != null && threadReply.Replies.Count > 0) { #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 var pageData = threadReply.Replies.Where(r => r.PageNo == pageNo); if (pageData != null && pageData.Count() > 0) { var lastItem = pageData.Last(); if (lastItem != null) { if (lastItem.Index2 == _pageSize) // 当前页已加载满 { return; } else { threadReply.Replies.RemoveAll(r => r.PageNo == pageNo); } } } else { if (pageNo == 1 && threadReply.Replies.Count > 0) { threadReply.Replies.Clear(); } } } else { threadReply = new ReplyPageModel { ThreadId = threadId, Replies = new List <ReplyItemModel>() }; _replyData.Add(threadReply); } // 先移除 IsLast 为 True 的标记项,确保此标记项永远只出现在最后面 threadReply.Replies.RemoveAll(r => r.IsLast); // 读取数据 string url = string.Format("http://www.hi-pda.com/forum/viewthread.php?tid={0}&page={1}&ordertype={2}&_={3}", threadId, pageNo, string.Empty, DateTime.Now.Ticks.ToString("x")); string htmlStr = await _httpClient.GetAsync(url, cts); // 实例化 HtmlAgilityPack.HtmlDocument 对象 HtmlDocument doc = new HtmlDocument(); // 载入HTML doc.LoadHtml(htmlStr); // 最先读取提醒数据 var promptContentNode = doc.DocumentNode.Descendants().FirstOrDefault(n => n.Name.Equals("div") && n.GetAttributeValue("class", "").Equals("promptcontent")); PromptService.GetPromptData(promptContentNode); // 读取最大页码 var pagesNode = doc.DocumentNode.Descendants().FirstOrDefault(n => n.Name.Equals("div") && n.GetAttributeValue("class", "").Equals("pages")); _maxPageNo = CommonService.GetMaxPageNo(pagesNode); var data = doc.DocumentNode.Descendants().FirstOrDefault(n => n.Name.Equals("div") && n.GetAttributeValue("id", "").Equals("postlist"))?.ChildNodes; if (data == null) { return; } // 读取所属版块之名称及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(); } int i = threadReply.Replies.Count(); int j = 1; foreach (var item in data) { 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; 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") || n.GetAttributeValue("class", "").Equals("specialmsg"))); 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 (j > 1) { 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 }); }
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 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++; } }