-
-
Save viezel/5781083 to your computer and use it in GitHub Desktop.
// This is an example of use. | |
// Here we use the new Bearer Token thats make it possible to get tweets without user login | |
// More info on Bearer here: https://dev.twitter.com/docs/auth/application-only-auth | |
// Full Codebird API is here: https://github.com/mynetx/codebird-js | |
var Codebird = require("codebird"); | |
var cb = new Codebird(); | |
cb.setConsumerKey('CONSUMER_KEY', 'CONSUMER_SECRET_KEY'); | |
var bearerToken = Ti.App.Properties.getString('TwitterBearerToken', null); | |
if(bearerToken == null){ | |
cb.__call( | |
'oauth2_token', | |
{}, | |
function (reply) { | |
var bearer_token = reply.access_token; | |
cb.setBearerToken(bearer_token); | |
Ti.App.Properties.setString('TwitterBearerToken', bearer_token); | |
fetchTwitter(); | |
} | |
); | |
} else { | |
Ti.API.info("We do have a bearer token..."); | |
cb.setBearerToken(bearerToken); | |
fetchTwitter(); | |
} | |
function fetchTwitter(){ | |
cb.__call( | |
'search_tweets', | |
"q="+Ti.Network.encodeURIComponent("#awesome"), | |
function (reply) { | |
// ... | |
Ti.API.info(reply); | |
}, | |
true // this parameter required | |
); | |
} |
/** | |
* A Twitter library in JavaScript | |
* https://github.com/mynetx/codebird-js | |
* | |
* @package codebird | |
* @version 2.4.0-dev | |
* @author J.M. <[email protected]> | |
* @copyright 2010-2013 J.M. <[email protected]> | |
* | |
* This program is free software: you can redistribute it and/or modify | |
* it under the terms of the GNU General Public License as published by | |
* the Free Software Foundation, either version 3 of the License, or | |
* (at your option) any later version. | |
* | |
* This program is distributed in the hope that it will be useful, | |
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
* GNU General Public License for more details. | |
* | |
* You should have received a copy of the GNU General Public License | |
* along with this program. If not, see <http://www.gnu.org/licenses/>. | |
*/ | |
/** | |
* Array.indexOf polyfill | |
*/ | |
if (! Array.indexOf) { | |
Array.prototype.indexOf = function (obj, start) { | |
for (var i = (start || 0); i < this.length; i++) { | |
if (this[i] == obj) { | |
return i; | |
} | |
} | |
return -1; | |
}; | |
} | |
/* | |
* A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined | |
* in FIPS PUB 180-1 | |
* Version 2.1 Copyright Paul Johnston 2000 - 2002. | |
* Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet | |
* Distributed under the BSD License | |
* See http://pajhome.org.uk/crypt/md5 for details. | |
*/ | |
var hexcase = 0; | |
var b64pad = ""; | |
var chrsz = 8; | |
function hex_sha1(s) { | |
return binb2hex(core_sha1(str2binb(s), s.length * chrsz)); | |
} | |
function b64_sha1(s) { | |
return binb2b64(core_sha1(str2binb(s), s.length * chrsz)); | |
} | |
function str_sha1(s) { | |
return binb2str(core_sha1(str2binb(s), s.length * chrsz)); | |
} | |
function hex_hmac_sha1(key, data) { | |
return binb2hex(core_hmac_sha1(key, data)); | |
} | |
function b64_hmac_sha1(key, data) { | |
return binb2b64(core_hmac_sha1(key, data)); | |
} | |
function str_hmac_sha1(key, data) { | |
return binb2str(core_hmac_sha1(key, data)); | |
} | |
function sha1_vm_test() { | |
return hex_sha1("abc") == "a9993e364706816aba3e25717850c26c9cd0d89d"; | |
} | |
function core_sha1(x, len) { | |
x[len >> 5] |= 0x80 << (24 - len % 32); | |
x[((len + 64 >> 9) << 4) + 15] = len; | |
var w = Array(80); | |
var a = 1732584193; | |
var b = -271733879; | |
var c = -1732584194; | |
var d = 271733878; | |
var e = -1009589776; | |
for (var i = 0; i < x.length; i += 16) { | |
var olda = a; | |
var oldb = b; | |
var oldc = c; | |
var oldd = d; | |
var olde = e; | |
for (var j = 0; j < 80; j++) { | |
if (j < 16) | |
w[j] = x[i + j]; | |
else | |
w[j] = rol(w[j - 3] ^ w[j - 8] ^ w[j - 14] ^ w[j - 16], 1); | |
var t = safe_add(safe_add(rol(a, 5), sha1_ft(j, b, c, d)), safe_add(safe_add(e, w[j]), sha1_kt(j))); | |
e = d; | |
d = c; | |
c = rol(b, 30); | |
b = a; | |
a = t; | |
} | |
a = safe_add(a, olda); | |
b = safe_add(b, oldb); | |
c = safe_add(c, oldc); | |
d = safe_add(d, oldd); | |
e = safe_add(e, olde); | |
} | |
return Array(a, b, c, d, e); | |
} | |
function sha1_ft(t, b, c, d) { | |
if (t < 20) | |
return (b & c) | ((~b) & d); | |
if (t < 40) | |
return b ^ c ^ d; | |
if (t < 60) | |
return (b & c) | (b & d) | (c & d); | |
return b ^ c ^ d; | |
} | |
function sha1_kt(t) { | |
return (t < 20) ? 1518500249 : (t < 40) ? 1859775393 : (t < 60) ? -1894007588 : -899497514; | |
} | |
function core_hmac_sha1(key, data) { | |
var bkey = str2binb(key); | |
if (bkey.length > 16) | |
bkey = core_sha1(bkey, key.length * chrsz); | |
var ipad = Array(16), opad = Array(16); | |
for (var i = 0; i < 16; i++) { | |
ipad[i] = bkey[i] ^ 0x36363636; | |
opad[i] = bkey[i] ^ 0x5C5C5C5C; | |
} | |
var hash = core_sha1(ipad.concat(str2binb(data)), 512 + data.length * chrsz); | |
return core_sha1(opad.concat(hash), 512 + 160); | |
} | |
function safe_add(x, y) { | |
var lsw = (x & 0xFFFF) + (y & 0xFFFF); | |
var msw = (x >> 16) + (y >> 16) + (lsw >> 16); | |
return (msw << 16) | (lsw & 0xFFFF); | |
} | |
function rol(num, cnt) { | |
return (num << cnt) | (num >>> (32 - cnt)); | |
} | |
function str2binb(str) { | |
var bin = Array(); | |
var mask = (1 << chrsz) - 1; | |
for (var i = 0; i < str.length * chrsz; i += chrsz) | |
bin[i >> 5] |= (str.charCodeAt(i / chrsz) & mask) << (24 - i % 32); | |
return bin; | |
} | |
function binb2str(bin) { | |
var str = ""; | |
var mask = (1 << chrsz) - 1; | |
for (var i = 0; i < bin.length * 32; i += chrsz) | |
str += String.fromCharCode((bin[i >> 5] >>> (24 - i % 32)) & mask); | |
return str; | |
} | |
function binb2hex(binarray) { | |
var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef"; | |
var str = ""; | |
for (var i = 0; i < binarray.length * 4; i++) { | |
str += hex_tab.charAt((binarray[i >> 2] >> ((3 - i % 4) * 8 + 4)) & 0xF) + hex_tab.charAt((binarray[i >> 2] >> ((3 - i % 4) * 8 )) & 0xF); | |
} | |
return str; | |
} | |
function binb2b64(binarray) { | |
var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; | |
var str = ""; | |
for (var i = 0; i < binarray.length * 4; i += 3) { | |
var triplet = (((binarray[i >> 2] >> 8 * (3 - i % 4)) & 0xFF) << 16) | (((binarray[i + 1 >> 2] >> 8 * (3 - (i + 1) % 4)) & 0xFF) << 8 ) | ((binarray[i + 2 >> 2] >> 8 * (3 - (i + 2) % 4)) & 0xFF); | |
for (var j = 0; j < 4; j++) { | |
if (i * 8 + j * 6 > binarray.length * 32) | |
str += b64pad; | |
else | |
str += tab.charAt((triplet >> 6 * (3 - j)) & 0x3F); | |
} | |
} | |
return str; | |
} | |
/** | |
* A Twitter library in JavaScript | |
* | |
* @package codebird | |
* @subpackage codebird-js | |
*/ | |
var Codebird = function () { | |
/** | |
* The OAuth consumer key of your registered app | |
*/ | |
var _oauth_consumer_key = null; | |
/** | |
* The corresponding consumer secret | |
*/ | |
var _oauth_consumer_secret = null; | |
/** | |
* The app-only bearer token. Used to authorize app-only requests | |
*/ | |
var _oauth_bearer_token = null; | |
/** | |
* The API endpoint base to use | |
*/ | |
var _endpoint_base = 'https://api.twitter.com/'; | |
/** | |
* The API endpoint to use | |
*/ | |
var _endpoint = _endpoint_base + '1.1/'; | |
/** | |
* The API endpoint to use for OAuth requests | |
*/ | |
var _endpoint_oauth = _endpoint_base; | |
/** | |
* API proxy endpoint | |
*/ | |
var _endpoint_proxy = 'https://api.jublo.net/codebird/'; | |
/** | |
* Use JSONP for GET requests in IE7-9 | |
*/ | |
var _use_jsonp = false; | |
/** | |
* Whether to access the API via a proxy that is allowed by CORS | |
*/ | |
var _use_proxy = false; | |
/** | |
* The Request or access token. Used to sign requests | |
*/ | |
var _oauth_token = null; | |
/** | |
* The corresponding request or access token secret | |
*/ | |
var _oauth_token_secret = null; | |
/** | |
* The current Codebird version | |
*/ | |
var _version = '2.4.0-dev'; | |
/** | |
* Sets the OAuth consumer key and secret (App key) | |
* | |
* @param string key OAuth consumer key | |
* @param string secret OAuth consumer secret | |
* | |
* @return void | |
*/ | |
var setConsumerKey = function (key, secret) { | |
_oauth_consumer_key = key; | |
_oauth_consumer_secret = secret; | |
}; | |
/** | |
* Sets the OAuth2 app-only auth bearer token | |
* | |
* @param string token OAuth2 bearer token | |
* | |
* @return void | |
*/ | |
var setBearerToken = function (token) { | |
_oauth_bearer_token = token; | |
}; | |
/** | |
* Gets the current Codebird version | |
* | |
* @return string The version number | |
*/ | |
var getVersion = function () { | |
return _version; | |
}; | |
/** | |
* Sets the OAuth request or access token and secret (User key) | |
* | |
* @param string token OAuth request or access token | |
* @param string secret OAuth request or access token secret | |
* | |
* @return void | |
*/ | |
var setToken = function (token, secret) { | |
_oauth_token = token; | |
_oauth_token_secret = secret; | |
}; | |
/** | |
* Enables or disables CORS proxy | |
* | |
* @param bool use_proxy Whether to use CORS proxy or not | |
* | |
* @return void | |
*/ | |
var setUseProxy = function (use_proxy) { | |
_use_proxy = !! use_proxy; | |
}; | |
/** | |
* Parse URL-style parameters into object | |
* | |
* @param string str String to parse | |
* @param array array to load data into | |
* | |
* @return object | |
*/ | |
function parse_str(str, array) { | |
// Parses GET/POST/COOKIE data and sets global variables | |
// | |
// version: 1109.2015 | |
// discuss at: http://phpjs.org/functions/parse_str // + original by: Cagri Ekin | |
// + improved by: Michael White (http://getsprink.com) | |
// + tweaked by: Jack | |
// + bugfixed by: Onno Marsman | |
// + reimplemented by: stag019 // + bugfixed by: Brett Zamir (http://brett-zamir.me) | |
// + bugfixed by: stag019 | |
// - depends on: urldecode | |
// + input by: Dreamer | |
// + bugfixed by: Brett Zamir (http://brett-zamir.me) // % note 1: When no argument is specified, will put variables in global scope. | |
// * example 1: var arr = {}; | |
// * example 1: parse_str('first=foo&second=bar', arr); | |
// * results 1: arr == { first: 'foo', second: 'bar' } | |
// * example 2: var arr = {}; // * example 2: parse_str('str_a=Jack+and+Jill+didn%27t+see+the+well.', arr); | |
// * results 2: arr == { str_a: "Jack and Jill didn't see the well." } | |
var glue1 = '=', | |
glue2 = '&', | |
array2 = String(str).replace(/^&?([\s\S]*?)&?$/, '$1').split(glue2), | |
i, j, chr, tmp, key, value, bracket, keys, evalStr, that = this, | |
fixStr = function (str) { | |
return unescape(str).replace(/([\\"'])/g, '\\$1').replace(/\n/g, '\\n').replace(/\r/g, '\\r'); | |
}; | |
if (!array) { | |
array = this.window; | |
} | |
for (i = 0; i < array2.length; i++) { | |
tmp = array2[i].split(glue1); | |
if (tmp.length < 2) { | |
tmp = [tmp, '']; | |
} | |
key = fixStr(tmp[0]); | |
value = fixStr(tmp[1]); | |
while (key.charAt(0) === ' ') { | |
key = key.substr(1); | |
} | |
if (key.indexOf('\0') !== -1) { | |
key = key.substr(0, key.indexOf('\0')); | |
} | |
if (key && key.charAt(0) !== '[') { | |
keys = []; | |
bracket = 0; | |
for (j = 0; j < key.length; j++) { | |
if (key.charAt(j) === '[' && !bracket) { | |
bracket = j + 1; | |
} else if (key.charAt(j) === ']') { | |
if (bracket) { | |
if (!keys.length) { | |
keys.push(key.substr(0, bracket - 1)); | |
} | |
keys.push(key.substr(bracket, j - bracket)); | |
bracket = 0; | |
if (key.charAt(j + 1) !== '[') { | |
break; | |
} | |
} | |
} | |
} | |
if (!keys.length) { | |
keys = [key]; | |
} | |
for (j = 0; j < keys[0].length; j++) { | |
chr = keys[0].charAt(j); | |
if (chr === ' ' || chr === '.' || chr === '[') { | |
keys[0] = keys[0].substr(0, j) + '_' + keys[0].substr(j + 1); | |
} | |
if (chr === '[') { | |
break; | |
} | |
} | |
evalStr = 'array'; | |
for (j = 0; j < keys.length; j++) { | |
key = keys[j]; | |
if ((key !== '' && key !== ' ') || j === 0) { | |
key = "'" + key + "'"; | |
} else { | |
key = eval(evalStr + '.push([]);') - 1; | |
} | |
evalStr += '[' + key + ']'; | |
if (j !== keys.length - 1 && eval('typeof ' + evalStr) === 'undefined') { | |
eval(evalStr + ' = [];'); | |
} | |
} | |
evalStr += " = '" + value + "';\n"; | |
eval(evalStr); | |
} | |
} | |
} | |
/** | |
* Main API handler working on any requests you issue | |
* | |
* @param string fn The member function you called | |
* @param array params The parameters you sent along | |
* @param function callback The callback to call with the reply | |
* @param bool app_only_auth Whether to use app-only auth | |
* | |
* @return mixed The API reply encoded in the set return_format | |
*/ | |
var __call = function (fn, params, callback, app_only_auth) { | |
if (typeof params == 'undefined') { | |
var params = {}; | |
} | |
if (typeof app_only_auth == 'undefined') { | |
var app_only_auth = false; | |
} | |
if (typeof callback != 'function' && typeof params == 'function') { | |
callback = params; | |
params = {}; | |
if (typeof callback == 'bool') { | |
app_only_auth = callback; | |
} | |
} else if (typeof callback == 'undefined') { | |
var callback = function (reply) {}; | |
} | |
switch (fn) { | |
case "oauth_authenticate": | |
case "oauth_authorize": | |
return this[fn](params, callback); | |
break; | |
case "oauth2_token": | |
return this[fn](callback); | |
} | |
// parse parameters | |
var apiparams = {}; | |
if (typeof params == 'object') { | |
apiparams = params; | |
} else { | |
parse_str(params, apiparams); //TODO | |
} | |
// map function name to API method | |
var method = ''; | |
// replace _ by / | |
var path = fn.split('_'); | |
for (var i = 0; i < path.length; i++) { | |
if (i > 0) { | |
method += '/'; | |
} | |
method += path[i]; | |
} | |
// undo replacement for URL parameters | |
var url_parameters_with_underscore = ['screen_name']; | |
for (i = 0; i < url_parameters_with_underscore.length; i++) { | |
var param = url_parameters_with_underscore[i].toUpperCase(); | |
var replacement_was = param.split('_').join('/'); | |
method = method.split(replacement_was).join(param); | |
} | |
// replace AA by URL parameters | |
var method_template = method; | |
var match = []; | |
if (match = method.match(/[A-Z_]{2,}/)) { | |
for (var i = 0; i < match.length; i++) { | |
var param = match[i]; | |
var param_l = param.toLowerCase(); | |
method_template = method_template.split(param).join(':' + param_l); | |
if (typeof apiparams[param_l] == 'undefined') { | |
for (j = 0; j < 26; j++) { | |
method_template = method_template.split(String.fromCharCode(65 + j)).join('_' + String.fromCharCode(97 + j)); | |
} | |
console.warn('To call the templated method "' + method_template + '", specify the parameter value for "' + param_l + '".'); | |
} | |
method = method.split(param).join(apiparams[param_l]); | |
delete apiparams[param_l]; | |
} | |
} | |
// replace A-Z by _a-z | |
for (i = 0; i < 26; i++) { | |
method = method.split(String.fromCharCode(65 + i)).join('_' + String.fromCharCode(97 + i)); | |
method_template = method_template.split(String.fromCharCode(65 + i)).join('_' + String.fromCharCode(97 + i)); | |
} | |
var httpmethod = _detectMethod(method_template, apiparams); | |
var multipart = _detectMultipart(method_template); | |
return _callApi( | |
httpmethod, | |
method, | |
method_template, | |
apiparams, | |
multipart, | |
app_only_auth, | |
callback | |
); | |
}; | |
/** | |
* Gets the OAuth authenticate URL for the current request token | |
* | |
* @return string The OAuth authenticate URL | |
*/ | |
var oauth_authenticate = function (params, callback) { | |
if (typeof params.force_login == "undefined") { | |
params.force_login = null; | |
} | |
if (typeof params.screen_name == "undefined") { | |
params.screen_name = null; | |
} | |
if (_oauth_token == null) { | |
console.warn('To get the authenticate URL, the OAuth token must be set.'); | |
} | |
var url = _endpoint_oauth + 'oauth/authenticate?oauth_token=' + _url(_oauth_token); | |
if (params.force_login === true) { | |
url += "?force_login=1"; | |
if (params.screen_name !== null) { | |
url += "&screen_name=" + params.screen_name; | |
} | |
} | |
callback(url); | |
return true; | |
}; | |
/** | |
* Gets the OAuth authorize URL for the current request token | |
* | |
* @return string The OAuth authorize URL | |
*/ | |
var oauth_authorize = function (params, callback) { | |
if (typeof params.force_login == "undefined") { | |
params.force_login = null; | |
} | |
if (typeof params.screen_name == "undefined") { | |
params.screen_name = null; | |
} | |
if (_oauth_token == null) { | |
console.warn('To get the authorize URL, the OAuth token must be set.'); | |
} | |
var url = _endpoint_oauth + 'oauth/authorize?oauth_token=' + _url(_oauth_token); | |
if (params.force_login === true) { | |
url += "?force_login=1"; | |
if (params.screen_name !== null) { | |
url += "&screen_name=" + params.screen_name; | |
} | |
} | |
callback(url); | |
return true; | |
}; | |
/** | |
* Gets the OAuth bearer token | |
* | |
* @return string The OAuth bearer token | |
*/ | |
var oauth2_token = function (callback) { | |
if (_oauth_consumer_key == null) { | |
console.warn('To obtain a bearer token, the consumer key must be set.'); | |
} | |
if (typeof callback == "undefined") { | |
var callback = function (reply) {}; | |
} | |
var post_fields = "grant_type=client_credentials"; | |
var url = _endpoint_oauth + "oauth2/token"; | |
if (_use_proxy) { | |
url = url.replace( | |
_endpoint_base, | |
_endpoint_proxy | |
); | |
} | |
var xml; | |
xml = Ti.Network.createHTTPClient(); | |
xml.open("POST", url, true); | |
xml.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); | |
xml.setRequestHeader( | |
(_use_proxy ? "X-" : "") + "Authorization", | |
"Basic " + base64_encode(_oauth_consumer_key + ":" + _oauth_consumer_secret) | |
); | |
xml.onreadystatechange = function () { | |
if (xml.readyState >= 4) { | |
var httpstatus = 12027; | |
try { | |
httpstatus = xml.status; | |
} catch (e) {} | |
var reply = _parseApiReply("oauth2/token", xml.responseText); | |
reply.httpstatus = httpstatus; | |
if (httpstatus == 200) { | |
setBearerToken(reply.access_token); | |
} | |
callback(reply); | |
} | |
}; | |
xml.send(post_fields); | |
}; | |
/** | |
* Signing helpers | |
*/ | |
/** | |
* URL-encodes the given data | |
* | |
* @param mixed data | |
* | |
* @return mixed The encoded data | |
*/ | |
var _url = function (data) { | |
if (typeof data == 'array') { | |
return array_map([ // TODO | |
this, '_url'], data); | |
} else if ((/boolean|number|string/).test(typeof data)) { | |
return encodeURIComponent(data).replace(/!/g, '%21').replace(/'/g, '%27').replace(/\(/g, '%28').replace(/\)/g, '%29').replace(/\*/g, '%2A'); | |
} else { | |
return ''; | |
} | |
} | |
/** | |
* Gets the base64-encoded SHA1 hash for the given data | |
* | |
* @param string data The data to calculate the hash from | |
* | |
* @return string The hash | |
*/ | |
var _sha1 = function (data) { | |
if (_oauth_consumer_secret == null) { | |
console.warn('To generate a hash, the consumer secret must be set.'); | |
} | |
if (typeof b64_hmac_sha1 != 'function') { | |
console.warn('To generate a hash, the Javascript SHA1.js must be available.'); | |
} | |
b64pad = '='; | |
return b64_hmac_sha1(_oauth_consumer_secret + '&' + (_oauth_token_secret != null ? _oauth_token_secret : ''), data); | |
}; | |
var base64_encode = function (data) { | |
// http://kevin.vanzonneveld.net | |
// + original by: Tyler Akins (http://rumkin.com) | |
// + improved by: Bayron Guevara | |
// + improved by: Thunder.m | |
// + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) | |
// + bugfixed by: Pellentesque Malesuada | |
// + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) | |
// + improved by: Rafał Kukawski (http://kukawski.pl) | |
// * example 1: base64_encode('Kevin van Zonneveld'); | |
// * returns 1: 'S2V2aW4gdmFuIFpvbm5ldmVsZA==' | |
// mozilla has this native | |
// - but breaks in 2.0.0.12! | |
//if (typeof this.window['btoa'] == 'function') { | |
// return btoa(data); | |
//} | |
var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; | |
var o1, o2, o3, h1, h2, h3, h4, bits, i = 0, | |
ac = 0, | |
enc = "", | |
tmp_arr = []; | |
if (! data) { | |
return data; | |
} | |
do { // pack three octets into four hexets | |
o1 = data.charCodeAt(i++); | |
o2 = data.charCodeAt(i++); | |
o3 = data.charCodeAt(i++); | |
bits = o1 << 16 | o2 << 8 | o3; | |
h1 = bits >> 18 & 0x3f; | |
h2 = bits >> 12 & 0x3f; | |
h3 = bits >> 6 & 0x3f; | |
h4 = bits & 0x3f; | |
// use hexets to index into b64, and append result to encoded string | |
tmp_arr[ac++] = b64.charAt(h1) + b64.charAt(h2) + b64.charAt(h3) + b64.charAt(h4); | |
} while (i < data.length); | |
enc = tmp_arr.join(''); | |
var r = data.length % 3; | |
return (r ? enc.slice(0, r - 3) : enc) + '==='.slice(r || 3); | |
}; | |
var http_build_query = function (formdata, numeric_prefix, arg_separator) { | |
// http://kevin.vanzonneveld.net | |
// + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) | |
// + improved by: Legaev Andrey | |
// + improved by: Michael White (http://getsprink.com) | |
// + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) | |
// + improved by: Brett Zamir (http://brett-zamir.me) | |
// + revised by: stag019 | |
// + input by: Dreamer | |
// + bugfixed by: Brett Zamir (http://brett-zamir.me) | |
// + bugfixed by: MIO_KODUKI (http://mio-koduki.blogspot.com/) | |
// % note 1: If the value is null, key and value is skipped in http_build_query of PHP. But, phpjs is not. | |
var value, key, tmp = [], | |
that = http_build_query; | |
var _http_build_query_helper = function (key, val, arg_separator) { | |
var k, tmp = []; | |
if (val === true) { | |
val = "1"; | |
} else if (val === false) { | |
val = "0"; | |
} | |
if (val != null) { | |
if(typeof(val) === "object") { | |
for (k in val) { | |
if (val[k] != null) { | |
tmp.push(_http_build_query_helper(key + "[" + k + "]", val[k], arg_separator)); | |
} | |
} | |
return tmp.join(arg_separator); | |
} else if (typeof(val) !== "function") { | |
return _url(key) + "=" + _url(val); | |
} else { | |
throw new Error('There was an error processing for http_build_query().'); | |
} | |
} else { | |
return ''; | |
} | |
}; | |
if (!arg_separator) { | |
arg_separator = "&"; | |
} | |
for (key in formdata) { | |
value = formdata[key]; | |
if (numeric_prefix && !isNaN(key)) { | |
key = String(numeric_prefix) + key; | |
} | |
var query=_http_build_query_helper(key, value, arg_separator); | |
if(query != '') { | |
tmp.push(query); | |
} | |
} | |
return tmp.join(arg_separator); | |
}; | |
/** | |
* Generates a (hopefully) unique random string | |
* | |
* @param int optional length The length of the string to generate | |
* | |
* @return string The random string | |
*/ | |
var _nonce = function (length) { | |
if (typeof length == 'undefined') { | |
var length = 8; | |
} | |
if (length < 1) { | |
console.warn('Invalid nonce length.'); | |
} | |
var nonce = ''; | |
for (var i = 0; i < length; i++) { | |
var character = Math.floor(Math.random() * 61); | |
nonce += '0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz'.substring(character, character + 1); | |
} | |
return nonce; | |
}; | |
var _ksort = function (inputArr) { | |
// http://kevin.vanzonneveld.net | |
// + original by: GeekFG (http://geekfg.blogspot.com) | |
// + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) | |
// + improved by: Brett Zamir (http://brett-zamir.me) | |
var tmp_arr = {}, | |
keys = [], | |
sorter, i, k, that = this, | |
strictForIn = false, | |
populateArr = {}; | |
sorter = function (a, b) { | |
var aFloat = parseFloat(a), | |
bFloat = parseFloat(b), | |
aNumeric = aFloat + '' === a, | |
bNumeric = bFloat + '' === b; | |
if (aNumeric && bNumeric) { | |
return aFloat > bFloat ? 1 : aFloat < bFloat ? -1 : 0; | |
} else if (aNumeric && !bNumeric) { | |
return 1; | |
} else if (!aNumeric && bNumeric) { | |
return -1; | |
} | |
return a > b ? 1 : a < b ? -1 : 0; | |
}; | |
// Make a list of key names | |
for (k in inputArr) { | |
if (inputArr.hasOwnProperty(k)) { | |
keys.push(k); | |
} | |
} | |
keys.sort(sorter); | |
return keys; | |
}; | |
/** | |
* Clone objects | |
* | |
* @param object obj The object to clone | |
* | |
* @return object clone The cloned object | |
*/ | |
var _clone = function (obj) { | |
var clone = {}; | |
for (var i in obj) { | |
if (typeof(obj[i]) == "object") { | |
clone[i] = clone(obj[i]); | |
} else { | |
clone[i] = obj[i]; | |
} | |
} | |
return clone; | |
}; | |
/** | |
* Generates an OAuth signature | |
* | |
* @param string httpmethod Usually either 'GET' or 'POST' or 'DELETE' | |
* @param string method The API method to call | |
* @param array optional params The API call parameters, associative | |
* @param bool optional append_to_get Whether to append the OAuth params to GET | |
* | |
* @return string Authorization HTTP header | |
*/ | |
var _sign = function (httpmethod, method, params, append_to_get) { | |
if (typeof params == 'undefined') { | |
var params = {}; | |
} | |
if (typeof append_to_get == "undefined") { | |
var append_to_get = false; | |
} | |
if (_oauth_consumer_key == null) { | |
console.warn('To generate a signature, the consumer key must be set.'); | |
} | |
var sign_params = { | |
consumer_key: _oauth_consumer_key, | |
version: '1.0', | |
timestamp: Math.round(new Date().getTime() / 1000), | |
nonce: _nonce(), | |
signature_method: 'HMAC-SHA1' | |
}; | |
var sign_base_params = {}; | |
for (var key in sign_params) { | |
var value = sign_params[key]; | |
sign_base_params['oauth_' + key] = _url(value); | |
} | |
if (_oauth_token != null) { | |
sign_base_params['oauth_token'] = _url(_oauth_token); | |
} | |
oauth_params = _clone(sign_base_params); | |
for (var key in params) { | |
var value = params[key]; | |
sign_base_params[key] = _url(value); | |
} | |
var keys = _ksort(sign_base_params); | |
var sign_base_string = ''; | |
for (var i=0;i<keys.length;i++) { | |
var key = keys[i]; | |
var value = sign_base_params[key]; | |
sign_base_string += key + '=' + value + '&'; | |
} | |
sign_base_string = sign_base_string.substring(0, sign_base_string.length - 1); | |
var signature = _sha1(httpmethod + '&' + _url(method) + '&' + _url(sign_base_string)); | |
params = append_to_get ? sign_base_params : oauth_params; | |
params['oauth_signature'] = signature; | |
if (append_to_get) { | |
var authorization = ''; | |
for(var key in params) { | |
var value = params[key]; | |
authorization += key + "=" + _url(value) + "&"; | |
} | |
return authorization.substring(0, authorization.length - 1); | |
} | |
var authorization = 'OAuth '; | |
for (var key in params) { | |
var value = params[key]; | |
authorization += key + '="' + _url(value) + '", '; | |
} | |
return authorization.substring(0, authorization.length - 2); | |
}; | |
/** | |
* Detects HTTP method to use for API call | |
* | |
* @param string method The API method to call | |
* @param array params The parameters to send along | |
* | |
* @return string The HTTP method that should be used | |
*/ | |
var _detectMethod = function (method, params) { | |
// multi-HTTP method endpoints | |
switch(method) { | |
case 'account/settings': | |
method = params.length ? method + '__post' : method; | |
break; | |
} | |
var httpmethods = {}; | |
httpmethods['GET'] = [ | |
// Timelines | |
'statuses/mentions_timeline', | |
'statuses/user_timeline', | |
'statuses/home_timeline', | |
'statuses/retweets_of_me', | |
// Tweets | |
'statuses/retweets/:id', | |
'statuses/show/:id', | |
'statuses/oembed', | |
// Search | |
'search/tweets', | |
// Direct Messages | |
'direct_messages', | |
'direct_messages/sent', | |
'direct_messages/show', | |
// Friends & Followers | |
'friendships/no_retweets/ids', | |
'friends/ids', | |
'followers/ids', | |
'friendships/lookup', | |
'friendships/incoming', | |
'friendships/outgoing', | |
'friendships/show', | |
'friends/list', | |
'followers/list', | |
// Users | |
'account/settings', | |
'account/verify_credentials', | |
'blocks/list', | |
'blocks/ids', | |
'users/lookup', | |
'users/show', | |
'users/search', | |
'users/contributees', | |
'users/contributors', | |
'users/profile_banner', | |
// Suggested Users | |
'users/suggestions/:slug', | |
'users/suggestions', | |
'users/suggestions/:slug/members', | |
// Favorites | |
'favorites/list', | |
// Lists | |
'lists/list', | |
'lists/statuses', | |
'lists/memberships', | |
'lists/subscribers', | |
'lists/subscribers/show', | |
'lists/members/show', | |
'lists/members', | |
'lists/show', | |
'lists/subscriptions', | |
// Saved searches | |
'saved_searches/list', | |
'saved_searches/show/:id', | |
// Places & Geo | |
'geo/id/:place_id', | |
'geo/reverse_geocode', | |
'geo/search', | |
'geo/similar_places', | |
// Trends | |
'trends/place', | |
'trends/available', | |
'trends/closest', | |
// OAuth | |
'oauth/authenticate', | |
'oauth/authorize', | |
// Help | |
'help/configuration', | |
'help/languages', | |
'help/privacy', | |
'help/tos', | |
'application/rate_limit_status' | |
]; | |
httpmethods['POST'] = [ | |
// Tweets | |
'statuses/destroy/:id', | |
'statuses/update', | |
'statuses/retweet/:id', | |
'statuses/update_with_media', | |
// Direct Messages | |
'direct_messages/destroy', | |
'direct_messages/new', | |
// Friends & Followers | |
'friendships/create', | |
'friendships/destroy', | |
'friendships/update', | |
// Users | |
'account/settings__post', | |
'account/update_delivery_device', | |
'account/update_profile', | |
'account/update_profile_background_image', | |
'account/update_profile_colors', | |
'account/update_profile_image', | |
'blocks/create', | |
'blocks/destroy', | |
'account/update_profile_banner', | |
'account/remove_profile_banner', | |
// Favorites | |
'favorites/destroy', | |
'favorites/create', | |
// Lists | |
'lists/members/destroy', | |
'lists/subscribers/create', | |
'lists/subscribers/destroy', | |
'lists/members/create_all', | |
'lists/members/create', | |
'lists/destroy', | |
'lists/update', | |
'lists/create', | |
'lists/members/destroy_all', | |
// Saved Searches | |
'saved_searches/create', | |
'saved_searches/destroy/:id', | |
// Places & Geo | |
'geo/place', | |
// Spam Reporting | |
'users/report_spam', | |
// OAuth | |
'oauth/access_token', | |
'oauth/request_token', | |
'oauth2/token', | |
'oauth2/invalidate_token' | |
]; | |
for (var httpmethod in httpmethods) { | |
if (httpmethods[httpmethod].indexOf(method) > -1) { | |
return httpmethod; | |
} | |
} | |
console.warn('Can\'t find HTTP method to use for "' + method + '".'); | |
}; | |
/** | |
* Detects if API call should use multipart/form-data | |
* | |
* @param string method The API method to call | |
* | |
* @return bool Whether the method should be sent as multipart | |
*/ | |
var _detectMultipart = function (method) { | |
var multiparts = [ | |
// Tweets | |
'statuses/update_with_media', | |
// Users | |
'account/update_profile_background_image', | |
'account/update_profile_image', | |
'account/update_profile_banner' | |
]; | |
return multiparts.indexOf(method) > -1; | |
}; | |
/** | |
* Builds the complete API endpoint url | |
* | |
* @param string method The API method to call | |
* @param string method_template The API method template to call | |
* | |
* @return string The URL to send the request to | |
*/ | |
var _getEndpoint = function (method, method_template) { | |
if (method.substring(0, 5) == 'oauth') { | |
var url = _endpoint_oauth + method; | |
} else { | |
var url = _endpoint + method + '.json'; | |
} | |
return url; | |
}; | |
/** | |
* Calls the API using cURL | |
* | |
* @param string httpmethod The HTTP method to use for making the request | |
* @param string method The API method to call | |
* @param string method_template The templated API method to call | |
* @param array optional params The parameters to send along | |
* @param bool optional multipart Whether to use multipart/form-data | |
* @param bool optional $app_only_auth Whether to use app-only bearer authentication | |
* @param function callback The function to call with the API call result | |
* | |
* @return mixed The API reply, encoded in the set return_format | |
*/ | |
var _callApi = function (httpmethod, method, method_template, params, multipart, app_only_auth, callback) { | |
if (typeof params == 'undefined') { | |
var params = {}; | |
} | |
if (typeof multipart == 'undefined') { | |
var multipart = false; | |
} | |
if (typeof app_only_auth == 'undefined') { | |
var app_only_auth = false; | |
} | |
if (typeof callback != 'function') { | |
var callback = function (reply) {}; | |
} | |
var url = _getEndpoint(method, method_template); | |
var authorization = null; | |
var xml = Ti.Network.createHTTPClient(); | |
if (httpmethod == 'GET') { | |
var url_with_params = url; | |
if (JSON.stringify(params) != "{}") { | |
url_with_params += '?' + http_build_query(params); | |
} | |
authorization = _sign(httpmethod, url, params); | |
// append auth params to GET url for IE7-9, to send via JSONP | |
if (_use_jsonp) { | |
if (JSON.stringify(params) != "{}") { | |
url_with_params += '&'; | |
} else { | |
url_with_params += '?'; | |
} | |
var callback_name = _nonce(); | |
window[callback_name] = function (reply) { | |
reply.httpstatus = 200; | |
callback(reply); | |
}; | |
params.callback = callback_name; | |
url_with_params = url + "?" + _sign(httpmethod, url, params, true); | |
var tag = document.createElement("script"); | |
tag.type = "text/javascript"; | |
tag.src = url_with_params; | |
var body = document.getElementsByTagName("body")[0]; | |
body.appendChild(tag); | |
return; | |
} else if (_use_proxy) { | |
url_with_params = url_with_params.replace( | |
_endpoint_base, | |
_endpoint_proxy | |
); | |
} | |
xml.open(httpmethod, url_with_params, true); | |
} else { | |
if (_use_jsonp) { | |
console.warn('Sending POST requests is not supported for IE7-9.'); | |
return; | |
} | |
authorization = _sign(httpmethod, url, {}); | |
if (! multipart) { | |
authorization = _sign(httpmethod, url, params); | |
params = http_build_query(params); | |
} | |
post_fields = params; | |
if (_use_proxy) { | |
url = url.replace( | |
_endpoint_base, | |
_endpoint_proxy | |
); | |
} | |
xml.open(httpmethod, url, true); | |
if (multipart) { | |
xml.setRequestHeader("Content-Type", "multipart/form-data"); | |
} else { | |
xml.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); | |
} | |
} | |
if (app_only_auth) { | |
if (_oauth_consumer_key == null) { | |
console.warn('To make an app-only auth API request, the consumer key must be set.'); | |
} | |
// automatically fetch bearer token, if necessary | |
if (_oauth_bearer_token == null) { | |
return oauth2_token(function (reply) { | |
_callApi(httpmethod, method, method_template, params, multipart, app_only_auth, callback); | |
}); | |
} | |
authorization = 'Bearer ' + _oauth_bearer_token; | |
} | |
if (authorization !== null) { | |
xml.setRequestHeader((_use_proxy ? "X-" : "") + "Authorization", authorization); | |
} | |
xml.onreadystatechange = function () { | |
if (xml.readyState >= 4) { | |
var httpstatus = 12027; | |
try { | |
httpstatus = xml.status; | |
} catch (e) {} | |
if(!httpstatus){ | |
httpstatus = 12027; | |
} | |
var reply = _parseApiReply(method_template, xml.responseText); | |
if(!reply){ | |
callback(null); | |
} | |
reply.httpstatus = httpstatus; | |
callback(reply); | |
} | |
}; | |
xml.send(httpmethod == "GET" ? null : post_fields); | |
return true; | |
}; | |
/** | |
* Parses the API reply to encode it in the set return_format | |
* | |
* @param string method The method that has been called | |
* @param string reply The actual reply, JSON-encoded or URL-encoded | |
* | |
* @return array|object The parsed reply | |
*/ | |
var _parseApiReply = function (method, reply) { | |
if (reply == '[]' || reply == null) { | |
return []; | |
} | |
var parsed = false; | |
try { | |
parsed = JSON.parse(reply); | |
} catch (e) { | |
parsed = {}; | |
if (reply.indexOf('<' + '?xml version="1.0" encoding="UTF-8"?' + '>') === 0) { | |
// we received XML... | |
// since this only happens for errors, | |
// don't perform a full decoding | |
parsed["request"] = reply.match(/<request>(.*)<\/request>/)[1]; | |
parsed["error"] = reply.match(/<error>(.*)<\/error>/)[1]; | |
} else { | |
// assume query format | |
var elements = reply.split("&"); | |
for (var i = 0; i < elements.length; i++) { | |
var element = elements[i].split("=", 2); | |
if (element.length > 1) { | |
parsed[element[0]] = unescape(element[1]); | |
} else { | |
parsed[element[0]] = null; | |
} | |
} | |
} | |
} | |
return parsed; | |
}; | |
return { | |
setConsumerKey: setConsumerKey, | |
getVersion: getVersion, | |
setToken: setToken, | |
setBearerToken: setBearerToken, | |
setUseProxy: setUseProxy, | |
__call: __call, | |
oauth_authenticate: oauth_authenticate, | |
oauth_authorize: oauth_authorize, | |
oauth2_token: oauth2_token | |
}; | |
}; | |
module.exports = Codebird; |
@fit4him i managed to get the user timeline doing some editing to the codebird.js file.
in line 472 to 480 you got this:
var method = '';
// replace _ by /
var path = fn.split('_');
for (var i = 0; i < path.length; i++) {
if (i > 0) {
method += '/';
}
method += path[i];
}
here they replace _ by / which makes a wrong call to twitter's api, you need: statuses/user_timeline and you got statuses/user/timeline thats why you are getting that erro. so i changed it to this:
var method = '';
if (fn == 'statuses/user_timeline') {
method = fn;
}else{
// replace _ by /
var path = fn.split('_');
for (var i = 0; i < path.length; i++) {
if (i > 0) {
method += '/';
}
method += path[i];
}
}
so this is how i managed to get de users time line... i didnt read all the file so am not shure if there is a better way to do this. so good luck and i hope this help you.
@nivx2 Thanks very much for your helpful comment. The code below worked when the cb__call was
'statuses/user_timeline'
But when I changed it to
'statuses/mentions_timeline'
I received the following error:
Uncaught Error: undefined method not supported.
Source: xml.send(httpmethod == "GET"? null: post_fields);
The source is in the codebird.js file.
Have you or has anyone else experienced this issue?
function fetchTwitter(){
var data = [];
cb.__call(
'statuses/user_timeline',
"screen_name=ClassicHits4FM",
function (reply) {
// ...
Ti.API.info("newest and Example that should work just reply------------------------------"+ reply);
Ti.API.info("newest and Example that may work, reply's text ------------------------------"+ reply[0].text);
Ti.API.info("newest and Example that may work, reply's text ------------------------------"+ reply[0].user.profile_image_url);
)
Anyone have any luck using the search query params?
This is not returning what I'd expect (5 tweets using 'rpp') :
function getTweets() {
var params = {
q: 'test',
rpp: '5',
};
cb.__call(
'search_tweets',
params,
function (reply) { ... },
true
);
The query for 'test' works, but it returns more than 5 tweets.
Hi All,
I am trying to run a retweet with.
cb.__call('statuses_retweet', {
id : id
}, function(reply) {
Ti.API.info(reply);
});
But i keep getting this error message i can see the call in codebird.js
[WARN] : Can't find HTTP method to use for "statuses/retweet".
[WARN] : Assertion failed: (self.method != nil), function -[APSHTTPRequest send], file /Users/vduggal/ForkedRepos/APSHTTPClient/APSHTTPClient/APSHTTPRequest.m, line 66.
-- End simulator log ---------------------------------------------------------
Can anyone help with this please.
Thanks
Greeting All!
After login with my twitter credential, I saw 7 digits pin to complete authorization process. How can I solve it? Actually, goto authorizeUICallback function but it don't have any value from this line
var val = window.evalJS('window.document.querySelector('kbd[aria-labelledby="code-desc"] > code').innerHTML');
When val is null, never go to this code at below
setTweet();
accessToken = reply.oauth_token;
accessTokenSecret=reply.oauth_token_secret;
saveAccessToken('twitter');
Thanks
Would love to get codebird implemented. I get the following error when running code below: Any ideas?
Can't find HTTP method to use for "statuses/user/timeline".
[WARN] : 2013-07-10 11:18:53.085 LFCMobileAlloy[95028:21407] 95028: CFNetwork internal error (0xc01a:/SourceCache/CFNetwork_Sim/CFNetwork-609.1.4/HTTP/HTTPRequestParserClient.h:28)
[WARN] : 2013-07-10 11:18:53.087 LFCMobileAlloy[95028:21407] [WARN] Unable to securely connect to api.twitter.com with the latest TLS. Trying again with TLS1.0. It is highly suggested that the server be updated to the latest TLS support.
[WARN] : 2013-07-10 11:18:53.173 LFCMobileAlloy[95028:21407] 95028: CFNetwork internal error (0xc01a:/SourceCache/CFNetwork_Sim/CFNetwork-609.1.4/HTTP/HTTPRequestParserClient.h:28)
cb.__call(
'statuses/user_timeline',
"purplepastor",
function (tweets) {
);