Skip to content

Instantly share code, notes, and snippets.

@codepony
Created March 10, 2013 13:38
Show Gist options
  • Save codepony/5128602 to your computer and use it in GitHub Desktop.
Save codepony/5128602 to your computer and use it in GitHub Desktop.
Used to get hotot working with identica again (Be aware: twitter support will be fucked up after changing to that file) Also: `Retweets by me' shows the public timeline now. (Licensed under the LGPLv3 by lyricat - https://github.com/lyricat/ )
// vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79:
if (typeof(lib) == 'undefined') var lib = {};
if (typeof(lib.twitter) == 'undefined') lib.twitter = {};
function TwitterClient() {
var self = this;
self.use_oauth = false;
self.username = '';
self.password = '';
self.api_base = 'https://api.twitter.com/';
self.sign_api_base = 'https://api.twitter.com/';
self.search_api_base2 = 'https://twitter.com/phoenix_search.phoenix';
self.upload_api_base = 'https://upload.twitter.com/1/';
self.use_same_sign_api_base = true;
self.source = 'Hotot';
self.oauth = null;
self.network = null;
self.default_error_method = 'notify';
self.http_code_msg_table = {
0: 'Lost connection with server.',
400: 'Bad Request: The request was invalid.',
401: 'Server cannot authenticate you. Please check your username/password and API base.',
403: {
'update': 'Twitter does not allow to update duplicate status :(',
'retweet': 'You have already retweeted this tweet, or it is protected.',
'fav': 'You have already marked this tweet as favorite.',
'unknown': 'Twitter refuse your request.'
},
404: 'The URL you request does not exist. Please check your API Base/OAuth Base/Search Base.',
500: 'Server is broken. Please try again later.',
502: 'Server is down or being upgraded. Please try again later.',
503: 'Server is in overcapacity. Please try again later.'
};
self.default_error_handler = function default_error_handler(url, xhr, textStatus, errorThrown) {
var msg = '';
var tech_info = '';
if (xhr.status in self.http_code_msg_table) {
if (xhr.status != 403) {
msg = self.http_code_msg_table[xhr.status];
} else {
if (url.indexOf('favorites/create/') !== - 1) {
msg = self.http_code_msg_table[403]['fav'];
} else if (url.indexOf('statuses/retweet/') !== - 1) {
msg = self.http_code_msg_table[403]['retweet'];
} else if (url.indexOf('statuses/update.json') !== - 1) {
msg = self.http_code_msg_table[403]['update'];
} else {
msg = self.http_code_msg_table[403]['unknown'];
}
}
tech_info = 'HTTP Code:' + xhr.status + '\nDetails:' + xhr.statusText + '\nURL:' + url;
} else {
msg = 'Unknow Error';
tech_info = 'HTTP Code:' + xhr.status + '\nReason:' + xhr.statusText + '\nURL:' + url;
}
switch (self.default_error_method) {
case 'notify':
if (xhr.status !== 0) {
hotot_notify('Ooops, An Error Occurred!', msg + '\n' + tech_info, null, 'content');
} else {
toast.set('Lost Connection').show(1);
}
break;
case 'dialog':
ui.ErrorDlg.alert('Ooops, An Error Occurred!', msg, tech_info);
break;
case 'toast':
toast.set('Error #' + xhr.status + ': ' + msg).show();
break;
default:
break;
}
hotot_log('Error #' + xhr.status + ',' + xhr.statusText, msg + ' ' + url);
return;
};
self.success_handler = function success_handler(data, textStatus, xhr) {
self.ratelimit_limit = xhr.getResponseHeader('X-RateLimit-Limit');
self.ratelimit_remaning = xhr.getResponseHeader('X-RateLimit-Remaining');
self.ratelimit_reset = xhr.getResponseHeader('X-RateLimit-Reset');
if (self.ratelimit_limit == null) {
return;
}
var html = '<span>' + _('my_power') + ': {%REMANING%}/{%LIMIT%} - <span style="color:{%STATUS_COLOR%}">{%STATUS%}</span></span><br><span>' + _('reset_time') + ': {%RESET_TIME%}</span>';
html = html.replace('{%REMANING%}', self.ratelimit_remaning);
html = html.replace('{%LIMIT%}', self.ratelimit_limit);
var d = new Date();
d.setTime(self.ratelimit_reset * 1000);
html = html.replace('{%RESET_TIME%}', d.toLocaleTimeString());
var k = self.ratelimit_remaning / self.ratelimit_limit;
html = html.replace('{%STATUS%}', k < 0.25 ? _('nearly_dead') : k < 0.5 ? _('weakness') : k < 0.75 ? _('fine') : _('powerfull'));
html = html.replace('{%STATUS_COLOR%}', k < 0.25 ? '#f33': k < 0.5 ? 'yellow': k < 0.75 ? 'lightgreen': '#0f3');
globals.ratelimit_bubble.set_content(html);
};
self.basic_auth = function basic_auth() {
return 'Basic ' + encodeBase64(
self.username + ':' + self.password);
};
self.get = function get(ajax_url, ajax_params, on_success, on_error) {
self.do_ajax('GET', ajax_url, ajax_params, {
'X-PHX': 'true'
},
function(result, textStatus, xhr) {
self.success_handler(result, textStatus, xhr);
on_success(result, textStatus, xhr);
},
function(xhr, textStatus, errorThrown) {
if (on_error == undefined || on_error == null) {
self.default_error_handler(ajax_url, xhr, textStatus, errorThrown);
} else {
on_error(xhr, textStatus, errorThrown);
}
});
};
self.post = function post(ajax_url, ajax_params, on_success, on_error) {
self.do_ajax('POST', ajax_url, ajax_params, {},
function(result, textStatus, xhr) {
self.success_handler(result, textStatus, xhr);
on_success(result, textStatus, xhr);
},
function(xhr, textStatus, errorThrown) {
if (on_error == undefined || on_error == null) {
self.default_error_handler(ajax_url, xhr, textStatus, errorThrown);
} else {
on_error(xhr, textStatus, errorThrown);
}
});
};
self.do_ajax = function do_ajax(method, url, params, headers, on_success, on_error) {
params['source'] = self.source;
sign_url = self.use_same_sign_api_base ? url: url.replace(self.api_base_url(1), self.sign_api_base);
if (self.use_oauth) {
var signed_params = self.oauth.form_signed_params(
sign_url, self.oauth.access_token, method, params, self.network.py_request && method == 'POST');
if (method == 'GET') {
url = url + '?' + signed_params;
params = {};
} else {
params = signed_params
}
self.network.do_request(
method, url, params, headers, null, on_success, on_error);
} else {
if (method == 'GET') {
arr = []
for (var k in params) {
arr.push(encodeURIComponent(k) + '=' + encodeURIComponent(params[k]));
}
url = url + '?' + arr.join('&');
params = {};
}
headers['Authorization'] = self.basic_auth();
self.network.do_request(
method, url, params, headers, null, on_success, on_error);
}
};
self.update_status = function update_status(text, reply_to_id, on_success, on_error) {
var url = self.api_base + 'statuses/update.json';
var params = {
'status': text,
'include_entities': '1'
};
if (reply_to_id) {
params['in_reply_to_status_id'] = reply_to_id;
}
self.post(url, params, on_success, on_error);
};
self.update_with_media = function update_with_media(text, reply_to_id, file, file_data, on_success, on_error) {
var url = self.upload_api_base + 'statuses/update_with_media.json';
var signed_params = self.oauth.form_signed_params(
url, self.oauth.access_token, 'POST', {},
true);
var params = {
'status': text,
'include_entities': '1'
};
if (reply_to_id) {
params['in_reply_to_status_id'] = reply_to_id;
}
$.extend(params, signed_params);
var auth_str = 'OAuth oauth_consumer_key="' + signed_params.oauth_consumer_key + '"' + ', oauth_signature_method="' + signed_params.oauth_signature_method + '"' + ', oauth_token="' + signed_params.oauth_token + '"' + ', oauth_timestamp="' + signed_params.oauth_timestamp + '"' + ', oauth_nonce="' + signed_params.oauth_nonce + '"' + ', oauth_version="' + signed_params.oauth_version + '"' + ', oauth_signature="' + encodeURIComponent(signed_params.oauth_signature) + '"';
var headers = {
'Authorization': auth_str
};
var form_data = self.network.encode_multipart_formdata(
params, file, 'media[]', file_data);
$.extend(headers, form_data[0]);
self.network.do_request('POST', url, signed_params, headers, form_data[1] // body
, on_success, on_error);
},
self.update_with_media_filename = function update_with_media_filename(text, reply_to_id, filename, on_success, on_error) {
var url = self.upload_api_base + 'statuses/update_with_media.json';
var signed_params = self.oauth.form_signed_params(
url, self.oauth.access_token, 'POST', {},
true);
var params = {
'status': text,
'include_entities': '1'
};
if (reply_to_id) {
params['in_reply_to_status_id'] = reply_to_id;
}
$.extend(params, signed_params);
var auth_str = 'OAuth oauth_consumer_key="' + signed_params.oauth_consumer_key + '"' + ', oauth_signature_method="' + signed_params.oauth_signature_method + '"' + ', oauth_token="' + signed_params.oauth_token + '"' + ', oauth_timestamp="' + signed_params.oauth_timestamp + '"' + ', oauth_nonce="' + signed_params.oauth_nonce + '"' + ', oauth_version="' + signed_params.oauth_version + '"' + ', oauth_signature="' + encodeURIComponent(signed_params.oauth_signature) + '"';
var headers = {
'Authorization': auth_str
};
self.network.do_request('POST', url, params, headers, [['media', filename]], on_success, on_error);
};
self.retweet_status = function retweet_status(retweet_id, on_success) {
var url = self.api_base + 'statuses/retweet/' + retweet_id + '.json';
self.post(url, {},
on_success);
};
self.destroy_status = function destroy_status(retweet_id, on_success) {
var url = self.api_base + 'statuses/destroy/' + retweet_id + '.json';
self.post(url, {},
on_success);
};
self.new_direct_messages = function new_direct_messages(text, user_id, screen_name, on_success, on_error) {
var url = self.api_base + 'direct_messages/new.json';
var params = {
'text': text,
'screen_name': screen_name
};
if (user_id != null) params['user_id'] = user_id;
self.post(url, params, on_success, on_error);
};
self.destroy_direct_messages = function destroy_direct_messages(id, on_success) {
var url = self.api_base + 'direct_messages/destroy.json';
var params = {
'id': id,
'include_entities': '1'
};
self.post(url, params, on_success);
};
self.create_favorite = function create_favorite(fav_id, on_success) {
var url = self.api_base + 'favorites/create.json';
var params = {
'id': fav_id,
'include_entities': '1'
};
self.post(url, params, on_success);
};
self.destroy_favorite = function destroy_favorite(fav_id, on_success) {
var url = self.api_base + 'favorites/destroy.json';
var params = {
'id': fav_id,
'include_entities': '1'
};
self.post(url, params, on_success);
};
self.get_home_timeline = function get_home_timeline(since_id, max_id, count, on_success) {
var url = self.api_base + 'statuses/home_timeline.json';
var params = {
'include_entities': '1',
'page': '0',
'count': count
};
if (since_id != null) params['since_id'] = since_id;
if (max_id != null) params['max_id'] = max_id;
self.get(url, params, on_success);
return;
};
self.get_mentions = function get_mentions(since_id, max_id, count, on_success) {
var url = self.api_base + 'statuses/mentions.json';
var params = {
'include_entities': '1',
// 'include_rts': '1', // include_rts has been removed in API v1.1
'page': '0',
'count': count
};
if (since_id != null) params['since_id'] = since_id;
if (max_id != null) params['max_id'] = max_id;
self.get(url, params, on_success);
return;
};
self.get_favorites = function get_favorites(screen_name, page, on_success) {
var url = self.api_base + 'favorites.json';
var params = {
'screen_name': screen_name,
'include_entities': '1',
'page': page
};
self.get(url, params, on_success);
return;
};
self.get_trending_topics = function get_trending_topics(woeid, on_success) {
var url = self.api_base + 'trends/place.json';
var params = {
'id': woeid,
};
self.get(url, params, on_success);
return;
};
self.get_direct_messages = function get_direct_messages(since_id, max_id, count, on_success) {
var url = self.api_base + 'direct_messages.json';
var params = {
'include_entities': '1',
'page': '0',
'count': count
};
if (since_id != null) params['since_id'] = since_id;
if (max_id != null) params['max_id'] = max_id;
self.get(url, params, on_success);
return;
};
self.get_sent_direct_messages = function get_sent_direct_messages(since_id, max_id, count, on_success) {
var url = self.api_base + 'direct_messages/sent.json';
var params = {
'include_entities': '1',
'page': '0',
'count': count
};
if (since_id != null) params['since_id'] = since_id;
if (max_id != null) params['max_id'] = max_id;
self.get(url, params, on_success);
return;
};
self.get_retweeted_by_me = function get_retweeted_by_me(since_id, max_id, count, on_success) {
var url = self.api_base + '/statuses/public_timeline.json';
var params = {
'include_entities': '1',
'page': '0',
'count': count
};
if (since_id != null) params['since_id'] = since_id;
if (max_id != null) params['max_id'] = max_id;
self.get(url, params, on_success);
return;
// has been removed in API v1.1
};
self.get_retweeted_to_me = function get_retweeted_to_me(since_id, max_id, count, on_success) {
var url = self.api_base + '1/statuses/retweeted_to_me.json';
var params = {
'include_entities': '1',
'page': '0',
'count': count
};
if (since_id != null) params['since_id'] = since_id;
if (max_id != null) params['max_id'] = max_id;
self.get(url, params, on_success);
return;
// has been removed in API v1.1
};
self.get_retweets_of_me = function get_retweets_of_me(since_id, max_id, count, on_success) {
var url = self.api_base + 'statuses/retweets_of_me.json';
var params = {
'include_entities': '1',
'page': '0',
'count': count
};
if (since_id != null) params['since_id'] = since_id;
if (max_id != null) params['max_id'] = max_id;
self.get(url, params, on_success);
return;
};
self.get_retweeted_by_whom = function get_retweeted_by_whom(tweet_id, count, on_success) {
var url = self.api_base + 'statuses/retweets/' + tweet_id + '.json';
var params = {
'count': count
};
self.get(url, params, function(result, textStatus, xhr) {
console.log(result);
on_success(result, textStatus, xhr);
});
return;
};
self.get_user_timeline = function get_user_timeline(user_id, screen_name, since_id, max_id, count, on_success, on_error) {
var url = self.api_base + 'statuses/user_timeline.json';
var params = {
'include_entities': '1',
'include_rts': '1',
'page': '0',
'count': count
};
if (since_id != null) params['since_id'] = since_id;
if (max_id != null) params['max_id'] = max_id;
if (user_id != null) params['user_id'] = user_id;
if (screen_name != null) params['screen_name'] = screen_name;
self.get(url, params, on_success, on_error);
return;
};
self.show_status = function show_status(id, on_success, on_error) {
var url = self.api_base + 'statuses/show/' + id + '.json';
var params = {
'include_entities': '1'
};
self.get(url, params, on_success, on_error);
};
self.show_user = function show_user(screen_name, on_success, on_error) {
var url = self.api_base + 'users/show.json';
var params = {
'include_entities': '1',
'screen_name': screen_name
};
self.get(url, params, on_success, on_error);
};
self.search_user = function search_user(query, page, on_success, on_error) {
var url = self.api_base + 'users/search.json';
var params = {
'q': query,
'page': page,
'per_page': 20,
'include_entities': '1'
};
self.get(url, params, on_success, on_error);
};
self.get_user_friends = function get_user_friends(screen_name, cursor, on_success) {
var url = self.api_base + 'friends/list.json';
var params = {
'include_entities': '1',
'screen_name': screen_name,
'cursor': cursor
};
self.get(url, params, on_success);
};
self.get_user_followers = function get_user_followers(screen_name, cursor, on_success) {
var url = self.api_base + 'followers/list.json';
var params = {
'include_entities': '1',
'screen_name': screen_name,
'cursor': cursor
};
self.get(url, params, on_success);
};
self.get_user_friends_ids = function get_user_friends_ids(screen_name, cursor, on_success) {
var url = self.api_base + 'friends/ids.json';
var params = {
'screen_name': screen_name,
'cursor': cursor
};
self.get(url, params, on_success);
};
self.get_user_profile_image = function get_user_profile_image(screen_name, size) {
var url = self.api_base + '1/users/profile_image/twitter.json' + '?size=' + size + '&screen_name=' + screen_name + '&rnd=' + Math.random();
return url;
// has been removed in API v1.1
};
self.update_profile_image = function update_profile_image(file, file_data, on_success) {
var url = self.api_base + 'account/update_profile_image.json';
var signed_params = self.oauth.form_signed_params(
url, self.oauth.access_token, 'POST', {},
true);
var auth_str = 'OAuth oauth_consumer_key="' + signed_params.oauth_consumer_key + '"' + ', oauth_signature_method="' + signed_params.oauth_signature_method + '"' + ', oauth_token="' + signed_params.oauth_token + '"' + ', oauth_timestamp="' + signed_params.oauth_timestamp + '"' + ', oauth_nonce="' + signed_params.oauth_nonce + '"' + ', oauth_version="' + signed_params.oauth_version + '"' + ', oauth_signature="' + encodeURIComponent(signed_params.oauth_signature) + '"';
var headers = {
'Authorization': auth_str
};
var form_data = self.network.encode_multipart_formdata(
signed_params, file, 'image', file_data);
$.extend(headers, form_data[0]);
self.network.do_request('POST', url, signed_params, headers, form_data[1] // body
, on_success, null);
//self.post(url, params, on_success);
};
self.update_profile = function update_profile(name, website, location, description, on_success) {
var url = self.api_base + 'account/update_profile.json';
var params = {
'name': name,
'website': website,
'location': location,
'description': description
};
self.post(url, params, on_success);
};
self.exists_friendships = function exists_friendships(source, target, on_success) {
var url = self.api_base + '1/friendships/exists.json';
var params = {
'user_a': source,
'user_b': target
};
self.get(url, params, on_success);
// has been removed in API v1.1
// can use show_friendships instead
};
self.show_friendships = function show_friendships(source, target, on_success) {
var url = self.api_base + 'friendships/show.json';
var params = {
'source_screen_name': source,
'target_screen_name': target
};
self.get(url, params, on_success);
};
self.create_friendships = function create_friendships(screen_name, on_success) {
var url = self.api_base + 'friendships/create.json';
var params = {
'screen_name': screen_name,
'follow': 'true'
};
self.post(url, params, on_success);
};
self.destroy_friendships = function destroy_friendships(screen_name, on_success) {
var url = self.api_base + 'friendships/destroy.json';
var params = {
'screen_name': screen_name
};
self.post(url, params, on_success);
};
self.create_blocks = function create_blocks(screen_name, on_success) {
var url = self.api_base + 'blocks/create.json';
var params = {
'screen_name': screen_name,
'follow': 'true' // undocumented argument but kept
};
self.post(url, params, on_success);
};
self.destroy_blocks = function destroy_blocks(screen_name, on_success) {
var url = self.api_base + 'blocks/destroy.json';
var params = {
'screen_name': screen_name
};
self.post(url, params, on_success);
};
self.get_blocking_ids = function get_blocking_ids(cursor, on_success, on_error) {
var url = self.api_base + 'blocks/ids.json';
var params = {
'stringify_ids': true,
'cursor': cursor
};
self.get(url, params, on_success, on_error);
};
self.get_user_listed_lists = function get_listed_lists(screen_name, cursor, on_success) {
var url = self.api_base + 'lists/memberships.json';
var params = {
'screen_name': screen_name,
'cursor': cursor
};
self.get(url, params, on_success);
};
self.get_user_lists = function get_user_lists(screen_name, cursor, on_success) {
var url = self.api_base + 'lists/list.json';
var params = {
'screen_name': screen_name
//'cursor': cursor // cursor has been removed in API v1.1
};
self.get(url, params, on_success);
};
self.get_list_statuses = function get_list_statuses(owner_screen_name, slug, since_id, max_id, on_success, on_error) {
var url = self.api_base + 'lists/statuses.json';
var params = {
'include_entities': '1',
'include_rts': '1',
'owner_screen_name': owner_screen_name,
'slug': slug
};
if (since_id != null) params['since_id'] = since_id;
if (max_id != null) params['max_id'] = max_id;
self.get(url, params, on_success, on_error);
};
self.get_list_subscribers = function get_list_subscribers(owner_screen_name, slug, cursor, on_success) {
var url = self.api_base + 'lists/subscribers.json';
var params = {
'include_entities': '1',
'owner_screen_name': owner_screen_name,
'slug': slug,
'cursor': cursor
};
self.get(url, params, on_success);
};
self.get_list_members = function get_list_members(owner_screen_name, slug, cursor, on_success) {
var url = self.api_base + 'lists/members.json';
var params = {
'include_entities': '1',
'owner_screen_name': owner_screen_name,
'slug': slug,
'cursor': cursor
};
self.get(url, params, on_success);
};
self.create_list_member = function create_list_member(id, screen_name, on_success, on_error) {
var url = self.api_base + 'lists/members/create.json';
var params = {
'list_id': id,
'screen_name': screen_name
};
self.post(url, params, on_success);
};
self.destroy_list_member = function destroy_list_member(owner_screen_name, slug, screen_name, on_success) {
var url = self.api_base + 'lists/members/destroy.json';
var params = {
'owner_screen_name': owner_screen_name,
'slug': slug,
'screen_name': screen_name
};
self.post(url, params, on_success);
};
self.create_list_subscriber = function create_list_subscriber(owner_screen_name, slug, on_success) {
var url = self.api_base + 'lists/subscribers/create.json';
var params = {
'owner_screen_name': owner_screen_name,
'slug': slug
};
self.post(url, params, on_success);
};
self.destroy_list_subscriber = function destroy_list_subscriber(owner_screen_name, slug, on_success) {
var url = self.api_base + 'lists/subscribers/destroy.json';
var params = {
'owner_screen_name': owner_screen_name,
'slug': slug
};
self.post(url, params, on_success);
};
self.create_list = function create_list(slug, description, mode, on_success) {
var url = self.api_base + 'lists/create.json';
var params = {
'name': slug,
'mode': mode,
'description': description
};
self.post(url, params, on_success);
};
self.destroy_list = function destroy_list(owner_screen_name, slug, on_success) {
var url = self.api_base + 'lists/destroy.json';
var params = {
'owner_screen_name': owner_screen_name,
'slug': slug
};
self.post(url, params, on_success);
};
self.show_list = function show_list(owner_screen_name, slug, on_success, on_error) {
var url = self.api_base + 'lists/show.json';
var params = {
'owner_screen_name': owner_screen_name,
'slug': slug
};
self.get(url, params, on_success, on_error);
};
self.update_list = function update_list(owner_screen_name, slug, description, mode, on_success, on_error) {
var url = self.api_base + 'lists/update.json';
var params = {
'owner_screen_name': owner_screen_name,
'slug': slug,
'mode': mode,
'description': description
};
self.post(url, params, on_success, on_error);
};
self.verify = function verify(on_success, on_error) {
var url = self.api_base + 'account/verify_credentials.json';
self.get(url, {},
on_success, on_error);
};
self.create_saved_search = function create_saved_search(query, on_success, on_error) {
var url = self.api_base + 'saved_searches/create.json';
self.post(url, {
'query': query
},
on_success, on_error);
return;
};
self.destroy_saved_search = function create_saved_search(id, on_success, on_error) {
var url = self.api_base + 'saved_searches/destroy/' + id + '.json';
self.post(url, {},
on_success, on_error);
return;
};
self.get_saved_searches = function get_saved_searches(on_success, on_error) {
var url = self.api_base + 'saved_searches.json';
self.get(url, {},
on_success, on_error);
return;
};
//@TODO the two APIs is undocumented
self.get_activity_about_me = function get_activity_about_me(since_id, max_id, count, on_success) {
var url = 'https://api.twitter.com/i/' + 'activity/about_me.json';
var params = {
'include_entities': '1',
'count': count
};
if (since_id != null) params['since_id'] = since_id;
if (max_id != null) params['max_id'] = max_id;
self.get(url, params, on_success);
};
self.get_activity_by_friends = function get_activity_by_friends(since_id, max_id, count, on_success) {
var url = 'https://api.twitter.com/i/' + 'activity/by_friends.json';
var params = {
'include_entities': '1',
'count': count
};
if (since_id != null) params['since_id'] = since_id;
if (max_id != null) params['max_id'] = max_id;
self.get(url, params, on_success);
};
self.search = function search(query, page, since_id, max_id, on_success, on_error) {
var url = self.search_api_base2;
if (url == 'https://twitter.com/phoenix_search.phoenix') {
var params = {
'q': query
};
params['format'] = 'phoenix';
params['include_entities'] = 'true';
if (since_id != null) params['since_id'] = since_id;
if (max_id != null) params['max_id'] = max_id;
_page = [];
_page.push('rpp=100');
_page.push('q=' + encodeURI(query));
if (max_id != null) _page.push('max_id=' + max_id);
if (page != null) _page.push('page=' + page);
params['page'] = _page.join('&');
self.source = '';
self.get(url, params, on_success, on_error);
self.source = 'Hotot';
} else {
var params = {
'q': query
};
if (since_id != null) params['since_id'] = since_id;
if (max_id != null) params['max_id'] = max_id;
if (page != null) params['page'] = page;
self.source = '';
self.get(url, params, on_success, on_error);
self.source = 'Hotot';
}
};
self.abort_watch_user_streams = function abort_watch_user_streams() {};
self.watch_user_streams = function watch_user_streams(callback) {
if (!self.use_oauth || watch_user_streams.is_running || watch_user_streams.disable || self.api_base.indexOf('https://api.twitter.com/') < 0) {
return;
}
if (!watch_user_streams.times) {
watch_user_streams.times = 0;
}
watch_user_streams.times += 1;
watch_user_streams.is_running = true;
watch_user_streams.last_text_length = 0;
var empty_tester = new RegExp('^[\n\r\t ]*$', 'g');
var url = 'https://userstream.twitter.com/2/user.json';
var sign_url = url;
var params = {
'with': 'followings'
};
// since some browsers trigger readystatechange rather randomly we need
// to reassemble broken stream responses
// the var is used to store the intermediate response
var interrupted_response = ''
var signed_params = self.oauth.form_signed_params(
sign_url, self.oauth.access_token, 'GET', params, false);
url = url + '?' + signed_params;
params = {};
hotot_log('Streams Open', removeTokensFromUrl(url));
var xhr = new XMLHttpRequest();
watch_user_streams.xhr = xhr;
xhr.open('GET', url, true);
xhr.setRequestHeader('X-User-Agent', 'Hotot');
try {
xhr.setRequestHeader('User-Agent', 'Hotot');
} catch (e) {
}
xhr.createAt = new Date().toLocaleString();
xhr.onabort = xhr.onerror = function() {
if (xhr.status == 401 || xhr.status == 407) {
hotot_log('Streams XHR', 'OAuth error');
watch_user_streams.disable = true;
}
if (xhr.status == 420) {
hotot_log('Streams XHR', '420 error');
watch_user_streams.is_running = false;
}
watch_user_streams.is_running = false;
hotot_log('Streams Exit', xhr.createAt + ' -> ' + new Date().toLocaleString());
}
xhr.onreadystatechange = function() {
if (xhr.readyState === 2 && xhr.status === 200) {
hotot_log('Streams Start', 'Connected');
} else if (xhr.readyState === 3) {
// Receiving
var newText = xhr.responseText.substr(watch_user_streams.last_text_length);
watch_user_streams.last_text_length = xhr.responseText.length;
// limit xhr.responseText length & abort
if (xhr.responseText.length > 500000) {
hotot_log('Streams Rec', xhr.responseText.length);
setTimeout(function() {
xhr.abort();
},
100);
}
// empty reply, twitter use newline to keep stream alive
if (empty_tester.test(newText)) {
hotot_log('Streams XHR', 'Got nothing useful');
return;
}
if (callback) {
// @TODO the procedure to process tweets can be simpler.
// because all json objects are complete.
// prepend the unprocessed data from the
// interrupted_response
newText = interrupted_response + newText;
interrupted_response = ''
var lines = newText.split(/[\n\r]/g);
for (var i = 0; i < lines.length; i += 1) {
var line = lines[i].split(/({[^\0]+})/gm);
for (var j = 0; j < line.length; j += 1) {
if (!empty_tester.test(line[j])) {
try {
ret = JSON.parse(line[j]);
} catch(e) {
// The log is disabled to not trigger
// irritations with users
// hotot_log('Streams XHR', e.message + '\n' + line);
// store the interrupted response for later
// processing
interrupted_response = newText;
// do not quit streaming
//return;
}
try {
callback(ret);
} catch(e) {
console.log('Streams callback: ' + e.message + '\n' + line);
return;
}
}
}
}
}
} else if (xhr.readyState === 4) {
hotot_log('Streams End', 'Connection completed');
}
}
xhr.send(null);
self.abort_watch_user_streams = function() {
xhr.abort();
}
};
self.add_streaming_filter = function add_streaming_filter(filter, callback) {
var xhr = new XMLHttpRequest();
xhr.open('POST', 'http://stream.twitter.com/1/statuses/filter.json?track=', true);
xhr.setRequestHeader('Authorization', encodeBase64(':'));
xhr.onreadystatechange = function() {
if (xhr.readyState == 3) {
var obj = null;
try {
obj = JSON.parse(xhr.responseText)
} catch(e) {}
if (obj) {
hotot_log('Streaming', obj.id_str + "," + obj.user.screen_name + ":" + obj.text)
}
}
}
params = [];
for (var k in filter) {
params.push(k + '=' + encodeURIComponent(filter[k]));
}
xhr.send(params.join('&'));
};
};
lib.twitter.Client = TwitterClient;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment