/// <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}"); }