public static Task <IApiResult <TwitterUploadedMedia> > UploadMediaAsync( [NotNull] this IApiAccessor accessor, [NotNull] byte[] image, [CanBeNull] long[] additionalOwners, CancellationToken cancellationToken) { if (accessor == null) { throw new ArgumentNullException(nameof(accessor)); } if (image == null) { throw new ArgumentNullException(nameof(image)); } // maximum image size is 5MB. if (image.Length > 5 * 1024 * 1024) { throw new ArgumentOutOfRangeException(nameof(image), "image file must be smaller than 5MB."); } var content = new MultipartFormDataContent { { new ByteArrayContent(image), "media", System.IO.Path.GetRandomFileName() + ".png" } }; if (additionalOwners != null) { content.Add(new StringContent(additionalOwners.Select(id => id.ToString()).JoinString(",")), "additional_owners"); } return(accessor.UploadMediaCoreAsync(content, cancellationToken)); }
public static async Task <IApiResult <TwitterUploadedMedia> > UploadLargeMediaAsync( [NotNull] this IApiAccessor accessor, [NotNull] byte[] media, [NotNull] string mimeType, [CanBeNull] long[] additionalOwners, int?chunkSize, [CanBeNull] IProgress <int> sentBytesCallback, CancellationToken cancellationToken) { if (accessor == null) { throw new ArgumentNullException(nameof(accessor)); } if (media == null) { throw new ArgumentNullException(nameof(media)); } if (mimeType == null) { throw new ArgumentNullException(nameof(mimeType)); } var mediaType = MediaFileUtility.GetMediaType(media); // maximum video size is 15MB (maximum image is 5MB) if (media.Length > 15 * 1024 * 1024) { throw new ArgumentOutOfRangeException(nameof(media), "media file must be smaller than 5MB."); } // check the bit array could be chunked var csize = chunkSize ?? 5 * 1024 * 1024; if (!mediaType.IsMovie() && media.Length <= csize) { // this item is not needed to split it into pieces return(await accessor.UploadMediaAsync(media, additionalOwners, cancellationToken) .ConfigureAwait(false)); } if (csize < 1 || media.Length / csize > 999) { throw new ArgumentOutOfRangeException(nameof(chunkSize), "chunk size is not appropriate."); } // chunking media var chunks = media.Select((b, i) => new { Data = b, Index = i / csize }) .GroupBy(b => b.Index) .Select(g => g.Select(b => b.Data).ToArray()) .ToArray(); // send INIT request var initialContent = new MultipartFormDataContent { { new StringContent("INIT"), "command" }, { new StringContent(media.Length.ToString()), "total_bytes" }, { new StringContent(mimeType), "media_type" } }; if (additionalOwners != null) { initialContent.Add(new StringContent(additionalOwners.Select(id => id.ToString()).JoinString(",")), "additional_owners"); } var initialResult = await accessor.UploadMediaCoreAsync(initialContent, cancellationToken).ConfigureAwait(false); // read initial result and prepare sending content var mediaId = initialResult.Result.MediaId; var fileName = System.IO.Path.GetRandomFileName(); var index = 0; var sentSize = 0; // send APPEND request for uploading contents foreach (var part in chunks) { var content = new MultipartFormDataContent { { new StringContent("APPEND"), "command" }, { new StringContent(mediaId.ToString()), "media_id" }, { new ByteArrayContent(part), "media", fileName }, { new StringContent(index.ToString()), "segment_index" } }; await UploadCoreAsync(accessor, content, cancellationToken).ConfigureAwait(false); sentSize += part.Length; sentBytesCallback?.Report(sentSize); index++; } // send FINALIZE var finalContent = new MultipartFormDataContent { { new StringContent("FINALIZE"), "command" }, { new StringContent(mediaId.ToString()), "media_id" } }; return(await UploadMediaCoreAsync(accessor, finalContent, cancellationToken).ConfigureAwait(false)); }