private void primeCommentMonitor(DateTime lastActivityTimeUtc) { bool lastCommentSet = false; _subreddit.GetComments().Where(c => c.CreatedUTC > lastActivityTimeUtc.AddMinutes(-5)) .ForEach(comment => { if (!lastCommentSet && isValidComment(comment.FullName).Result) { _db4Repository.SetLastProcessedCommentId(comment.FullName); lastCommentSet = true; } }); }
private static async Task DoBotLoop() { while (true) { //Get the latest 1000 comments on the subreddit, the filter to the ones that have the keyword //and have not already been replied to Console.WriteLine("Getting comments..."); List <Comment> comments = await subReddit.GetComments(1000, 1000).Where(c => c.Body.Contains(BOTKEYWORD)).ToList(); comments = RemoveAlreadyRepliedTo(comments); foreach (Comment comment in comments) { try { string reply = GetReplyForComment(comment); await comment.ReplyAsync(reply); Console.WriteLine($"Replied to comment {comment.Id}"); LogCommentBeenRepliedTo(comment); } catch (RateLimitException) { Console.WriteLine("Rate limit hit. Postponing reply until next iteration"); } catch (Exception e) { Console.WriteLine($"Exception occurred with comment https://reddit.com{comment.Permalink}"); Console.WriteLine($"{e.Message}\n{e.StackTrace}"); } } Console.WriteLine("Sleeping for 10 seconds..."); Thread.Sleep(10000); //Sleep for 10 seconds so as not to overload reddit } }
async Task test() { applicationStart = DateTime.UtcNow; using (StreamReader sr = new StreamReader(new FileStream("data//Config.json", FileMode.Open))) Config = JsonConvert.DeserializeObject <Dictionary <string, string> >(sr.ReadToEnd()); using (StreamReader sr = new StreamReader(new FileStream("data//FlairConfig.json", FileMode.Open))) FlairConfig = JsonConvert.DeserializeObject <Dictionary <string, int> >(sr.ReadToEnd()); var webAgent = new BotWebAgent(Config["botAcc"], Config["botPw"], Config["clientId"], Config["clientSecret"], Config["redirectURI"]); reddit = new Reddit(webAgent, false); await reddit.InitOrUpdateUserAsync(); subreddit = await reddit.GetSubredditAsync(Config["subreddit"]); CancellationTokenSource source = new CancellationTokenSource(); CancellationToken token = source.Token; ListingStream <Post> postStream = subreddit.GetPosts(Subreddit.Sort.New).Stream(); postStream.Subscribe(async post => await newPost(post)); ListingStream <Comment> commentStream = subreddit.GetComments().Stream(); commentStream.Subscribe(async comment => await newComment(comment)); ListingStream <VotableThing> removedStream = subreddit.GetRemoved().Stream(); removedStream.Subscribe(async thing => await removedThing(thing)); await Task.WhenAll(new Task[] { postStream.Enumerate(token), commentStream.Enumerate(token), removedStream.Enumerate(token) }); }
private async void monitorComments(int commentScanIntervalSeconds) { await Task.Factory.StartNew(async() => { while (true) { try { if (DateTime.UtcNow > _lastCommentCheckUtc.AddSeconds(commentScanIntervalSeconds)) { // Get the last valid processed comment // This looping / comment checking has to be done // since deleted comments won't return anything var lastCommentIds = _db4Repository.GetLastProcessedCommentIds(); string lastProcessedCommentId = string.Empty; foreach (string lastCommentId in lastCommentIds) { if (await isValidComment(lastCommentId)) { lastProcessedCommentId = lastCommentId; break; } } // If we got here with no commentId, DeltaBot can't continue. if (string.IsNullOrEmpty(lastProcessedCommentId)) { var latestComments = await _subreddit.GetComments(1).OrderByDescending(c => c.CreatedUTC).ToList(); if (latestComments != null && latestComments.Count > 0) { lastProcessedCommentId = latestComments[0].FullName; // Need to have a good starting point ASAP _db4Repository.SetLastProcessedCommentId(lastProcessedCommentId); _logger.Warn($"WARN: Had to bootstrap from latest comment: {lastProcessedCommentId}!!"); } else { _logger.Error(new Exception(), "CRITICAL: No valid last processed comment found. DeltaBot cannot continue monitoring comments..."); break; } } var commentsJson = await _subreddit.WebAgent.Get($"/r/{_subreddit.Name}/comments.json?before={lastProcessedCommentId}&limit=100"); var children = commentsJson["data"]["children"] as JArray; var comments = new List <Comment>(); if (children != null && children.Count > 0) { foreach (var child in children) { comments.Add(Thing.Parse <Comment>(_subreddit.WebAgent, child)); } } if (comments.Count > 0) { // Make sure comments are sorted oldest to newest so oldest get processed first var sortedComments = comments.OrderBy(c => c.CreatedUTC).ToList(); foreach (var comment in sortedComments) { // Record the time when this was processed. // Whenever DeltaBot stops, it's going to read this time // and query / process all things starting from this time _db4Repository.SetLastActivityTimeUtc(); // Send to queue for processing _activityDispatcher.SendToQueue(comment); // Mark as the last processed comment _db4Repository.SetLastProcessedCommentId(comment.FullName); } } _lastCommentCheckUtc = DateTime.UtcNow; } Thread.Sleep(100); } catch (Exception ex) { _logger.Error(ex, "Error in comment monitor loop - continuing..."); } } }, _cancellationTokenSource.Token); _logger.Info("Started monitoring comments..."); }
private async Task Go() { Config = Cfg.Config; bool d1 = bool.Parse(Config["Delete"]); bool o1 = bool.Parse(Config["Overwrite"]); if (d1 && !o1) { Console.WriteLine("Fix your configuration file. If you delete without also overwriting, then the original comment will remain in the reddit database even though the comment is deleted, according to Reddit admins."); return; } rand = new Random(BitConverter.ToInt32(new Guid().ToByteArray().Take(4).ToArray())); AuthenticatedFixture authFixture = new AuthenticatedFixture(); Reddit reddit = new Reddit(authFixture.WebAgent, true); IEnumerable <string> srs = Config.GetSection("Places:SubReddits").GetChildren().ToList().Select(x => x.Value); foreach (string srn in srs) { Subreddit sr = await reddit.GetSubredditAsync(srn, true); //by comment Console.WriteLine($"comments from {srn} follow"); List <InterestingComment> interstingComments = new List <InterestingComment>(); int junk = 0; IAsyncEnumerator <Comment> comments = sr.GetComments().GetEnumerator(50, -1, false); while (await comments.MoveNext(CancellationToken.None)) { Comment comment = comments.Current; if (comment.Vote == VotableThing.VoteType.Upvote && bool.Parse(Config["UnUpVote"])) { try { await comment.ClearVote(); InterestingLog("un-up-vote +1 => 0 | " + comment.AsString()); } catch (Exception ex) { //can't check for archived without walking up the heirarchy... //InterestingLog($"failed to un-up-vote because {ex.Message} | {comment.AsString()}"); } } else if (comment.Vote == VotableThing.VoteType.Downvote && bool.Parse(Config["UnDownVote"])) { try { await comment.ClearVote(); InterestingLog("un-down-vote -1 => 0 | " + comment.AsString()); } catch (Exception ex) { //can't check for archived without walking up the heirarchy... //InterestingLog($"failed to un-down-vote because {ex.Message} | {comment.AsString()}"); } } if (IsInteresting(comment)) { if (UserIsAuthor(comment)) { try { InterestingComment inter = new InterestingComment() { Comment = comment }; InterestingLog(inter); interstingComments.Add(inter); if (bool.Parse(Config["Overwrite"])) { await comment.EditTextAsync(Dust()); await Task.Delay(1000); // just in case... inter.Overwritten = true; InterestingLog(inter); } if (bool.Parse(Config["Delete"])) { await comment.DelAsync(); inter.Deleted = true; await Task.Delay(1000); // just in case... InterestingLog(inter); } } catch (Exception ex) { Debugger.Break(); } } else { InterestingLog(new InterestingComment() { Comment = comment }); } } else { JunkLog(new JunkComment() { Comment = comment }); junk++; } } Console.WriteLine($"done with {srn} comments, interesting: {interstingComments.Count}, junk: {junk}"); if (interstingComments.Count > 0) { Console.WriteLine(); Console.WriteLine($"Interesting comments from {srn} follow:"); foreach (InterestingComment inter in interstingComments) { Console.WriteLine(inter); } Console.WriteLine(); } //by post Console.WriteLine($"posts from {srn} follow"); List <InterestingPost> interstingPosts = new List <InterestingPost>(); junk = 0; IAsyncEnumerator <Post> posts = sr.GetPosts().GetEnumerator(50, -1, false); while (await posts.MoveNext(CancellationToken.None)) { Post post = posts.Current; if (IsInteresting(post)) { if (UserIsAuthor(post)) { try { InterestingPost inter = new InterestingPost() { Post = post }; InterestingLog(inter); interstingPosts.Add(inter); if (bool.Parse(Config["Overwrite"])) { await post.EditTextAsync(Dust()); await Task.Delay(1000); // just in case... inter.Overwritten = true; InterestingLog(inter); } if (bool.Parse(Config["Delete"])) { await post.DelAsync(); inter.Deleted = true; await Task.Delay(1000); // just in case... InterestingLog(inter); } } catch (Exception ex) { Debugger.Break(); } } else { InterestingLog(new InterestingPost() { Post = post }); } } else { JunkLog(new JunkPost() { Post = post }); junk++; } } Console.WriteLine($"done with {srn} posts, interesting: {interstingPosts.Count}, junk: {junk}"); if (interstingPosts.Count > 0) { Console.WriteLine(); Console.WriteLine($"Interesting posts from {srn} follow:"); foreach (InterestingPost inter in interstingPosts) { Console.WriteLine(inter); } Console.WriteLine(); } } if (bool.Parse(Config["UnDownVote"]) || bool.Parse(Config["UnUpVote"])) { RedditUser user = await RedditUser.GetUserAsync(authFixture.WebAgent, authFixture.UserName); if (bool.Parse(Config["UnDownVote"])) { IAsyncEnumerator <Post> enumDisliked = user.GetDislikedPosts().GetEnumerator(); while (await enumDisliked.MoveNext(CancellationToken.None)) { Post disliked = enumDisliked.Current; if (!disliked.IsArchived) { try { await disliked.SetVoteAsync(VotableThing.VoteType.None); InterestingLog("un-down-vote -1 => 0 | " + disliked.AsString()); } catch (Exception ex) { InterestingLog($"failed to un-down-vote because {ex.Message} | {disliked.AsString()}"); } } } } if (bool.Parse(Config["UnUpVote"])) { IAsyncEnumerator <Post> enumLiked = user.GetLikedPosts().GetEnumerator(); while (await enumLiked.MoveNext(CancellationToken.None)) { Post liked = enumLiked.Current; if (!liked.IsArchived) { try { await liked.SetVoteAsync(VotableThing.VoteType.None); } catch (Exception ex) { InterestingLog($"failed to un-up-vote because {ex.Message} | {liked.AsString()}"); } InterestingLog("un-up-vote +1 => 0 | " + liked.AsString()); } } } } }