How would you upload a video to twitter using the POST media/upload (chunked) endpoint with node?
            Asked
            
        
        
            Active
            
        
            Viewed 2,872 times
        
    2 Answers
9
            This goes through all of the steps outlined in the link above: INIT, APPEND, FINALIZE and STATUS
var bufferLength, filePath, finished, fs, oauthCredentials, offset, request, segment_index, theBuffer;
request = require('request');
fs = require('fs');
filePath = '/thevideo.mp4';
bufferLength = 1000000;
theBuffer = new Buffer(bufferLength);
offset = 0;
segment_index = 0;
finished = 0;
oauthCredentials = {
    consumer_key: '',
    consumer_secret: '',
    token: '',
    token_secret: ''
};
fs.stat(filePath, function(err, stats) {
    var formData, normalAppendCallback, options;
    formData = {
        command: "INIT",
        media_type: 'video/mp4',
        total_bytes: stats.size
    };
    options = {
        url: 'https://upload.twitter.com/1.1/media/upload.json',
        oauth: oauthCredentials,
        formData: formData
    };
    normalAppendCallback = function(media_id) {
        return function(err, response, body) {
            finished++;
            if (finished === segment_index) {
                options.formData = {
                    command: 'FINALIZE',
                    media_id: media_id
                };
                request.post(options, function(err, response, body) {
                    console.log('FINALIZED',response.statusCode,body);
                    delete options.formData;
                    //Note: This is not working as expected yet.
                    options.qs = {
                        command: 'STATUS',
                        media_id: media_id
                    };
                    request.get(options, function(err, response, body) {
                        console.log('STATUS: ', response.statusCode, body);
                    });
                });
            }
        };
    };
    request.post(options, function(err, response, body) {
        var media_id;
        media_id = JSON.parse(body).media_id_string;
        fs.open(filePath, 'r', function(err, fd) {
            var bytesRead, data;
            while (offset < stats.size) {
                bytesRead = fs.readSync(fd, theBuffer, 0, bufferLength, null);
                data = bytesRead < bufferLength ? theBuffer.slice(0, bytesRead) : theBuffer;
                options.formData = {
                    command: "APPEND",
                    media_id: media_id,
                    segment_index: segment_index,
                    media_data: data.toString('base64')
                };
                request.post(options, normalAppendCallback(media_id));
                offset += bufferLength;
                segment_index++
            }
        });
    });
});
        Piotr Tomasik
        
- 9,074
 - 4
 - 44
 - 57
 
- 
                    1Worked nicely. Thanks for sharing that. – Sebastian Sastre Jun 01 '16 at 18:46
 - 
                    How can I connect this with HTML to upload the video? – C.Gkalfas Jan 30 '18 at 07:06
 - 
                    @piotr can you please help here: https://twittercommunity.com/t/finalize-step-in-media-chunk-upload-giving-400-error-message/164706/2 – aryat Jan 09 '22 at 17:15
 
4
            
            
        Please try this
const splitFile = require('split-file')
const Twitter = require('twitter')
const fs = require('fs-extra')
const Promise = require('bluebird')
const pathToMovie = __dirname + '/test/152.mp4';
const mediaType = 'video/mp4' // `'video/mp4'` is also supported
let Names
const mediaSize = require('fs').statSync(pathToMovie).size
/* Twitter support Maximum  15MB video files. So we need to split this 
file in to three files */
splitFile.splitFile(pathToMovie, 3)
.then((names) => {
  Names = names
  return init()
})
.catch((err) => {
console.log('Error: ', err)
})
const client = new Twitter({
  consumer_key: '<your consumer_key >',
  consumer_secret: '<your consumer_secret >',
  access_token_key: '<your access_token_key >',
  access_token_secret: '<access_token_secret>'
});
const init = () => {
  initTweetUpload(mediaSize, mediaType) // Declare that you wish to upload some media
  .then(appendTweetUpload) // Send the data for the media
  .then(appendTweetUpload) // Send the data for the media
  .then(appendTweetUpload) // Send the data for the media
  .then(finalizeTweetUpload) // Declare that you are done uploading chunks
 // eslint-disable-next-line promise/always-return
  .then((data) => {
    const status = {
      media_ids: data,
      status: 'NodeJS Media Upload',
  }
  client.post('statuses/update', status, (error, tweet, response) => {
    console.log(error)
    console.log(tweet)
  })
 }).catch((err) => {
  console.log('Error: ', err)
  })
 }
const initTweetUpload = (mediaSize, mediaType) => makePost('media/upload', 
{
 command: 'INIT',
 total_bytes: mediaSize,
 media_type: mediaType,
}).then((data) => data.media_id_string)
let i = 0
const appendTweetUpload = (mediaId) => {
 const p = Names.shift()
 /* mediaData is the  raw binary file content being uploaded ,It must be 
<= 5 MB */
const mediaData = fs.readFileSync(p)
return makePost('media/upload', {
  command: 'APPEND',
  media_id: mediaId,
  media: mediaData,
  segment_index: i++,
}).then((data) => mediaId)
}
const finalizeTweetUpload = (mediaId) => makePost('media/upload', {
command: 'FINALIZE',
media_id: mediaId,
}).then((data) => mediaId)
const makePost = (endpoint, params) =>
// params.media_category = 'tweet_video';
new Promise((resolve, reject) => {
client.post(endpoint, params, (error, data, response) => {
  if (error) {
    reject(error)
  } else {
    resolve(data)
  }
 })
 })
dependencies 
 1. https://www.npmjs.com/package/twitter
 2. https://www.npmjs.com/package/split-file
        Joshua Varghese
        
- 5,082
 - 1
 - 13
 - 34
 
        Aji Aneesh
        
- 121
 - 8
 
- 
                    Can you please help here: https://twittercommunity.com/t/finalize-step-in-media-chunk-upload-giving-400-error-message/164706/2 – aryat Jan 09 '22 at 17:14