Beispiel #1
0
        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&amp;pid=".Length).Replace("&amp;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++;
            }
        }
Beispiel #2
0
        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);
                }
            }
        }
Beispiel #3
0
        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++;
            }
        }
Beispiel #4
0
        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));
        }
Beispiel #5
0
        /// <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("&nbsp;", "  ");

                    // 转换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>作者被禁止或删除&#160;内容自动屏蔽</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 });
        }
Beispiel #6
0
        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}");
        }
Beispiel #7
0
        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++;
            }
        }