Ejemplo n.º 1
0
        public async Task SchedulePostWithVideoAsync()
        {
            var videoType = Path.GetExtension(TestsBase.TestVideoPath);
            var bytes     = File.ReadAllBytes(TestsBase.TestVideoPath);

            var post = new VideoCreatingRequest(videoType)
            {
                Source                 = bytes,
                FileSize               = bytes.Length,
                Description            = $"Description_{TestsBase.Context.TestName}_{Guid.NewGuid().ToString("N")}",
                Name                   = $"Name_{TestsBase.Context.TestName}_{Guid.NewGuid().ToString("N").Remove(16)}",
                Title                  = $"Title_{TestsBase.Context.TestName}_{Guid.NewGuid().ToString("N").Remove(8)}",
                Published              = false,
                UnpublishedContentType = UnpublishedContentType.Scheduled,
                ScheduledPublishTime   = DateTimeUtil.CountTimeStamp(DateTime.Now.AddHours(1))
            };

            var response = await post.PostAsync(TestsBase.PageId, TestsBase.PageAccessToken);

            Assert.IsTrue(response.Code == ResponseCode.SUCCESS, response.ReasonPhrase ?? String.Empty);

            var jobj = JObject.Parse(response.Data);

            Assert.IsTrue(jobj["id"] != null && !String.IsNullOrEmpty(jobj["id"].ToString()));
        }
Ejemplo n.º 2
0
 /// <summary>
 ///     Simplify the target <see cref="VideoCreatingRequest"/> object.
 /// </summary>
 /// <param name="request">
 ///     A <see cref="VideoCreatingRequest"/> object.
 /// </param>
 private static void SimplifyVideoCreatingRequest(VideoCreatingRequest request)
 {
     request.EndOffset       = null;
     request.FileUrl         = null;
     request.Source          = null;
     request.StartOffset     = null;
     request.UploadPhase     = null;
     request.UploadSessionId = null;
     request.VideoFileChunk  = null;
 }
Ejemplo n.º 3
0
        public void Initialize()
        {
            var videoType = Path.GetExtension(TestsBase.TestVideoPath);

            _request = new VideoCreatingRequest(videoType)
            {
                Description = $"Description_{TestsBase.Context.TestName}_{Guid.NewGuid().ToString("N")}",
                Name        = $"Name_{TestsBase.Context.TestName}_{Guid.NewGuid().ToString("N").Remove(16)}",
                Title       = $"Title_{TestsBase.Context.TestName}_{Guid.NewGuid().ToString("N").Remove(8)}"
            };
        }
Ejemplo n.º 4
0
        /// <summary>
        ///     Uploads an ad video to facebook by non-resumable upload as an asynchronous operation.
        /// </summary>
        /// <param name="filename">
        ///     The full file path of the video.
        /// </param>
        /// <param name="adAccountId">
        ///     The ad account id of user.
        /// </param>
        /// <param name="accessToken">
        ///     Access token.
        /// </param>
        /// <param name="request">
        ///     A <see cref="VideoCreatingRequest"/> object, of which basic information will be in use.
        /// </param>
        /// <returns>
        ///     The task object representing the asynchronous operation.
        /// </returns>
        /// <exception cref="FileNotFoundException">
        ///     Throw if the target file doesn't exists.
        /// </exception>
        /// <exception cref="ArgumentNullException">
        ///     Throw if the parameter targetId or accessToken is null or empty string, or request equals to null.
        /// </exception>
        public static async Task <ResponseMessage <string> > UploadAsAdVideoAsync(string filename, string adAccountId, string accessToken, VideoCreatingRequest request)
        {
            #region Data check & preprocess.
            if (!File.Exists(filename))
            {
                throw new FileNotFoundException($"Cannot find file {filename}");
            }

            if (String.IsNullOrEmpty(adAccountId) || String.IsNullOrEmpty(accessToken) || request == null)
            {
                throw new ArgumentNullException();
            }

            SimplifyVideoCreatingRequest(request);
            #endregion

            request.Source = await File.ReadAllBytesAsync(filename);

            request.FileSize = request.Source.Length;

            return(await request.PostAsAdVideoAsync(adAccountId, accessToken));
        }
Ejemplo n.º 5
0
        /// <summary>
        ///     Uploads a video to facebook by resumable upload as an asynchronous operation.
        /// </summary>
        /// <param name="filename">
        ///     The full file path of the video.
        /// </param>
        /// <param name="request">
        ///     A <see cref="VideoCreatingRequest"/> object, of which basic information will be in use.
        /// </param>
        /// <param name="retries">
        ///     Chances of retry. The retry operation will be triggered on failed to upload chunk file.
        /// </param>
        /// <param name="asyncRequestOperation">
        ///     A function to post <see cref="VideoCreatingRequest"/> asynchronously, a
        ///     <see cref="ResponseMessage{TResult}"/> object should be returns.
        /// </param>
        /// <returns>
        ///     The task object representing the asynchronous operation.
        /// </returns>
        private static async Task <ResponseMessage <string> > UploadInChunksAsync(string filename, VideoCreatingRequest request, int retries, Func <VideoCreatingRequest, Task <ResponseMessage <string> > > asyncRequestOperation)
        {
            var response = new ResponseMessage <string>();

            var       fileExtension   = Path.GetExtension(filename);
            var       fileInfo        = new FileInfo(filename);
            var       videoId         = String.Empty;
            var       uploadSessionId = String.Empty;
            var       allUploaded     = false;
            JObject   jobj            = null;
            Exception exception       = null;

            // To init chunked upload.
            var initRequest = new VideoCreatingRequest(fileExtension)
            {
                UploadPhase = UploadPhase.Start,
                FileSize    = fileInfo.Length
            };

            response = await asyncRequestOperation(initRequest);

#if DEBUG
            System.Diagnostics.Debug.WriteLine($"Initializes chunked upload returns {response.Data}");
#endif

            if (response.Code == ResponseCode.SUCCESS)
            {
                jobj = JObject.Parse(response.Data);

                if (jobj["video_id"] != null &&
                    jobj["upload_session_id"] != null &&
                    !String.IsNullOrEmpty(jobj["video_id"].ToString()) &&
                    !String.IsNullOrEmpty(jobj["upload_session_id"].ToString()))
                {
                    videoId         = jobj["video_id"].ToString();
                    uploadSessionId = jobj["upload_session_id"].ToString();

                    var transferRequest = new VideoCreatingRequest(fileExtension)
                    {
                        UploadSessionId = uploadSessionId,
                        StartOffset     = Int64.Parse(jobj["start_offset"].ToString()),
                        EndOffset       = Int64.Parse(jobj["end_offset"].ToString()),
                        UploadPhase     = UploadPhase.Transfer
                    };

                    // To open file and transfer data.
                    using (var fs = fileInfo.OpenRead())
                    {
                        do
                        {
                            var bufferLength = (Int32)(transferRequest.EndOffset - transferRequest.StartOffset).Value;
                            var buffer       = new byte[bufferLength];
                            fs.Position = transferRequest.StartOffset.Value;
                            fs.Read(buffer, 0, bufferLength);
                            transferRequest.VideoFileChunk = buffer;

                            var uploaded      = false; // Indicates if current chunk file uploaded successfully.
                            var uploadCounter = 0;     // Indicates the uploading attempts of current chunk file.

                            #region Transfers single chunk file.
                            do
                            {
                                try
                                {
                                    exception = null; // Reset exception.
#if DEBUG
                                    var startTime = DateTime.Now;
#endif
                                    response = await asyncRequestOperation(transferRequest);

#if DEBUG
                                    var duration = DateTime.Now - startTime;
                                    System.Diagnostics.Debug.WriteLine($"Transfering {transferRequest.StartOffset}-{transferRequest.EndOffset} returns {response.Code}. Duration: {duration.TotalSeconds.ToString("N2")}s.");
#endif

                                    if (response.Code == ResponseCode.SUCCESS)
                                    {
                                        jobj = JObject.Parse(response.Data);

                                        if (jobj["start_offset"] != null &&
                                            jobj["end_offset"] != null &&
                                            !String.IsNullOrEmpty(jobj["start_offset"].ToString()) &&
                                            !String.IsNullOrEmpty(jobj["end_offset"].ToString()))
                                        {
                                            transferRequest.StartOffset = Int64.Parse(jobj["start_offset"].ToString());
                                            transferRequest.EndOffset   = Int64.Parse(jobj["end_offset"].ToString());

                                            uploaded = true;
                                        }
                                    }
                                }
                                catch (Exception ex)
                                {
                                    exception = ex;

                                    await Task.Delay(1000);
                                }
                            }while (!uploaded && uploadCounter++ < retries);
                            #endregion

                            if (!uploaded)
                            {
                                if (exception != null)
                                {
                                    throw exception; // Throw exception if it occured during the last attempt.
                                }
                                else
                                {
                                    break; // None successful attempt, break.
                                }
                            }
                            else if (transferRequest.StartOffset >= transferRequest.EndOffset)
                            {
                                allUploaded = true;
                            }
                        }while (!allUploaded);
                    }

                    if (allUploaded)
                    {
                        // To complete chunked upload.
                        SimplifyVideoCreatingRequest(request);

                        request.UploadSessionId = uploadSessionId;
                        request.UploadPhase     = UploadPhase.Finish;

                        response = await asyncRequestOperation(request);

                        jobj             = JObject.Parse(response.Data);
                        jobj["video_id"] = videoId;
                        response.Data    = jobj.ToString();
                    }
                }
            }

            return(response);
        }
Ejemplo n.º 6
0
        /// <summary>
        ///     Uploads an ad video to facebook by resumable upload as an asynchronous operation.
        /// </summary>
        /// <param name="filename">
        ///     The full file path of the video.
        /// </param>
        /// <param name="adAccountId">
        ///     The ad account id of user.
        /// </param>
        /// <param name="accessToken">
        ///     Access token.
        /// </param>
        /// <param name="request">
        ///     A <see cref="VideoCreatingRequest"/> object, of which basic information will be in use.
        /// </param>
        /// <param name="retries">
        ///     Chances of retry. The retry operation will be triggered on failed to upload chunk file.
        /// </param>
        /// <returns>
        ///     The task object representing the asynchronous operation.
        /// </returns>
        /// <exception cref="FileNotFoundException">
        ///     Throw if the target file doesn't exists.
        /// </exception>
        /// <exception cref="ArgumentNullException">
        ///     Throw if the parameter targetId or accessToken is null or empty string, or request equals to null.
        /// </exception>
        public static async Task <ResponseMessage <string> > UploadAsAdVideoInChunksAsync(string filename, string adAccountId, string accessToken, VideoCreatingRequest request, int retries = 2)
        {
            #region Data check.
            if (!File.Exists(filename))
            {
                throw new FileNotFoundException($"Cannot find file {filename}");
            }

            if (String.IsNullOrEmpty(adAccountId) || String.IsNullOrEmpty(accessToken) || request == null)
            {
                throw new ArgumentNullException();
            }
            #endregion

            return(await UploadInChunksAsync(filename, request, retries, async (req) =>
            {
                return await req.PostAsAdVideoAsync(adAccountId, accessToken);
            }));
        }
Ejemplo n.º 7
0
        /// <summary>
        ///     Publishes video ad to facebook with a specified cover as an asynchronous operation.
        /// </summary>
        /// <param name="video">
        ///     The filepath of the ad video.
        /// </param>
        /// <param name="cover">
        ///     The url or filepath of the video cover. Sets to null or an empty string to use the thumbnail that
        ///     generated by facebook as the cover.
        /// </param>
        /// <param name="request">
        ///     An object of <see cref="AdCreativeCreatingRequest"/>, which contains most of publish infomation.
        /// </param>
        /// <param name="adAccountId">
        ///     The ad account id of user.
        /// </param>
        /// <param name="accessToken">
        ///     User access token.
        /// </param>
        /// <param name="pageAccessToken">
        ///     Page access token.
        /// </param>
        /// <param name="publish">
        ///     If true, the photo ad will be published to a facebook page immediately.
        /// </param>
        /// <param name="threshold">
        ///     If the filesize (in MByte) of video exceeded this value, the video will be uploaded in resumable upload;
        ///     otherwise, non-resumable upload. The default threshold is set to 50MB.
        /// </param>
        /// <returns>
        ///     The task object representing the asynchronous operation.
        /// </returns>
        /// <exception cref="FileNotFoundException">
        ///     Throw if the target video or cover file doesn't exist.
        /// </exception>
        public static async Task <ResponseMessage <string> > PublishVideoAdAsync(string video, string cover, AdCreativeCreatingRequest request, string adAccountId, string accessToken, string pageAccessToken, bool publish, int threshold = 50)
        {
            ResponseMessage <string> response = null;

            JObject jobj = null;

            var videoId    = String.Empty;
            var coverUrl   = String.Empty;
            var adCreative = new AdCreative();

            // 1. Gets the video_id.
            #region Uploads video to facebook.
            if (!File.Exists(video))
            {
                throw new FileNotFoundException($"Cannot find file {video}");
            }

            var videoInfo            = new FileInfo(video);
            var videoSize            = videoInfo.Length;
            var enableChunkedUpload  = videoSize > (50L * 1024 * 1024);
            var videoCreatingRequest = new VideoCreatingRequest(videoInfo.Extension)
            {
                Name  = videoInfo.Name,
                Title = Path.GetFileNameWithoutExtension(video)
            };

            response = enableChunkedUpload ?
                       await VideoUploader.UploadAsAdVideoInChunksAsync(video, adAccountId, accessToken, videoCreatingRequest) :
                       await VideoUploader.UploadAsAdVideoAsync(video, adAccountId, accessToken, videoCreatingRequest);

            if (response.Code == ResponseCode.SUCCESS)
            {
                jobj = JObject.Parse(response.Data);

                if (enableChunkedUpload)
                {
                    // Parses resumable upload result.
                    if (jobj["video_id"] != null && !String.IsNullOrEmpty(jobj["video_id"].ToString()))
                    {
                        videoId = jobj["video_id"].ToString();
                    }
                }
                else
                {
                    // Parses non-resumable upload result.
                    if (jobj["id"] != null && !String.IsNullOrEmpty(jobj["id"].ToString()))
                    {
                        videoId = jobj["id"].ToString();
                    }
                }

                if (String.IsNullOrEmpty(videoId))
                {
                    return(new ResponseMessage <string>
                    {
                        Code = ResponseCode.UNKNOWN_ERROR,
                        ReasonPhrase = $"Failed to upload video {video} to facebook."
                    });
                }
            }
            else
            {
                return(response);
            }
            #endregion

#if DEBUG
            System.Diagnostics.Debug.WriteLine($"Got video_id: {videoId}");
#endif

            // 2. Gets the url of cover.
            if (!String.IsNullOrEmpty(cover))
            {
                // Customizes cover.
#pragma warning disable SA1008
                var(AdPhotoUrl, AdPhotoResponse) = await GetAdPhotoUrlAsync(cover, adAccountId, accessToken);

#pragma warning restore SA1008

                if (String.IsNullOrEmpty(AdPhotoUrl))
                {
                    return(AdPhotoResponse);
                }

                coverUrl = AdPhotoUrl;
            }

            /* The thumbnail won't be generated until the video has been decoded by facebook successfully,
             * just wait for a while.
             * */
            await Task.Delay(10_000);

#pragma warning disable SA1008
            var(ThumbnailUrl, ThumbnailResponse) = await GetVideoThumbnailAsync(videoId, accessToken, 20);

#pragma warning restore SA1008

            if (String.IsNullOrEmpty(cover))
            {
                if (String.IsNullOrEmpty(ThumbnailUrl))
                {
                    return(ThumbnailResponse);
                }

                coverUrl = ThumbnailUrl;
            }

#if DEBUG
            System.Diagnostics.Debug.WriteLine($"Got cover_url: {coverUrl}");
#endif

            // 3. Posts ad creative creating request.
            request.ObjectStorySpec.VideoData.VideoId = videoId;
            request.ObjectStorySpec.VideoData.Cover   = coverUrl;

#pragma warning disable SA1008
            var(AdCreativeId, AdCreativeResponse) = await PostAdCreativeAsync(request, adAccountId, accessToken);

#pragma warning restore SA1008

            if (String.IsNullOrEmpty(AdCreativeId))
            {
                return(AdCreativeResponse);
            }

            adCreative.Id = AdCreativeId;

#if DEBUG
            System.Diagnostics.Debug.WriteLine($"Got ad_creative_id: {AdCreativeId}");
#endif

            if (publish)
            {
                // 4. Publishes ad creative.
                response = await adCreative.PublishAsync(accessToken, pageAccessToken);
            }

            return(response);
        }