tweetinvi Chunked Uploads for large uploads - twitter

I am trying to file upload with tweetinvi.File upload work for image but same code does not work for video(large video more than 20 mb)
I asked here but now answear
TweetInvi Large Video Upload Failing With Null Reference
so I look for another solution.There is tweetinvi chunked uploads
I coded this but it does not work,it does not give error but it does not work
if (file.ContentType.Contains("video"))//video
{
var video1 = System.IO.File.ReadAllBytes(path);
var chunk = Upload.CreateChunkedUploader(); //Create an instance of the ChunkedUploader class (I believe this is the only way to get this object)
using (FileStream fs = System.IO.File.OpenRead(path))
{
chunk.Init("video/mp4", (int)fs.Length); //Important! When initialized correctly, your "chunk" object will now have a type long "MediaId"
byte[] buffer = new byte[video1.Length]; //Your chunk MUST be 5MB or less or else the Append function will fail silently.
int bytesRead = 0;
while ((bytesRead = fs.Read(buffer, 0, buffer.Length)) > 0)
{
byte[] copy = new byte[bytesRead];
Buffer.BlockCopy(buffer, 0, copy, 0, bytesRead);
TimeSpan s = new TimeSpan();
chunk.Append(copy, chunk.NextSegmentIndex.ToString()); //The library says the NextSegment Parameter is optional, however I wasn't able to get it to work if I left it out.
}
}
var video = chunk.Complete(); //This tells the API that we are done uploading.
listMedia.Add(video);
}

I wanted to say that after working on your bug I was able to identify the problem you were encountering.
The issue is that you were not specifying the media_category of the upload.
In addition to this you need to wait for the media to be processed by Twitter.
In Tweetinvi 2.1, the process should be made easier. Please use the following code :
var binary = File.ReadAllBytes(#"video_path");
var media = Upload.UploadVideo(binary);
// The upload is completed but it does not mean it succeeded!
if (!media.HasBeenUploaded)
{
// Something went wrong during the upload.
// Please retry or check the video type/settings.
return;
}
// Just wait for Twitter to have processed the upload (RECOMMENDED)
Upload.WaitForMediaProcessingToGetAllMetadata(media);
// Now the media is ready to be used in a Tweet
var tweet = Tweet.PublishTweet("hello", new PublishTweetOptionalParameters
{
Medias = { media }
});
You can read more about the upload in the updated documentation : https://github.com/linvi/tweetinvi/wiki/Upload#upload-status-video
Finally please note that further improvements of upload are planned for version 2.2 and 2.3.
Have a great day and thank you for reporting this problem,
Cheers
Linvi

Related

Random image from folder

How can I make possible that the app will load all of the images from the specific folder and then put in array and choose one image randomly? When chose one then pass to the fronted to show the image. How to do that too?
I am C# developer but not long time ago I found ElectronJS and this framework does everything easier so therefore I am moving to this framework.
I did in C# programming this way:
// basic settings.
var ext = new List<string> { ".jpg", ".gif", ".png" };
// we use same directory where program is.
string targetDirectory = Directory.GetCurrentDirectory() + "\\assets\\" + "images\\" + "animals\\";
// Here we create our list of files
// New list
// Use GetFiles to getfilenames
// Filter unwanted stuff away (like our program)
if (Directory.Exists(targetDirectory))
{
Files = new List<string>
(Directory.GetFiles(targetDirectory, "*.*", SearchOption.TopDirectoryOnly)
.Where(s => ext.Any(es => s.EndsWith(es))));
// Show first picture so we dont need wait 3 secs.
ChangePicture();
}
else
{
panel5.BackgroundImage = new Bitmap(Resources.doggy);
}
I don't know how to do in ElectronJS.
Thank you in advance the answers.
Alright. I found the solution.
However I don't understand the people who are giving negative reputation for the opened question. If they are giving negative reputation then they could explain why.
Well anyway, I did fix this issue with this way:
I created images.js file and added this:
var fs = require('fs');
function getRandImage() {
var files = fs.readdirSync('./assets/images/animals/')
/* now files is an Array of the name of the files in the folder and you can pick a random name inside of that array */
let chosenFile = files[Math.floor(Math.random() * files.length)]
console.log('../assets/images/animals/' + chosenFile);
return '../assets/images/animals/' + chosenFile;
}
module.exports = { getRandImage }
I used console to see if the value is correct, otherwise others can delete that part.
Sending the data to the renderer process:
const { getRandImage } = require('./images');
child.webContents.send('random-image', getRandImage());
I did put in the preload.js file the following (I used the starter pack electronjs github to start with something):
var { ipcRenderer } = require('electron');
ipcRenderer.on('random-image', function (event, store) {
document.getElementById("randompic").src = store;
console.log(store);
});
Same here, I did use console.log just for test the value is correct and I used to change the randompic ID related image src html to the randomly chosen image.
Hopefully I did helping those people who are newbie as me.

"The audience claim value is invalid for current resource" when using ChunkedUploadProvider for Attachment in Microsoft Graph Client API

I am trying to use the following code, but am getting "Message: The audience claim value is invalid for current resource. Audience claim is 'https://graph.microsoft.com', request url is 'https://outlook.office.com/api/beta/Users..."
I get it on the provider.GetUploadChunkRequests(); call below:
AttachmentItem attachmentItem= new AttachmentItem
{
Name = [Name],
AttachmentType = AttachmentType.File,
Size = [Size]
};
var session = graphClient.Users[USEREMAIL].Messages[MESSAGEID].Attachments.CreateUploadSession(attachmentItem).Request().PostAsync().Result;
var stream = new MemoryStream(BYTEARRAY);
var maxSizeChunk = DEFAULT_CHUNK_SIZE;
var provider = new ChunkedUploadProvider(session, graphClient, stream, maxSizeChunk);
var chunkRequests = provider.GetUploadChunkRequests();
(I am using the graphClient to send emails successfully, and have also used it to upload large files using the uploadSession method)
From Andrue Eastman on GitHub:
You are most likely getting the error because of using the ChunkedUploadPorvider instead of using the FileUploadTask to upload the attachment which is setting the Auth header to cause the error you are receiving.
To use the file upload task, follow the following steps
First create an upload session and handing it over to the task as illustrated.
// Create task
var maxSliceSize = 320 * 1024; // 320 KB - Change this to your chunk size. 4MB is the default.
LargeFileUploadTask<FileAttachment> largeFileUploadTask = new LargeFileUploadTask<FileAttachment>(uploadSession, stream, maxSliceSize);
Create an upload monitor (optional)
// Setup the progress monitoring
IProgress<long> progress = new Progress<long>(progress =>
{
Console.WriteLine($"Uploaded {progress} bytes of {stream.Length} bytes");
});
The service only returns location URI which can be read off from the result object as follows.
UploadResult<FileAttachment> uploadResult = null;
try
{
uploadResult = await largeFileUploadTask.UploadAsync(progress);
if (uploadResult.UploadSucceeded)
{
Console.WriteLine(uploadResult.Location);//the location of the object
}
}
catch (ServiceException e)
{
Console.WriteLine(e.Message);
}

audio Blob not working in IOS / Safari

I am recording audio, sending it as a blob to a nodejs server. The nodejs server then sends it to all connected users that are not currently recording.
Sending the blob:
mediaRecorder.onstop = function(e) {
var blob = new Blob(this.chunks, { 'type' : 'audio/ogg; codecs=opus' });
socket.emit('radio', blob);
};
Server receiving the blob:
socket.on('radio', function(blob) {
socket.broadcast.emit('voice', blob);
});
Listener receiving the blob:
socket.on('voice', function(arrayBuffer) {
var blob = new Blob([arrayBuffer], { 'type' : 'audio/ogg; codecs=opus' });
var audio = document.getElementById('audio');
audio.src = window.URL.createObjectURL(blob);
audio.play();
});
This works in all browsers/devices except safari and any ios device. Taking it further with safari's inspector I found this:
Does safari require something else in its headers for blob objects to be interpreted properly? I've researched accepted audio types, tried aac/mp3/ogg without any success. Upon reading further I've heard references to the fact that there is a bug with streaming blob audio/video data in safari and IOS though I'm not too clear any the details.
Guidance in the rite direction would be very helpful!
EDIT: It looks like this line audio.src = window.URL.createObjectURL(blob); in the receiving blob is what is causing the blob errors (image i linked)
EDIT 2: I tried to see if using another format other than blob would work, opting for base64 encoded string. Looks like this works on all devices and browsers except for IOS and Safari. I'm getting the impression it has something to do with how IOS interprets/loads the data...
For me the solution was to insert a source element into the audio element, and use the sourceElement.src attribute to refer to the blob. I didn't even need to attach the audio-element to the DOM. Example below, hope it helps someone.
var audioElement = document.createElement('audio')
var sourceElement = document.createElement('source')
audioElement.appendChild(sourceElement)
sourceElement.src = '<your blob url>'
sourceElement.type = 'audio/mp3' // or whatever
audioElement.load()
audioElement.play()
I haven't been able to find a solution using an audio element, however the Web Audio Api seems to do the trick: https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API
var audioContext = new (window.AudioContext || window.webkitAudioContext);
socket.on('voice', function(arrayBuffer) {
audioContext.decodeAudioData(arrayBuffer, audioData => {
var source = audioContext.createBufferSource();
source.buffer = audioData;
source.connect(audioContext.destination);
source.start()
});
You may still have an issue on iOS as any audio/video must be triggered by a user action.
I had a similar problem this week. I was recording the audio on Safari and the audio blob was being generated just fine. But when I tried to send the blob to server, no data was getting there. The solution bellow reads the blob with File Reader to convert it to base64, and afterwards send it to server. Here is what worked for me:
const reader = new FileReader();
reader.readAsDataURL(audioBlob);
reader.onloadend = () => {
const base64data = reader.result;
const audioName = uuid.v4() + '.mp3';
this.http.post(this.app.cloudStorageEndpoint + '/audios/local?audioName=' + audioName, base64data , header).subscribe(
res => { resolve(audioName); },
err => { reject(err); }
);
};
I've tested with Safari 12 on both iPad and iPhone and it worked fine.

Getting error when uploading video using Tweetinvi

I am trying to upload files larger than 5MB but less than 15MB. In this case its 10MB... sample video from sample-videos.com
I am using Tweetinvi, and it works great with files less than 5MB, but fails on chunked uploads. I've tried the easy and the hard way.
Easy way:
var video = File.ReadAllBytes(#"D:\Projects\SampleVideo_1280x720_10mb.mp4");
var media = Upload.UploadVideo(video); // Error here... Invalid Content
var tweet = user.PublishTweet(message, new PublishTweetOptionalParameters
{
Medias = { media }
});
I've pulled in the Tweetinvi solution from Git (currently 0.9.13.0 repository here) and see that the above is getting an error "Invalid Content" when calling Upload.UploadVideo(...). It appears to fail on the command FINALIZE.
Tried the hard way:
using (var fileStream = File.OpenRead(#"D:\Projects\SampleVideo_1280x720_10mb.mp4"))
{
var initSucceeded = uploader.Init("video/mp4", (int)fileStream.Length);
byte[] buffer = new byte[4900000]; //Your chunk MUST be 5MB or less or else the Append function will fail silently.
int bytesRead = 0;
while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) > 0)
{
byte[] copy = new byte[bytesRead];
Buffer.BlockCopy(buffer, 0, copy, 0, bytesRead);
var appendResult = uploader.Append(new ChunkUploadAppendParameters(copy, "video/mp4", null) { SegmentIndex = uploader.NextSegmentIndex });
}
var video = uploader.Complete(); // Fails here... Returned error: Segments do not add up to provided total file size
var tweet = user.PublishTweet(message, new PublishTweetOptionalParameters()
{
//Medias = { video }
MediaIds = { video.MediaId.Value }
});
}
The above fails on upload.Complete() with the Twitter API returning "Segments do not add up to provided total file size"
What am I missing?
TIA
I think the problem you have is with the video file. The video seems to be using a 6 channels audio and Twitter Public Upload API only allow developers to upload video with mono or stereo audio.
Source : https://dev.twitter.com/rest/media/uploading-media
I am no expert in video properties so feel free to prove me wrong if I am.
The above fails on upload.Complete() with the Twitter API returning "Segments do not add up to provided total file size"
This error means that you are not actually sending all the byte that you promised Twitter. During the INIT, you tell Twitter the size of your media, if what it receives in the combined APPEND is not equals to the value you specified in the INIT, the error you described is thrown.
PS : I have tried using a 2 channels 14.8 MB mp4 and it works properly. var media = Upload.UploadVideo(binary);

http response got truncated in docker

I've built a http server using netty. Everything is fine when it's running in my mac, but when I run it in a docker image, the http response always get truncated when great than 460k.
What's the problem will be? Please help.
Do you use aggregator to aggregate the http response or not? Take a look at the source code of HttpObjectDecoder. It will chunk bigger http response no matter if the http message itself is transfer coding or not.
The default maxChunk size is 8k.And even readable bytes is enough, it will chunk it. see the code below:
` case READ_FIXED_LENGTH_CONTENT: {
int readLimit = actualReadableBytes();
// Check if the buffer is readable first as we use the readable byte count
// to create the HttpChunk. This is needed as otherwise we may end up with
// create a HttpChunk instance that contains an empty buffer and so is
// handled like it is the last HttpChunk.
//
// See https://github.com/netty/netty/issues/433
if (readLimit == 0) {
return;
}
int toRead = Math.min(readLimit, maxChunkSize);
if (toRead > chunkSize) {
toRead = (int) chunkSize;
}
ByteBuf content = readBytes(ctx.alloc(), buffer, toRead);
chunkSize -= toRead;
`

Resources