public async Task <SearchResultPage> Search(
            string terms, string author, string parentAuthor, string category, int page, bool oldestFirst = false)
        {
            if (string.IsNullOrEmpty(category))
            {
                category = "all";
            }

            var query = HttpUtility.ParseQueryString("");

            query.Add("chatty", "1");
            query.Add("type", "4");
            query.Add("chatty_term", terms);
            query.Add("chatty_user", author);
            query.Add("chatty_author", parentAuthor);
            query.Add("chatty_filter", category);
            query.Add("page", $"{page}");
            query.Add("result_sort", oldestFirst ? "postdate_asc" : "postdate_desc");

            var html = await _downloadService.DownloadWithSharedLogin(
                "http://www.shacknews.com/search?" + query.ToString());

            var p = new Parser(html);
            var searchResultPage =
                new SearchResultPage
            {
                Results     = new List <SearchResult>(),
                CurrentPage = page
            };

            if (p.Peek(1, "<h2 class=\"search-num-found\"") != -1)
            {
                searchResultPage.TotalResults = int.Parse(p.Clip(
                                                              new[] { "<h2 class=\"search-num-found\"", ">" },
                                                              " ").Replace(",", ""));
            }

            while (p.Peek(1, "<li class=\"result") != -1 &&
                   p.Peek(1, "<span class=\"chatty-author\">") != -1)
            {
                var result = new SearchResult();
                result.Author = p.Clip(
                    new[] { "<span class=\"chatty-author\">", "<a class=\"more\"", ">" },
                    ":</a></span>");
                result.Date = DateParser.Parse(p.Clip(
                                                   new[] { "<span class=\"postdate\"", ">", " " },
                                                   "</span>"));
                result.Id = int.Parse(p.Clip(
                                          new[] { "<a href=\"/chatty", "chatty/", "/" },
                                          "\""));
                result.Preview = p.Clip(
                    new[] { ">" },
                    "</a>");
                searchResultPage.Results.Add(result);
            }

            return(searchResultPage);
        }
        public async Task <List <FrontPageArticle> > GetStories()
        {
            var html = await _downloadService.DownloadWithSharedLogin("https://www.shacknews.com/feed/rss",
                                                                      verifyLoginStatus : false);

            var list = new List <FrontPageArticle>();
            var p    = new Parser(html);

            p.Seek(1, "<channel>");
            while (p.Peek(1, "<item>") != -1)
            {
                p.Seek(1, "<item>");
                var endPos = p.Peek(1, "</item>");
                var title  = p.Clip(
                    new[] { "<title><![CDATA[", "CDATA[", "[" },
                    "]]></title>");
                var link = p.Clip(
                    new[] { "<link>", ">" },
                    "</link>");
                var pubDateStr = p.Clip(
                    new[] { "<pubDate>", ">" },
                    "</pubDate>");
                var time = DateParser.Parse(pubDateStr);
                // the time zone offset in this time is a lie. this is really UTC.
                time = new DateTimeOffset(time.DateTime, TimeSpan.Zero);
                var description = p.Clip(
                    new[] { "<description><![CDATA[", "CDATA[", "[" },
                    "]]></description>");
                var linkParts = link.Split('/');
                var id        = int.Parse(linkParts[linkParts.Length - 2]);
                list.Add(
                    new FrontPageArticle
                {
                    Body    = description,
                    Date    = time,
                    Id      = id,
                    Name    = title,
                    Preview = description,
                    Url     = link
                });
            }
            return(list);
        }
Ejemplo n.º 3
0
        // if the ID doesn't exist, the returned list will be empty
        public async Task <List <ChattyPost> > GetThreadBodies(int threadId)
        {
            var url  = $"https://www.shacknews.com/frame_laryn.x?root={threadId}";
            var html = await _downloadService.DownloadWithSharedLogin(url, verifyLoginStatus : false);

            if (!html.Contains("</html>", StringComparison.Ordinal))
            {
                throw new ParsingException("Shacknews thread tree HTML ended prematurely.");
            }

            var p    = new Parser(html);
            var list = new List <ChattyPost>();

            while (p.Peek(1, "<div id=\"item_") != -1)
            {
                var reply = new ChattyPost();
                reply.Id = int.Parse(p.Clip(
                                         _threadBodiesReplyIdStart,
                                         "\">"));
                reply.Category = V2ModerationFlagConverter.Parse(p.Clip(
                                                                     new[] { "<div class=\"fullpost", "fpmod_", "_" },
                                                                     " "));
                var authorSection = p.Clip(_threadBodiesAuthorSectionStart, "\"");
                reply.AuthorId = int.Parse(authorSection.Replace("fpfrozen", ""));
                reply.IsFrozen = authorSection.Contains("fpfrozen", StringComparison.Ordinal);
                reply.Author   = HtmlDecodeExceptLtGt(p.Clip(
                                                          _threadBodiesReplyAuthorStart,
                                                          "</a>")).Trim();
                reply.AuthorFlair = ParseUserFlair(p.Clip(_threadBodiesAuthorFlairStart, "</span>"));
                reply.Body        = MakeSpoilersClickable(HtmlDecodeExceptLtGt(RemoveNewlines(p.Clip(
                                                                                                  _threadBodiesReplyBodyStart,
                                                                                                  "</div>"))));
                reply.Date = DateParser.Parse(StripTags(p.Clip(
                                                            _threadBodiesReplyDateStart,
                                                            "T</div")).Replace("Flag", "") + "T");
                list.Add(reply);
            }

            return(list);
        }
Ejemplo n.º 4
0
        public async Task <(string Json, ChattyLolCounts LolCounts)> DownloadChattyLolCounts(
            string previousJson = null, ChattyLolCounts previousChattyLolCounts = null)
        {
            var json = await _downloadService.DownloadWithSharedLogin(
                "https://www.shacknews.com/api2/api-index.php?action2=ext_get_counts",
                verifyLoginStatus : false);

            if (json == previousJson)
            {
                return(json, previousChattyLolCounts);
            }

            var response = JsonSerializer.Deserialize <Dictionary <string, Dictionary <string, Dictionary <string, string> > > >(
                json);

            return(json,
                   new ChattyLolCounts
            {
                CountsByThreadId = (
                    from threadPair in response
                    let threadId = int.Parse(threadPair.Key)
                                   let threadTagsDict = (
                        from postPair in threadPair.Value
                        let postId = int.Parse(postPair.Key)
                                     let postLols = (
                            from x in postPair.Value
                            select new LolModel {
                    Tag = x.Key, Count = int.Parse(x.Value)
                }
                            ).ToList()
                                                    select(PostId: postId, PostTags: postLols)
                        ).ToDictionary(x => x.PostId, x => x.PostTags)
                                                        let threadLolCounts = new ThreadLolCounts {
                    CountsByPostId = threadTagsDict
                }
                    select(ThreadId: threadId, ThreadLolCounts: threadLolCounts)
                    ).ToDictionary(x => x.ThreadId, x => x.ThreadLolCounts)
            });
        }
Ejemplo n.º 5
0
        public async Task <CortexUserData> GetCortexUserData(int userId)
        {
            var page = await _downloadService.DownloadWithSharedLogin($"https://www.shacknews.com/cortex/user/{userId}");

            var parser   = new Parser(page);
            var userData = new CortexUserData();

            userData.UserId   = userId;
            userData.Username = parser.Clip(new string[] { "<span class=\"user-name\"", ">" }, "</span>");
            //Order matters, because we're lazy here.
            userData.Points           = int.Parse(parser.Clip(new string[] { "<span class=\"stat-number\"", ">" }, "</span>"), NumberStyles.Any);
            userData.Comments         = int.Parse(parser.Clip(new string[] { "<span class=\"stat-number\"", ">" }, "</span>"), NumberStyles.Any);
            userData.CortexPosts      = int.Parse(parser.Clip(new string[] { "<span class=\"stat-number\"", ">" }, "</span>"), NumberStyles.Any);
            userData.Wins             = int.Parse(parser.Clip(new string[] { "<span class=\"stat-number\"", ">" }, "</span>"), NumberStyles.Any);
            userData.RegistrationDate = DateTime.Parse(parser.Clip(new string[] { "<span class=\"stat-number\"", ">" }, "</span>"));
            return(userData);
        }
Ejemplo n.º 6
0
        public async Task <(string Html, ChattyPage Page)> GetChattyPage(StepStopwatch stopwatch,
                                                                         int page, string previousHtml = null, ChattyPage previousChattyPage = null)
        {
            stopwatch?.Step($"Download_{page}");
            var url  = $"https://www.shacknews.com/chatty?page={page}";
            var html = await _downloadService.DownloadWithSharedLogin(url);

            stopwatch?.Step($"Parse_{page}");
            // remove the progress meter which changes on every load, so that we'll get identical html when nothing
            // has changed
            html = _progressMeterRegex.Replace(html, "");

            // remove the comment count too, it appears on all pages even though some pages haven't changed
            html = _commentCountRegex.Replace(html, "");

            return(html, html == previousHtml ? previousChattyPage : ParseChattyPage(html));
        }