public void CreateAlbum()
    {
        Thread t = new Thread(() =>
        {
            using (WebClient client = new WebClient())
            {
                client.Headers.Add("Authorization", "Client-ID " + _clientId);

                NameValueCollection parameters = new NameValueCollection()
                {
                    { "privacy", "public" }
                };

                byte[] response = client.UploadValues(_baseAlbumCreationUrl, parameters);
                string json     = Encoding.UTF8.GetString(response);
                ImgurUploadResponse serializedResponse = JsonUtility.FromJson <ImgurUploadResponse>(json);

                StreamWriter writer = File.CreateText(_albumDelethashFileLocation);
                writer.Write(serializedResponse.data.deletehash);
                writer.Close();

                writer = File.CreateText(_albumIdFileLocation);
                writer.Write(serializedResponse.data.id);
                writer.Close();
            }
        })
        {
            IsBackground = true
        };

        t.Start();
    }
 public OnImageUploadedEventArgs(ImgurUploadResponse response)
 {
     this.response = response;
 }
Beispiel #3
0
        private async Task ProcessRequests(List <RedditThing> requests)
        {
            // Get parent of each request.
            Dictionary <RedditThing, RedditThing> requestsWithParents = new Dictionary <RedditThing, RedditThing>();

            foreach (RedditThing request in requests)
            {
                RedditThing immediateParent = await redditClient.GetInfoOfCommentOrLink(request.Subreddit, request.ParentId);

                // Determine whether to use the root link or the request's immediate parent.
                RedditThing   parentPost;
                List <string> splitRequest = request.GetCommandTextFromMention(redditClient.Username).Split().ToList();
                if (immediateParent.Kind == "t3" || (splitRequest.Count > 1 && splitRequest[1].ToLower() == "!immediate"))
                {
                    parentPost = immediateParent;
                }
                else
                {
                    parentPost = await redditClient.GetInfoOfCommentOrLink(request.Subreddit, immediateParent.LinkId);
                }

                requestsWithParents.Add(request, parentPost);
            }

            // Process each request.
            Dictionary <string, List <RedditThing> > processedRequestsByUser = new Dictionary <string, List <RedditThing> >();

            foreach (var kvp in requestsWithParents)
            {
                try
                {
                    RedditThing mentionComment = kvp.Key;
                    RedditThing parentPost     = kvp.Value;

                    // If we have already processed a request from this user in this batch of requests:...
                    if (processedRequestsByUser.ContainsKey(mentionComment.Author))
                    {
                        // If this is a duplicate request: discard it.
                        if (processedRequestsByUser[mentionComment.Author].Any(rt => rt.ParentId == mentionComment.ParentId && rt.Body == mentionComment.Body))
                        {
                            Log.Information($"Skipping {mentionComment.Name}: Post is a duplicate. ({mentionComment.Author}: '{mentionComment.Body}')");
                            await redditClient.MarkMessagesAsRead(new List <string> {
                                mentionComment.Name
                            });

                            continue;
                        }
                        // If we have already processed enough requests from this user in this batch: temporarily skip it.
                        else if (processedRequestsByUser[mentionComment.Author].Count >= 2)
                        {
                            Log.Information($"Temporarily skipping {mentionComment.Name}: Too many recent requests. ({mentionComment.Author}: '{mentionComment.Body}')");
                            continue;
                        }

                        processedRequestsByUser[mentionComment.Author].Add(mentionComment);
                    }
                    else
                    {
                        processedRequestsByUser.Add(mentionComment.Author, new List <RedditThing> {
                            mentionComment
                        });
                    }

                    bool requestorIsAdmin = settings.Administrators.Contains(mentionComment.Author);

                    // Verify that the media post is old enough.
                    if (!requestorIsAdmin && parentPost.CreatedUtc.Value.UnixTimeToDateTime() > DateTime.Now.ToUniversalTime().AddMinutes(-settings.FilterSettings.MinimumPostAgeInMinutes))
                    {
                        Log.Information($"Temporarily skipping {mentionComment.Name}: Post is too recent. ({mentionComment.Author}: '{mentionComment.Body}')");
                        continue;
                    }

                    await redditClient.MarkMessagesAsRead(new List <string> {
                        mentionComment.Name
                    });

                    // Verify that the requestor isn't blacklisted.
                    if (databaseAccessor.GetBlacklistedUser(mentionComment.Author) != null)
                    {
                        Log.Information($"Skipping {mentionComment.Name}: Requestor is blacklisted. ({mentionComment.Author}: '{mentionComment.Body}')");
                        continue;
                    }

                    Func <string, Task> onFailedToProcessPost = async(reason) =>
                    {
                        Log.Information($"Skipping {mentionComment.Name}: {reason} ({mentionComment.Author}: '{mentionComment.Body}')");
                        await PostReplyToFallbackThread($"/u/{mentionComment.Author} I was unable to process your [request](https://reddit.com{mentionComment.Context}).  \nReason: {reason}");
                    };

                    // Verify that the post is safe to process.
                    Tuple <bool, string> postSafetyInfo = await PostIsSafeToProcess(parentPost, true);

                    if (!requestorIsAdmin && !postSafetyInfo.Item1)
                    {
                        await onFailedToProcessPost($"{postSafetyInfo.Item2} See [here](https://www.reddit.com/r/IVAEbot/wiki/index#wiki_limitations) for more information.");

                        continue;
                    }

                    // Get the commands from the mention comment.
                    List <IVAECommand> commands;
                    try
                    {
                        commands = IVAECommandFactory.CreateCommands(mentionComment.GetCommandTextFromMention(redditClient.Username));

                        IVAECommand speedupCommand = commands.FirstOrDefault(c => c.GetType() == typeof(AdjustSpeedCommand) && ((AdjustSpeedCommand)c).FrameRate > 1);
                        if (speedupCommand != null)
                        {
                            commands.Remove(speedupCommand);
                            commands.Insert(0, speedupCommand);
                        }

                        IVAECommand trimCommand = commands.FirstOrDefault(c => c.GetType() == typeof(TrimCommand));
                        if (trimCommand != null)
                        {
                            commands.Remove(trimCommand);
                            commands.Insert(0, trimCommand);
                        }
                    }
                    catch (ArgumentException ex)
                    {
                        await onFailedToProcessPost($"{ex.Message}  \nSee [here](https://www.reddit.com/r/IVAEbot/wiki/index#wiki_commands) for a list of valid commands.");

                        continue;
                    }
                    catch (Exception ex)
                    {
                        Log.Warning(ex.ToString());
                        await onFailedToProcessPost($"An error occurred while trying to parse commands.  \nSee [here](https://www.reddit.com/r/IVAEbot/wiki/index#wiki_commands) for a list of valid commands.");

                        continue;
                    }

                    if (commands != null && commands.Any(command => commands.Count(cmd => cmd.GetType() == command.GetType()) > 1)) // This is O(n^2), consider something more efficient.
                    {
                        await onFailedToProcessPost("Multiple commands of same type.");

                        continue;
                    }

                    // Get url to media file.
                    Uri mediaUrl = GetMediaUrlFromPost(parentPost);
                    if (mediaUrl == null || string.IsNullOrWhiteSpace(mediaUrl.AbsoluteUri))
                    {
                        await onFailedToProcessPost("Invalid media URL.");

                        continue;
                    }

                    // Ensure that the download directory exists.
                    if (!System.IO.Directory.Exists(DOWNLOAD_DIR))
                    {
                        System.IO.Directory.CreateDirectory(DOWNLOAD_DIR);
                    }

                    string mediaFilePath = null;
                    try
                    {
                        // Download the media file.
                        System.Diagnostics.Stopwatch stopwatch = System.Diagnostics.Stopwatch.StartNew();
                        string fileNameWithoutExtension        = Guid.NewGuid().ToString();
                        string filePathWithoutExtension        = System.IO.Path.Combine(DOWNLOAD_DIR, fileNameWithoutExtension);
                        string mediaUrlFileExtension           = System.IO.Path.GetExtension(mediaUrl.AbsoluteUri).ToLower();
                        if (mediaUrlFileExtension == ".jpg" || mediaUrlFileExtension == ".png")
                        {
                            // Verify that the file is not too large.
                            if (!TryGetMediaFileSize(mediaUrl.AbsoluteUri, out long fileSize))
                            {
                                await onFailedToProcessPost("Failed to get media file size.");

                                continue;
                            }
                            else if (fileSize > settings.FilterSettings.MaximumDownloadFileSizeInMB * 10000000)
                            {
                                await onFailedToProcessPost("Media file too large.");

                                continue;
                            }

                            mediaFilePath = $"{filePathWithoutExtension}{mediaUrlFileExtension}";

                            using (System.Net.WebClient client = new System.Net.WebClient())
                            {
                                client.DownloadFile(mediaUrl, mediaFilePath);
                            }
                        }
                        else if (mediaUrl.Host == "v.redd.it")
                        {
                            // Temporary override for v.redd.it links until youtube-dl is fixed.
                            mediaFilePath = $"{filePathWithoutExtension}.mp4";

                            using (System.Net.WebClient client = new System.Net.WebClient())
                            {
                                client.DownloadFile(mediaUrl, mediaFilePath);

                                try
                                {
                                    string audioUrl         = $"{mediaUrl.AbsoluteUri.Substring(0, mediaUrl.AbsoluteUri.LastIndexOf("/"))}/audio";
                                    string audioFilePath    = System.IO.Path.Combine(DOWNLOAD_DIR, $"{System.IO.Path.GetFileNameWithoutExtension(mediaFilePath)}_audio");
                                    string combinedFilePath = System.IO.Path.Combine(DOWNLOAD_DIR, "combined.mp4");
                                    client.DownloadFile(audioUrl, audioFilePath);
                                    new MediaManipulation.FFmpegProcessRunner().Run($"-i {mediaFilePath} -i {audioFilePath} -acodec copy -vcodec copy \"{combinedFilePath}\"");
                                    System.IO.File.Delete(audioFilePath);
                                    System.IO.File.Delete(mediaFilePath);
                                    System.IO.File.Move(combinedFilePath, mediaFilePath);
                                }
                                catch (Exception) { }
                            }
                        }
                        else
                        {
                            YoutubedlProcessRunner youtubedlProcessRunner = new YoutubedlProcessRunner();
                            List <string>          downloadOutput         = youtubedlProcessRunner.Run($"\"{mediaUrl.AbsoluteUri}\" --max-filesize {settings.FilterSettings.MaximumDownloadFileSizeInMB}m -o \"{filePathWithoutExtension}.%(ext)s\" -f mp4");
                            mediaFilePath = System.IO.Directory.GetFiles(DOWNLOAD_DIR, $"{fileNameWithoutExtension}*").SingleOrDefault();
                        }

                        if (mediaFilePath == null)
                        {
                            await onFailedToProcessPost("Failed to download media file. (The file may have been too big.)");

                            continue;
                        }

                        // Execute all commands on the media file.
                        long origFileSize = new System.IO.FileInfo(mediaFilePath).Length;
                        foreach (IVAECommand command in commands)
                        {
                            string path = command.Execute(mediaFilePath);
                            System.IO.File.Delete(mediaFilePath);

                            if (System.IO.File.Exists(path))
                            {
                                mediaFilePath = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(mediaFilePath), $"{System.IO.Path.GetFileNameWithoutExtension(mediaFilePath)}{System.IO.Path.GetExtension(path)}");
                                System.IO.File.Move(path, mediaFilePath);
                            }
                        }

                        if (!System.IO.File.Exists(mediaFilePath))
                        {
                            await onFailedToProcessPost($"Failed to create output file.");

                            continue;
                        }

                        double transformedFileSizeInMB = ((double)new System.IO.FileInfo(mediaFilePath).Length) / 1000000;
                        MediaManipulation.MediaFileInfo transformedMFI = new MediaManipulation.MediaFileInfo(mediaFilePath);
                        if (!transformedMFI.IsValidMediaFile)
                        {
                            await onFailedToProcessPost($"Output file was broken.");

                            continue;
                        }
                        if (transformedFileSizeInMB > settings.FilterSettings.MaximumUploadFileSizeInMB)
                        {
                            await onFailedToProcessPost($"Output file ({transformedFileSizeInMB.ToString("N2")}MB) can not be larger than {settings.FilterSettings.MaximumUploadFileSizeInMB}MB.");

                            continue;
                        }
                        else if (transformedMFI.Duration > settings.FilterSettings.MaximumUploadFileDurationInSeconds)
                        {
                            await onFailedToProcessPost($"Output file ({transformedMFI.Duration.Value.ToString("N2")}s) can not be longer than {settings.FilterSettings.MaximumUploadFileDurationInSeconds} seconds.");

                            continue;
                        }

                        // Upload transformed media file.
                        byte[] mediaFileBytes = System.IO.File.ReadAllBytes(mediaFilePath);
                        string deleteKey, uploadDestination, uploadPath, uploadLink;
                        if (!transformedMFI.HasVideo || transformedMFI.Duration <= 30)
                        {
                            uploadDestination = "imgur";

                            string videoFormat = null;
                            if (System.IO.Path.GetExtension(mediaFilePath) == ".mp4")
                            {
                                videoFormat = "mp4";
                            }
                            ImgurUploadResponse imgurUploadResponse = await imgurClient.Upload(mediaFileBytes, videoFormat);

                            if (imgurUploadResponse == null)
                            {
                                await onFailedToProcessPost("Failed to upload transformed file.");

                                continue;
                            }

                            deleteKey  = imgurUploadResponse.DeleteHash;
                            uploadLink = imgurUploadResponse.Link;
                            uploadPath = imgurUploadResponse.Name;
                        }
                        else
                        {
                            uploadDestination = "gfycat";
                            string gfyname = await gfycatClient.Upload(mediaFileBytes);

                            if (gfyname == null)
                            {
                                await onFailedToProcessPost("Failed to upload transformed file.");

                                continue;
                            }

                            deleteKey  = gfyname;
                            uploadLink = $"https://giant.gfycat.com/{gfyname}.mp4";
                            uploadPath = gfyname;
                        }

                        // Respond with link.
                        stopwatch.Stop();
                        Guid uploadId = Guid.NewGuid();

                        string responseText = $"[Direct File Link]({uploadLink})\n\n" +
                                              $"***\n" +
                                              $"Finished in {(stopwatch.Elapsed.TotalMinutes >= 1 ? $"{stopwatch.Elapsed.ToString("mm")} minutes " : "" )}{stopwatch.Elapsed.ToString("ss")} seconds. {((double)origFileSize / 1000000).ToString("N2")}MB -> {transformedFileSizeInMB.ToString("N2")}MB.  \n" +
                                              $"[How To Use](https://www.reddit.com/r/IVAEbot/wiki/index) | [Submit Feedback](https://www.reddit.com/message/compose/?to=TheTollski&subject=IVAEbot%20Feedback) | [Delete](https://www.reddit.com/message/compose/?to=IVAEbot&subject=Command&message=delete%20{uploadId.ToString()}) (Requestor Only)  \n" +
                                              $"^^I ^^am ^^a ^^bot ^^in ^^beta ^^testing ^^and ^^need ^^more ^^[testers](https://www.reddit.com/r/IVAEbot/comments/bp3aha/testers_needed/). ^^Feel ^^free ^^to ^^learn ^^what ^^I ^^can ^^do ^^and ^^summon ^^me.";
                        string replyCommentName = await redditClient.PostComment(mentionComment.Name, responseText);

                        if (replyCommentName == null)
                        {
                            replyCommentName = await PostReplyToFallbackThread($"/u/{mentionComment.Author} I was unable to repond directly to your [request]({mentionComment.Permalink}) so I have posted my response here.\n\n{responseText}");
                        }

                        databaseAccessor.InsertUploadLog(new UploadLog
                        {
                            Id                = uploadId,
                            PostFullname      = parentPost.Name,
                            ReplyDeleted      = false,
                            ReplyFullname     = replyCommentName,
                            RequestorUsername = mentionComment.Author,
                            UploadDatetime    = DateTime.UtcNow,
                            UploadDeleted     = false,
                            UploadDeleteKey   = deleteKey,
                            UploadDestination = uploadDestination,
                            UploadPath        = uploadPath
                        });
                    }
                    catch (Exception)
                    {
                        if (!string.IsNullOrWhiteSpace(mediaFilePath) && System.IO.File.Exists(mediaFilePath))
                        {
                            System.IO.File.Delete(mediaFilePath);
                        }

                        throw;
                    }
                }
                catch (Exception ex)
                {
                    Log.Error(ex, "Exception occurred while processing a request.");
                }
            }
        }