From ab2ff7efb39020dd7fa807a6bb35b048a41b7035 Mon Sep 17 00:00:00 2001 From: EricCao Date: Tue, 3 Dec 2013 15:56:14 +0800 Subject: [PATCH 1/2] Using Lists api version 1.1 --- lib/twitter.js | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/lib/twitter.js b/lib/twitter.js index edc52464..5c5b79c0 100644 --- a/lib/twitter.js +++ b/lib/twitter.js @@ -690,15 +690,18 @@ Twitter.prototype.getLists = function(id, params, callback) { params = null; } - var defaults = {key:'lists'}; + var defaults = {}; if (typeof id === 'string') defaults.screen_name = id; else defaults.user_id = id; params = utils.merge(defaults, params); - var url = '/lists.json'; - this._getUsingCursor(url, params, callback); + // FIX by Eric Cao + //var url = '/lists.json'; + //this._getUsingCursor(url, params, callback); + var url = '/lists/list.json'; + this.get(url, params, callback); return this; } @@ -738,6 +741,25 @@ Twitter.prototype.getListSubscriptions = function(id, params, callback) { return this; } +// Added by Eric Cao +Twitter.prototype.getListsStatuses = function(id, screen_name, params, callback) { + if (typeof params === 'function') { + callback = params; + params = null; + } + + var defaults = { + list_id: id, + owner_screen_name: screen_name + }; + params = utils.merge(defaults, params); + + + var url = '/lists/statuses.json'; + this.get(url, params, callback); + return this; +} + // FIXME: Uses deprecated Twitter lists API Twitter.prototype.showList = function(screen_name, list_id, callback) { var url = '/' + escape(screen_name) + '/lists/' + escape(list_id) + '.json'; From 6fbcc0bec832d9411fe911a8ca54869b94a29924 Mon Sep 17 00:00:00 2001 From: EricCao Date: Wed, 4 Dec 2013 16:46:55 +0800 Subject: [PATCH 2/2] add support to 'update_status_with_media.json' --- lib/twitter.js | 117 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 117 insertions(+) diff --git a/lib/twitter.js b/lib/twitter.js index 5c5b79c0..d672bb57 100644 --- a/lib/twitter.js +++ b/lib/twitter.js @@ -1,5 +1,6 @@ var VERSION = '0.2.8', http = require('http'), + https = require('https'), querystring = require('querystring'), oauth = require('oauth'), Cookies = require('cookies'), @@ -539,6 +540,122 @@ Twitter.prototype.updateStatus = function(text, params, callback) { return this; } +Twitter.prototype.updateStatusWithMedia = function(status, media_name, media_row, encoding, params, callback) { + if (status === undefined) { + throw new Error('Missing required parameter: status.'); + } + + if (media_name === undefined) { + throw new Error('Missing required parameter: media_name.'); + } + + if (media_row === undefined) { + throw new Error('Missing required parameter: media_row.'); + } + + if (typeof encoding === 'function') { + callback = encoding; + encoding = 'base64'; // default encodingf + params = null; + } + + if (typeof params === 'function') { + callback = params; + params = null; + } + + var url = this.options.rest_base + '/statuses/update_with_media.json'; + var defaults = { + status: status + }; + params = utils.merge(defaults, params); + + // Workaround: oauth + booleans == broken signatures + if (params && typeof params === 'object') { + Object.keys(params).forEach(function(e) { + if ( typeof params[e] === 'boolean' ) + params[e] = params[e].toString(); + }); + } + + // oauth - multipart post + var crlf = '\r\n'; + var boundary = 'ece072908565ge59x89ch983452389hosdfd8923y523hedhf923y53'; + var separator = '--' + boundary; + var footer = crlf + separator + '--' + crlf; + var fileHttpHeader = 'Content-Disposition: form-data; name="media[]"; filename="' + media_name + '"'; + if (encoding === 'base64') { + fileHttpHeader = fileHttpHeader + crlf + 'Content-Transfer-Encoding: base64'; + media_row = new Buffer(media_row); // convert base64 string to binary + } + var contents = separator + crlf + + 'Content-Disposition: form-data; name="status"' + crlf + + crlf + + status + crlf + + separator + crlf + + 'Content-Type: application/octet-stream' + crlf + + fileHttpHeader + crlf + + crlf; + + var multipartBody = Buffer.concat([ + new Buffer(contents), + media_row, + new Buffer(footer) + ]); + + var hostname = 'api.twitter.com'; + var authorization = this.oauth.authHeader( + 'https://api.twitter.com/1.1/statuses/update_with_media.json', + this.options.access_token_key, this.options.access_token_secret, 'POST'); + var headers = { + 'Authorization': authorization, + 'Content-Type': 'multipart/form-data;boundary=' + boundary, + 'Host': hostname, + 'Content-Length': multipartBody.length/*, + 'Connection': 'Keep-Alive'*/ + }; + var options = { + host: hostname, + port: 443, + path: '/1.1/statuses/update_with_media.json', + method: 'POST', + headers: headers + }; + + var req = https.request(options, function (res) { + res.setEncoding('utf8'); + res.on('data', function (chunk) { + try { + var json = JSON.parse(chunk); + } + catch(err) { + return callback(err); + } + callback(null, json); + }); + res.on('end', function () { + }); + }); + req.write(multipartBody); + req.end(); + + req.on('error', function(error) { + if ( error && error.statusCode ) { + var err = new Error('HTTP Error ' + + error.statusCode + ': ' + + http.STATUS_CODES[error.statusCode] + + ', API message: ' + error.data); + err.data = error.data; + err.statusCode = error.statusCode; + callback(err); + } else if (error) { + callback(error); + } + }); + + return this; +} + Twitter.prototype.destroyStatus = function(id, callback) { var url = '/statuses/destroy/' + escape(id) + '.json'; this.post(url, null, null, callback);