Пример #1
0
        public ThrottledBufferedStream(Stream baseStream, long maximumBytesPerSecond, Action <YoutubeUploadStats> updateUploadProgress, YoutubeUploadStats stats, Upload upload)
        {
            if (ThrottledBufferedStream.historyForUploadInSeconds > ThrottledBufferedStream.keepHistoryForInSeconds)
            {
                throw new InvalidOperationException("History not long enough for upload throttling.");
            }

            if (ThrottledBufferedStream.historyForStatsInSeconds > ThrottledBufferedStream.keepHistoryForInSeconds)
            {
                throw new InvalidOperationException("History not long enough for stats.");
            }

            if (baseStream == null)
            {
                throw new ArgumentNullException("baseStream");
            }

            if (maximumBytesPerSecond < 0)
            {
                throw new ArgumentOutOfRangeException("maximumBytesPerSecond",
                                                      maximumBytesPerSecond, "The maximum number of bytes per second can't be negatie.");
            }

            this.updateUploadProgress = updateUploadProgress;
            this.stats           = stats;
            this.upload          = upload;
            this.lastStatsUpdate = DateTime.Now;

            this.baseStream = baseStream;
            this.maximumBytesPerSecondRead = maximumBytesPerSecond;
            this.position = this.baseStream.Position;
        }
Пример #2
0
        public static async Task <UploadResult> Upload(Upload upload, long maxUploadInBytesPerSecond, Action <YoutubeUploadStats> updateUploadProgress, CancellationToken cancellationToken)
        {
            Tracer.Write($"YoutubeUploadService.Upload: Start with upload: {upload.FilePath}, maxUploadInBytesPerSecond: {maxUploadInBytesPerSecond}.");

            upload.UploadErrorMessage = string.Empty;

            UploadResult uploadResult = new UploadResult()
            {
                VideoResult          = VideoResult.Failed,
                ThumbnailSuccessFull = false,
                PlaylistSuccessFull  = false
            };

            if (!File.Exists(upload.FilePath))
            {
                Tracer.Write($"YoutubeUploadService.Upload: End, file doesn't exist.");

                upload.UploadErrorMessage = "File does not exist.";
                upload.UploadStatus       = UplStatus.Failed;
                return(uploadResult);
            }

            StringBuilder errors = new StringBuilder();

            try
            {
                Tracer.Write($"YoutubeUploadService.Upload: Initialize upload.");
                long uploadByteIndex = await YoutubeUploadService.initializeUpload(upload);

                JsonSerializationContent.JsonSerializer.SerializeAllUploads();
                Tracer.Write($"YoutubeUploadService.Upload: Initial uploadByteIndex: {uploadByteIndex}.");

                upload.BytesSent = uploadByteIndex;
                long initialBytesSent = uploadByteIndex;

                YoutubeUploadStats stats = new YoutubeUploadStats();
                using (FileStream fileStream = new FileStream(upload.FilePath, FileMode.Open))
                    using (ThrottledBufferedStream inputStream = new ThrottledBufferedStream(fileStream, maxUploadInBytesPerSecond, updateUploadProgress, stats, upload))
                    {
                        inputStream.Position        = uploadByteIndex;
                        YoutubeUploadService.stream = inputStream;
                        long totalBytesSentInSession = 0;

                        long       fileLength = upload.FileLength;
                        HttpClient client     = await HttpHelper.GetAuthenticatedUploadClient();

                        //on IOExceptions try 2 times more to upload the chunk.
                        //no response from the server shall be requested on IOException.
                        short uploadTry = 1;
                        int   package   = 0;
                        bool  error     = false;

                        Tracer.Write($"YoutubeUploadService.Upload: fileLength: {fileLength}.");
                        PartStream          chunkStream;
                        HttpResponseMessage message;
                        StreamContent       content;

                        while (fileLength > totalBytesSentInSession + initialBytesSent)
                        {
                            if (error)
                            {
                                error = false;
                                if (uploadTry > 3)
                                {
                                    Tracer.Write($"YoutubeUploadService.Upload: End, Upload not successful after 3 tries for package {package}.");

                                    upload.UploadErrorMessage = $"YoutubeUploadService.Upload: Upload not successful after 3 tries for package {package}. Errors: {errors.ToString()}";
                                    upload.UploadStatus       = UplStatus.Failed;
                                    return(uploadResult);
                                }

                                //give a little time on IOException, e.g. to await router redial in on 24h disconnect
                                await Task.Delay(TimeSpan.FromSeconds(2));

                                Tracer.Write($"YoutubeUploadService.Upload: Getting range due to upload retry.");
                                uploadByteIndex = await YoutubeUploadService.getUploadByteIndex(upload);

                                Tracer.Write($"YoutubeUploadService.Upload: Upload retry uploadByteIndex: {uploadByteIndex}.");

                                inputStream.Position    = uploadByteIndex;
                                upload.BytesSent        = uploadByteIndex;
                                totalBytesSentInSession = uploadByteIndex - initialBytesSent;
                            }
                            else
                            {
                                package++;
                                Tracer.Write($"YoutubeUploadService.Upload: Upload try: Package {package} Try {uploadTry}.");
                            }

                            chunkStream = new PartStream(inputStream, YoutubeUploadService.uploadChunkSizeInBytes);

                            Tracer.Write($"YoutubeUploadService.Upload: Creating content.");
                            using (content = HttpHelper.GetStreamContentResumableUpload(chunkStream, inputStream.Length, uploadByteIndex, YoutubeUploadService.uploadChunkSizeInBytes, MimeTypesMap.GetMimeType(upload.FilePath)))
                            {
                                try
                                {
                                    Tracer.Write($"YoutubeUploadService.Upload: Start uploading.");
                                    message = await client.PutAsync(upload.ResumableSessionUri, content, cancellationToken);
                                }
                                catch (TaskCanceledException)
                                {
                                    Tracer.Write($"YoutubeUploadService.Upload: End, Upload stopped by user.");

                                    upload.UploadStatus      = UplStatus.Stopped;
                                    uploadResult.VideoResult = VideoResult.Stopped;
                                    return(uploadResult);
                                }
                                catch (Exception e)
                                {
                                    Tracer.Write($"YoutubeUploadService.Upload: HttpClient.PutAsync Exception package {package} try {uploadTry}: {e.ToString()}.");
                                    errors.AppendLine($"YoutubeUploadService.Upload: HttpClient.PutAsync Exception package {package} try {uploadTry}: {e.GetType().ToString()}: {e.Message}.");

                                    error = true;
                                    uploadTry++;
                                    continue;
                                }
                            }

                            using (message)
                            {
                                if ((int)message.StatusCode == 308)
                                {
                                    //one upload package succeeded, reset upload counter.
                                    uploadTry = 1;
                                    Tracer.Write($"YoutubeUploadService.Upload: Package {package} finished.");
                                }
                                else
                                {
                                    if (!message.IsSuccessStatusCode)
                                    {
                                        Tracer.Write($"YoutubeUploadService.Upload: HttpResponseMessage unexpected status code package {package} try {uploadTry}: {message.StatusCode} with message {message.ReasonPhrase}.");
                                        errors.AppendLine($"YoutubeUploadService.Upload: HttpResponseMessage unexpected status code package {package} try {uploadTry}: {message.StatusCode} with message {message.ReasonPhrase}.");
                                        error = true;
                                        uploadTry++;
                                        continue;
                                    }

                                    var definition = new { Id = "" };
                                    var response   = JsonConvert.DeserializeAnonymousType(await message.Content.ReadAsStringAsync(), definition);
                                    upload.VideoId = response.Id;

                                    //last stats update to reach 0 bytes and time left.
                                    stats.CurrentSpeedInBytesPerSecond = 1;
                                    upload.BytesSent = inputStream.Position;
                                    updateUploadProgress(stats);

                                    upload.UploadStatus      = UplStatus.Finished;
                                    uploadResult.VideoResult = VideoResult.Finished;
                                    Tracer.Write($"YoutubeUploadService.Upload: Upload finished with {package}, video id {upload.VideoId}.");
                                }
                            }

                            uploadByteIndex         += YoutubeUploadService.uploadChunkSizeInBytes;
                            totalBytesSentInSession += YoutubeUploadService.uploadChunkSizeInBytes;
                        }
                    }
            }
            catch (Exception e)
            {
                Tracer.Write($"YoutubeUploadService.Upload: End, Unexpected Exception: {e.ToString()}.");

                upload.UploadErrorMessage += $"YoutubeUploadService.Upload: Unexpected Exception: : {e.GetType().ToString()}: {e.Message}.";
                upload.UploadStatus        = UplStatus.Failed;
                return(uploadResult);
            }

            uploadResult.ThumbnailSuccessFull = await YoutubeThumbnailService.AddThumbnail(upload);

            uploadResult.PlaylistSuccessFull = await YoutubePlaylistService.AddToPlaylist(upload);

            Tracer.Write($"YoutubeUploadService.Upload: End.");
            return(uploadResult);
        }