示例#1
0
        private async Task ProcessModLog()
        {
            var yt = new YouTubeService(new BaseClientService.Initializer {
                ApiKey = YouTubeAPIKey
            });

            var req            = yt.Videos.List("snippet");
            var lastRemoval    = PostRemoval.GetLastProcessedRemovalDate(Subreddit);
            var processedCount = 0;
            var modActions     = RedditClient.GetSubreddit(Subreddit).GetModerationLog(ModActionType.RemoveLink).GetListing(300, 100);
            var newPosts       = new Dictionary <string, List <UserPost> >();

            foreach (var modAct in modActions)
            {
                if (modAct.TimeStamp <= lastRemoval || processedCount > 100)
                {
                    break;                                                            //probably dumb and unnecessary
                }
                processedCount++;
                var post = RedditClient.GetThingByFullname(modAct.TargetThingFullname) as Post;

                var userPost = new UserPost();
                userPost.ThingID   = post.Id;
                userPost.Link      = post.Url.ToString();
                userPost.PostTime  = post.CreatedUTC;
                userPost.UserName  = post.AuthorName;
                userPost.Subreddit = Subreddit;

                var removal = new PostRemoval(modAct);
                removal.Post = userPost;

                var newPost = PostRemoval.AddRemoval(removal);
                if (newPost != null)
                {
                    var ytID = YouTubeHelpers.ExtractVideoId(post.Url.ToString());
                    if (!string.IsNullOrEmpty(ytID))
                    {
                        if (!newPosts.ContainsKey(ytID))
                        {
                            newPosts.Add(ytID, new List <UserPost>());
                        }
                        newPosts[ytID].Add(newPost);
                    }
                }

                if (processedCount % 75 == 0)
                {
                    await UpdateChannels(newPosts, req);

                    newPosts.Clear();
                }
            }

            await UpdateChannels(newPosts, req);
        }
示例#2
0
        public async Task <Dictionary <string, PostAnalysisResults> > Analyze(List <Post> posts)
        {
            var toReturn     = new Dictionary <string, PostAnalysisResults>();
            var youTubePosts = new Dictionary <string, List <Post> >();

            foreach (var post in posts)
            {
                toReturn.Add(post.Id, new PostAnalysisResults(post, ModuleEnum));
                var ytID = YouTubeHelpers.ExtractVideoId(post.Url.ToString());

                if (!string.IsNullOrEmpty(ytID))
                {
                    if (!youTubePosts.ContainsKey(ytID))
                    {
                        youTubePosts.Add(ytID, new List <Post>());
                    }
                    youTubePosts[ytID].Add(post);
                }
            }
            var yt = new YouTubeService(new BaseClientService.Initializer {
                ApiKey = YouTubeAPIKey
            });

            var req = yt.Videos.List("snippet");

            for (var i = 0; i < youTubePosts.Keys.Count; i += 50)
            {
                var ids = youTubePosts.Keys.Skip(i).Take(50);
                req.Id = string.Join(",", ids);

                var ytScrape = ScrapeYouTube(youTubePosts.Skip(i).Take(50).ToDictionary(p => p.Key, p => p.Value), toReturn);
                var response = await req.ExecuteAsync();

                foreach (var vid in response.Items)
                {
                    var redditPosts = youTubePosts[vid.Id];
                    //var scores = toReturn[post.Id].Scores;

                    var termMatches = TermMatching.Matches(vid.Snippet.Description).Cast <Match>().Select(m => m.Value).ToList();
                    termMatches.AddRange(TermMatching.Matches(vid.Snippet.Title).Cast <Match>().Select(m => m.Value).ToList().Distinct());
                    if (termMatches.Count > 0)
                    {
                        foreach (var post in redditPosts)
                        {
                            toReturn[post.Id].Scores.Add(new AnalysisScore(STRINGMATCH_SCORE * Settings.ScoreMultiplier, "YouTube video title or description has the following term(s): " + string.Join(", ", termMatches), "Match: " + string.Join(", ", termMatches), ModuleName, RemovalFlair));
                        }
                    }
                }
                await ytScrape;
            }

            return(toReturn);
        }
示例#3
0
        public async Task <Dictionary <string, PostAnalysisResults> > Analyze(List <Post> posts)
        {
            //return await Task.Run( () => {
            var modLog       = ProcessModLog();
            var toReturn     = new Dictionary <string, PostAnalysisResults>();
            var youTubePosts = new Dictionary <string, List <Post> >();

            foreach (var post in posts)
            {
                toReturn.Add(post.Id, new PostAnalysisResults(post, ModuleEnum));
                var ytID = YouTubeHelpers.ExtractVideoId(post.Url.ToString());

                if (!string.IsNullOrEmpty(ytID))
                {
                    if (!youTubePosts.ContainsKey(ytID))
                    {
                        youTubePosts.Add(ytID, new List <Post>());
                    }
                    youTubePosts[ytID].Add(post);
                }
            }
            var yt = new YouTubeService(new BaseClientService.Initializer {
                ApiKey = YouTubeAPIKey
            });

            var req = yt.Videos.List("snippet");

            for (var i = 0; i < youTubePosts.Keys.Count; i += 50)
            {
                req.Id = string.Join(",", youTubePosts.Keys.Skip(i).Take(50));
                var response = await req.ExecuteAsync();

                foreach (var vid in response.Items)
                {
                    foreach (var post in youTubePosts[vid.Id])
                    {
                        UserPost.InsertPost(new UserPost {
                            ChannelID = vid.Snippet.ChannelId, ChannelName = vid.Snippet.ChannelTitle, ThingID = post.Id, Link = post.Url.ToString(), PostTime = post.CreatedUTC, UserName = post.AuthorName, Subreddit = post.SubredditName
                        });
                    }
                }
            }
            //Task.Run( () => {


            //} );
            await modLog;

            return(toReturn);
            //} );
        }
示例#4
0
        public async Task <Dictionary <string, PostAnalysisResults> > Analyze(List <rs.Post> posts)
        {
            var toReturn       = new Dictionary <string, PostAnalysisResults>();
            var youTubePosts   = new Dictionary <string, List <rs.Post> >();
            var amWrangler     = new BotFunctions.AutoModWrangler(Program.Client.GetSubreddit(Program.Subreddit));
            var bannedChannels = amWrangler.GetBannedList(Models.BannedEntity.EntityType.Channel);

            foreach (var post in posts)     //TODO error handling
            {
                toReturn.Add(post.Id, new PostAnalysisResults(post, ModuleEnum));
                string postYTID = YouTubeHelpers.ExtractVideoId(post.Url.ToString());

                if (!string.IsNullOrWhiteSpace(postYTID))
                {
                    if (!youTubePosts.ContainsKey(postYTID))
                    {
                        youTubePosts.Add(postYTID, new List <rs.Post>());
                    }
                    youTubePosts[postYTID].Add(post);
                }
            }
            var yt = new YouTubeService(new BaseClientService.Initializer {
                ApiKey = YouTubeAPIKey
            });
            var req = yt.Videos.List("snippet");

            for (var i = 0; i < youTubePosts.Keys.Count; i += 50)
            {
                req.Id = string.Join(",", youTubePosts.Keys.Skip(i).Take(50));
                var response = req.ExecuteAsync();
                await Task.WhenAll(response, bannedChannels);

                foreach (var vid in response.Result.Items)
                {
                    //if the channel is banned
                    var chan = bannedChannels.Result.Where(c => c.EntityString == vid.Snippet.ChannelId).FirstOrDefault();
                    if (chan != null)
                    {
                        foreach (var ytPost in youTubePosts[vid.Id])
                        {
                            //ring 'er up
                            toReturn[ytPost.Id].Scores.Add(new AnalysisScore(9999, $"Channel ID: {chan.EntityString} was banned by {chan.BannedBy} on {chan.BanDate} for reason: {chan.BanReason}", "Banned Channel", ModuleName));
                        }
                    }
                }
            }
            return(toReturn);
        }
        public async Task <Dictionary <string, PostAnalysisResults> > Analyze(List <Post> posts)
        {
            var toReturn = new Dictionary <string, PostAnalysisResults>();

            foreach (var post in posts)     //TODO error handling
            {
                var youTubePosts = new Dictionary <string, List <Post> >();

                toReturn.Add(post.Id, new PostAnalysisResults(post, ModuleEnum));
                string postYTID = YouTubeHelpers.ExtractVideoId(post.Url.ToString());
                Task <Logging.UserPostingHistory> hist;
                if (!string.IsNullOrEmpty(postYTID))
                {
                    //It's a YouTube vid so we can kick off the analysis and get cookin
                    hist = Logging.UserPostingHistory.GetUserPostingHistory(post.AuthorName);
                    if (!youTubePosts.ContainsKey(postYTID))
                    {
                        youTubePosts.Add(postYTID, new List <Post>());
                    }
                    youTubePosts[postYTID].Add(post);
                }
                else
                {
                    //not a YouTube post, so bail out
                    continue;
                }
                bool success    = false;
                int  nonYTPosts = 0;
                int  tries      = 0;
                while (!success && tries < 3)
                {
                    success = true;
                    try {
                        var recentPosts = RedditClient.Search <RedditSharp.Things.Post>($"author:{post.AuthorName} self:no", RedditSharp.Sorting.New).GetListing(100, 100);
                        foreach (var recentPost in recentPosts)
                        {
                            string ytID = YouTubeHelpers.ExtractVideoId(recentPost.Url.ToString());

                            if (!string.IsNullOrEmpty(ytID))
                            {
                                if (!youTubePosts.ContainsKey(ytID))
                                {
                                    youTubePosts.Add(ytID, new List <Post>());
                                }
                                youTubePosts[ytID].Add(post);
                            }
                            else
                            {
                                nonYTPosts++;
                            }
                        }
                    }
                    catch (Exception ex) {
                        success = false;
                        tries++;
                        if (tries > 3)
                        {
                            Console.WriteLine($"Failed to get search results: {ex.Message}");
                            processedCache.Remove(post.Id);
                            break;
                        }
                        await Task.Delay(100);
                    }
                }
                if (tries > 3)
                {
                    continue;
                }
                var yt = new YouTubeService(new BaseClientService.Initializer {
                    ApiKey = YouTubeAPIKey
                });

                Dictionary <string, List <string> > postHistory = ( await hist ).PostingHistory;
                string postChannelID   = "";
                string postChannelName = "";
                var    req             = yt.Videos.List("snippet");
                for (var i = 0; i < youTubePosts.Keys.Count; i += 50)
                {
                    req.Id = string.Join(",", youTubePosts.Keys.Skip(i).Take(50));
                    var response = await req.ExecuteAsync();

                    foreach (var vid in response.Items)
                    {
                        foreach (var ytPost in youTubePosts[vid.Id])
                        {
                            if (!postHistory.ContainsKey(vid.Snippet.ChannelId))
                            {
                                postHistory.Add(vid.Snippet.ChannelId, new List <string>());
                            }
                            //check to see if it already exists (aka wasnt deleted and showed up in search results)
                            if (!postHistory[vid.Snippet.ChannelId].Contains(ytPost.Id))
                            {
                                postHistory[vid.Snippet.ChannelId].Add(ytPost.Id);
                            }

                            if (vid.Id == postYTID)
                            {
                                postChannelID   = vid.Snippet.ChannelId;
                                postChannelName = vid.Snippet.ChannelTitle;
                            }
                        }
                    }
                }

                if (string.IsNullOrEmpty(postChannelID))
                {
                    //shouldn't ever happen, but might if the video is deleted or the channel deleted or something
                    Console.WriteLine($"Channel for post {post.Id} by {post.AuthorName} couldn't be found");
                    continue;
                }

                int totalPosts   = postHistory.Sum(ph => ph.Value.Count) + nonYTPosts;
                int channelPosts = postHistory[postChannelID].Count;
                if (!IncludePostInPercentage)
                {
                    totalPosts--;
                    channelPosts--;
                    postHistory[postChannelID].Remove(post.Id);
                }
                double percent = ((double)channelPosts / totalPosts) * 100;
                if (percent > PercentageThreshold && channelPosts > GracePeriod)
                {
                    var score = new AnalysisScore();
                    score.ModuleName   = "SelfPromotionCombustor";
                    score.ReportReason = $"SelfPromo: {Math.Round( percent, 2 )}%";
                    score.Reason       = $"Self Promotion for channel '{postChannelName}' with a posting percentage of {Math.Round( percent, 2 )}. Found PostIDs: {string.Join( ", ", postHistory[postChannelID] )}";
                    score.Score        = OVER_PERCENT_SCORE * Settings.ScoreMultiplier;
                    score.RemovalFlair = RemovalFlair;

                    toReturn[post.Id].Scores.Add(score);
                }
            }
            return(toReturn);
        }
 /// <summary>
 /// Builds the HTML embed iframe for the specified video.
 /// </summary>
 /// <param name="videoId">The YouTube ID of the video.</param>
 /// <param name="width">The desired width of the iframe.</param>
 /// <param name="height">The desired height of the iframe.</param>
 /// <param name="showRelations">By the default, YouTube will show
 /// related videos at the end of videos. Setting this to
 /// <var>FALSE</var> will disable the feature.</param>
 /// <param name="wmode">The flash video player doesn't really
 /// play well with layers (mostly in IE). Setting this
 /// parameter to <var>transarent</var> will solve most
 /// of these issues.</param>
 public static string YouTubeEmbed(this string videoId, int width, int height, bool showRelations, string wmode)
 {
     return(YouTubeHelpers.GetEmbedHtml(videoId, width, height, showRelations, wmode));
 }
 /// <summary>
 /// Builds the HTML embed iframe for the specified video.
 /// </summary>
 /// <param name="videoId">The YouTube ID of the video.</param>
 /// <param name="width">The desired width of the iframe.</param>
 /// <param name="height">The desired height of the iframe.</param>
 public static string YouTubeEmbed(this string videoId, int width, int height)
 {
     return(YouTubeHelpers.GetEmbedHtml(videoId, width, height));
 }
 /// <summary>
 /// Uses regular expressions for finding a YouTube video ID in the string.
 /// </summary>
 /// <param name="subject">The string to search.</param>
 /// <param name="videoId">The YouTube video ID if found, otherwise <var>NULL</var>.</param>
 /// <returns>Returns <var>TRUE</var> if a video ID is found, otherwise <var>FALSE</var>.</returns>
 public static bool GetYouTubeId(this string subject, out string videoId)
 {
     return(YouTubeHelpers.GetIdFromString(subject, out videoId));
 }
 /// <summary>
 /// Uses regular expressions for finding a YouTube video ID in the string.
 /// </summary>
 /// <param name="subject">The string to search.</param>
 /// <returns>The YouTube video ID if found, otherwise <var>NULL</var>.</returns>
 public static string GetYouTubeId(this string subject)
 {
     return(YouTubeHelpers.GetIdFromString(subject));
 }
 /// <summary>
 /// Attempts to find a YouTube video ID the specified string and get
 /// information about that video.
 /// </summary>
 /// <param name="subject">The string to search.</param>
 public static YouTubeVideo GetYouTubeVideo(this string subject)
 {
     return(YouTubeHelpers.GetVideoFromString(subject));
 }
 /// <summary>
 /// Gets the thumbnail URL for a video with the specified ID. The default thumbnail (index = 0)
 /// measures 480x360 pixels, while the others measures 120x90 pixels.
 /// </summary>
 /// <param name="videoId">The ID of the video.</param>
 /// <param name="index">The index of the thumbnail URL to return
 /// (valid range is from 0 to 3 - both inclusive).</param>
 /// <returns>The thumbnail URL if the video ID is valid, otherwise <var>NULL</var>.</returns>
 public static string GetYouTubeThumbnail(this string videoId, int index)
 {
     return(YouTubeHelpers.GetYouTubeThumbnail(videoId, index));
 }
示例#12
0
        public async Task <Dictionary <string, PostAnalysisResults> > Analyze(List <Post> posts)
        {
            var toReturn     = new Dictionary <string, PostAnalysisResults>();
            var youTubePosts = new Dictionary <string, List <Post> >();

            foreach (var post in posts)
            {
                var ytID = YouTubeHelpers.ExtractVideoId(post.Url.ToString());
                toReturn.Add(post.Id, new PostAnalysisResults(post, ModuleEnum));

                if (!string.IsNullOrEmpty(ytID))
                {
                    if (!youTubePosts.ContainsKey(ytID))
                    {
                        youTubePosts.Add(ytID, new List <Post>());
                    }
                    youTubePosts[ytID].Add(post);
                }
            }


            var yt = new YouTubeService(new BaseClientService.Initializer {
                ApiKey = YouTubeAPIKey
            });

            var req = yt.Videos.List("snippet,contentDetails,statistics");

            var    settings    = (YouTubeSpamDetectorSettings)Settings;
            double availWeight = 0;

            availWeight += settings.ChannelAgeThreshold.Enabled ? settings.ChannelAgeThreshold.Weight : 0;
            availWeight += settings.ViewCountThreshold.Enabled ? settings.ViewCountThreshold.Weight : 0;
            availWeight += settings.NegativeVoteRatio.Enabled ? settings.NegativeVoteRatio.Weight : 0;
            availWeight += settings.RedditAccountAgeThreshold.Enabled ? settings.RedditAccountAgeThreshold.Weight : 0;
            availWeight += settings.LicensedChannel.Enabled ? settings.LicensedChannel.Weight : 0;
            availWeight += settings.ImgurSubmissionRatio.Enabled ? settings.ImgurSubmissionRatio.Weight : 0;
            availWeight += settings.CommentCountThreshold.Enabled ? settings.CommentCountThreshold.Weight : 0;
            availWeight += settings.VoteCountThreshold.Enabled ? settings.VoteCountThreshold.Weight : 0;

            var chanAgeScore              = (settings.ChannelAgeThreshold.Weight / availWeight) * MAX_MODULE_SCORE * Settings.ScoreMultiplier;
            var viewCountScore            = (settings.ViewCountThreshold.Weight / availWeight) * MAX_MODULE_SCORE * Settings.ScoreMultiplier;
            var negativeVoteScore         = (settings.NegativeVoteRatio.Weight / availWeight) * MAX_MODULE_SCORE * Settings.ScoreMultiplier;
            var redditAccountAgeScore     = (settings.RedditAccountAgeThreshold.Weight / availWeight) * MAX_MODULE_SCORE * Settings.ScoreMultiplier;
            var licensedScore             = (settings.LicensedChannel.Weight / availWeight) * MAX_MODULE_SCORE * Settings.ScoreMultiplier;
            var imgurSubmissionRatioScore = (settings.ImgurSubmissionRatio.Weight / availWeight) * MAX_MODULE_SCORE * Settings.ScoreMultiplier;
            var commentCountScore         = (settings.CommentCountThreshold.Weight / availWeight) * MAX_MODULE_SCORE * Settings.ScoreMultiplier;
            var totalVotesScore           = (settings.VoteCountThreshold.Weight / availWeight) * MAX_MODULE_SCORE * Settings.ScoreMultiplier;


            for (var i = 0; i < youTubePosts.Keys.Count; i += 50)
            {
                var channels = new Dictionary <string, List <Post> >();
                req.Id = string.Join(",", youTubePosts.Keys.Skip(i).Take(50));
                var response = await req.ExecuteAsync();

                foreach (var vid in response.Items)
                {
                    foreach (var post in youTubePosts[vid.Id])
                    {
                        var scores = toReturn[post.Id].Scores;
                        if (!channels.ContainsKey(vid.Snippet.ChannelId))
                        {
                            channels[vid.Snippet.ChannelId] = new List <Post>();
                        }
                        channels[vid.Snippet.ChannelId].Add(post);

                        if (settings.ViewCountThreshold.Enabled && vid.Statistics?.ViewCount.Value <= (ulong)Math.Abs(settings.ViewCountThreshold.Value))        //TODO Fix this math.abs nonsense with some validation
                        {
                            scores.Add(new AnalysisScore(viewCountScore, "View Count is below threshold", "Low Views", ModuleName));
                        }
                        if (settings.LicensedChannel.Enabled && vid.ContentDetails.LicensedContent.Value)
                        {
                            scores.Add(new AnalysisScore(licensedScore, "Channel is likely monetized", "Possibly Monetized", ModuleName));
                        }
                        if (settings.CommentCountThreshold.Enabled && vid.Statistics?.CommentCount <= (ulong)Math.Abs(settings.CommentCountThreshold.Value))        //TODO Fix this math.abs nonsense with some validation
                        {
                            scores.Add(new AnalysisScore(commentCountScore, "Number of comments is below threshold", "Low comments", ModuleName));
                        }
                        if (settings.NegativeVoteRatio.Enabled && vid.Statistics?.DislikeCount > vid.Statistics?.LikeCount)
                        {
                            scores.Add(new AnalysisScore(negativeVoteScore, "More dislikes than likes on video", ">50% dislikes", ModuleName));
                        }
                        if (settings.VoteCountThreshold.Enabled && vid.Statistics?.DislikeCount + vid.Statistics?.LikeCount <= (ulong)Math.Abs(settings.VoteCountThreshold.Value))        //TODO Fix this math.abs nonsense with some validation
                        {
                            scores.Add(new AnalysisScore(totalVotesScore, "Total vote count is below threshold", "Low Total Votes", ModuleName));
                        }
                        DateTime authorCreated = DateTime.UtcNow;
                        bool     shadowbanned  = false;
                        try {
                            authorCreated = post.Author.Created;
                        }
                        catch (WebException ex) {
                            if ((ex.Response as HttpWebResponse).StatusCode == HttpStatusCode.NotFound)
                            {
                                authorCreated = DateTime.UtcNow;
                                shadowbanned  = true;
                            }
                            else
                            {
                                throw;
                            }
                        }
                        if (settings.RedditAccountAgeThreshold.Enabled && authorCreated.AddDays(settings.RedditAccountAgeThreshold.Value) >= DateTime.UtcNow)
                        {
                            scores.Add(new AnalysisScore(redditAccountAgeScore, "Reddit Account age is below threshold", "New Reddit Acct", ModuleName));
                        }
                        if (settings.ImgurSubmissionRatio.Enabled && !shadowbanned && ((double)100 / post.Author.Posts.Take(100).Count(p => p.Domain.ToLower().Contains("imgur"))) * 100 >= settings.ImgurSubmissionRatio.Value)
                        {
                            scores.Add(new AnalysisScore(imgurSubmissionRatioScore, "User has Imgur submissions above threshold for last 100 posts", "Lots of Imgur", ModuleName));
                        }
                    }
                }
                if (settings.ChannelAgeThreshold.Enabled)
                {
                    var chanReq = yt.Channels.List("snippet");
                    chanReq.Id = string.Join(",", channels.Keys);
                    var chanResponse = chanReq.Execute();
                    //get the channel info
                    foreach (var channel in chanResponse.Items)
                    {
                        //if the channel was created less than the settings.ChannelAgeThreshold days ago
                        DateTime channelCreationDate = channel.Snippet.PublishedAt.HasValue ? channel.Snippet.PublishedAt.Value : DateTime.UtcNow;
                        foreach (var post in channels[channel.Id])
                        {
                            if (channelCreationDate.AddDays(settings.ChannelAgeThreshold.Value) >= post.CreatedUTC)
                            {
                                //Add the score to the posts
                                toReturn[post.Id].Scores.Add(new AnalysisScore(chanAgeScore, "Channel Age Below Threshold", "Channel Age", ModuleName));
                            }
                        }
                    }
                }
            }

            return(toReturn);
        }